Page MenuHomeFreeBSD

D4111.id10146.diff
No OneTemporary

D4111.id10146.diff

Index: sys/net/if.c
===================================================================
--- sys/net/if.c
+++ sys/net/if.c
@@ -126,7 +126,7 @@
void (*bridge_linkstate_p)(struct ifnet *ifp);
void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
-void (*lagg_linkstate_p)(struct ifnet *ifp, int state);
+void (*lagg_linkstate_p)(struct ifnet *ifp);
/* These are external hooks for CARP. */
void (*carp_linkstate_p)(struct ifnet *ifp);
void (*carp_demote_adj_p)(int, char *);
@@ -1980,6 +1980,8 @@
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
+ if (ifp->if_lagg)
+ (*lagg_linkstate_p)(ifp);
rt_ifmsg(ifp);
}
@@ -2001,6 +2003,8 @@
pfctlinput(PRC_IFUP, ifa->ifa_addr);
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
+ if (ifp->if_lagg)
+ (*lagg_linkstate_p)(ifp);
rt_ifmsg(ifp);
#ifdef INET6
in6_if_up(ifp);
@@ -2015,17 +2019,27 @@
int (*vlan_setcookie_p)(struct ifnet *, void *);
void *(*vlan_cookie_p)(struct ifnet *);
+void
+if_link_state_change(struct ifnet *ifp, int link_state)
+{
+
+ return if_link_state_change_cond(ifp, link_state, 0);
+}
+
/*
* Handle a change in the interface link state. To avoid LORs
* between driver lock and upper layer locks, as well as possible
* recursions, we post event to taskqueue, and all job
* is done in static do_link_state_change().
+ *
+ * If the current link state matches link_state and force isn't
+ * specified no action is taken.
*/
void
-if_link_state_change(struct ifnet *ifp, int link_state)
+if_link_state_change_cond(struct ifnet *ifp, int link_state, int force)
{
- /* Return if state hasn't changed. */
- if (ifp->if_link_state == link_state)
+
+ if (ifp->if_link_state == link_state && !force)
return;
ifp->if_link_state = link_state;
@@ -2053,7 +2067,7 @@
if (ifp->if_bridge)
(*bridge_linkstate_p)(ifp);
if (ifp->if_lagg)
- (*lagg_linkstate_p)(ifp, link_state);
+ (*lagg_linkstate_p)(ifp);
if (IS_DEFAULT_VNET(curvnet))
devctl_notify("IFNET", ifp->if_xname,
Index: sys/net/if_lagg.h
===================================================================
--- sys/net/if_lagg.h
+++ sys/net/if_lagg.h
@@ -281,7 +281,7 @@
#define LAGG_UNLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_UNLOCKED)
extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
-extern void (*lagg_linkstate_p)(struct ifnet *, int );
+extern void (*lagg_linkstate_p)(struct ifnet *);
int lagg_enqueue(struct ifnet *, struct mbuf *);
Index: sys/net/if_lagg.c
===================================================================
--- sys/net/if_lagg.c
+++ sys/net/if_lagg.c
@@ -106,7 +106,7 @@
static int lagg_port_destroy(struct lagg_port *, int);
static struct mbuf *lagg_input(struct ifnet *, struct mbuf *);
static void lagg_linkstate(struct lagg_softc *);
-static void lagg_port_state(struct ifnet *, int);
+static void lagg_port_state(struct ifnet *);
static int lagg_port_ioctl(struct ifnet *, u_long, caddr_t);
static int lagg_port_output(struct ifnet *, struct mbuf *,
const struct sockaddr *, struct route *);
@@ -1128,7 +1128,7 @@
LAGG_WUNLOCK(sc);
}
-static void
+static __noinline void
lagg_port2req(struct lagg_port *lp, struct lagg_reqport *rp)
{
struct lagg_softc *sc = lp->lp_softc;
@@ -1779,7 +1779,12 @@
break;
}
}
- if_link_state_change(sc->sc_ifp, new_link);
+
+ /*
+ * Force state change to ensure ifnet_link_event is generated allowing
+ * protocols to notify other nodes of potential address move.
+ */
+ if_link_state_change_cond(sc->sc_ifp, new_link, 1);
/* Update if_baudrate to reflect the max possible speed */
switch (sc->sc_proto) {
@@ -1802,7 +1807,7 @@
}
static void
-lagg_port_state(struct ifnet *ifp, int state)
+lagg_port_state(struct ifnet *ifp)
{
struct lagg_port *lp = (struct lagg_port *)ifp->if_lagg;
struct lagg_softc *sc = NULL;
@@ -1818,7 +1823,7 @@
LAGG_WUNLOCK(sc);
}
-struct lagg_port *
+static struct lagg_port *
lagg_link_active(struct lagg_softc *sc, struct lagg_port *lp)
{
struct lagg_port *lp_next, *rval = NULL;
Index: sys/net/if_var.h
===================================================================
--- sys/net/if_var.h
+++ sys/net/if_var.h
@@ -492,6 +492,7 @@
void if_free(struct ifnet *);
void if_initname(struct ifnet *, const char *, int);
void if_link_state_change(struct ifnet *, int);
+void if_link_state_change_cond(struct ifnet *, int, int);
int if_printf(struct ifnet *, const char *, ...) __printflike(2, 3);
void if_ref(struct ifnet *);
void if_rele(struct ifnet *);
Index: sys/netinet/if_ether.h
===================================================================
--- sys/netinet/if_ether.h
+++ sys/netinet/if_ether.h
@@ -119,7 +119,8 @@
void arprequest(struct ifnet *, const struct in_addr *,
const struct in_addr *, u_char *);
void arp_ifinit(struct ifnet *, struct ifaddr *);
-void arp_announce_ifaddr(struct ifnet *, struct in_addr addr, u_char *);
+void arp_announce(struct ifnet *);
+void arp_announce_ifaddr(struct ifnet *, const struct in_addr *addr, u_char *);
#endif
#endif
Index: sys/netinet/if_ether.c
===================================================================
--- sys/netinet/if_ether.c
+++ sys/netinet/if_ether.c
@@ -145,6 +145,7 @@
static void arp_iflladdr(void *arg __unused, struct ifnet *ifp);
static eventhandler_tag iflladdr_tag;
+static eventhandler_tag ifnet_link_event_tag;
static const struct netisr_handler arp_nh = {
.nh_name = "arp",
@@ -1144,43 +1145,96 @@
if (ntohl(dst_in->sin_addr.s_addr) == INADDR_ANY)
return;
- arp_announce_ifaddr(ifp, dst_in->sin_addr, IF_LLADDR(ifp));
+ arp_announce_ifaddr(ifp, &dst_in->sin_addr, IF_LLADDR(ifp));
arp_add_ifa_lle(ifp, dst);
}
void
-arp_announce_ifaddr(struct ifnet *ifp, struct in_addr addr, u_char *enaddr)
+arp_announce_ifaddr(struct ifnet *ifp, const struct in_addr *addr, u_char *enaddr)
{
- if (ntohl(addr.s_addr) != INADDR_ANY)
- arprequest(ifp, &addr, &addr, enaddr);
+ if (ntohl(addr->s_addr) != INADDR_ANY)
+ arprequest(ifp, addr, addr, enaddr);
}
/*
- * Sends gratuitous ARPs for each ifaddr to notify other
- * nodes about the address change.
+ * Send gratuitous ARPs for all interfaces addresses to notify other nodes of
+ * changes.
+ *
+ * This is a noop if the interface isn't up or has been flagged for no ARP.
*/
-static __noinline void
-arp_handle_ifllchange(struct ifnet *ifp)
+void __noinline
+arp_announce(struct ifnet *ifp)
{
+ int i, cnt, entries;
+ u_char *lladdr;
struct ifaddr *ifa;
+ struct in_addr *addr, *head;
+
+ if (!(ifp->if_flags & IFF_UP) || (ifp->if_flags & IFF_NOARP))
+ return;
+
+ entries = 8;
+ cnt = 0;
+ head = malloc(sizeof(*addr) * entries, M_TEMP, M_NOWAIT);
+ if (head == NULL) {
+ log(LOG_INFO, "arp_announce: malloc %d entries failed\n",
+ entries);
+ return;
+ }
+ /* Take a copy then process to avoid locking issues. */
+ IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- if (ifa->ifa_addr->sa_family == AF_INET)
- arp_ifinit(ifp, ifa);
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+
+ if (cnt == entries) {
+ addr = (struct in_addr *)realloc(head, sizeof(*addr) *
+ (entries + 8), M_TEMP, M_NOWAIT);
+ if (addr == NULL) {
+ log(LOG_INFO, "arp_announce: realloc to %d "
+ "entries failed\n", entries + 8);
+ /* Process what we have. */
+ break;
+ }
+ entries += 8;
+ head = addr;
+ }
+
+ addr = head + cnt;
+ bcopy(IFA_IN(ifa), addr, sizeof(*addr));
+ cnt++;
}
+ IF_ADDR_RUNLOCK(ifp);
+
+ lladdr = IF_LLADDR(ifp);
+ for (i = 0; i < cnt; i++) {
+ arp_announce_ifaddr(ifp, head + i, lladdr);
+ }
+ free(head, M_TEMP);
+}
+
+/*
+ * A handler for interface linkstate change events.
+ */
+static void
+arp_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int linkstate)
+{
+
+ if (linkstate == LINK_STATE_UP)
+ arp_announce(ifp);
}
/*
- * A handler for interface link layer address change event.
+ * A handler for interface link layer address change events.
*/
static __noinline void
arp_iflladdr(void *arg __unused, struct ifnet *ifp)
{
- if ((ifp->if_flags & IFF_UP) != 0)
- arp_handle_ifllchange(ifp);
+ arp_announce(ifp);
}
static void
@@ -1188,8 +1242,12 @@
{
netisr_register(&arp_nh);
- if (IS_DEFAULT_VNET(curvnet))
+
+ if (IS_DEFAULT_VNET(curvnet)) {
iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
arp_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
+ ifnet_link_event_tag = EVENTHANDLER_REGISTER(ifnet_link_event,
+ arp_ifnet_link_event, 0, EVENTHANDLER_PRI_ANY);
+ }
}
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);
Index: sys/netinet/in_var.h
===================================================================
--- sys/netinet/in_var.h
+++ sys/netinet/in_var.h
@@ -129,6 +129,9 @@
#define IN_IFADDR_WLOCK_ASSERT() rm_assert(&in_ifaddr_lock, RA_WLOCKED)
#define IN_IFADDR_WUNLOCK() rm_wunlock(&in_ifaddr_lock)
+#define IFA_IN(ifa) \
+ (&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr)
+
/*
* Macro for finding the internet address structure (in_ifaddr)
* corresponding to one of our IP addresses (in_addr).
Index: sys/netinet/ip_carp.c
===================================================================
--- sys/netinet/ip_carp.c
+++ sys/netinet/ip_carp.c
@@ -1009,13 +1009,12 @@
carp_send_arp(struct carp_softc *sc)
{
struct ifaddr *ifa;
- struct in_addr addr;
CARP_FOREACH_IFA(sc, ifa) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
- addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
- arp_announce_ifaddr(sc->sc_carpdev, addr, LLADDR(&sc->sc_addr));
+ arp_announce_ifaddr(sc->sc_carpdev, IFA_IN(ifa),
+ LLADDR(&sc->sc_addr));
}
}
@@ -1037,18 +1036,16 @@
static void
carp_send_na(struct carp_softc *sc)
{
- static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
struct ifaddr *ifa;
- struct in6_addr *in6;
CARP_FOREACH_IFA(sc, ifa) {
- if (ifa->ifa_addr->sa_family != AF_INET6)
+ if (ifa->ifa_addr->sa_family != AF_INET6 ||
+ IFA_ND6_NA_UNSOLICITED_SKIP(ifa))
continue;
- in6 = IFA_IN6(ifa);
- nd6_na_output(sc->sc_carpdev, &mcast, in6,
- ND_NA_FLAG_OVERRIDE, 1, NULL);
- DELAY(1000); /* XXX */
+ nd6_na_output_unsolicited_addr(sc->sc_carpdev, IFA_IN6(ifa),
+ IFA_ND6_NA_BASE_FLAGS(sc->sc_carpdev, ifa));
+ nd6_na_unsolicited_addr_delay(ifa);
}
}
Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -113,7 +113,7 @@
#define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix)
/*
- * Definitions of some costant IP6 addresses.
+ * Definitions of some constant IP6 addresses.
*/
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
Index: sys/netinet6/in6_var.h
===================================================================
--- sys/netinet6/in6_var.h
+++ sys/netinet6/in6_var.h
@@ -399,6 +399,16 @@
#define IA6_SIN6(ia) (&((ia)->ia_addr))
#define IA6_DSTSIN6(ia) (&((ia)->ia_dstaddr))
#define IFA_IN6(x) (&((struct sockaddr_in6 *)((x)->ifa_addr))->sin6_addr)
+#define IFA_IN6_FLAGS(ifa) ((struct in6_ifaddr *)ifa)->ia6_flags
+#define IFA_ND6_NA_BASE_FLAGS(ifp, ifa) \
+ (IFA_IN6_FLAGS(ifa) & IN6_IFF_ANYCAST ? 0 : ND_NA_FLAG_OVERRIDE) | \
+ ((V_ip6_forwarding && !(ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && \
+ V_ip6_norbit_raif)) ? ND_NA_FLAG_ROUTER : 0)
+#define IFA_ND6_NA_UNSOLICITED_SKIP(ifa) \
+ (IFA_IN6_FLAGS(ifa) & (IN6_IFF_DUPLICATED | IN6_IFF_DEPRECATED | \
+ IN6_IFF_TENTATIVE)) != 0
+#define IN6_MAX_ANYCAST_DELAY_TIME_MS 1000000
+#define IN6_BROADCAST_DELAY_TIME_MS 1000
#define IFA_DSTIN6(x) (&((struct sockaddr_in6 *)((x)->ifa_dstaddr))->sin6_addr)
#define IFPR_IN6(x) (&((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr)
Index: sys/netinet6/nd6.h
===================================================================
--- sys/netinet6/nd6.h
+++ sys/netinet6/nd6.h
@@ -398,6 +398,10 @@
#ifdef VIMAGE
void nd6_destroy(void);
#endif
+void nd6_na_output_unsolicited(struct ifnet *);
+void nd6_na_output_unsolicited_addr(struct ifnet *, const struct in6_addr *,
+ u_long);
+int nd6_na_unsolicited_addr_delay(struct ifaddr *);
struct nd_ifinfo *nd6_ifattach(struct ifnet *);
void nd6_ifdetach(struct nd_ifinfo *);
int nd6_is_addr_neighbor(const struct sockaddr_in6 *, struct ifnet *);
Index: sys/netinet6/nd6.c
===================================================================
--- sys/netinet6/nd6.c
+++ sys/netinet6/nd6.c
@@ -38,6 +38,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/callout.h>
+#include <sys/random.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
@@ -112,6 +113,7 @@
#endif
static eventhandler_tag lle_event_eh;
+static eventhandler_tag ifnet_link_event_eh;
/* for debugging? */
#if 0
@@ -196,6 +198,13 @@
type == RTM_ADD ? RTF_UP: 0), 0, RT_DEFAULT_FIB);
}
+static void
+nd6_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int linkstate)
+{
+
+ if (linkstate == LINK_STATE_UP)
+ nd6_na_output_unsolicited(ifp);
+}
void
nd6_init(void)
{
@@ -211,9 +220,12 @@
nd6_slowtimo, curvnet);
nd6_dad_init();
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
lle_event_eh = EVENTHANDLER_REGISTER(lle_event, nd6_lle_event,
NULL, EVENTHANDLER_PRI_ANY);
+ ifnet_link_event_eh = EVENTHANDLER_REGISTER(ifnet_link_event,
+ nd6_ifnet_link_event, NULL, EVENTHANDLER_PRI_ANY);
+ }
}
#ifdef VIMAGE
@@ -223,8 +235,10 @@
callout_drain(&V_nd6_slowtimo_ch);
callout_drain(&V_nd6_timer_ch);
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh);
+ EVENTHANDLER_DEREGISTER(ifnet_link_event, ifnet_link_event_eh);
+ }
}
#endif
Index: sys/netinet6/nd6_nbr.c
===================================================================
--- sys/netinet6/nd6_nbr.c
+++ sys/netinet6/nd6_nbr.c
@@ -124,20 +124,16 @@
struct in6_addr saddr6 = ip6->ip6_src;
struct in6_addr daddr6 = ip6->ip6_dst;
struct in6_addr taddr6;
- struct in6_addr myaddr6;
char *lladdr = NULL;
struct ifaddr *ifa = NULL;
+ u_long flags;
int lladdrlen = 0;
- int anycast = 0, proxy = 0, tentative = 0;
+ int proxy = 0;
int tlladdr;
- int rflag;
union nd_opts ndopts;
struct sockaddr_dl proxydl;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
- rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0;
- if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif)
- rflag = 0;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, icmp6len,);
nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
@@ -229,10 +225,7 @@
* In implementation, we add target link-layer address by default.
* We do not add one in MUST NOT cases.
*/
- if (!IN6_IS_ADDR_MULTICAST(&daddr6))
- tlladdr = 0;
- else
- tlladdr = 1;
+ tlladdr = !IN6_IS_ADDR_MULTICAST(&daddr6);
/*
* Target address (taddr6) must be either:
@@ -289,9 +282,6 @@
*/
goto freeit;
}
- myaddr6 = *IFA_IN6(ifa);
- anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
- tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
goto freeit;
@@ -303,7 +293,7 @@
goto bad;
}
- if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
+ if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &saddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
ip6_sprintf(ip6bufs, &saddr6)));
goto freeit;
@@ -321,7 +311,7 @@
*
* The processing is defined in RFC 2462.
*/
- if (tentative) {
+ if (IFA_IN6_FLAGS(ifa) & IN6_IFF_TENTATIVE) {
/*
* If source address is unspecified address, it is for
* duplicate address detection.
@@ -335,6 +325,10 @@
goto freeit;
}
+ flags = IFA_ND6_NA_BASE_FLAGS(ifp, ifa);
+ if (proxy || !tlladdr)
+ flags &= ~ND_NA_FLAG_OVERRIDE;
+
/*
* If the source address is unspecified address, entries must not
* be created or updated.
@@ -349,20 +343,16 @@
in6_all = in6addr_linklocal_allnodes;
if (in6_setscope(&in6_all, ifp, NULL) != 0)
goto bad;
- nd6_na_output_fib(ifp, &in6_all, &taddr6,
- ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
- M_GETFIB(m));
+ nd6_na_output_fib(ifp, &in6_all, &taddr6, flags, tlladdr,
+ proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
goto freeit;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
ND_NEIGHBOR_SOLICIT, 0);
- nd6_na_output_fib(ifp, &saddr6, &taddr6,
- ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- rflag | ND_NA_FLAG_SOLICITED, tlladdr,
- proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
+ nd6_na_output_fib(ifp, &saddr6, &taddr6, flags | ND_NA_FLAG_SOLICITED,
+ tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
freeit:
if (ifa != NULL)
ifa_free(ifa);
@@ -1589,3 +1579,99 @@
nd6_dad_rele(dp);
}
}
+
+/*
+ * Send unsolicited neighbor advertisements for all interface addresses to
+ * notify other nodes of changes.
+ *
+ * This is a noop if the interface isn't up.
+ */
+void __noinline
+nd6_na_output_unsolicited(struct ifnet *ifp)
+{
+ int i, cnt, entries;
+ struct ifaddr *ifa;
+ struct ann {
+ struct in6_addr addr;
+ u_long flags;
+ int delay;
+ } *ann1, *head;
+
+ if (!(ifp->if_flags & IFF_UP))
+ return;
+
+ entries = 8;
+ cnt = 0;
+ head = malloc(sizeof(struct ann) * entries, M_TEMP, M_WAITOK);
+
+ /* Take a copy then process to avoid locking issues. */
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6 ||
+ IFA_ND6_NA_UNSOLICITED_SKIP(ifa))
+ continue;
+
+ if (cnt == entries) {
+ ann1 = (struct ann*)realloc(head, sizeof(struct ann) *
+ (entries + 8), M_TEMP, M_NOWAIT);
+ if (ann1 == NULL) {
+ log(LOG_INFO, "nd6_announce: realloc to %d "
+ "entries failed\n", entries + 8);
+ /* Process what we have. */
+ break;
+ }
+ entries += 8;
+ head = ann1;
+ }
+
+ ann1 = head + cnt;
+ bcopy(IFA_IN6(ifa), &ann1->addr, sizeof(ann1->addr));
+ ann1->flags = IFA_ND6_NA_BASE_FLAGS(ifp, ifa);
+ ann1->delay = nd6_na_unsolicited_addr_delay(ifa);
+ cnt++;
+ }
+ IF_ADDR_RUNLOCK(ifp);
+
+ for (i = 0; i < cnt;) {
+ ann1 = head + i;
+ nd6_na_output_unsolicited_addr(ifp, &ann1->addr, ann1->flags);
+ i++;
+ if (i == cnt)
+ break;
+ DELAY(ann1->delay);
+ }
+ free(head, M_TEMP);
+}
+
+/*
+ * Return the delay required for announcements of the address as per RFC 4861.
+ */
+int
+nd6_na_unsolicited_addr_delay(struct ifaddr *ifa)
+{
+
+ if (IFA_IN6_FLAGS(ifa) & IN6_IFF_ANYCAST) {
+ /*
+ * Random value between 0 and MAX_ANYCAST_DELAY_TIME
+ * as per section 7.2.7.
+ */
+ return (random() % IN6_MAX_ANYCAST_DELAY_TIME_MS);
+ }
+
+ /* Small delay as per section 7.2.6. */
+ return (IN6_BROADCAST_DELAY_TIME_MS);
+}
+
+/*
+ * Send an unsolicited neighbor advertisement for an address to notify other
+ * nodes of changes.
+ */
+void
+nd6_na_output_unsolicited_addr(struct ifnet *ifp, const struct in6_addr *addr,
+ u_long flags)
+{
+
+ nd6_na_output(ifp, &in6addr_linklocal_allnodes, addr, flags, 1, NULL);
+}
+
+

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 16, 4:36 AM (11 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28766857
Default Alt Text
D4111.id10146.diff (18 KB)

Event Timeline