Annotation of src/sys/netinet6/nd6_nbr.c, Revision 1.105
1.105 ! roy 1: /* $NetBSD: nd6_nbr.c,v 1.104 2015/02/23 19:15:59 martin Exp $ */
1.28 itojun 2: /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.22 itojun 7: *
1.2 itojun 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
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
1.22 itojun 19: *
1.2 itojun 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
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: */
1.33 lukem 32:
33: #include <sys/cdefs.h>
1.105 ! roy 34: __KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.104 2015/02/23 19:15:59 martin Exp $");
1.2 itojun 35:
36: #include "opt_inet.h"
1.5 thorpej 37: #include "opt_ipsec.h"
1.2 itojun 38:
39: #include <sys/param.h>
40: #include <sys/systm.h>
41: #include <sys/malloc.h>
42: #include <sys/mbuf.h>
43: #include <sys/socket.h>
1.86 ad 44: #include <sys/socketvar.h>
1.2 itojun 45: #include <sys/sockio.h>
46: #include <sys/time.h>
47: #include <sys/kernel.h>
48: #include <sys/errno.h>
49: #include <sys/ioctl.h>
50: #include <sys/syslog.h>
51: #include <sys/queue.h>
1.21 itojun 52: #include <sys/callout.h>
1.2 itojun 53:
54: #include <net/if.h>
55: #include <net/if_types.h>
56: #include <net/if_dl.h>
57: #include <net/route.h>
58:
59: #include <netinet/in.h>
60: #include <netinet/in_var.h>
61: #include <netinet6/in6_var.h>
1.62 rpaulo 62: #include <netinet6/in6_ifattach.h>
1.14 itojun 63: #include <netinet/ip6.h>
1.2 itojun 64: #include <netinet6/ip6_var.h>
1.59 rpaulo 65: #include <netinet6/scope6_var.h>
1.2 itojun 66: #include <netinet6/nd6.h>
1.14 itojun 67: #include <netinet/icmp6.h>
1.85 thorpej 68: #include <netinet6/icmp6_private.h>
1.2 itojun 69:
1.64 liamjfoy 70: #include "carp.h"
71: #if NCARP > 0
72: #include <netinet/ip_carp.h>
73: #endif
74:
1.9 itojun 75: #include <net/net_osdep.h>
76:
1.2 itojun 77: struct dadq;
1.72 dyoung 78: static struct dadq *nd6_dad_find(struct ifaddr *);
79: static void nd6_dad_starttimer(struct dadq *, int);
80: static void nd6_dad_stoptimer(struct dadq *);
81: static void nd6_dad_timer(struct ifaddr *);
82: static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
83: static void nd6_dad_ns_input(struct ifaddr *);
84: static void nd6_dad_na_input(struct ifaddr *);
1.2 itojun 85:
1.9 itojun 86: static int dad_ignore_ns = 0; /* ignore NS in DAD - specwise incorrect*/
87: static int dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */
1.2 itojun 88:
89: /*
1.61 rpaulo 90: * Input a Neighbor Solicitation Message.
1.2 itojun 91: *
92: * Based on RFC 2461
1.61 rpaulo 93: * Based on RFC 2462 (duplicate address detection)
1.2 itojun 94: */
95: void
1.72 dyoung 96: nd6_ns_input(struct mbuf *m, int off, int icmp6len)
1.2 itojun 97: {
98: struct ifnet *ifp = m->m_pkthdr.rcvif;
99: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.16 itojun 100: struct nd_neighbor_solicit *nd_ns;
1.2 itojun 101: struct in6_addr saddr6 = ip6->ip6_src;
102: struct in6_addr daddr6 = ip6->ip6_dst;
1.16 itojun 103: struct in6_addr taddr6;
1.2 itojun 104: struct in6_addr myaddr6;
105: char *lladdr = NULL;
106: struct ifaddr *ifa;
107: int lladdrlen = 0;
108: int anycast = 0, proxy = 0, tentative = 0;
1.39 itojun 109: int router = ip6_forwarding;
1.2 itojun 110: int tlladdr;
111: union nd_opts ndopts;
1.78 dyoung 112: const struct sockaddr_dl *proxydl = NULL;
1.2 itojun 113:
1.26 itojun 114: IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
115: if (nd_ns == NULL) {
1.85 thorpej 116: ICMP6_STATINC(ICMP6_STAT_TOOSHORT);
1.26 itojun 117: return;
118: }
119: ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
120: taddr6 = nd_ns->nd_ns_target;
1.59 rpaulo 121: if (in6_setscope(&taddr6, ifp, NULL) != 0)
122: goto bad;
1.26 itojun 123:
1.2 itojun 124: if (ip6->ip6_hlim != 255) {
1.26 itojun 125: nd6log((LOG_ERR,
126: "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
127: ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
128: ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
129: goto bad;
1.2 itojun 130: }
131:
132: if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
1.61 rpaulo 133: /* dst has to be a solicited node multicast address. */
1.39 itojun 134: /* don't check ifindex portion */
135: if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
136: daddr6.s6_addr32[1] == 0 &&
137: daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
138: daddr6.s6_addr8[12] == 0xff) {
1.31 itojun 139: ; /* good */
1.2 itojun 140: } else {
1.26 itojun 141: nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
1.39 itojun 142: "(wrong ip6 dst)\n"));
1.2 itojun 143: goto bad;
144: }
1.89 matt 145: } else {
1.99 roy 146: struct sockaddr_in6 ssin6;
147:
1.89 matt 148: /*
149: * Make sure the source address is from a neighbor's address.
150: */
1.99 roy 151: sockaddr_in6_init(&ssin6, &saddr6, 0, 0, 0);
152: if (nd6_is_addr_neighbor(&ssin6, ifp) == 0) {
1.89 matt 153: nd6log((LOG_INFO, "nd6_ns_input: "
154: "NS packet from non-neighbor\n"));
155: goto bad;
156: }
1.2 itojun 157: }
158:
1.89 matt 159:
1.2 itojun 160: if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
1.26 itojun 161: nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
1.2 itojun 162: goto bad;
163: }
164:
165: icmp6len -= sizeof(*nd_ns);
166: nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
167: if (nd6_options(&ndopts) < 0) {
1.26 itojun 168: nd6log((LOG_INFO,
169: "nd6_ns_input: invalid ND option, ignored\n"));
170: /* nd6_options have incremented stats */
171: goto freeit;
1.2 itojun 172: }
173:
174: if (ndopts.nd_opts_src_lladdr) {
1.31 itojun 175: lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
1.2 itojun 176: lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
177: }
1.42 itojun 178:
1.2 itojun 179: if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
1.26 itojun 180: nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
181: "(link-layer address option)\n"));
1.2 itojun 182: goto bad;
183: }
184:
185: /*
186: * Attaching target link-layer address to the NA?
187: * (RFC 2461 7.2.4)
188: *
1.62 rpaulo 189: * NS IP dst is multicast MUST add
190: * Otherwise MAY be omitted
1.2 itojun 191: *
1.62 rpaulo 192: * In this implementation, we omit the target link-layer address
193: * in the "MAY" case.
1.2 itojun 194: */
195: #if 0 /* too much! */
196: ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
197: if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
198: tlladdr = 0;
199: else
200: #endif
201: if (!IN6_IS_ADDR_MULTICAST(&daddr6))
202: tlladdr = 0;
203: else
204: tlladdr = 1;
205:
206: /*
207: * Target address (taddr6) must be either:
208: * (1) Valid unicast/anycast address for my receiving interface,
209: * (2) Unicast address for which I'm offering proxy service, or
210: * (3) "tentative" address on which DAD is being performed.
211: */
212: /* (1) and (3) check. */
1.64 liamjfoy 213: #if NCARP > 0
214: if (ifp->if_carp && ifp->if_type != IFT_CARP)
215: ifa = carp_iamatch6(ifp->if_carp, &taddr6);
216: else
217: ifa = NULL;
218: if (!ifa)
219: ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
220: #else
1.2 itojun 221: ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
1.64 liamjfoy 222: #endif
1.2 itojun 223:
224: /* (2) check. */
1.62 rpaulo 225: if (ifa == NULL) {
1.2 itojun 226: struct rtentry *rt;
227: struct sockaddr_in6 tsin6;
228:
1.81 dyoung 229: sockaddr_in6_init(&tsin6, &taddr6, 0, 0, 0);
1.2 itojun 230:
1.17 itojun 231: rt = rtalloc1((struct sockaddr *)&tsin6, 0);
1.16 itojun 232: if (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
233: rt->rt_gateway->sa_family == AF_LINK) {
1.2 itojun 234: /*
1.16 itojun 235: * proxy NDP for single entry
1.2 itojun 236: */
1.16 itojun 237: ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
238: IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
239: if (ifa) {
1.2 itojun 240: proxy = 1;
1.78 dyoung 241: proxydl = satocsdl(rt->rt_gateway);
1.39 itojun 242: router = 0; /* XXX */
1.16 itojun 243: }
1.2 itojun 244: }
1.16 itojun 245: if (rt)
246: rtfree(rt);
1.2 itojun 247: }
1.62 rpaulo 248: if (ifa == NULL) {
1.2 itojun 249: /*
1.60 wiz 250: * We've got an NS packet, and we don't have that address
1.2 itojun 251: * assigned for us. We MUST silently ignore it.
252: * See RFC2461 7.2.3.
253: */
1.16 itojun 254: goto freeit;
1.2 itojun 255: }
1.9 itojun 256: myaddr6 = *IFA_IN6(ifa);
1.2 itojun 257: anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
258: tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
259: if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
1.16 itojun 260: goto freeit;
1.2 itojun 261:
262: if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
1.39 itojun 263: nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
1.2 itojun 264: "(if %d, NS packet %d)\n",
1.39 itojun 265: ip6_sprintf(&taddr6), ifp->if_addrlen, lladdrlen - 2));
1.26 itojun 266: goto bad;
1.2 itojun 267: }
268:
269: if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
1.39 itojun 270: nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
1.31 itojun 271: ip6_sprintf(&saddr6)));
1.16 itojun 272: goto freeit;
1.2 itojun 273: }
274:
275: /*
276: * We have neighbor solicitation packet, with target address equals to
277: * one of my tentative address.
278: *
279: * src addr how to process?
280: * --- ---
281: * multicast of course, invalid (rejected in ip6_input)
282: * unicast somebody is doing address resolution -> ignore
283: * unspec dup address detection
284: *
285: * The processing is defined in RFC 2462.
286: */
287: if (tentative) {
288: /*
289: * If source address is unspecified address, it is for
1.61 rpaulo 290: * duplicate address detection.
1.2 itojun 291: *
292: * If not, the packet is for addess resolution;
293: * silently ignore it.
294: */
295: if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
296: nd6_dad_ns_input(ifa);
297:
1.16 itojun 298: goto freeit;
1.2 itojun 299: }
300:
301: /*
302: * If the source address is unspecified address, entries must not
303: * be created or updated.
304: * It looks that sender is performing DAD. Output NA toward
305: * all-node multicast address, to tell the sender that I'm using
306: * the address.
307: * S bit ("solicited") must be zero.
308: */
309: if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
1.59 rpaulo 310: struct in6_addr in6_all;
311:
312: in6_all = in6addr_linklocal_allnodes;
313: if (in6_setscope(&in6_all, ifp, NULL) != 0)
314: goto bad;
315: nd6_na_output(ifp, &in6_all, &taddr6,
1.39 itojun 316: ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
1.59 rpaulo 317: (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
1.78 dyoung 318: tlladdr, (const struct sockaddr *)proxydl);
1.16 itojun 319: goto freeit;
1.2 itojun 320: }
321:
1.7 itojun 322: nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_NEIGHBOR_SOLICIT, 0);
1.2 itojun 323:
324: nd6_na_output(ifp, &saddr6, &taddr6,
1.39 itojun 325: ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
326: (router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
1.78 dyoung 327: tlladdr, (const struct sockaddr *)proxydl);
1.16 itojun 328: freeit:
329: m_freem(m);
1.2 itojun 330: return;
331:
332: bad:
1.26 itojun 333: nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)));
334: nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)));
335: nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)));
1.85 thorpej 336: ICMP6_STATINC(ICMP6_STAT_BADNS);
1.16 itojun 337: m_freem(m);
1.2 itojun 338: }
339:
340: /*
1.61 rpaulo 341: * Output a Neighbor Solicitation Message. Caller specifies:
1.2 itojun 342: * - ICMP6 header source IP6 address
343: * - ND6 header target IP6 address
344: * - ND6 header source datalink address
345: *
346: * Based on RFC 2461
1.61 rpaulo 347: * Based on RFC 2462 (duplicate address detection)
1.2 itojun 348: */
349: void
1.72 dyoung 350: nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
351: const struct in6_addr *taddr6,
352: struct llinfo_nd6 *ln, /* for source address determination */
353: int dad /* duplicate address detection */)
1.2 itojun 354: {
355: struct mbuf *m;
356: struct ip6_hdr *ip6;
357: struct nd_neighbor_solicit *nd_ns;
1.59 rpaulo 358: struct in6_addr *src, src_in;
1.2 itojun 359: struct ip6_moptions im6o;
360: int icmp6len;
1.15 itojun 361: int maxlen;
1.80 dyoung 362: const void *mac;
1.73 dyoung 363: struct route ro;
1.39 itojun 364:
1.2 itojun 365: if (IN6_IS_ADDR_MULTICAST(taddr6))
366: return;
367:
1.82 dyoung 368: memset(&ro, 0, sizeof(ro));
369:
1.15 itojun 370: /* estimate the size of message */
371: maxlen = sizeof(*ip6) + sizeof(*nd_ns);
372: maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
1.29 itojun 373: #ifdef DIAGNOSTIC
1.15 itojun 374: if (max_linkhdr + maxlen >= MCLBYTES) {
375: printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
376: "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
1.29 itojun 377: panic("nd6_ns_output: insufficient MCLBYTES");
378: /* NOTREACHED */
379: }
1.15 itojun 380: #endif
381:
382: MGETHDR(m, M_DONTWAIT, MT_DATA);
383: if (m && max_linkhdr + maxlen >= MHLEN) {
384: MCLGET(m, M_DONTWAIT);
385: if ((m->m_flags & M_EXT) == 0) {
386: m_free(m);
387: m = NULL;
388: }
389: }
390: if (m == NULL)
1.2 itojun 391: return;
1.31 itojun 392: m->m_pkthdr.rcvif = NULL;
1.2 itojun 393:
394: if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
395: m->m_flags |= M_MCAST;
396: im6o.im6o_multicast_ifp = ifp;
397: im6o.im6o_multicast_hlim = 255;
398: im6o.im6o_multicast_loop = 0;
399: }
400:
401: icmp6len = sizeof(*nd_ns);
402: m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
1.31 itojun 403: m->m_data += max_linkhdr; /* or MH_ALIGN() equivalent? */
1.2 itojun 404:
405: /* fill neighbor solicitation packet */
406: ip6 = mtod(m, struct ip6_hdr *);
407: ip6->ip6_flow = 0;
1.10 itojun 408: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
409: ip6->ip6_vfc |= IPV6_VERSION;
1.2 itojun 410: /* ip6->ip6_plen will be set later */
411: ip6->ip6_nxt = IPPROTO_ICMPV6;
412: ip6->ip6_hlim = 255;
413: if (daddr6)
1.59 rpaulo 414: ip6->ip6_dst = *daddr6;
1.2 itojun 415: else {
1.59 rpaulo 416: ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
417: ip6->ip6_dst.s6_addr16[1] = 0;
418: ip6->ip6_dst.s6_addr32[1] = 0;
419: ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
420: ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
421: ip6->ip6_dst.s6_addr8[12] = 0xff;
422: if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
423: goto bad;
1.2 itojun 424: }
425: if (!dad) {
426: /*
427: * RFC2461 7.2.2:
428: * "If the source address of the packet prompting the
429: * solicitation is the same as one of the addresses assigned
430: * to the outgoing interface, that address SHOULD be placed
431: * in the IP Source Address of the outgoing solicitation.
432: * Otherwise, any one of the addresses assigned to the
433: * interface should be used."
434: *
435: * We use the source address for the prompting packet
1.59 rpaulo 436: * (hsrc), if:
437: * - hsrc is given from the caller (by giving "ln"), and
438: * - hsrc belongs to the outgoing interface.
1.39 itojun 439: * Otherwise, we perform the source address selection as usual.
1.2 itojun 440: */
1.31 itojun 441: struct ip6_hdr *hip6; /* hold ip6 */
1.59 rpaulo 442: struct in6_addr *hsrc = NULL;
1.2 itojun 443:
444: if (ln && ln->ln_hold) {
1.62 rpaulo 445: /*
446: * assuming every packet in ln_hold has the same IP
447: * header
448: */
1.2 itojun 449: hip6 = mtod(ln->ln_hold, struct ip6_hdr *);
450: /* XXX pullup? */
451: if (sizeof(*hip6) < ln->ln_hold->m_len)
1.59 rpaulo 452: hsrc = &hip6->ip6_src;
1.2 itojun 453: else
1.59 rpaulo 454: hsrc = NULL;
455: }
456: if (hsrc && in6ifa_ifpwithaddr(ifp, hsrc))
457: src = hsrc;
1.2 itojun 458: else {
1.39 itojun 459: int error;
1.59 rpaulo 460: struct sockaddr_in6 dst_sa;
1.39 itojun 461:
1.81 dyoung 462: sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0);
1.59 rpaulo 463:
464: src = in6_selectsrc(&dst_sa, NULL,
1.73 dyoung 465: NULL, &ro, NULL, NULL, &error);
1.59 rpaulo 466: if (src == NULL) {
1.39 itojun 467: nd6log((LOG_DEBUG,
468: "nd6_ns_output: source can't be "
469: "determined: dst=%s, error=%d\n",
470: ip6_sprintf(&dst_sa.sin6_addr), error));
471: goto bad;
1.2 itojun 472: }
473: }
474: } else {
475: /*
476: * Source address for DAD packet must always be IPv6
477: * unspecified address. (0::0)
1.39 itojun 478: * We actually don't have to 0-clear the address (we did it
479: * above), but we do so here explicitly to make the intention
480: * clearer.
1.2 itojun 481: */
1.92 cegger 482: memset(&src_in, 0, sizeof(src_in));
1.59 rpaulo 483: src = &src_in;
1.2 itojun 484: }
1.59 rpaulo 485: ip6->ip6_src = *src;
1.2 itojun 486: nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);
487: nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
488: nd_ns->nd_ns_code = 0;
489: nd_ns->nd_ns_reserved = 0;
490: nd_ns->nd_ns_target = *taddr6;
1.59 rpaulo 491: in6_clearscope(&nd_ns->nd_ns_target); /* XXX */
1.2 itojun 492:
493: /*
494: * Add source link-layer address option.
495: *
496: * spec implementation
497: * --- ---
498: * DAD packet MUST NOT do not add the option
499: * there's no link layer address:
500: * impossible do not add the option
501: * there's link layer address:
502: * Multicast NS MUST add one add the option
503: * Unicast NS SHOULD add one add the option
504: */
505: if (!dad && (mac = nd6_ifptomac(ifp))) {
506: int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
507: struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
1.8 is 508: /* 8 byte alignments... */
509: optlen = (optlen + 7) & ~7;
1.42 itojun 510:
1.2 itojun 511: m->m_pkthdr.len += optlen;
512: m->m_len += optlen;
513: icmp6len += optlen;
1.92 cegger 514: memset((void *)nd_opt, 0, optlen);
1.2 itojun 515: nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
516: nd_opt->nd_opt_len = optlen >> 3;
1.94 tsutsui 517: memcpy((void *)(nd_opt + 1), mac, ifp->if_addrlen);
1.2 itojun 518: }
519:
1.51 itojun 520: ip6->ip6_plen = htons((u_int16_t)icmp6len);
1.2 itojun 521: nd_ns->nd_ns_cksum = 0;
1.39 itojun 522: nd_ns->nd_ns_cksum =
523: in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
1.2 itojun 524:
1.59 rpaulo 525: ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL, NULL);
1.32 itojun 526: icmp6_ifstat_inc(ifp, ifs6_out_msg);
527: icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
1.85 thorpej 528: ICMP6_STATINC(ICMP6_STAT_OUTHIST + ND_NEIGHBOR_SOLICIT);
1.32 itojun 529:
1.73 dyoung 530: rtcache_free(&ro);
1.32 itojun 531: return;
532:
533: bad:
1.73 dyoung 534: rtcache_free(&ro);
1.32 itojun 535: m_freem(m);
536: return;
1.2 itojun 537: }
538:
539: /*
540: * Neighbor advertisement input handling.
541: *
542: * Based on RFC 2461
1.61 rpaulo 543: * Based on RFC 2462 (duplicate address detection)
1.16 itojun 544: *
545: * the following items are not implemented yet:
546: * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
547: * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
1.2 itojun 548: */
549: void
1.72 dyoung 550: nd6_na_input(struct mbuf *m, int off, int icmp6len)
1.2 itojun 551: {
552: struct ifnet *ifp = m->m_pkthdr.rcvif;
553: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.16 itojun 554: struct nd_neighbor_advert *nd_na;
1.2 itojun 555: struct in6_addr saddr6 = ip6->ip6_src;
556: struct in6_addr daddr6 = ip6->ip6_dst;
1.16 itojun 557: struct in6_addr taddr6;
558: int flags;
559: int is_router;
560: int is_solicited;
561: int is_override;
1.2 itojun 562: char *lladdr = NULL;
563: int lladdrlen = 0;
564: struct ifaddr *ifa;
565: struct llinfo_nd6 *ln;
566: struct rtentry *rt;
567: struct sockaddr_dl *sdl;
568: union nd_opts ndopts;
1.99 roy 569: struct sockaddr_in6 ssin6;
1.103 roy 570: int rt_announce;
1.2 itojun 571:
572: if (ip6->ip6_hlim != 255) {
1.26 itojun 573: nd6log((LOG_ERR,
574: "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n",
575: ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
576: ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
577: goto bad;
1.16 itojun 578: }
579:
580: IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
581: if (nd_na == NULL) {
1.85 thorpej 582: ICMP6_STATINC(ICMP6_STAT_TOOSHORT);
1.2 itojun 583: return;
584: }
1.59 rpaulo 585:
1.16 itojun 586: flags = nd_na->nd_na_flags_reserved;
587: is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
588: is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
589: is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
1.2 itojun 590:
1.59 rpaulo 591: taddr6 = nd_na->nd_na_target;
592: if (in6_setscope(&taddr6, ifp, NULL))
593: return; /* XXX: impossible */
1.2 itojun 594:
595: if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
1.26 itojun 596: nd6log((LOG_ERR,
1.2 itojun 597: "nd6_na_input: invalid target address %s\n",
1.26 itojun 598: ip6_sprintf(&taddr6)));
599: goto bad;
1.2 itojun 600: }
1.39 itojun 601: if (is_solicited && IN6_IS_ADDR_MULTICAST(&daddr6)) {
602: nd6log((LOG_ERR,
603: "nd6_na_input: a solicited adv is multicasted\n"));
604: goto bad;
605: }
1.2 itojun 606:
607: icmp6len -= sizeof(*nd_na);
608: nd6_option_init(nd_na + 1, icmp6len, &ndopts);
609: if (nd6_options(&ndopts) < 0) {
1.26 itojun 610: nd6log((LOG_INFO,
611: "nd6_na_input: invalid ND option, ignored\n"));
612: /* nd6_options have incremented stats */
1.16 itojun 613: goto freeit;
1.2 itojun 614: }
615:
616: if (ndopts.nd_opts_tgt_lladdr) {
617: lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
618: lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
619: }
620:
621: ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
622:
623: /*
624: * Target address matches one of my interface address.
625: *
626: * If my address is tentative, this means that there's somebody
627: * already using the same address as mine. This indicates DAD failure.
628: * This is defined in RFC 2462.
629: *
630: * Otherwise, process as defined in RFC 2461.
631: */
632: if (ifa
633: && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
634: nd6_dad_na_input(ifa);
1.16 itojun 635: goto freeit;
1.2 itojun 636: }
637:
1.31 itojun 638: /* Just for safety, maybe unnecessary. */
1.2 itojun 639: if (ifa) {
640: log(LOG_ERR,
641: "nd6_na_input: duplicate IP6 address %s\n",
642: ip6_sprintf(&taddr6));
1.16 itojun 643: goto freeit;
1.2 itojun 644: }
1.99 roy 645:
1.90 matt 646: /*
647: * Make sure the source address is from a neighbor's address.
648: */
1.99 roy 649: sockaddr_in6_init(&ssin6, &saddr6, 0, 0, 0);
650: if (nd6_is_addr_neighbor(&ssin6, ifp) == 0) {
651: nd6log((LOG_INFO, "nd6_na_input: "
1.90 matt 652: "ND packet from non-neighbor\n"));
653: goto bad;
654: }
1.2 itojun 655:
656: if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
1.39 itojun 657: nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "
658: "(if %d, NA packet %d)\n", ip6_sprintf(&taddr6),
659: ifp->if_addrlen, lladdrlen - 2));
1.26 itojun 660: goto bad;
1.2 itojun 661: }
662:
663: /*
1.39 itojun 664: * If no neighbor cache entry is found, NA SHOULD silently be
665: * discarded.
1.2 itojun 666: */
667: rt = nd6_lookup(&taddr6, 0, ifp);
668: if ((rt == NULL) ||
669: ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
1.78 dyoung 670: ((sdl = satosdl(rt->rt_gateway)) == NULL))
1.16 itojun 671: goto freeit;
1.2 itojun 672:
1.103 roy 673: rt_announce = 0;
1.2 itojun 674: if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
675: /*
676: * If the link-layer has address, and no lladdr option came,
677: * discard the packet.
678: */
679: if (ifp->if_addrlen && !lladdr)
1.16 itojun 680: goto freeit;
1.2 itojun 681:
682: /*
683: * Record link-layer address, and update the state.
684: */
1.80 dyoung 685: (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr,
686: ifp->if_addrlen);
1.103 roy 687: rt_announce = 1;
1.2 itojun 688: if (is_solicited) {
689: ln->ln_state = ND6_LLINFO_REACHABLE;
1.27 itojun 690: ln->ln_byhint = 0;
1.47 itojun 691: if (!ND6_LLINFO_PERMANENT(ln)) {
692: nd6_llinfo_settimer(ln,
693: (long)ND_IFINFO(rt->rt_ifp)->reachable * hz);
694: }
1.28 itojun 695: } else {
1.2 itojun 696: ln->ln_state = ND6_LLINFO_STALE;
1.47 itojun 697: nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
1.31 itojun 698: }
699: if ((ln->ln_router = is_router) != 0) {
700: /*
701: * This means a router's state has changed from
702: * non-reachable to probably reachable, and might
703: * affect the status of associated prefixes..
704: */
705: pfxlist_onlink_check();
1.28 itojun 706: }
1.2 itojun 707: } else {
708: int llchange;
709:
710: /*
711: * Check if the link-layer address has changed or not.
712: */
1.62 rpaulo 713: if (lladdr == NULL)
1.2 itojun 714: llchange = 0;
715: else {
716: if (sdl->sdl_alen) {
1.91 cegger 717: if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen))
1.103 roy 718: llchange = rt_announce = 1;
1.2 itojun 719: else
720: llchange = 0;
721: } else
1.103 roy 722: llchange = rt_announce = 1;
1.2 itojun 723: }
724:
725: /*
726: * This is VERY complex. Look at it with care.
727: *
728: * override solicit lladdr llchange action
729: * (L: record lladdr)
730: *
731: * 0 0 n -- (2c)
732: * 0 0 y n (2b) L
733: * 0 0 y y (1) REACHABLE->STALE
734: * 0 1 n -- (2c) *->REACHABLE
735: * 0 1 y n (2b) L *->REACHABLE
736: * 0 1 y y (1) REACHABLE->STALE
737: * 1 0 n -- (2a)
738: * 1 0 y n (2a) L
739: * 1 0 y y (2a) L *->STALE
740: * 1 1 n -- (2a) *->REACHABLE
741: * 1 1 y n (2a) L *->REACHABLE
742: * 1 1 y y (2a) L *->REACHABLE
743: */
1.62 rpaulo 744: if (!is_override && lladdr != NULL && llchange) { /* (1) */
1.2 itojun 745: /*
746: * If state is REACHABLE, make it STALE.
747: * no other updates should be done.
748: */
1.28 itojun 749: if (ln->ln_state == ND6_LLINFO_REACHABLE) {
1.2 itojun 750: ln->ln_state = ND6_LLINFO_STALE;
1.47 itojun 751: nd6_llinfo_settimer(ln, (long)nd6_gctimer * hz);
1.28 itojun 752: }
1.16 itojun 753: goto freeit;
1.2 itojun 754: } else if (is_override /* (2a) */
1.62 rpaulo 755: || (!is_override && lladdr != NULL && !llchange) /* (2b) */
756: || lladdr == NULL) { /* (2c) */
1.2 itojun 757: /*
758: * Update link-local address, if any.
759: */
1.62 rpaulo 760: if (lladdr != NULL) {
1.80 dyoung 761: (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len,
762: lladdr, ifp->if_addrlen);
1.2 itojun 763: }
764:
765: /*
766: * If solicited, make the state REACHABLE.
767: * If not solicited and the link-layer address was
768: * changed, make it STALE.
769: */
770: if (is_solicited) {
771: ln->ln_state = ND6_LLINFO_REACHABLE;
1.27 itojun 772: ln->ln_byhint = 0;
1.47 itojun 773: if (!ND6_LLINFO_PERMANENT(ln)) {
774: nd6_llinfo_settimer(ln,
775: (long)ND_IFINFO(ifp)->reachable * hz);
1.2 itojun 776: }
777: } else {
1.28 itojun 778: if (lladdr && llchange) {
1.2 itojun 779: ln->ln_state = ND6_LLINFO_STALE;
1.47 itojun 780: nd6_llinfo_settimer(ln,
781: (long)nd6_gctimer * hz);
1.28 itojun 782: }
1.2 itojun 783: }
784: }
785:
786: if (ln->ln_router && !is_router) {
787: /*
788: * The peer dropped the router flag.
789: * Remove the sender from the Default Router List and
790: * update the Destination Cache entries.
791: */
792: struct nd_defrouter *dr;
1.77 dyoung 793: const struct in6_addr *in6;
1.2 itojun 794: int s;
795:
1.77 dyoung 796: in6 = &satocsin6(rt_getkey(rt))->sin6_addr;
1.29 itojun 797:
798: /*
799: * Lock to protect the default router list.
800: * XXX: this might be unnecessary, since this function
801: * is only called under the network software interrupt
1.37 itojun 802: * context. However, we keep it just for safety.
1.29 itojun 803: */
1.4 itojun 804: s = splsoftnet();
1.2 itojun 805: dr = defrouter_lookup(in6, rt->rt_ifp);
806: if (dr)
1.104 martin 807: defrtrlist_del(dr, NULL);
1.46 itojun 808: else if (!ip6_forwarding) {
1.2 itojun 809: /*
810: * Even if the neighbor is not in the default
811: * router list, the neighbor may be used
812: * as a next hop for some destinations
813: * (e.g. redirect case). So we must
814: * call rt6_flush explicitly.
815: */
816: rt6_flush(&ip6->ip6_src, rt->rt_ifp);
817: }
818: splx(s);
819: }
820: ln->ln_router = is_router;
821: }
822: rt->rt_flags &= ~RTF_REJECT;
823: ln->ln_asked = 0;
1.74 dyoung 824: nd6_llinfo_release_pkts(ln, ifp, rt);
1.103 roy 825: if (rt_announce) /* tell user process about any new lladdr */
826: nd6_rtmsg(RTM_CHANGE, rt);
1.16 itojun 827:
828: freeit:
829: m_freem(m);
1.26 itojun 830: return;
831:
832: bad:
1.85 thorpej 833: ICMP6_STATINC(ICMP6_STAT_BADNA);
1.26 itojun 834: m_freem(m);
1.2 itojun 835: }
836:
837: /*
838: * Neighbor advertisement output handling.
839: *
840: * Based on RFC 2461
841: *
1.16 itojun 842: * the following items are not implemented yet:
843: * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
844: * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
1.2 itojun 845: */
846: void
1.83 matt 847: nd6_na_output(
848: struct ifnet *ifp,
849: const struct in6_addr *daddr6_0,
850: const struct in6_addr *taddr6,
851: u_long flags,
852: int tlladdr, /* 1 if include target link-layer address */
853: const struct sockaddr *sdl0) /* sockaddr_dl (= proxy NA) or NULL */
1.2 itojun 854: {
855: struct mbuf *m;
856: struct ip6_hdr *ip6;
857: struct nd_neighbor_advert *nd_na;
858: struct ip6_moptions im6o;
1.73 dyoung 859: struct sockaddr *dst;
860: union {
861: struct sockaddr dst;
862: struct sockaddr_in6 dst6;
863: } u;
1.59 rpaulo 864: struct in6_addr *src, daddr6;
1.39 itojun 865: int icmp6len, maxlen, error;
1.78 dyoung 866: const void *mac;
1.73 dyoung 867: struct route ro;
1.39 itojun 868:
869: mac = NULL;
1.69 dyoung 870: memset(&ro, 0, sizeof(ro));
1.15 itojun 871:
1.59 rpaulo 872: daddr6 = *daddr6_0; /* make a local copy for modification */
873:
1.15 itojun 874: /* estimate the size of message */
875: maxlen = sizeof(*ip6) + sizeof(*nd_na);
876: maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
1.29 itojun 877: #ifdef DIAGNOSTIC
1.15 itojun 878: if (max_linkhdr + maxlen >= MCLBYTES) {
879: printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
880: "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
1.29 itojun 881: panic("nd6_na_output: insufficient MCLBYTES");
882: /* NOTREACHED */
883: }
1.15 itojun 884: #endif
885:
886: MGETHDR(m, M_DONTWAIT, MT_DATA);
887: if (m && max_linkhdr + maxlen >= MHLEN) {
888: MCLGET(m, M_DONTWAIT);
889: if ((m->m_flags & M_EXT) == 0) {
890: m_free(m);
891: m = NULL;
892: }
893: }
894: if (m == NULL)
1.2 itojun 895: return;
1.31 itojun 896: m->m_pkthdr.rcvif = NULL;
1.2 itojun 897:
1.59 rpaulo 898: if (IN6_IS_ADDR_MULTICAST(&daddr6)) {
1.2 itojun 899: m->m_flags |= M_MCAST;
900: im6o.im6o_multicast_ifp = ifp;
901: im6o.im6o_multicast_hlim = 255;
902: im6o.im6o_multicast_loop = 0;
903: }
904:
905: icmp6len = sizeof(*nd_na);
906: m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
1.31 itojun 907: m->m_data += max_linkhdr; /* or MH_ALIGN() equivalent? */
1.2 itojun 908:
909: /* fill neighbor advertisement packet */
910: ip6 = mtod(m, struct ip6_hdr *);
911: ip6->ip6_flow = 0;
1.10 itojun 912: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
913: ip6->ip6_vfc |= IPV6_VERSION;
1.2 itojun 914: ip6->ip6_nxt = IPPROTO_ICMPV6;
915: ip6->ip6_hlim = 255;
1.59 rpaulo 916: if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) {
1.2 itojun 917: /* reply to DAD */
1.59 rpaulo 918: daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
919: daddr6.s6_addr16[1] = 0;
920: daddr6.s6_addr32[1] = 0;
921: daddr6.s6_addr32[2] = 0;
922: daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
923: if (in6_setscope(&daddr6, ifp, NULL))
924: goto bad;
1.39 itojun 925:
1.2 itojun 926: flags &= ~ND_NA_FLAG_SOLICITED;
1.39 itojun 927: }
1.59 rpaulo 928: ip6->ip6_dst = daddr6;
1.73 dyoung 929: sockaddr_in6_init(&u.dst6, &daddr6, 0, 0, 0);
930: dst = &u.dst;
931: rtcache_setdst(&ro, dst);
1.2 itojun 932:
933: /*
934: * Select a source whose scope is the same as that of the dest.
935: */
1.88 dyoung 936: src = in6_selectsrc(satosin6(dst), NULL, NULL, &ro, NULL, NULL, &error);
1.59 rpaulo 937: if (src == NULL) {
1.39 itojun 938: nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
939: "determined: dst=%s, error=%d\n",
1.73 dyoung 940: ip6_sprintf(&satocsin6(dst)->sin6_addr), error));
1.39 itojun 941: goto bad;
1.2 itojun 942: }
1.59 rpaulo 943: ip6->ip6_src = *src;
1.2 itojun 944: nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
945: nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
946: nd_na->nd_na_code = 0;
947: nd_na->nd_na_target = *taddr6;
1.59 rpaulo 948: in6_clearscope(&nd_na->nd_na_target); /* XXX */
1.2 itojun 949:
950: /*
951: * "tlladdr" indicates NS's condition for adding tlladdr or not.
952: * see nd6_ns_input() for details.
953: * Basically, if NS packet is sent to unicast/anycast addr,
954: * target lladdr option SHOULD NOT be included.
955: */
1.16 itojun 956: if (tlladdr) {
957: /*
958: * sdl0 != NULL indicates proxy NA. If we do proxy, use
959: * lladdr in sdl0. If we are not proxying (sending NA for
960: * my address) use lladdr configured for the interface.
961: */
962: if (sdl0 == NULL)
963: mac = nd6_ifptomac(ifp);
964: else if (sdl0->sa_family == AF_LINK) {
1.78 dyoung 965: const struct sockaddr_dl *sdl;
966: sdl = satocsdl(sdl0);
1.16 itojun 967: if (sdl->sdl_alen == ifp->if_addrlen)
1.78 dyoung 968: mac = CLLADDR(sdl);
1.16 itojun 969: }
970: }
971: if (tlladdr && mac) {
1.2 itojun 972: int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
973: struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
1.42 itojun 974:
1.8 is 975: /* roundup to 8 bytes alignment! */
976: optlen = (optlen + 7) & ~7;
977:
1.2 itojun 978: m->m_pkthdr.len += optlen;
979: m->m_len += optlen;
980: icmp6len += optlen;
1.92 cegger 981: memset((void *)nd_opt, 0, optlen);
1.2 itojun 982: nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
983: nd_opt->nd_opt_len = optlen >> 3;
1.94 tsutsui 984: memcpy((void *)(nd_opt + 1), mac, ifp->if_addrlen);
1.2 itojun 985: } else
986: flags &= ~ND_NA_FLAG_OVERRIDE;
987:
1.51 itojun 988: ip6->ip6_plen = htons((u_int16_t)icmp6len);
1.2 itojun 989: nd_na->nd_na_flags_reserved = flags;
990: nd_na->nd_na_cksum = 0;
991: nd_na->nd_na_cksum =
1.39 itojun 992: in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
1.2 itojun 993:
1.87 dyoung 994: ip6_output(m, NULL, NULL, 0, &im6o, NULL, NULL);
1.32 itojun 995:
996: icmp6_ifstat_inc(ifp, ifs6_out_msg);
997: icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);
1.85 thorpej 998: ICMP6_STATINC(ICMP6_STAT_OUTHIST + ND_NEIGHBOR_ADVERT);
1.39 itojun 999:
1.73 dyoung 1000: rtcache_free(&ro);
1.39 itojun 1001: return;
1002:
1003: bad:
1.73 dyoung 1004: rtcache_free(&ro);
1.39 itojun 1005: m_freem(m);
1006: return;
1.2 itojun 1007: }
1008:
1.80 dyoung 1009: const void *
1010: nd6_ifptomac(const struct ifnet *ifp)
1.2 itojun 1011: {
1012: switch (ifp->if_type) {
1.8 is 1013: case IFT_ARCNET:
1.2 itojun 1014: case IFT_ETHER:
1015: case IFT_FDDI:
1.23 onoe 1016: case IFT_IEEE1394:
1.39 itojun 1017: case IFT_PROPVIRTUAL:
1.64 liamjfoy 1018: case IFT_CARP:
1.39 itojun 1019: case IFT_L2VLAN:
1020: case IFT_IEEE80211:
1.80 dyoung 1021: return CLLADDR(ifp->if_sadl);
1.2 itojun 1022: default:
1023: return NULL;
1024: }
1025: }
1026:
1027: TAILQ_HEAD(dadq_head, dadq);
1028: struct dadq {
1029: TAILQ_ENTRY(dadq) dad_list;
1030: struct ifaddr *dad_ifa;
1.55 itojun 1031: int dad_count; /* max NS to send */
1.9 itojun 1032: int dad_ns_tcount; /* # of trials to send NS */
1.2 itojun 1033: int dad_ns_ocount; /* NS sent so far */
1034: int dad_ns_icount;
1035: int dad_na_icount;
1.21 itojun 1036: struct callout dad_timer_ch;
1.2 itojun 1037: };
1038:
1039: static struct dadq_head dadq;
1.26 itojun 1040: static int dad_init = 0;
1.2 itojun 1041:
1042: static struct dadq *
1.72 dyoung 1043: nd6_dad_find(struct ifaddr *ifa)
1.2 itojun 1044: {
1045: struct dadq *dp;
1046:
1.72 dyoung 1047: TAILQ_FOREACH(dp, &dadq, dad_list) {
1.2 itojun 1048: if (dp->dad_ifa == ifa)
1049: return dp;
1050: }
1051: return NULL;
1052: }
1053:
1.26 itojun 1054: static void
1.72 dyoung 1055: nd6_dad_starttimer(struct dadq *dp, int ticks)
1.26 itojun 1056: {
1057:
1058: callout_reset(&dp->dad_timer_ch, ticks,
1.72 dyoung 1059: (void (*)(void *))nd6_dad_timer, (void *)dp->dad_ifa);
1.26 itojun 1060: }
1061:
1062: static void
1.75 christos 1063: nd6_dad_stoptimer(struct dadq *dp)
1.26 itojun 1064: {
1065:
1066: callout_stop(&dp->dad_timer_ch);
1067: }
1068:
1.2 itojun 1069: /*
1.61 rpaulo 1070: * Start Duplicate Address Detection (DAD) for specified interface address.
1.72 dyoung 1071: *
1.100 ozaki-r 1072: * Note that callout is used when xtick > 0 and not when xtick == 0.
1073: *
1.72 dyoung 1074: * xtick: minimum delay ticks for IFF_UP event
1.2 itojun 1075: */
1076: void
1.72 dyoung 1077: nd6_dad_start(struct ifaddr *ifa, int xtick)
1.2 itojun 1078: {
1079: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1080: struct dadq *dp;
1081:
1082: if (!dad_init) {
1083: TAILQ_INIT(&dadq);
1084: dad_init++;
1085: }
1086:
1087: /*
1088: * If we don't need DAD, don't do it.
1089: * There are several cases:
1090: * - DAD is disabled (ip6_dad_count == 0)
1091: * - the interface address is anycast
1092: */
1093: if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
1.15 itojun 1094: log(LOG_DEBUG,
1095: "nd6_dad_start: called with non-tentative address "
1.2 itojun 1096: "%s(%s)\n",
1097: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1098: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1.2 itojun 1099: return;
1100: }
1.97 roy 1101: if (ia->ia6_flags & IN6_IFF_ANYCAST || !ip6_dad_count) {
1.2 itojun 1102: ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1.105 ! roy 1103: rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
1.2 itojun 1104: return;
1105: }
1.62 rpaulo 1106: if (ifa->ifa_ifp == NULL)
1.2 itojun 1107: panic("nd6_dad_start: ifa->ifa_ifp == NULL");
1108: if (!(ifa->ifa_ifp->if_flags & IFF_UP))
1109: return;
1110: if (nd6_dad_find(ifa) != NULL) {
1111: /* DAD already in progress */
1112: return;
1113: }
1114:
1115: dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
1116: if (dp == NULL) {
1.15 itojun 1117: log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
1.2 itojun 1118: "%s(%s)\n",
1119: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1120: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1.2 itojun 1121: return;
1122: }
1.92 cegger 1123: memset(dp, 0, sizeof(*dp));
1.86 ad 1124: callout_init(&dp->dad_timer_ch, CALLOUT_MPSAFE);
1.2 itojun 1125: TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
1126:
1.26 itojun 1127: nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
1128: ip6_sprintf(&ia->ia_addr.sin6_addr)));
1.2 itojun 1129:
1130: /*
1131: * Send NS packet for DAD, ip6_dad_count times.
1132: * Note that we must delay the first transmission, if this is the
1133: * first packet to be sent from the interface after interface
1134: * (re)initialization.
1135: */
1136: dp->dad_ifa = ifa;
1.101 rmind 1137: ifaref(ifa); /* just for safety */
1.2 itojun 1138: dp->dad_count = ip6_dad_count;
1139: dp->dad_ns_icount = dp->dad_na_icount = 0;
1.9 itojun 1140: dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
1.63 rpaulo 1141: if (xtick == 0) {
1.9 itojun 1142: nd6_dad_ns_output(dp, ifa);
1.38 itojun 1143: nd6_dad_starttimer(dp,
1.47 itojun 1144: (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
1.62 rpaulo 1145: } else
1.63 rpaulo 1146: nd6_dad_starttimer(dp, xtick);
1.2 itojun 1147: }
1148:
1.26 itojun 1149: /*
1150: * terminate DAD unconditionally. used for address removals.
1151: */
1152: void
1.72 dyoung 1153: nd6_dad_stop(struct ifaddr *ifa)
1.26 itojun 1154: {
1155: struct dadq *dp;
1156:
1157: if (!dad_init)
1158: return;
1159: dp = nd6_dad_find(ifa);
1.62 rpaulo 1160: if (dp == NULL) {
1.26 itojun 1161: /* DAD wasn't started yet */
1162: return;
1163: }
1164:
1165: nd6_dad_stoptimer(dp);
1166:
1.66 dyoung 1167: TAILQ_REMOVE(&dadq, dp, dad_list);
1.26 itojun 1168: free(dp, M_IP6NDP);
1169: dp = NULL;
1.101 rmind 1170: ifafree(ifa);
1.26 itojun 1171: }
1172:
1.2 itojun 1173: static void
1.72 dyoung 1174: nd6_dad_timer(struct ifaddr *ifa)
1.2 itojun 1175: {
1176: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1177: struct dadq *dp;
1178:
1.86 ad 1179: mutex_enter(softnet_lock);
1180: KERNEL_LOCK(1, NULL);
1.2 itojun 1181:
1182: /* Sanity check */
1183: if (ia == NULL) {
1.15 itojun 1184: log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
1.2 itojun 1185: goto done;
1186: }
1187: dp = nd6_dad_find(ifa);
1188: if (dp == NULL) {
1.15 itojun 1189: log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
1.2 itojun 1190: goto done;
1191: }
1192: if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
1.61 rpaulo 1193: log(LOG_ERR, "nd6_dad_timer: called with duplicate address "
1.2 itojun 1194: "%s(%s)\n",
1195: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1196: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1.2 itojun 1197: goto done;
1198: }
1199: if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
1.15 itojun 1200: log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
1.2 itojun 1201: "%s(%s)\n",
1202: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1203: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1204: goto done;
1205: }
1206:
1207: /* timeouted with IFF_{RUNNING,UP} check */
1208: if (dp->dad_ns_tcount > dad_maxtry) {
1.26 itojun 1209: nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
1210: if_name(ifa->ifa_ifp)));
1.9 itojun 1211:
1.66 dyoung 1212: TAILQ_REMOVE(&dadq, dp, dad_list);
1.9 itojun 1213: free(dp, M_IP6NDP);
1214: dp = NULL;
1.101 rmind 1215: ifafree(ifa);
1.2 itojun 1216: goto done;
1217: }
1218:
1219: /* Need more checks? */
1.55 itojun 1220: if (dp->dad_ns_ocount < dp->dad_count) {
1.2 itojun 1221: /*
1222: * We have more NS to go. Send NS packet for DAD.
1223: */
1.9 itojun 1224: nd6_dad_ns_output(dp, ifa);
1.38 itojun 1225: nd6_dad_starttimer(dp,
1.47 itojun 1226: (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
1.2 itojun 1227: } else {
1228: /*
1229: * We have transmitted sufficient number of DAD packets.
1230: * See what we've got.
1231: */
1232: int duplicate;
1233:
1234: duplicate = 0;
1235:
1236: if (dp->dad_na_icount) {
1237: /*
1238: * the check is in nd6_dad_na_input(),
1239: * but just in case
1240: */
1241: duplicate++;
1242: }
1243:
1.55 itojun 1244: if (dp->dad_ns_icount) {
1245: /* We've seen NS, means DAD has failed. */
1246: duplicate++;
1.2 itojun 1247: }
1248:
1249: if (duplicate) {
1250: /* (*dp) will be freed in nd6_dad_duplicated() */
1251: dp = NULL;
1252: nd6_dad_duplicated(ifa);
1253: } else {
1254: /*
1255: * We are done with DAD. No NA came, no NS came.
1.61 rpaulo 1256: * No duplicate address found.
1.2 itojun 1257: */
1258: ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1.105 ! roy 1259: rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
1.2 itojun 1260:
1.26 itojun 1261: nd6log((LOG_DEBUG,
1.15 itojun 1262: "%s: DAD complete for %s - no duplicates found\n",
1263: if_name(ifa->ifa_ifp),
1.26 itojun 1264: ip6_sprintf(&ia->ia_addr.sin6_addr)));
1.6 thorpej 1265:
1.66 dyoung 1266: TAILQ_REMOVE(&dadq, dp, dad_list);
1.2 itojun 1267: free(dp, M_IP6NDP);
1268: dp = NULL;
1.101 rmind 1269: ifafree(ifa);
1.2 itojun 1270: }
1271: }
1272:
1273: done:
1.86 ad 1274: KERNEL_UNLOCK_ONE(NULL);
1275: mutex_exit(softnet_lock);
1.2 itojun 1276: }
1277:
1278: void
1.72 dyoung 1279: nd6_dad_duplicated(struct ifaddr *ifa)
1.2 itojun 1280: {
1281: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1.62 rpaulo 1282: struct ifnet *ifp;
1.2 itojun 1283: struct dadq *dp;
1284:
1285: dp = nd6_dad_find(ifa);
1286: if (dp == NULL) {
1.15 itojun 1287: log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
1.2 itojun 1288: return;
1289: }
1290:
1.62 rpaulo 1291: ifp = ifa->ifa_ifp;
1.31 itojun 1292: log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
1293: "NS in/out=%d/%d, NA in=%d\n",
1.62 rpaulo 1294: if_name(ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
1.31 itojun 1295: dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
1.2 itojun 1296:
1297: ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1298: ia->ia6_flags |= IN6_IFF_DUPLICATED;
1299:
1300: /* We are done with DAD, with duplicated address found. (failure) */
1.26 itojun 1301: nd6_dad_stoptimer(dp);
1.2 itojun 1302:
1.15 itojun 1303: log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
1.62 rpaulo 1304: if_name(ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
1.15 itojun 1305: log(LOG_ERR, "%s: manual intervention required\n",
1.62 rpaulo 1306: if_name(ifp));
1307:
1.97 roy 1308: /* Inform the routing socket that DAD has completed */
1.105 ! roy 1309: rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
1.97 roy 1310:
1.62 rpaulo 1311: /*
1312: * If the address is a link-local address formed from an interface
1313: * identifier based on the hardware address which is supposed to be
1314: * uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP
1315: * operation on the interface SHOULD be disabled.
1316: * [rfc2462bis-03 Section 5.4.5]
1317: */
1318: if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
1319: struct in6_addr in6;
1320:
1321: /*
1322: * To avoid over-reaction, we only apply this logic when we are
1323: * very sure that hardware addresses are supposed to be unique.
1324: */
1325: switch (ifp->if_type) {
1326: case IFT_ETHER:
1327: case IFT_FDDI:
1328: case IFT_ATM:
1329: case IFT_IEEE1394:
1330: #ifdef IFT_IEEE80211
1331: case IFT_IEEE80211:
1332: #endif
1333: in6 = ia->ia_addr.sin6_addr;
1334: if (in6_get_hw_ifid(ifp, &in6) == 0 &&
1335: IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) {
1336: ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
1337: log(LOG_ERR, "%s: possible hardware address "
1338: "duplication detected, disable IPv6\n",
1339: if_name(ifp));
1340: }
1341: break;
1342: }
1343: }
1.6 thorpej 1344:
1.66 dyoung 1345: TAILQ_REMOVE(&dadq, dp, dad_list);
1.2 itojun 1346: free(dp, M_IP6NDP);
1347: dp = NULL;
1.101 rmind 1348: ifafree(ifa);
1.2 itojun 1349: }
1350:
1.9 itojun 1351: static void
1.72 dyoung 1352: nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa)
1.9 itojun 1353: {
1354: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1355: struct ifnet *ifp = ifa->ifa_ifp;
1356:
1357: dp->dad_ns_tcount++;
1358: if ((ifp->if_flags & IFF_UP) == 0) {
1359: #if 0
1360: printf("%s: interface down?\n", if_name(ifp));
1361: #endif
1362: return;
1363: }
1364: if ((ifp->if_flags & IFF_RUNNING) == 0) {
1365: #if 0
1366: printf("%s: interface not running?\n", if_name(ifp));
1367: #endif
1368: return;
1369: }
1370:
1.65 drochner 1371: dp->dad_ns_tcount = 0;
1.9 itojun 1372: dp->dad_ns_ocount++;
1373: nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
1374: }
1375:
1376: static void
1.72 dyoung 1377: nd6_dad_ns_input(struct ifaddr *ifa)
1.2 itojun 1378: {
1379: struct in6_ifaddr *ia;
1.32 itojun 1380: const struct in6_addr *taddr6;
1.2 itojun 1381: struct dadq *dp;
1382: int duplicate;
1383:
1.62 rpaulo 1384: if (ifa == NULL)
1.2 itojun 1385: panic("ifa == NULL in nd6_dad_ns_input");
1386:
1387: ia = (struct in6_ifaddr *)ifa;
1388: taddr6 = &ia->ia_addr.sin6_addr;
1389: duplicate = 0;
1390: dp = nd6_dad_find(ifa);
1391:
1392: /* Quickhack - completely ignore DAD NS packets */
1393: if (dad_ignore_ns) {
1.26 itojun 1394: nd6log((LOG_INFO,
1395: "nd6_dad_ns_input: ignoring DAD NS packet for "
1.2 itojun 1396: "address %s(%s)\n", ip6_sprintf(taddr6),
1.26 itojun 1397: if_name(ifa->ifa_ifp)));
1.2 itojun 1398: return;
1399: }
1400:
1401: /*
1402: * if I'm yet to start DAD, someone else started using this address
1403: * first. I have a duplicate and you win.
1404: */
1.62 rpaulo 1405: if (dp == NULL || dp->dad_ns_ocount == 0)
1.2 itojun 1406: duplicate++;
1407:
1408: /* XXX more checks for loopback situation - see nd6_dad_timer too */
1409:
1410: if (duplicate) {
1411: dp = NULL; /* will be freed in nd6_dad_duplicated() */
1412: nd6_dad_duplicated(ifa);
1413: } else {
1414: /*
1415: * not sure if I got a duplicate.
1416: * increment ns count and see what happens.
1417: */
1418: if (dp)
1419: dp->dad_ns_icount++;
1420: }
1421: }
1422:
1.9 itojun 1423: static void
1.72 dyoung 1424: nd6_dad_na_input(struct ifaddr *ifa)
1.2 itojun 1425: {
1426: struct dadq *dp;
1427:
1.62 rpaulo 1428: if (ifa == NULL)
1.2 itojun 1429: panic("ifa == NULL in nd6_dad_na_input");
1430:
1431: dp = nd6_dad_find(ifa);
1432: if (dp)
1433: dp->dad_na_icount++;
1434:
1435: /* remove the address. */
1436: nd6_dad_duplicated(ifa);
1437: }
CVSweb <webmaster@jp.NetBSD.org>