Deleted Added
sdiff udiff text old ( 61965 ) new ( 62587 )
full compact
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/netinet6/nd6_nbr.c 61965 2000-06-22 19:04:41Z ume $
30 */
31
32#include "opt_ipsec.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/malloc.h>
37#include <sys/mbuf.h>
38#include <sys/socket.h>
39#include <sys/sockio.h>

--- 6 unchanged lines hidden (view full) ---

46#include <net/if.h>
47#include <net/if_types.h>
48#include <net/if_dl.h>
49#include <net/route.h>
50
51#include <netinet/in.h>
52#include <netinet/in_var.h>
53#include <netinet6/in6_var.h>
54#include <netinet6/ip6.h>
55#include <netinet6/ip6_var.h>
56#include <netinet6/nd6.h>
57#include <netinet6/icmp6.h>
58
59#include <net/net_osdep.h>
60
61#define SDL(s) ((struct sockaddr_dl *)s)
62
63struct dadq;
64static struct dadq *nd6_dad_find __P((struct ifaddr *));
65static void nd6_dad_timer __P((struct ifaddr *));
66static void nd6_dad_ns_input __P((struct ifaddr *));
67static void nd6_dad_na_input __P((struct ifaddr *));
68
69/* ignore NS in DAD - specwise incorrect, */
70int dad_ignore_ns = 0;
71
72/*
73 * Input an Neighbor Solicitation Message.
74 *
75 * Based on RFC 2461
76 * Based on RFC 2462 (duplicated address detection)
77 *
78 * XXX proxy advertisement
79 */
80void
81nd6_ns_input(m, off, icmp6len)
82 struct mbuf *m;
83 int off, icmp6len;
84{
85 struct ifnet *ifp = m->m_pkthdr.rcvif;
86 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
87 struct nd_neighbor_solicit *nd_ns
88 = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
89 struct in6_addr saddr6 = ip6->ip6_src;
90 struct in6_addr daddr6 = ip6->ip6_dst;
91 struct in6_addr taddr6 = nd_ns->nd_ns_target;
92 struct in6_addr myaddr6;
93 char *lladdr = NULL;
94 struct ifaddr *ifa;
95 int lladdrlen = 0;
96 int anycast = 0, proxy = 0, tentative = 0;
97 int tlladdr;
98 union nd_opts ndopts;
99
100 if (ip6->ip6_hlim != 255) {
101 log(LOG_ERR,
102 "nd6_ns_input: invalid hlim %d\n", ip6->ip6_hlim);
103 return;
104 }
105
106 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
107 /* dst has to be solicited node multicast address. */
108 if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL
109 /*don't check ifindex portion*/
110 && daddr6.s6_addr32[1] == 0
111 && daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE
112 && daddr6.s6_addr8[12] == 0xff) {
113 ; /*good*/
114 } else {
115 log(LOG_INFO, "nd6_ns_input: bad DAD packet "
116 "(wrong ip6 dst)\n");
117 goto bad;
118 }
119 }
120
121 if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
122 log(LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n");
123 goto bad;
124 }
125
126 if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
127 taddr6.s6_addr16[1] = htons(ifp->if_index);
128

--- 20 unchanged lines hidden (view full) ---

149 * (RFC 2461 7.2.4)
150 *
151 * NS IP dst is unicast/anycast MUST NOT add
152 * NS IP dst is solicited-node multicast MUST add
153 *
154 * In implementation, we add target link-layer address by default.
155 * We do not add one in MUST NOT cases.
156 */
157 if (!IN6_IS_ADDR_MULTICAST(&daddr6))
158 tlladdr = 0;
159 else
160 tlladdr = 1;
161
162 /*
163 * Target address (taddr6) must be either:
164 * (1) Valid unicast/anycast address for my receiving interface,
165 * (2) Unicast address for which I'm offering proxy service, or
166 * (3) "tentative" address on which DAD is being performed.
167 */
168 /* (1) and (3) check. */
169 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
170
171 /* (2) check. */
172 if (!ifa && nd6_proxyall) {
173 struct rtentry *rt;
174 struct sockaddr_in6 tsin6;
175
176 bzero(&tsin6, sizeof tsin6);
177 tsin6.sin6_len = sizeof(struct sockaddr_in6);
178 tsin6.sin6_family = AF_INET6;
179 tsin6.sin6_addr = taddr6;
180
181 rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
182 if (rt && rt->rt_ifp != ifp) {
183 /*
184 * search link local addr for ifp, and use it for
185 * proxy NA.
186 */
187 ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
188 if (ifa)
189 proxy = 1;
190 }
191 rtfree(rt);
192 }
193 if (!ifa) {
194 /*
195 * We've got a NS packet, and we don't have that adddress
196 * assigned for us. We MUST silently ignore it.
197 * See RFC2461 7.2.3.
198 */
199 return;
200 }
201 myaddr6 = *IFA_IN6(ifa);
202 anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
203 tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
204 if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
205 return;
206
207 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
208 log(LOG_INFO,
209 "nd6_ns_input: lladdrlen mismatch for %s "
210 "(if %d, NS packet %d)\n",
211 ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2);
212 }
213
214 if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
215 log(LOG_INFO,
216 "nd6_ns_input: duplicate IP6 address %s\n",
217 ip6_sprintf(&saddr6));
218 return;
219 }
220
221 /*
222 * We have neighbor solicitation packet, with target address equals to
223 * one of my tentative address.
224 *
225 * src addr how to process?
226 * --- ---

--- 9 unchanged lines hidden (view full) ---

236 * duplicated address detection.
237 *
238 * If not, the packet is for addess resolution;
239 * silently ignore it.
240 */
241 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
242 nd6_dad_ns_input(ifa);
243
244 return;
245 }
246
247 /*
248 * If the source address is unspecified address, entries must not
249 * be created or updated.
250 * It looks that sender is performing DAD. Output NA toward
251 * all-node multicast address, to tell the sender that I'm using
252 * the address.
253 * S bit ("solicited") must be zero.
254 */
255 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
256 saddr6 = in6addr_linklocal_allnodes;
257 saddr6.s6_addr16[1] = htons(ifp->if_index);
258 nd6_na_output(ifp, &saddr6, &taddr6,
259 ((anycast || proxy || !tlladdr)
260 ? 0 : ND_NA_FLAG_OVERRIDE)
261 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
262 tlladdr);
263 return;
264 }
265
266 nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
267
268 nd6_na_output(ifp, &saddr6, &taddr6,
269 ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE)
270 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0)
271 | ND_NA_FLAG_SOLICITED,
272 tlladdr);
273 return;
274
275 bad:
276 log(LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6));
277 log(LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6));
278 log(LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6));
279 return;
280}
281
282/*
283 * Output an Neighbor Solicitation Message. Caller specifies:
284 * - ICMP6 header source IP6 address
285 * - ND6 header target IP6 address
286 * - ND6 header source datalink address
287 *

--- 8 unchanged lines hidden (view full) ---

296 int dad; /* duplicated address detection */
297{
298 struct mbuf *m;
299 struct ip6_hdr *ip6;
300 struct nd_neighbor_solicit *nd_ns;
301 struct in6_ifaddr *ia = NULL;
302 struct ip6_moptions im6o;
303 int icmp6len;
304 caddr_t mac;
305 struct ifnet *outif = NULL;
306
307 if (IN6_IS_ADDR_MULTICAST(taddr6))
308 return;
309
310 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
311 return;
312
313 if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
314 m->m_flags |= M_MCAST;
315 im6o.im6o_multicast_ifp = ifp;
316 im6o.im6o_multicast_hlim = 255;
317 im6o.im6o_multicast_loop = 0;
318 }
319
320 icmp6len = sizeof(*nd_ns);
321 m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
322 MH_ALIGN(m, m->m_len + 16); /* 1+1+6 is enought. but just in case */
323
324 /* fill neighbor solicitation packet */
325 ip6 = mtod(m, struct ip6_hdr *);
326 ip6->ip6_flow = 0;
327 ip6->ip6_vfc = IPV6_VERSION;
328 /* ip6->ip6_plen will be set later */
329 ip6->ip6_nxt = IPPROTO_ICMPV6;
330 ip6->ip6_hlim = 255;
331 if (daddr6)
332 ip6->ip6_dst = *daddr6;
333 else {
334 ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
335 ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
336 ip6->ip6_dst.s6_addr32[1] = 0;
337 ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
338 ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
339 ip6->ip6_dst.s6_addr8[12] = 0xff;
340 }
341 if (!dad) {
342 /* spec-wise correct, scope match */
343 /*
344 * RFC2461 7.2.2:
345 * "If the source address of the packet prompting the
346 * solicitation is the same as one of the addresses assigned
347 * to the outgoing interface, that address SHOULD be placed
348 * in the IP Source Address of the outgoing solicitation.
349 * Otherwise, any one of the addresses assigned to the
350 * interface should be used."
351 *

--- 20 unchanged lines hidden (view full) ---

372 else {
373 ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
374 if (ia == NULL) {
375 m_freem(m); /*XXX*/
376 return;
377 }
378 ip6->ip6_src = ia->ia_addr.sin6_addr;
379 }
380 } else {
381 /*
382 * Source address for DAD packet must always be IPv6
383 * unspecified address. (0::0)
384 */
385 bzero(&ip6->ip6_src, sizeof(ip6->ip6_src));
386 }
387 nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);

--- 32 unchanged lines hidden (view full) ---

420 bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
421 }
422
423 ip6->ip6_plen = htons((u_short)icmp6len);
424 nd_ns->nd_ns_cksum = 0;
425 nd_ns->nd_ns_cksum
426 = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
427
428 ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif);
429 if (outif) {
430 icmp6_ifstat_inc(outif, ifs6_out_msg);
431 icmp6_ifstat_inc(outif, ifs6_out_neighborsolicit);
432 }
433 icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
434}
435
436/*
437 * Neighbor advertisement input handling.
438 *
439 * Based on RFC 2461
440 * Based on RFC 2462 (duplicated address detection)
441 */
442void
443nd6_na_input(m, off, icmp6len)
444 struct mbuf *m;
445 int off, icmp6len;
446{
447 struct ifnet *ifp = m->m_pkthdr.rcvif;
448 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
449 struct nd_neighbor_advert *nd_na
450 = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
451 struct in6_addr daddr6 = ip6->ip6_dst;
452 struct in6_addr taddr6 = nd_na->nd_na_target;
453 int flags = nd_na->nd_na_flags_reserved;
454 int is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
455 int is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
456 int is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
457 char *lladdr = NULL;
458 int lladdrlen = 0;
459 struct ifaddr *ifa;
460 struct llinfo_nd6 *ln;
461 struct rtentry *rt;
462 struct sockaddr_dl *sdl;
463 union nd_opts ndopts;
464
465 if (ip6->ip6_hlim != 255) {
466 log(LOG_ERR,
467 "nd6_na_input: invalid hlim %d\n", ip6->ip6_hlim);
468 return;
469 }
470
471 if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
472 taddr6.s6_addr16[1] = htons(ifp->if_index);
473
474 if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
475 log(LOG_ERR,
476 "nd6_na_input: invalid target address %s\n",
477 ip6_sprintf(&taddr6));
478 return;
479 }
480 if (IN6_IS_ADDR_MULTICAST(&daddr6))
481 if (is_solicited) {
482 log(LOG_ERR,
483 "nd6_na_input: a solicited adv is multicasted\n");
484 return;
485 }
486
487 icmp6len -= sizeof(*nd_na);
488 nd6_option_init(nd_na + 1, icmp6len, &ndopts);
489 if (nd6_options(&ndopts) < 0) {
490 log(LOG_INFO, "nd6_na_input: invalid ND option, ignored\n");
491 return;
492 }
493
494 if (ndopts.nd_opts_tgt_lladdr) {
495 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
496 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
497 }
498
499 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);

--- 5 unchanged lines hidden (view full) ---

505 * already using the same address as mine. This indicates DAD failure.
506 * This is defined in RFC 2462.
507 *
508 * Otherwise, process as defined in RFC 2461.
509 */
510 if (ifa
511 && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
512 nd6_dad_na_input(ifa);
513 return;
514 }
515
516 /* Just for safety, maybe unnecessery. */
517 if (ifa) {
518 log(LOG_ERR,
519 "nd6_na_input: duplicate IP6 address %s\n",
520 ip6_sprintf(&taddr6));
521 return;
522 }
523
524 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
525 log(LOG_INFO,
526 "nd6_na_input: lladdrlen mismatch for %s "
527 "(if %d, NA packet %d)\n",
528 ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2);
529 }
530
531 /*
532 * If no neighbor cache entry is found, NA SHOULD silently be discarded.
533 */
534 rt = nd6_lookup(&taddr6, 0, ifp);
535 if ((rt == NULL) ||
536 ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
537 ((sdl = SDL(rt->rt_gateway)) == NULL))
538 return;
539
540 if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
541 /*
542 * If the link-layer has address, and no lladdr option came,
543 * discard the packet.
544 */
545 if (ifp->if_addrlen && !lladdr)
546 return;
547
548 /*
549 * Record link-layer address, and update the state.
550 */
551 sdl->sdl_alen = ifp->if_addrlen;
552 bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
553 if (is_solicited) {
554 ln->ln_state = ND6_LLINFO_REACHABLE;
555 if (ln->ln_expire)
556 ln->ln_expire = time_second +
557 nd_ifinfo[rt->rt_ifp->if_index].reachable;
558 } else
559 ln->ln_state = ND6_LLINFO_STALE;
560 ln->ln_router = is_router;
561 } else {
562 int llchange;

--- 34 unchanged lines hidden (view full) ---

597 */
598 if (!is_override && (lladdr && llchange)) { /* (1) */
599 /*
600 * If state is REACHABLE, make it STALE.
601 * no other updates should be done.
602 */
603 if (ln->ln_state == ND6_LLINFO_REACHABLE)
604 ln->ln_state = ND6_LLINFO_STALE;
605 return;
606 } else if (is_override /* (2a) */
607 || (!is_override && (lladdr && !llchange)) /* (2b) */
608 || !lladdr) { /* (2c) */
609 /*
610 * Update link-local address, if any.
611 */
612 if (lladdr) {
613 sdl->sdl_alen = ifp->if_addrlen;
614 bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
615 }
616
617 /*
618 * If solicited, make the state REACHABLE.
619 * If not solicited and the link-layer address was
620 * changed, make it STALE.
621 */
622 if (is_solicited) {
623 ln->ln_state = ND6_LLINFO_REACHABLE;
624 if (ln->ln_expire) {
625 ln->ln_expire = time_second +
626 nd_ifinfo[ifp->if_index].reachable;
627 }
628 } else {
629 if (lladdr && llchange)
630 ln->ln_state = ND6_LLINFO_STALE;
631 }

--- 26 unchanged lines hidden (view full) ---

658 }
659 splx(s);
660 }
661 ln->ln_router = is_router;
662 }
663 rt->rt_flags &= ~RTF_REJECT;
664 ln->ln_asked = 0;
665 if (ln->ln_hold) {
666 nd6_output(ifp, ln->ln_hold,
667 (struct sockaddr_in6 *)rt_key(rt), rt);
668 ln->ln_hold = 0;
669 }
670}
671
672/*
673 * Neighbor advertisement output handling.
674 *
675 * Based on RFC 2461
676 *
677 * XXX NA delay for anycast address is not implemented yet
678 * (RFC 2461 7.2.7)
679 * XXX proxy advertisement?
680 */
681void
682nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr)
683 struct ifnet *ifp;
684 struct in6_addr *daddr6, *taddr6;
685 u_long flags;
686 int tlladdr; /* 1 if include target link-layer address */
687{
688 struct mbuf *m;
689 struct ip6_hdr *ip6;
690 struct nd_neighbor_advert *nd_na;
691 struct in6_ifaddr *ia = NULL;
692 struct ip6_moptions im6o;
693 int icmp6len;
694 caddr_t mac;
695 struct ifnet *outif;
696
697 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
698 return;
699
700 if (IN6_IS_ADDR_MULTICAST(daddr6)) {
701 m->m_flags |= M_MCAST;
702 im6o.im6o_multicast_ifp = ifp;
703 im6o.im6o_multicast_hlim = 255;
704 im6o.im6o_multicast_loop = 0;
705 }
706
707 icmp6len = sizeof(*nd_na);
708 m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
709 MH_ALIGN(m, m->m_len + 16); /* 1+1+6 is enough. but just in case */
710
711 /* fill neighbor advertisement packet */
712 ip6 = mtod(m, struct ip6_hdr *);
713 ip6->ip6_flow = 0;
714 ip6->ip6_vfc = IPV6_VERSION;
715 ip6->ip6_nxt = IPPROTO_ICMPV6;
716 ip6->ip6_hlim = 255;
717 if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
718 /* reply to DAD */
719 ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
720 ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
721 ip6->ip6_dst.s6_addr32[1] = 0;
722 ip6->ip6_dst.s6_addr32[2] = 0;

--- 19 unchanged lines hidden (view full) ---

742 nd_na->nd_na_target.s6_addr16[1] = 0;
743
744 /*
745 * "tlladdr" indicates NS's condition for adding tlladdr or not.
746 * see nd6_ns_input() for details.
747 * Basically, if NS packet is sent to unicast/anycast addr,
748 * target lladdr option SHOULD NOT be included.
749 */
750 if (tlladdr && (mac = nd6_ifptomac(ifp))) {
751 int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
752 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
753
754 /* roundup to 8 bytes alignment! */
755 optlen = (optlen + 7) & ~7;
756
757 m->m_pkthdr.len += optlen;
758 m->m_len += optlen;

--- 7 unchanged lines hidden (view full) ---

766
767 ip6->ip6_plen = htons((u_short)icmp6len);
768 nd_na->nd_na_flags_reserved = flags;
769 nd_na->nd_na_cksum = 0;
770 nd_na->nd_na_cksum =
771 in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
772
773#ifdef IPSEC
774 m->m_pkthdr.rcvif = NULL;
775#endif /*IPSEC*/
776 ip6_output(m, NULL, NULL, 0, &im6o, &outif);
777 if (outif) {
778 icmp6_ifstat_inc(outif, ifs6_out_msg);
779 icmp6_ifstat_inc(outif, ifs6_out_neighboradvert);
780 }
781 icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
782}
783

--- 12 unchanged lines hidden (view full) ---

796 }
797}
798
799TAILQ_HEAD(dadq_head, dadq);
800struct dadq {
801 TAILQ_ENTRY(dadq) dad_list;
802 struct ifaddr *dad_ifa;
803 int dad_count; /* max NS to send */
804 int dad_ns_ocount; /* NS sent so far */
805 int dad_ns_icount;
806 int dad_na_icount;
807 struct callout_handle dad_timer;
808};
809
810static struct dadq_head dadq;
811
812static struct dadq *
813nd6_dad_find(ifa)
814 struct ifaddr *ifa;
815{
816 struct dadq *dp;
817
818 TAILQ_FOREACH(dp, &dadq, dad_list) {
819 if (dp->dad_ifa == ifa)
820 return dp;
821 }
822 return NULL;
823}
824
825/*
826 * Start Duplicated Address Detection (DAD) for specified interface address.

--- 14 unchanged lines hidden (view full) ---

841
842 /*
843 * If we don't need DAD, don't do it.
844 * There are several cases:
845 * - DAD is disabled (ip6_dad_count == 0)
846 * - the interface address is anycast
847 */
848 if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
849 printf("nd6_dad_start: called with non-tentative address "
850 "%s(%s)\n",
851 ip6_sprintf(&ia->ia_addr.sin6_addr),
852 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
853 return;
854 }
855 if (ia->ia6_flags & IN6_IFF_ANYCAST) {
856 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
857 return;

--- 8 unchanged lines hidden (view full) ---

866 return;
867 if (nd6_dad_find(ifa) != NULL) {
868 /* DAD already in progress */
869 return;
870 }
871
872 dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
873 if (dp == NULL) {
874 printf("nd6_dad_start: memory allocation failed for "
875 "%s(%s)\n",
876 ip6_sprintf(&ia->ia_addr.sin6_addr),
877 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
878 return;
879 }
880 bzero(dp, sizeof(*dp));
881 TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
882
883#ifdef ND6_DEBUG
884 printf("%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
885 ip6_sprintf(&ia->ia_addr.sin6_addr));
886#endif
887
888 /*
889 * Send NS packet for DAD, ip6_dad_count times.
890 * Note that we must delay the first transmission, if this is the
891 * first packet to be sent from the interface after interface
892 * (re)initialization.
893 */
894 dp->dad_ifa = ifa;
895 ifa->ifa_refcnt++; /*just for safety*/
896 dp->dad_count = ip6_dad_count;
897 dp->dad_ns_icount = dp->dad_na_icount = 0;
898 dp->dad_ns_ocount = 0;
899 if (!tick) {
900 dp->dad_ns_ocount++;
901 nd6_ns_output(ifa->ifa_ifp, NULL, &ia->ia_addr.sin6_addr,
902 NULL, 1);
903 dp->dad_timer =
904 timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa,
905 nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
906 } else {
907 int ntick;
908
909 if (*tick == 0)
910 ntick = random() % (MAX_RTR_SOLICITATION_DELAY * hz);

--- 13 unchanged lines hidden (view full) ---

924 int s;
925 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
926 struct dadq *dp;
927
928 s = splnet(); /*XXX*/
929
930 /* Sanity check */
931 if (ia == NULL) {
932 printf("nd6_dad_timer: called with null parameter\n");
933 goto done;
934 }
935 dp = nd6_dad_find(ifa);
936 if (dp == NULL) {
937 printf("nd6_dad_timer: DAD structure not found\n");
938 goto done;
939 }
940 if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
941 printf("nd6_dad_timer: called with duplicated address "
942 "%s(%s)\n",
943 ip6_sprintf(&ia->ia_addr.sin6_addr),
944 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
945 goto done;
946 }
947 if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
948 printf("nd6_dad_timer: called with non-tentative address "
949 "%s(%s)\n",
950 ip6_sprintf(&ia->ia_addr.sin6_addr),
951 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
952 goto done;
953 }
954
955 /* Need more checks? */
956 if (dp->dad_ns_ocount < dp->dad_count) {
957 /*
958 * We have more NS to go. Send NS packet for DAD.
959 */
960 dp->dad_ns_ocount++;
961 nd6_ns_output(ifa->ifa_ifp, NULL, &ia->ia_addr.sin6_addr,
962 NULL, 1);
963 dp->dad_timer =
964 timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa,
965 nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
966 } else {
967 /*
968 * We have transmitted sufficient number of DAD packets.
969 * See what we've got.
970 */

--- 5 unchanged lines hidden (view full) ---

976 /*
977 * the check is in nd6_dad_na_input(),
978 * but just in case
979 */
980 duplicate++;
981 }
982
983 if (dp->dad_ns_icount) {
984 /* We've seen NS, means DAD has failed. */
985 duplicate++;
986 }
987
988 if (duplicate) {
989 /* (*dp) will be freed in nd6_dad_duplicated() */
990 dp = NULL;
991 nd6_dad_duplicated(ifa);
992 } else {
993 /*
994 * We are done with DAD. No NA came, no NS came.
995 * duplicated address found.
996 */
997 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
998
999#ifdef ND6_DEBUG
1000 printf("%s: DAD complete for %s - no duplicates "
1001 "found\n", if_name(ifa->ifa_ifp),
1002 ip6_sprintf(&ia->ia_addr.sin6_addr));
1003#endif
1004
1005 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1006 free(dp, M_IP6NDP);
1007 dp = NULL;
1008 ifa->ifa_refcnt--;
1009 }
1010 }
1011
1012done:
1013 splx(s);
1014}
1015
1016void
1017nd6_dad_duplicated(ifa)
1018 struct ifaddr *ifa;
1019{
1020 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1021 struct dadq *dp;
1022
1023 dp = nd6_dad_find(ifa);
1024 if (dp == NULL) {
1025 printf("nd6_dad_duplicated: DAD structure not found\n");
1026 return;
1027 }
1028
1029 log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: %d NS, "
1030 "%d NA\n", if_name(ifa->ifa_ifp),
1031 ip6_sprintf(&ia->ia_addr.sin6_addr),
1032 dp->dad_ns_icount, dp->dad_na_icount);
1033
1034 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1035 ia->ia6_flags |= IN6_IFF_DUPLICATED;
1036
1037 /* We are done with DAD, with duplicated address found. (failure) */
1038 untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa
1039 , dp->dad_timer);
1040
1041 printf("%s: DAD complete for %s - duplicate found\n",
1042 if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
1043 printf("%s: manual intervention required\n", if_name(ifa->ifa_ifp));
1044
1045 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1046 free(dp, M_IP6NDP);
1047 dp = NULL;
1048 ifa->ifa_refcnt--;
1049}
1050
1051void
1052nd6_dad_ns_input(ifa)
1053 struct ifaddr *ifa;
1054{
1055 struct in6_ifaddr *ia;
1056 struct ifnet *ifp;
1057 struct in6_addr *taddr6;
1058 struct dadq *dp;
1059 int duplicate;

--- 38 unchanged lines hidden (view full) ---

1098 * not sure if I got a duplicate.
1099 * increment ns count and see what happens.
1100 */
1101 if (dp)
1102 dp->dad_ns_icount++;
1103 }
1104}
1105
1106void
1107nd6_dad_na_input(ifa)
1108 struct ifaddr *ifa;
1109{
1110 struct dadq *dp;
1111
1112 if (!ifa)
1113 panic("ifa == NULL in nd6_dad_na_input");
1114
1115 dp = nd6_dad_find(ifa);
1116 if (dp)
1117 dp->dad_na_icount++;
1118
1119 /* remove the address. */
1120 nd6_dad_duplicated(ifa);
1121}