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