Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/nd6_nbr.c
| Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
| static void nd6_dad_duplicated(struct ifaddr *, struct dadq *); | static void nd6_dad_duplicated(struct ifaddr *, struct dadq *); | ||||
| static void nd6_dad_ns_output(struct dadq *); | static void nd6_dad_ns_output(struct dadq *); | ||||
| static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *); | static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *); | ||||
| static void nd6_dad_na_input(struct ifaddr *); | static void nd6_dad_na_input(struct ifaddr *); | ||||
| static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *, | static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *, | ||||
| const struct in6_addr *, u_long, int, struct sockaddr *, u_int); | const struct in6_addr *, u_long, int, struct sockaddr *, u_int); | ||||
| static void nd6_ns_output_fib(struct ifnet *, const struct in6_addr *, | static void nd6_ns_output_fib(struct ifnet *, const struct in6_addr *, | ||||
| const struct in6_addr *, const struct in6_addr *, uint8_t *, u_int); | const struct in6_addr *, const struct in6_addr *, uint8_t *, u_int); | ||||
| static void nd6_queue_add(struct ifaddr *, struct in6_addr *, int, uint32_t); | static void nd6_queue_add(struct ifaddr *, struct in6_addr *, | ||||
| struct in6_addr *, struct sockaddr_dl *, int, uint32_t); | |||||
| static struct ifaddr *nd6_proxy_fill_sdl(struct ifnet *, | static struct ifaddr *nd6_proxy_fill_sdl(struct ifnet *, | ||||
| const struct in6_addr *, struct sockaddr_dl *); | const struct in6_addr *, struct sockaddr_dl *); | ||||
| VNET_DEFINE_STATIC(int, dad_enhanced) = 1; | VNET_DEFINE_STATIC(int, dad_enhanced) = 1; | ||||
| #define V_dad_enhanced VNET(dad_enhanced) | #define V_dad_enhanced VNET(dad_enhanced) | ||||
| SYSCTL_DECL(_net_inet6_ip6); | SYSCTL_DECL(_net_inet6_ip6); | ||||
| Show All 9 Lines | |||||
| #define V_nd6_onlink_ns_rfc4861 VNET(nd6_onlink_ns_rfc4861) | #define V_nd6_onlink_ns_rfc4861 VNET(nd6_onlink_ns_rfc4861) | ||||
| SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_ONLINKNSRFC4861, | SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_ONLINKNSRFC4861, | ||||
| nd6_onlink_ns_rfc4861, CTLFLAG_VNET | CTLFLAG_RW, | nd6_onlink_ns_rfc4861, CTLFLAG_VNET | CTLFLAG_RW, | ||||
| &VNET_NAME(nd6_onlink_ns_rfc4861), 0, | &VNET_NAME(nd6_onlink_ns_rfc4861), 0, | ||||
| "Accept 'on-link' ICMPv6 NS messages in compliance with RFC 4861"); | "Accept 'on-link' ICMPv6 NS messages in compliance with RFC 4861"); | ||||
| struct nd_queue { | struct nd_queue { | ||||
| TAILQ_ENTRY(nd_queue) ndq_list; | TAILQ_ENTRY(nd_queue) ndq_list; | ||||
| struct ifaddr *ndq_ifa; | struct ifaddr *ndq_ifa; | ||||
| struct in6_addr ndq_daddr; | struct in6_addr ndq_daddr; | ||||
| struct in6_addr ndq_taddr; | |||||
| struct sockaddr_dl ndq_sdl; | |||||
| uint32_t ndq_flags; | uint32_t ndq_flags; | ||||
| struct callout ndq_callout; | struct callout ndq_callout; | ||||
| }; | }; | ||||
| /* | /* | ||||
| * Input a Neighbor Solicitation Message. | * Input a Neighbor Solicitation Message. | ||||
| * | * | ||||
| * Based on RFC 2461 | * Based on RFC 2461 | ||||
| * Based on RFC 2462 (duplicate address detection) | * Based on RFC 2462 (duplicate address detection) | ||||
| */ | */ | ||||
| void | void | ||||
| nd6_ns_input(struct mbuf *m, int off, int icmp6len) | nd6_ns_input(struct mbuf *m, int off, int icmp6len) | ||||
| { | { | ||||
| struct ifnet *ifp; | struct ifnet *ifp; | ||||
| struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
| struct nd_neighbor_solicit *nd_ns; | struct nd_neighbor_solicit *nd_ns; | ||||
| struct in6_addr daddr6, myaddr6, saddr6, taddr6; | struct in6_addr daddr6, myaddr6, saddr6, taddr6; | ||||
| struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
| struct sockaddr_dl proxydl; | struct sockaddr_dl proxydl; | ||||
| union nd_opts ndopts; | union nd_opts ndopts; | ||||
| char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; | char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; | ||||
| char *lladdr; | char *lladdr; | ||||
| int anycast, lladdrlen, proxy, rflag, tentative, tlladdr; | int lladdrlen, rflag, tentative, tlladdr; | ||||
| uint32_t dflags; | |||||
| ifa = NULL; | ifa = NULL; | ||||
| /* RFC 6980: Nodes MUST silently ignore fragments */ | /* RFC 6980: Nodes MUST silently ignore fragments */ | ||||
| if(m->m_flags & M_FRAGMENTED) | if(m->m_flags & M_FRAGMENTED) | ||||
| goto freeit; | goto freeit; | ||||
| ifp = m->m_pkthdr.rcvif; | ifp = m->m_pkthdr.rcvif; | ||||
| ▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | nd6_ns_input(struct mbuf *m, int off, int icmp6len) | ||||
| if (ifp->if_carp) { | if (ifp->if_carp) { | ||||
| ifa = (*carp_iamatch6_p)(ifp, &taddr6); | ifa = (*carp_iamatch6_p)(ifp, &taddr6); | ||||
| if (ifa != NULL) | if (ifa != NULL) | ||||
| tlladdr |= ND6_NA_CARP_MASTER; | tlladdr |= ND6_NA_CARP_MASTER; | ||||
| } else | } else | ||||
| ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); | ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); | ||||
| /* (2) check. */ | /* (2) check. */ | ||||
| proxy = 0; | dflags = 0; | ||||
| if (ifa == NULL) { | if (ifa == NULL) { | ||||
| if ((ifa = nd6_proxy_fill_sdl(ifp, &taddr6, &proxydl)) != NULL) | if ((ifa = nd6_proxy_fill_sdl(ifp, &taddr6, &proxydl)) != NULL) | ||||
pouria: This line here.
Since proxy address don't have a local `ifa`, they get a link-local address to… | |||||
| proxy = 1; | dflags |= ND6_QUEUE_FLAG_PROXY; | ||||
| } | } | ||||
| if (ifa == NULL) { | if (ifa == NULL) { | ||||
| /* | /* | ||||
| * We've got an NS packet, and we don't have that address | * We've got an NS packet, and we don't have that address | ||||
| * assigned for us. We MUST silently ignore it. | * assigned for us. We MUST silently ignore it. | ||||
| * See RFC2461 7.2.3. | * See RFC2461 7.2.3. | ||||
| */ | */ | ||||
| goto freeit; | goto freeit; | ||||
| } | } | ||||
| if ((((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) != 0) | |||||
| dflags |= ND6_QUEUE_FLAG_ANYCAST; | |||||
| myaddr6 = *IFA_IN6(ifa); | myaddr6 = *IFA_IN6(ifa); | ||||
| anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; | |||||
| tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; | tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; | ||||
| if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) | ||||
| goto freeit; | goto freeit; | ||||
| if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { | if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { | ||||
| nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " | nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " | ||||
| "(if %d, NS packet %d)\n", | "(if %d, NS packet %d)\n", | ||||
| ip6_sprintf(ip6bufs, &taddr6), | ip6_sprintf(ip6bufs, &taddr6), | ||||
| Show All 34 Lines | nd6_ns_input(struct mbuf *m, int off, int icmp6len) | ||||
| } | } | ||||
| /* | /* | ||||
| * If the Target Address is either an anycast address or a unicast | * If the Target Address is either an anycast address or a unicast | ||||
| * address for which the node is providing proxy service, or the Target | * address for which the node is providing proxy service, or the Target | ||||
| * Link-Layer Address option is not included, the Override flag SHOULD | * Link-Layer Address option is not included, the Override flag SHOULD | ||||
| * be set to zero. Otherwise, the Override flag SHOULD be set to one. | * be set to zero. Otherwise, the Override flag SHOULD be set to one. | ||||
| */ | */ | ||||
| if (anycast == 0 && proxy == 0 && (tlladdr & ND6_NA_OPT_LLA) != 0) | if (dflags == 0 && (tlladdr & ND6_NA_OPT_LLA) != 0) | ||||
| rflag |= ND_NA_FLAG_OVERRIDE; | rflag |= ND_NA_FLAG_OVERRIDE; | ||||
| /* | /* | ||||
| * If the source address is unspecified address, entries must not | * If the source address is unspecified address, entries must not | ||||
| * be created or updated. | * be created or updated. | ||||
| * It looks that sender is performing DAD. nd6_na_output() will | * It looks that sender is performing DAD. nd6_na_output() will | ||||
| * send NA toward all-node multicast address, to tell the sender | * send NA toward all-node multicast address, to tell the sender | ||||
| * that I'm using the address. | * that I'm using the address. | ||||
| * S bit ("solicited") must be zero. | * S bit ("solicited") must be zero. | ||||
| */ | */ | ||||
| if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { | if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { | ||||
| nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, | nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, | ||||
| ND_NEIGHBOR_SOLICIT, 0); | ND_NEIGHBOR_SOLICIT, 0); | ||||
| rflag |= ND_NA_FLAG_SOLICITED; | rflag |= ND_NA_FLAG_SOLICITED; | ||||
| } | } | ||||
| /* | /* | ||||
| * RFC 4861, anycast or proxy NA sent in response to a NS SHOULD | * RFC 4861, anycast or proxy NA sent in response to a NS SHOULD | ||||
| * be delayed by a random time between 0 and MAX_ANYCAST_DELAY_TIME | * be delayed by a random time between 0 and MAX_ANYCAST_DELAY_TIME | ||||
| * to reduce the probability of network congestion. | * to reduce the probability of network congestion. | ||||
| */ | */ | ||||
| if (anycast == 0) | if (dflags == 0) | ||||
| nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr, | nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr, NULL, M_GETFIB(m)); | ||||
| proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); | |||||
| else | else | ||||
| nd6_queue_add(ifa, &saddr6, arc4random() % | nd6_queue_add(ifa, &saddr6, &taddr6, &proxydl, arc4random() % | ||||
| (MAX_ANYCAST_DELAY_TIME * hz), ND6_QUEUE_FLAG_ANYCAST); | (MAX_ANYCAST_DELAY_TIME * hz), dflags); | ||||
| freeit: | freeit: | ||||
| if (ifa != NULL) | if (ifa != NULL) | ||||
| ifa_free(ifa); | ifa_free(ifa); | ||||
| m_freem(m); | m_freem(m); | ||||
| return; | return; | ||||
| bad: | bad: | ||||
| nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", | nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", | ||||
| ▲ Show 20 Lines • Show All 1,288 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static void | static void | ||||
| nd6_queue_timer(void *arg) | nd6_queue_timer(void *arg) | ||||
| { | { | ||||
| struct nd_queue *ndq = arg; | struct nd_queue *ndq = arg; | ||||
| struct ifaddr *ifa = ndq->ndq_ifa; | struct ifaddr *ifa = ndq->ndq_ifa; | ||||
| struct ifnet *ifp; | struct ifnet *ifp; | ||||
| struct in6_addr daddr; | struct in6_addr daddr, taddr; | ||||
| struct sockaddr_dl sdl; | |||||
| struct epoch_tracker et; | struct epoch_tracker et; | ||||
| int delay, tlladdr; | int delay, tlladdr; | ||||
| u_long flags; | u_long flags; | ||||
| bool proxy; | |||||
| KASSERT(ifa != NULL, ("ND6 queue entry %p with no address", ndq)); | KASSERT(ifa != NULL, ("ND6 queue entry %p with no address", ndq)); | ||||
| ifp = ifa->ifa_ifp; | ifp = ifa->ifa_ifp; | ||||
| CURVNET_SET(ifp->if_vnet); | CURVNET_SET(ifp->if_vnet); | ||||
| NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
| daddr = ndq->ndq_daddr; | daddr = ndq->ndq_daddr; | ||||
| taddr = ndq->ndq_taddr; | |||||
| tlladdr = ND6_NA_OPT_LLA; | tlladdr = ND6_NA_OPT_LLA; | ||||
| flags = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0; | flags = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0; | ||||
| if ((ifp->if_inet6->nd_flags & ND6_IFF_ACCEPT_RTADV) != 0 && V_ip6_norbit_raif) | if ((ifp->if_inet6->nd_flags & ND6_IFF_ACCEPT_RTADV) != 0 && V_ip6_norbit_raif) | ||||
| flags &= ~ND_NA_FLAG_ROUTER; | flags &= ~ND_NA_FLAG_ROUTER; | ||||
| /* | /* | ||||
| * RFC 9131 Section 6.1.2: If the address is preferred, | * RFC 9131 Section 6.1.2: If the address is preferred, | ||||
| * then the Override flag SHOULD NOT be set. | * then the Override flag SHOULD NOT be set. | ||||
| Show All 11 Lines | nd6_queue_timer(void *arg) | ||||
| * RFC 4861 Section 7.2.6: if link-layer address changed, | * RFC 4861 Section 7.2.6: if link-layer address changed, | ||||
| * The Override flag MAY be set to either zero or one. | * The Override flag MAY be set to either zero or one. | ||||
| */ | */ | ||||
| if ((ndq->ndq_flags & ND6_QUEUE_FLAG_LLADDR) != 0) | if ((ndq->ndq_flags & ND6_QUEUE_FLAG_LLADDR) != 0) | ||||
| flags |= ND_NA_FLAG_OVERRIDE; | flags |= ND_NA_FLAG_OVERRIDE; | ||||
| /* anycast advertisement delay rule (RFC 4861 7.2.7, SHOULD) */ | /* anycast advertisement delay rule (RFC 4861 7.2.7, SHOULD) */ | ||||
| if ((ndq->ndq_flags & ND6_QUEUE_FLAG_ANYCAST) != 0) | if ((ndq->ndq_flags & ND6_QUEUE_FLAG_ANYCAST) != 0) | ||||
| flags |= ND_NA_FLAG_SOLICITED; | flags |= ND_NA_FLAG_SOLICITED; | ||||
| /* proxy advertisement delay rule (RFC 4861 7.2.8, SHOULD) */ | |||||
| proxy = false; | |||||
| if ((ndq->ndq_flags & ND6_QUEUE_FLAG_PROXY) != 0) { | |||||
| flags |= ND_NA_FLAG_SOLICITED; | |||||
| sdl = ndq->ndq_sdl; | |||||
Done Inline ActionsWe already initialized tlladdr = ND6_NA_OPT_LLA at the beginning of the function. markj: We already initialized `tlladdr = ND6_NA_OPT_LLA` at the beginning of the function. | |||||
Done Inline ActionsOh, I left this one from previous revision. Thanks! pouria: Oh, I left this one from previous revision. Thanks! | |||||
| proxy = true; | |||||
| } | |||||
| /* | /* | ||||
| * if it was GRAND, wait at least a RetransTimer | * if it was GRAND, wait at least a RetransTimer | ||||
| * before removing from queue. | * before removing from queue. | ||||
| */ | */ | ||||
| if ((ndq->ndq_flags & ND6_QUEUE_GRAND_MASK) != 0) { | if ((ndq->ndq_flags & ND6_QUEUE_GRAND_MASK) != 0) { | ||||
| delay = ifp->if_inet6->nd_retrans * hz / 1000; | delay = ifp->if_inet6->nd_retrans * hz / 1000; | ||||
| callout_reset(&ndq->ndq_callout, delay, nd6_queue_rel, ndq); | callout_reset(&ndq->ndq_callout, delay, nd6_queue_rel, ndq); | ||||
| IF_ADDR_WUNLOCK(ifp); | IF_ADDR_WUNLOCK(ifp); | ||||
| } else | } else | ||||
| nd6_queue_rel(ndq); | nd6_queue_rel(ndq); | ||||
| if (__predict_true(in6_setscope(&daddr, ifp, NULL) == 0)) | if (__predict_true(in6_setscope(&daddr, ifp, NULL) == 0)) | ||||
| nd6_na_output_fib(ifp, &daddr, IFA_IN6(ifa), flags, tlladdr, | nd6_na_output_fib(ifp, &daddr, &taddr, flags, tlladdr, | ||||
| NULL, ifp->if_fib); | proxy ? (struct sockaddr *)&sdl : NULL, ifp->if_fib); | ||||
| NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
| CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
| } | } | ||||
| /* | |||||
| * Queue a delayed IPv6 Neighbor Advertisement. | |||||
| * | |||||
| * daddr: destination address (who the NA is sent to) | |||||
| * taddr: target address being advertised (used for proxy NAs) | |||||
| * sdl: link-layer address (used for proxy NAs) | |||||
| */ | |||||
| static void | static void | ||||
| nd6_queue_add(struct ifaddr *ifa, struct in6_addr *daddr, | nd6_queue_add(struct ifaddr *ifa, struct in6_addr *daddr, | ||||
Not Done Inline ActionsSome comment explaining the difference between taddr and daddr would be useful. markj: Some comment explaining the difference between `taddr` and `daddr` would be useful. | |||||
| int delay, uint32_t flags) | struct in6_addr *taddr, struct sockaddr_dl *sdl, int delay, uint32_t flags) | ||||
| { | { | ||||
| struct nd_queue *ndq = NULL; | struct nd_queue *ndq = NULL; | ||||
| struct ifnet *ifp; | struct ifnet *ifp; | ||||
| struct in6_ifextra *ext; | struct in6_ifextra *ext; | ||||
| char ip6buf[INET6_ADDRSTRLEN]; | char ip6buf[INET6_ADDRSTRLEN]; | ||||
| NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
| Show All 25 Lines | if (ndq == NULL) { | ||||
| callout_init_mtx(&ndq->ndq_callout, &ifp->if_addr_lock, | callout_init_mtx(&ndq->ndq_callout, &ifp->if_addr_lock, | ||||
| CALLOUT_TRYLOCK | CALLOUT_RETURNUNLOCKED); | CALLOUT_TRYLOCK | CALLOUT_RETURNUNLOCKED); | ||||
| ifa_ref(ifa); | ifa_ref(ifa); | ||||
| ndq->ndq_ifa = ifa; | ndq->ndq_ifa = ifa; | ||||
| TAILQ_INSERT_TAIL(&ext->nd_queue, ndq, ndq_list); | TAILQ_INSERT_TAIL(&ext->nd_queue, ndq, ndq_list); | ||||
| } | } | ||||
| memcpy(&ndq->ndq_daddr, daddr, sizeof(struct in6_addr)); | memcpy(&ndq->ndq_daddr, daddr, sizeof(struct in6_addr)); | ||||
| /* | |||||
| * For proxy NAs, the target address (taddr) being advertised differs from | |||||
| * the interface address (ifa), so we must explicitly store both the proxy | |||||
| * target address and its link-layer address (sdl). | |||||
| * For non-proxy NAs, use the interface address (ifa) itself as the target. | |||||
Done Inline ActionsI'd suggest to expand the macro. Right now it has * which negates the inside &. IMHO, this is mind blowing and doesn't improve readability. glebius: I'd suggest to expand the macro. Right now it has `*` which negates the inside `&`. IMHO, this… | |||||
Done Inline ActionsOr just use memcpy() like you do above. markj: Or just use memcpy() like you do above. | |||||
Done Inline ActionsI still don't like the mix of memcpy() and direct assignment. We should be consistent one way or the other. markj: I still don't like the mix of memcpy() and direct assignment. We should be consistent one way… | |||||
Done Inline ActionsDone. pouria: Done.
Honestly, I don't like to use memcpy whenever possible.
But for consistency, make sense. | |||||
| */ | |||||
| if ((flags & ND6_QUEUE_FLAG_PROXY) != 0) { | |||||
| memcpy(&ndq->ndq_taddr, taddr, sizeof(struct in6_addr)); | |||||
| memcpy(&ndq->ndq_sdl, sdl, sizeof(struct sockaddr_dl)); | |||||
| } else | |||||
| memcpy(&ndq->ndq_taddr, IFA_IN6(ifa), sizeof(struct in6_addr)); | |||||
| ndq->ndq_flags = flags; | ndq->ndq_flags = flags; | ||||
| nd6log((LOG_DEBUG, "%s: delay IPv6 NA for %s\n", if_name(ifp), | nd6log((LOG_DEBUG, "%s: delay IPv6 NA for %s\n", if_name(ifp), | ||||
| ip6_sprintf(ip6buf, IFA_IN6(ifa)))); | ip6_sprintf(ip6buf, IFA_IN6(ifa)))); | ||||
| callout_reset(&ndq->ndq_callout, delay, nd6_queue_timer, ndq); | callout_reset(&ndq->ndq_callout, delay, nd6_queue_timer, ndq); | ||||
| IF_ADDR_WUNLOCK(ifp); | IF_ADDR_WUNLOCK(ifp); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | nd6_grand_start(struct ifaddr *ifa, uint32_t flags) | ||||
| /* | /* | ||||
| * RFC 4861 Section 7.2.6: if link-layer address changed, | * RFC 4861 Section 7.2.6: if link-layer address changed, | ||||
| * use the all-nodes multicast address. | * use the all-nodes multicast address. | ||||
| */ | */ | ||||
| if ((flags & ND6_QUEUE_FLAG_LLADDR) != 0) | if ((flags & ND6_QUEUE_FLAG_LLADDR) != 0) | ||||
| daddr = in6addr_linklocal_allnodes; | daddr = in6addr_linklocal_allnodes; | ||||
| delay = ext->nd_retrans * hz / 1000; | delay = ext->nd_retrans * hz / 1000; | ||||
| nd6_queue_add(ifa, &daddr, count * delay, flags); | nd6_queue_add(ifa, &daddr, NULL, NULL, count * delay, flags); | ||||
| } | } | ||||
| /* | /* | ||||
| * drain nd6 queue. used for address removals. | * drain nd6 queue. used for address removals. | ||||
| */ | */ | ||||
| void | void | ||||
| nd6_queue_stop(struct ifaddr *ifa) | nd6_queue_stop(struct ifaddr *ifa) | ||||
| { | { | ||||
| Show All 18 Lines | |||||
This line here.
Since proxy address don't have a local ifa, they get a link-local address to use as its source.
Because of that, I can't use the ifa lock to protect the nd_queue list.
To reproduce, run the proxy_ndp tests with this patch.
At this point, I'm stuck and don't know how to resolve this specific scenario.