Deleted Added
sdiff udiff text old ( 61965 ) new ( 62587 )
full compact
1/* $FreeBSD: head/sys/netinet6/nd6_nbr.c 62587 2000-07-04 16:35:15Z itojun $ */
2/* $KAME: nd6_nbr.c,v 1.37 2000/06/04 12:46:13 itojun Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright

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

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

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

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

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

170 * (RFC 2461 7.2.4)
171 *
172 * NS IP dst is unicast/anycast MUST NOT add
173 * NS IP dst is solicited-node multicast MUST add
174 *
175 * In implementation, we add target link-layer address by default.
176 * We do not add one in MUST NOT cases.
177 */
178#if 0 /* too much! */
179 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
180 if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
181 tlladdr = 0;
182 else
183#endif
184 if (!IN6_IS_ADDR_MULTICAST(&daddr6))
185 tlladdr = 0;
186 else
187 tlladdr = 1;
188
189 /*
190 * Target address (taddr6) must be either:
191 * (1) Valid unicast/anycast address for my receiving interface,
192 * (2) Unicast address for which I'm offering proxy service, or
193 * (3) "tentative" address on which DAD is being performed.
194 */
195 /* (1) and (3) check. */
196 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
197
198 /* (2) check. */
199 if (!ifa) {
200 struct rtentry *rt;
201 struct sockaddr_in6 tsin6;
202
203 bzero(&tsin6, sizeof tsin6);
204 tsin6.sin6_len = sizeof(struct sockaddr_in6);
205 tsin6.sin6_family = AF_INET6;
206 tsin6.sin6_addr = taddr6;
207
208 rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
209 if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
210 rt->rt_gateway->sa_family == AF_LINK) {
211 /*
212 * proxy NDP for single entry
213 */
214 ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
215 IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
216 if (ifa) {
217 proxy = 1;
218 proxydl = SDL(rt->rt_gateway);
219 }
220 }
221 if (rt)
222 rtfree(rt);
223 }
224 if (!ifa) {
225 /*
226 * We've got a NS packet, and we don't have that adddress
227 * assigned for us. We MUST silently ignore it.
228 * See RFC2461 7.2.3.
229 */
230 goto freeit;
231 }
232 myaddr6 = *IFA_IN6(ifa);
233 anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
234 tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
235 if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
236 goto freeit;
237
238 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
239 log(LOG_INFO,
240 "nd6_ns_input: lladdrlen mismatch for %s "
241 "(if %d, NS packet %d)\n",
242 ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2);
243 }
244
245 if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
246 log(LOG_INFO,
247 "nd6_ns_input: duplicate IP6 address %s\n",
248 ip6_sprintf(&saddr6));
249 goto freeit;
250 }
251
252 /*
253 * We have neighbor solicitation packet, with target address equals to
254 * one of my tentative address.
255 *
256 * src addr how to process?
257 * --- ---

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

267 * duplicated address detection.
268 *
269 * If not, the packet is for addess resolution;
270 * silently ignore it.
271 */
272 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
273 nd6_dad_ns_input(ifa);
274
275 goto freeit;
276 }
277
278 /*
279 * If the source address is unspecified address, entries must not
280 * be created or updated.
281 * It looks that sender is performing DAD. Output NA toward
282 * all-node multicast address, to tell the sender that I'm using
283 * the address.
284 * S bit ("solicited") must be zero.
285 */
286 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
287 saddr6 = in6addr_linklocal_allnodes;
288 saddr6.s6_addr16[1] = htons(ifp->if_index);
289 nd6_na_output(ifp, &saddr6, &taddr6,
290 ((anycast || proxy || !tlladdr)
291 ? 0 : ND_NA_FLAG_OVERRIDE)
292 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
293 tlladdr, (struct sockaddr *)proxydl);
294 goto freeit;
295 }
296
297 nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
298
299 nd6_na_output(ifp, &saddr6, &taddr6,
300 ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE)
301 | (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0)
302 | ND_NA_FLAG_SOLICITED,
303 tlladdr, (struct sockaddr *)proxydl);
304 freeit:
305 m_freem(m);
306 return;
307
308 bad:
309 log(LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6));
310 log(LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6));
311 log(LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6));
312 m_freem(m);
313}
314
315/*
316 * Output an Neighbor Solicitation Message. Caller specifies:
317 * - ICMP6 header source IP6 address
318 * - ND6 header target IP6 address
319 * - ND6 header source datalink address
320 *

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

329 int dad; /* duplicated address detection */
330{
331 struct mbuf *m;
332 struct ip6_hdr *ip6;
333 struct nd_neighbor_solicit *nd_ns;
334 struct in6_ifaddr *ia = NULL;
335 struct ip6_moptions im6o;
336 int icmp6len;
337 int maxlen;
338 caddr_t mac;
339 struct ifnet *outif = NULL;
340
341 if (IN6_IS_ADDR_MULTICAST(taddr6))
342 return;
343
344 /* estimate the size of message */
345 maxlen = sizeof(*ip6) + sizeof(*nd_ns);
346 maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
347 if (max_linkhdr + maxlen >= MCLBYTES) {
348#ifdef DIAGNOSTIC
349 printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
350 "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
351#endif
352 return;
353 }
354
355 MGETHDR(m, M_DONTWAIT, MT_DATA);
356 if (m && max_linkhdr + maxlen >= MHLEN) {
357 MCLGET(m, M_DONTWAIT);
358 if ((m->m_flags & M_EXT) == 0) {
359 m_free(m);
360 m = NULL;
361 }
362 }
363 if (m == NULL)
364 return;
365
366 if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
367 m->m_flags |= M_MCAST;
368 im6o.im6o_multicast_ifp = ifp;
369 im6o.im6o_multicast_hlim = 255;
370 im6o.im6o_multicast_loop = 0;
371 }
372
373 icmp6len = sizeof(*nd_ns);
374 m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
375 m->m_data += max_linkhdr; /*or MH_ALIGN() equivalent?*/
376
377 /* fill neighbor solicitation packet */
378 ip6 = mtod(m, struct ip6_hdr *);
379 ip6->ip6_flow = 0;
380 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
381 ip6->ip6_vfc |= IPV6_VERSION;
382 /* ip6->ip6_plen will be set later */
383 ip6->ip6_nxt = IPPROTO_ICMPV6;
384 ip6->ip6_hlim = 255;
385 if (daddr6)
386 ip6->ip6_dst = *daddr6;
387 else {
388 ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
389 ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
390 ip6->ip6_dst.s6_addr32[1] = 0;
391 ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
392 ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
393 ip6->ip6_dst.s6_addr8[12] = 0xff;
394 }
395 if (!dad) {
396#if 0 /* KAME way, exact address scope match */
397 /*
398 * Select a source whose scope is the same as that of the dest.
399 * Typically, the dest is link-local solicitation multicast
400 * (i.e. neighbor discovery) or link-local/global unicast
401 * (i.e. neighbor un-reachability detection).
402 */
403 ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
404 if (ia == NULL) {
405 m_freem(m);
406 return;
407 }
408 ip6->ip6_src = ia->ia_addr.sin6_addr;
409#else /* spec-wise correct */
410 /*
411 * RFC2461 7.2.2:
412 * "If the source address of the packet prompting the
413 * solicitation is the same as one of the addresses assigned
414 * to the outgoing interface, that address SHOULD be placed
415 * in the IP Source Address of the outgoing solicitation.
416 * Otherwise, any one of the addresses assigned to the
417 * interface should be used."
418 *

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

439 else {
440 ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
441 if (ia == NULL) {
442 m_freem(m); /*XXX*/
443 return;
444 }
445 ip6->ip6_src = ia->ia_addr.sin6_addr;
446 }
447#endif
448 } else {
449 /*
450 * Source address for DAD packet must always be IPv6
451 * unspecified address. (0::0)
452 */
453 bzero(&ip6->ip6_src, sizeof(ip6->ip6_src));
454 }
455 nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);

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

488 bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
489 }
490
491 ip6->ip6_plen = htons((u_short)icmp6len);
492 nd_ns->nd_ns_cksum = 0;
493 nd_ns->nd_ns_cksum
494 = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
495
496#ifdef IPSEC
497 /* Don't lookup socket */
498 ipsec_setsocket(m, NULL);
499#endif
500 ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif);
501 if (outif) {
502 icmp6_ifstat_inc(outif, ifs6_out_msg);
503 icmp6_ifstat_inc(outif, ifs6_out_neighborsolicit);
504 }
505 icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
506}
507
508/*
509 * Neighbor advertisement input handling.
510 *
511 * Based on RFC 2461
512 * Based on RFC 2462 (duplicated address detection)
513 *
514 * the following items are not implemented yet:
515 * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
516 * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
517 */
518void
519nd6_na_input(m, off, icmp6len)
520 struct mbuf *m;
521 int off, icmp6len;
522{
523 struct ifnet *ifp = m->m_pkthdr.rcvif;
524 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
525 struct nd_neighbor_advert *nd_na;
526#if 0
527 struct in6_addr saddr6 = ip6->ip6_src;
528#endif
529 struct in6_addr daddr6 = ip6->ip6_dst;
530 struct in6_addr taddr6;
531 int flags;
532 int is_router;
533 int is_solicited;
534 int is_override;
535 char *lladdr = NULL;
536 int lladdrlen = 0;
537 struct ifaddr *ifa;
538 struct llinfo_nd6 *ln;
539 struct rtentry *rt;
540 struct sockaddr_dl *sdl;
541 union nd_opts ndopts;
542
543 if (ip6->ip6_hlim != 255) {
544 log(LOG_ERR,
545 "nd6_na_input: invalid hlim %d\n", ip6->ip6_hlim);
546 goto freeit;
547 }
548
549#ifndef PULLDOWN_TEST
550 IP6_EXTHDR_CHECK(m, off, icmp6len,);
551 nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
552#else
553 IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
554 if (nd_na == NULL) {
555 icmp6stat.icp6s_tooshort++;
556 return;
557 }
558#endif
559 taddr6 = nd_na->nd_na_target;
560 flags = nd_na->nd_na_flags_reserved;
561 is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
562 is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
563 is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
564
565 if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
566 taddr6.s6_addr16[1] = htons(ifp->if_index);
567
568 if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
569 log(LOG_ERR,
570 "nd6_na_input: invalid target address %s\n",
571 ip6_sprintf(&taddr6));
572 goto freeit;
573 }
574 if (IN6_IS_ADDR_MULTICAST(&daddr6))
575 if (is_solicited) {
576 log(LOG_ERR,
577 "nd6_na_input: a solicited adv is multicasted\n");
578 goto freeit;
579 }
580
581 icmp6len -= sizeof(*nd_na);
582 nd6_option_init(nd_na + 1, icmp6len, &ndopts);
583 if (nd6_options(&ndopts) < 0) {
584 log(LOG_INFO, "nd6_na_input: invalid ND option, ignored\n");
585 goto freeit;
586 }
587
588 if (ndopts.nd_opts_tgt_lladdr) {
589 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
590 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
591 }
592
593 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);

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

599 * already using the same address as mine. This indicates DAD failure.
600 * This is defined in RFC 2462.
601 *
602 * Otherwise, process as defined in RFC 2461.
603 */
604 if (ifa
605 && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
606 nd6_dad_na_input(ifa);
607 goto freeit;
608 }
609
610 /* Just for safety, maybe unnecessery. */
611 if (ifa) {
612 log(LOG_ERR,
613 "nd6_na_input: duplicate IP6 address %s\n",
614 ip6_sprintf(&taddr6));
615 goto freeit;
616 }
617
618 if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
619 log(LOG_INFO,
620 "nd6_na_input: lladdrlen mismatch for %s "
621 "(if %d, NA packet %d)\n",
622 ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2);
623 }
624
625 /*
626 * If no neighbor cache entry is found, NA SHOULD silently be discarded.
627 */
628 rt = nd6_lookup(&taddr6, 0, ifp);
629 if ((rt == NULL) ||
630 ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
631 ((sdl = SDL(rt->rt_gateway)) == NULL))
632 goto freeit;
633
634 if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
635 /*
636 * If the link-layer has address, and no lladdr option came,
637 * discard the packet.
638 */
639 if (ifp->if_addrlen && !lladdr)
640 goto freeit;
641
642 /*
643 * Record link-layer address, and update the state.
644 */
645 sdl->sdl_alen = ifp->if_addrlen;
646 bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
647 if (is_solicited) {
648 ln->ln_state = ND6_LLINFO_REACHABLE;
649 ln->ln_byhint = 0;
650 if (ln->ln_expire)
651 ln->ln_expire = time_second +
652 nd_ifinfo[rt->rt_ifp->if_index].reachable;
653 } else
654 ln->ln_state = ND6_LLINFO_STALE;
655 ln->ln_router = is_router;
656 } else {
657 int llchange;

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

692 */
693 if (!is_override && (lladdr && llchange)) { /* (1) */
694 /*
695 * If state is REACHABLE, make it STALE.
696 * no other updates should be done.
697 */
698 if (ln->ln_state == ND6_LLINFO_REACHABLE)
699 ln->ln_state = ND6_LLINFO_STALE;
700 goto freeit;
701 } else if (is_override /* (2a) */
702 || (!is_override && (lladdr && !llchange)) /* (2b) */
703 || !lladdr) { /* (2c) */
704 /*
705 * Update link-local address, if any.
706 */
707 if (lladdr) {
708 sdl->sdl_alen = ifp->if_addrlen;
709 bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
710 }
711
712 /*
713 * If solicited, make the state REACHABLE.
714 * If not solicited and the link-layer address was
715 * changed, make it STALE.
716 */
717 if (is_solicited) {
718 ln->ln_state = ND6_LLINFO_REACHABLE;
719 ln->ln_byhint = 0;
720 if (ln->ln_expire) {
721 ln->ln_expire = time_second +
722 nd_ifinfo[ifp->if_index].reachable;
723 }
724 } else {
725 if (lladdr && llchange)
726 ln->ln_state = ND6_LLINFO_STALE;
727 }

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

754 }
755 splx(s);
756 }
757 ln->ln_router = is_router;
758 }
759 rt->rt_flags &= ~RTF_REJECT;
760 ln->ln_asked = 0;
761 if (ln->ln_hold) {
762#ifdef OLDIP6OUTPUT
763 (*ifp->if_output)(ifp, ln->ln_hold, rt_key(rt), rt);
764#else
765 /*
766 * we assume ifp is not a p2p here, so just set the 2nd
767 * argument as the 1st one.
768 */
769 nd6_output(ifp, ifp, ln->ln_hold,
770 (struct sockaddr_in6 *)rt_key(rt), rt);
771#endif
772 ln->ln_hold = 0;
773 }
774
775 freeit:
776 m_freem(m);
777}
778
779/*
780 * Neighbor advertisement output handling.
781 *
782 * Based on RFC 2461
783 *
784 * the following items are not implemented yet:
785 * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
786 * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
787 */
788void
789nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
790 struct ifnet *ifp;
791 struct in6_addr *daddr6, *taddr6;
792 u_long flags;
793 int tlladdr; /* 1 if include target link-layer address */
794 struct sockaddr *sdl0; /* sockaddr_dl (= proxy NA) or NULL */
795{
796 struct mbuf *m;
797 struct ip6_hdr *ip6;
798 struct nd_neighbor_advert *nd_na;
799 struct in6_ifaddr *ia = NULL;
800 struct ip6_moptions im6o;
801 int icmp6len;
802 int maxlen;
803 caddr_t mac;
804 struct ifnet *outif = NULL;
805
806 /* estimate the size of message */
807 maxlen = sizeof(*ip6) + sizeof(*nd_na);
808 maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
809 if (max_linkhdr + maxlen >= MCLBYTES) {
810#ifdef DIAGNOSTIC
811 printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
812 "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
813#endif
814 return;
815 }
816
817 MGETHDR(m, M_DONTWAIT, MT_DATA);
818 if (m && max_linkhdr + maxlen >= MHLEN) {
819 MCLGET(m, M_DONTWAIT);
820 if ((m->m_flags & M_EXT) == 0) {
821 m_free(m);
822 m = NULL;
823 }
824 }
825 if (m == NULL)
826 return;
827
828 if (IN6_IS_ADDR_MULTICAST(daddr6)) {
829 m->m_flags |= M_MCAST;
830 im6o.im6o_multicast_ifp = ifp;
831 im6o.im6o_multicast_hlim = 255;
832 im6o.im6o_multicast_loop = 0;
833 }
834
835 icmp6len = sizeof(*nd_na);
836 m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
837 m->m_data += max_linkhdr; /*or MH_ALIGN() equivalent?*/
838
839 /* fill neighbor advertisement packet */
840 ip6 = mtod(m, struct ip6_hdr *);
841 ip6->ip6_flow = 0;
842 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
843 ip6->ip6_vfc |= IPV6_VERSION;
844 ip6->ip6_nxt = IPPROTO_ICMPV6;
845 ip6->ip6_hlim = 255;
846 if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
847 /* reply to DAD */
848 ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
849 ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
850 ip6->ip6_dst.s6_addr32[1] = 0;
851 ip6->ip6_dst.s6_addr32[2] = 0;

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

871 nd_na->nd_na_target.s6_addr16[1] = 0;
872
873 /*
874 * "tlladdr" indicates NS's condition for adding tlladdr or not.
875 * see nd6_ns_input() for details.
876 * Basically, if NS packet is sent to unicast/anycast addr,
877 * target lladdr option SHOULD NOT be included.
878 */
879 if (tlladdr) {
880 mac = NULL;
881 /*
882 * sdl0 != NULL indicates proxy NA. If we do proxy, use
883 * lladdr in sdl0. If we are not proxying (sending NA for
884 * my address) use lladdr configured for the interface.
885 */
886 if (sdl0 == NULL)
887 mac = nd6_ifptomac(ifp);
888 else if (sdl0->sa_family == AF_LINK) {
889 struct sockaddr_dl *sdl;
890 sdl = (struct sockaddr_dl *)sdl0;
891 if (sdl->sdl_alen == ifp->if_addrlen)
892 mac = LLADDR(sdl);
893 }
894 }
895 if (tlladdr && mac) {
896 int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
897 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
898
899 /* roundup to 8 bytes alignment! */
900 optlen = (optlen + 7) & ~7;
901
902 m->m_pkthdr.len += optlen;
903 m->m_len += optlen;

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

911
912 ip6->ip6_plen = htons((u_short)icmp6len);
913 nd_na->nd_na_flags_reserved = flags;
914 nd_na->nd_na_cksum = 0;
915 nd_na->nd_na_cksum =
916 in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
917
918#ifdef IPSEC
919 /* Don't lookup socket */
920 ipsec_setsocket(m, NULL);
921#endif
922 ip6_output(m, NULL, NULL, 0, &im6o, &outif);
923 if (outif) {
924 icmp6_ifstat_inc(outif, ifs6_out_msg);
925 icmp6_ifstat_inc(outif, ifs6_out_neighboradvert);
926 }
927 icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
928}
929

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

942 }
943}
944
945TAILQ_HEAD(dadq_head, dadq);
946struct dadq {
947 TAILQ_ENTRY(dadq) dad_list;
948 struct ifaddr *dad_ifa;
949 int dad_count; /* max NS to send */
950 int dad_ns_tcount; /* # of trials to send NS */
951 int dad_ns_ocount; /* NS sent so far */
952 int dad_ns_icount;
953 int dad_na_icount;
954 struct callout_handle dad_timer;
955};
956
957static struct dadq_head dadq;
958
959static struct dadq *
960nd6_dad_find(ifa)
961 struct ifaddr *ifa;
962{
963 struct dadq *dp;
964
965 for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {
966 if (dp->dad_ifa == ifa)
967 return dp;
968 }
969 return NULL;
970}
971
972/*
973 * Start Duplicated Address Detection (DAD) for specified interface address.

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

988
989 /*
990 * If we don't need DAD, don't do it.
991 * There are several cases:
992 * - DAD is disabled (ip6_dad_count == 0)
993 * - the interface address is anycast
994 */
995 if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
996 log(LOG_DEBUG,
997 "nd6_dad_start: called with non-tentative address "
998 "%s(%s)\n",
999 ip6_sprintf(&ia->ia_addr.sin6_addr),
1000 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1001 return;
1002 }
1003 if (ia->ia6_flags & IN6_IFF_ANYCAST) {
1004 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1005 return;

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

1014 return;
1015 if (nd6_dad_find(ifa) != NULL) {
1016 /* DAD already in progress */
1017 return;
1018 }
1019
1020 dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
1021 if (dp == NULL) {
1022 log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
1023 "%s(%s)\n",
1024 ip6_sprintf(&ia->ia_addr.sin6_addr),
1025 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1026 return;
1027 }
1028 bzero(dp, sizeof(*dp));
1029 TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
1030
1031#ifdef ND6_DEBUG
1032 log(LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
1033 ip6_sprintf(&ia->ia_addr.sin6_addr));
1034#endif
1035
1036 /*
1037 * Send NS packet for DAD, ip6_dad_count times.
1038 * Note that we must delay the first transmission, if this is the
1039 * first packet to be sent from the interface after interface
1040 * (re)initialization.
1041 */
1042 dp->dad_ifa = ifa;
1043 ifa->ifa_refcnt++; /*just for safety*/
1044 dp->dad_count = ip6_dad_count;
1045 dp->dad_ns_icount = dp->dad_na_icount = 0;
1046 dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
1047 if (!tick) {
1048 nd6_dad_ns_output(dp, ifa);
1049 dp->dad_timer =
1050 timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa,
1051 nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
1052 } else {
1053 int ntick;
1054
1055 if (*tick == 0)
1056 ntick = random() % (MAX_RTR_SOLICITATION_DELAY * hz);

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

1070 int s;
1071 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1072 struct dadq *dp;
1073
1074 s = splnet(); /*XXX*/
1075
1076 /* Sanity check */
1077 if (ia == NULL) {
1078 log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
1079 goto done;
1080 }
1081 dp = nd6_dad_find(ifa);
1082 if (dp == NULL) {
1083 log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
1084 goto done;
1085 }
1086 if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
1087 log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
1088 "%s(%s)\n",
1089 ip6_sprintf(&ia->ia_addr.sin6_addr),
1090 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1091 goto done;
1092 }
1093 if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
1094 log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
1095 "%s(%s)\n",
1096 ip6_sprintf(&ia->ia_addr.sin6_addr),
1097 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1098 goto done;
1099 }
1100
1101 /* timeouted with IFF_{RUNNING,UP} check */
1102 if (dp->dad_ns_tcount > dad_maxtry) {
1103 log(LOG_ERR, "%s: could not run DAD, driver problem?\n",
1104 if_name(ifa->ifa_ifp));
1105
1106 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1107 free(dp, M_IP6NDP);
1108 dp = NULL;
1109 IFAFREE(ifa);
1110 goto done;
1111 }
1112
1113 /* Need more checks? */
1114 if (dp->dad_ns_ocount < dp->dad_count) {
1115 /*
1116 * We have more NS to go. Send NS packet for DAD.
1117 */
1118 nd6_dad_ns_output(dp, ifa);
1119 dp->dad_timer =
1120 timeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa,
1121 nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
1122 } else {
1123 /*
1124 * We have transmitted sufficient number of DAD packets.
1125 * See what we've got.
1126 */

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

1132 /*
1133 * the check is in nd6_dad_na_input(),
1134 * but just in case
1135 */
1136 duplicate++;
1137 }
1138
1139 if (dp->dad_ns_icount) {
1140#if 0 /*heuristics*/
1141 /*
1142 * if
1143 * - we have sent many(?) DAD NS, and
1144 * - the number of NS we sent equals to the
1145 * number of NS we've got, and
1146 * - we've got no NA
1147 * we may have a faulty network card/driver which
1148 * loops back multicasts to myself.
1149 */
1150 if (3 < dp->dad_count
1151 && dp->dad_ns_icount == dp->dad_count
1152 && dp->dad_na_icount == 0) {
1153 log(LOG_INFO, "DAD questionable for %s(%s): "
1154 "network card loops back multicast?\n",
1155 ip6_sprintf(&ia->ia_addr.sin6_addr),
1156 if_name(ifa->ifa_ifp));
1157 /* XXX consider it a duplicate or not? */
1158 /* duplicate++; */
1159 } else {
1160 /* We've seen NS, means DAD has failed. */
1161 duplicate++;
1162 }
1163#else
1164 /* We've seen NS, means DAD has failed. */
1165 duplicate++;
1166#endif
1167 }
1168
1169 if (duplicate) {
1170 /* (*dp) will be freed in nd6_dad_duplicated() */
1171 dp = NULL;
1172 nd6_dad_duplicated(ifa);
1173 } else {
1174 /*
1175 * We are done with DAD. No NA came, no NS came.
1176 * duplicated address found.
1177 */
1178 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1179
1180#ifdef ND6_DEBUG
1181 log(LOG_INFO,
1182 "%s: DAD complete for %s - no duplicates found\n",
1183 if_name(ifa->ifa_ifp),
1184 ip6_sprintf(&ia->ia_addr.sin6_addr));
1185#endif
1186
1187 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1188 free(dp, M_IP6NDP);
1189 dp = NULL;
1190 IFAFREE(ifa);
1191 }
1192 }
1193
1194done:
1195 splx(s);
1196}
1197
1198void
1199nd6_dad_duplicated(ifa)
1200 struct ifaddr *ifa;
1201{
1202 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1203 struct dadq *dp;
1204
1205 dp = nd6_dad_find(ifa);
1206 if (dp == NULL) {
1207 log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
1208 return;
1209 }
1210
1211 log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: %d NS, "
1212 "%d NA\n", if_name(ifa->ifa_ifp),
1213 ip6_sprintf(&ia->ia_addr.sin6_addr),
1214 dp->dad_ns_icount, dp->dad_na_icount);
1215
1216 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1217 ia->ia6_flags |= IN6_IFF_DUPLICATED;
1218
1219 /* We are done with DAD, with duplicated address found. (failure) */
1220 untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)ifa
1221 , dp->dad_timer
1222 );
1223
1224 log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
1225 if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
1226 log(LOG_ERR, "%s: manual intervention required\n",
1227 if_name(ifa->ifa_ifp));
1228
1229 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
1230 free(dp, M_IP6NDP);
1231 dp = NULL;
1232 IFAFREE(ifa);
1233}
1234
1235static void
1236nd6_dad_ns_output(dp, ifa)
1237 struct dadq *dp;
1238 struct ifaddr *ifa;
1239{
1240 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1241 struct ifnet *ifp = ifa->ifa_ifp;
1242
1243 dp->dad_ns_tcount++;
1244 if ((ifp->if_flags & IFF_UP) == 0) {
1245#if 0
1246 printf("%s: interface down?\n", if_name(ifp));
1247#endif
1248 return;
1249 }
1250 if ((ifp->if_flags & IFF_RUNNING) == 0) {
1251#if 0
1252 printf("%s: interface not running?\n", if_name(ifp));
1253#endif
1254 return;
1255 }
1256
1257 dp->dad_ns_ocount++;
1258 nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
1259}
1260
1261static void
1262nd6_dad_ns_input(ifa)
1263 struct ifaddr *ifa;
1264{
1265 struct in6_ifaddr *ia;
1266 struct ifnet *ifp;
1267 struct in6_addr *taddr6;
1268 struct dadq *dp;
1269 int duplicate;

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

1308 * not sure if I got a duplicate.
1309 * increment ns count and see what happens.
1310 */
1311 if (dp)
1312 dp->dad_ns_icount++;
1313 }
1314}
1315
1316static void
1317nd6_dad_na_input(ifa)
1318 struct ifaddr *ifa;
1319{
1320 struct dadq *dp;
1321
1322 if (!ifa)
1323 panic("ifa == NULL in nd6_dad_na_input");
1324
1325 dp = nd6_dad_find(ifa);
1326 if (dp)
1327 dp->dad_na_icount++;
1328
1329 /* remove the address. */
1330 nd6_dad_duplicated(ifa);
1331}