Annotation of src/sys/netinet6/nd6_nbr.c, Revision 1.97
1.97 ! roy 1: /* $NetBSD: nd6_nbr.c,v 1.96 2012/03/22 20:34:41 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.97 ! roy 34: __KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.96 2012/03/22 20:34:41 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.97 ! roy 1059: * Routine to report address flag changes to the routing socket
! 1060: */
! 1061: void
! 1062: nd6_newaddrmsg(struct ifaddr *ifa)
! 1063: {
! 1064: struct sockaddr_in6 all1_sa;
! 1065: struct rtentry *nrt = NULL;
! 1066: int e;
! 1067:
! 1068: sockaddr_in6_init(&all1_sa, &in6mask128, 0, 0, 0);
! 1069:
! 1070: e = rtrequest(RTM_GET, ifa->ifa_addr, ifa->ifa_addr,
! 1071: (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt);
! 1072: if (e != 0) {
! 1073: log(LOG_ERR, "nd6_newaddrmsg: "
! 1074: "RTM_GET operation failed for %s (errno=%d)\n",
! 1075: ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
! 1076: e);
! 1077: }
! 1078:
! 1079: if (nrt) {
! 1080: rt_newaddrmsg(RTM_ADD, ifa, e, nrt);
! 1081: //#if 0
! 1082: log(LOG_DEBUG, "nd6_newaddrmsg: announced %s\n",
! 1083: ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr)
! 1084: );
! 1085: //#endif
! 1086: nrt->rt_refcnt--;
! 1087: }
! 1088: }
! 1089:
! 1090:
! 1091: /*
1.61 rpaulo 1092: * Start Duplicate Address Detection (DAD) for specified interface address.
1.72 dyoung 1093: *
1094: * xtick: minimum delay ticks for IFF_UP event
1.2 itojun 1095: */
1096: void
1.72 dyoung 1097: nd6_dad_start(struct ifaddr *ifa, int xtick)
1.2 itojun 1098: {
1099: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1100: struct dadq *dp;
1101:
1102: if (!dad_init) {
1103: TAILQ_INIT(&dadq);
1104: dad_init++;
1105: }
1106:
1107: /*
1108: * If we don't need DAD, don't do it.
1109: * There are several cases:
1110: * - DAD is disabled (ip6_dad_count == 0)
1111: * - the interface address is anycast
1112: */
1113: if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
1.15 itojun 1114: log(LOG_DEBUG,
1115: "nd6_dad_start: called with non-tentative address "
1.2 itojun 1116: "%s(%s)\n",
1117: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1118: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1.2 itojun 1119: return;
1120: }
1.97 ! roy 1121: if (ia->ia6_flags & IN6_IFF_ANYCAST || !ip6_dad_count) {
1.2 itojun 1122: ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1.97 ! roy 1123: nd6_newaddrmsg(ifa);
1.2 itojun 1124: return;
1125: }
1.62 rpaulo 1126: if (ifa->ifa_ifp == NULL)
1.2 itojun 1127: panic("nd6_dad_start: ifa->ifa_ifp == NULL");
1128: if (!(ifa->ifa_ifp->if_flags & IFF_UP))
1129: return;
1130: if (nd6_dad_find(ifa) != NULL) {
1131: /* DAD already in progress */
1132: return;
1133: }
1134:
1135: dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
1136: if (dp == NULL) {
1.15 itojun 1137: log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
1.2 itojun 1138: "%s(%s)\n",
1139: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1140: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1.2 itojun 1141: return;
1142: }
1.92 cegger 1143: memset(dp, 0, sizeof(*dp));
1.86 ad 1144: callout_init(&dp->dad_timer_ch, CALLOUT_MPSAFE);
1.2 itojun 1145: TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
1146:
1.26 itojun 1147: nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
1148: ip6_sprintf(&ia->ia_addr.sin6_addr)));
1.2 itojun 1149:
1150: /*
1151: * Send NS packet for DAD, ip6_dad_count times.
1152: * Note that we must delay the first transmission, if this is the
1153: * first packet to be sent from the interface after interface
1154: * (re)initialization.
1155: */
1156: dp->dad_ifa = ifa;
1.31 itojun 1157: IFAREF(ifa); /* just for safety */
1.2 itojun 1158: dp->dad_count = ip6_dad_count;
1159: dp->dad_ns_icount = dp->dad_na_icount = 0;
1.9 itojun 1160: dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
1.63 rpaulo 1161: if (xtick == 0) {
1.9 itojun 1162: nd6_dad_ns_output(dp, ifa);
1.38 itojun 1163: nd6_dad_starttimer(dp,
1.47 itojun 1164: (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
1.62 rpaulo 1165: } else
1.63 rpaulo 1166: nd6_dad_starttimer(dp, xtick);
1.2 itojun 1167: }
1168:
1.26 itojun 1169: /*
1170: * terminate DAD unconditionally. used for address removals.
1171: */
1172: void
1.72 dyoung 1173: nd6_dad_stop(struct ifaddr *ifa)
1.26 itojun 1174: {
1175: struct dadq *dp;
1176:
1177: if (!dad_init)
1178: return;
1179: dp = nd6_dad_find(ifa);
1.62 rpaulo 1180: if (dp == NULL) {
1.26 itojun 1181: /* DAD wasn't started yet */
1182: return;
1183: }
1184:
1185: nd6_dad_stoptimer(dp);
1186:
1.66 dyoung 1187: TAILQ_REMOVE(&dadq, dp, dad_list);
1.26 itojun 1188: free(dp, M_IP6NDP);
1189: dp = NULL;
1190: IFAFREE(ifa);
1191: }
1192:
1.2 itojun 1193: static void
1.72 dyoung 1194: nd6_dad_timer(struct ifaddr *ifa)
1.2 itojun 1195: {
1196: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1197: struct dadq *dp;
1198:
1.86 ad 1199: mutex_enter(softnet_lock);
1200: KERNEL_LOCK(1, NULL);
1.2 itojun 1201:
1202: /* Sanity check */
1203: if (ia == NULL) {
1.15 itojun 1204: log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
1.2 itojun 1205: goto done;
1206: }
1207: dp = nd6_dad_find(ifa);
1208: if (dp == NULL) {
1.15 itojun 1209: log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
1.2 itojun 1210: goto done;
1211: }
1212: if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
1.61 rpaulo 1213: log(LOG_ERR, "nd6_dad_timer: called with duplicate address "
1.2 itojun 1214: "%s(%s)\n",
1215: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1216: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1.2 itojun 1217: goto done;
1218: }
1219: if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
1.15 itojun 1220: log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
1.2 itojun 1221: "%s(%s)\n",
1222: ip6_sprintf(&ia->ia_addr.sin6_addr),
1.9 itojun 1223: ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1224: goto done;
1225: }
1226:
1227: /* timeouted with IFF_{RUNNING,UP} check */
1228: if (dp->dad_ns_tcount > dad_maxtry) {
1.26 itojun 1229: nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
1230: if_name(ifa->ifa_ifp)));
1.9 itojun 1231:
1.66 dyoung 1232: TAILQ_REMOVE(&dadq, dp, dad_list);
1.9 itojun 1233: free(dp, M_IP6NDP);
1234: dp = NULL;
1.13 thorpej 1235: IFAFREE(ifa);
1.2 itojun 1236: goto done;
1237: }
1238:
1239: /* Need more checks? */
1.55 itojun 1240: if (dp->dad_ns_ocount < dp->dad_count) {
1.2 itojun 1241: /*
1242: * We have more NS to go. Send NS packet for DAD.
1243: */
1.9 itojun 1244: nd6_dad_ns_output(dp, ifa);
1.38 itojun 1245: nd6_dad_starttimer(dp,
1.47 itojun 1246: (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
1.2 itojun 1247: } else {
1248: /*
1249: * We have transmitted sufficient number of DAD packets.
1250: * See what we've got.
1251: */
1252: int duplicate;
1253:
1254: duplicate = 0;
1255:
1256: if (dp->dad_na_icount) {
1257: /*
1258: * the check is in nd6_dad_na_input(),
1259: * but just in case
1260: */
1261: duplicate++;
1262: }
1263:
1.55 itojun 1264: if (dp->dad_ns_icount) {
1265: /* We've seen NS, means DAD has failed. */
1266: duplicate++;
1.2 itojun 1267: }
1268:
1269: if (duplicate) {
1270: /* (*dp) will be freed in nd6_dad_duplicated() */
1271: dp = NULL;
1272: nd6_dad_duplicated(ifa);
1273: } else {
1274: /*
1275: * We are done with DAD. No NA came, no NS came.
1.61 rpaulo 1276: * No duplicate address found.
1.2 itojun 1277: */
1278: ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1.97 ! roy 1279: nd6_newaddrmsg(ifa);
1.2 itojun 1280:
1.26 itojun 1281: nd6log((LOG_DEBUG,
1.15 itojun 1282: "%s: DAD complete for %s - no duplicates found\n",
1283: if_name(ifa->ifa_ifp),
1.26 itojun 1284: ip6_sprintf(&ia->ia_addr.sin6_addr)));
1.6 thorpej 1285:
1.66 dyoung 1286: TAILQ_REMOVE(&dadq, dp, dad_list);
1.2 itojun 1287: free(dp, M_IP6NDP);
1288: dp = NULL;
1.13 thorpej 1289: IFAFREE(ifa);
1.2 itojun 1290: }
1291: }
1292:
1293: done:
1.86 ad 1294: KERNEL_UNLOCK_ONE(NULL);
1295: mutex_exit(softnet_lock);
1.2 itojun 1296: }
1297:
1298: void
1.72 dyoung 1299: nd6_dad_duplicated(struct ifaddr *ifa)
1.2 itojun 1300: {
1301: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1.62 rpaulo 1302: struct ifnet *ifp;
1.2 itojun 1303: struct dadq *dp;
1304:
1305: dp = nd6_dad_find(ifa);
1306: if (dp == NULL) {
1.15 itojun 1307: log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
1.2 itojun 1308: return;
1309: }
1310:
1.62 rpaulo 1311: ifp = ifa->ifa_ifp;
1.31 itojun 1312: log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
1313: "NS in/out=%d/%d, NA in=%d\n",
1.62 rpaulo 1314: if_name(ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
1.31 itojun 1315: dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
1.2 itojun 1316:
1317: ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1318: ia->ia6_flags |= IN6_IFF_DUPLICATED;
1319:
1320: /* We are done with DAD, with duplicated address found. (failure) */
1.26 itojun 1321: nd6_dad_stoptimer(dp);
1.2 itojun 1322:
1.15 itojun 1323: log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
1.62 rpaulo 1324: if_name(ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
1.15 itojun 1325: log(LOG_ERR, "%s: manual intervention required\n",
1.62 rpaulo 1326: if_name(ifp));
1327:
1.97 ! roy 1328: /* Inform the routing socket that DAD has completed */
! 1329: nd6_newaddrmsg(ifa);
! 1330:
1.62 rpaulo 1331: /*
1332: * If the address is a link-local address formed from an interface
1333: * identifier based on the hardware address which is supposed to be
1334: * uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP
1335: * operation on the interface SHOULD be disabled.
1336: * [rfc2462bis-03 Section 5.4.5]
1337: */
1338: if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
1339: struct in6_addr in6;
1340:
1341: /*
1342: * To avoid over-reaction, we only apply this logic when we are
1343: * very sure that hardware addresses are supposed to be unique.
1344: */
1345: switch (ifp->if_type) {
1346: case IFT_ETHER:
1347: case IFT_FDDI:
1348: case IFT_ATM:
1349: case IFT_IEEE1394:
1350: #ifdef IFT_IEEE80211
1351: case IFT_IEEE80211:
1352: #endif
1353: in6 = ia->ia_addr.sin6_addr;
1354: if (in6_get_hw_ifid(ifp, &in6) == 0 &&
1355: IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) {
1356: ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
1357: log(LOG_ERR, "%s: possible hardware address "
1358: "duplication detected, disable IPv6\n",
1359: if_name(ifp));
1360: }
1361: break;
1362: }
1363: }
1.6 thorpej 1364:
1.66 dyoung 1365: TAILQ_REMOVE(&dadq, dp, dad_list);
1.2 itojun 1366: free(dp, M_IP6NDP);
1367: dp = NULL;
1.13 thorpej 1368: IFAFREE(ifa);
1.2 itojun 1369: }
1370:
1.9 itojun 1371: static void
1.72 dyoung 1372: nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa)
1.9 itojun 1373: {
1374: struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1375: struct ifnet *ifp = ifa->ifa_ifp;
1376:
1377: dp->dad_ns_tcount++;
1378: if ((ifp->if_flags & IFF_UP) == 0) {
1379: #if 0
1380: printf("%s: interface down?\n", if_name(ifp));
1381: #endif
1382: return;
1383: }
1384: if ((ifp->if_flags & IFF_RUNNING) == 0) {
1385: #if 0
1386: printf("%s: interface not running?\n", if_name(ifp));
1387: #endif
1388: return;
1389: }
1390:
1.65 drochner 1391: dp->dad_ns_tcount = 0;
1.9 itojun 1392: dp->dad_ns_ocount++;
1393: nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
1394: }
1395:
1396: static void
1.72 dyoung 1397: nd6_dad_ns_input(struct ifaddr *ifa)
1.2 itojun 1398: {
1399: struct in6_ifaddr *ia;
1.32 itojun 1400: const struct in6_addr *taddr6;
1.2 itojun 1401: struct dadq *dp;
1402: int duplicate;
1403:
1.62 rpaulo 1404: if (ifa == NULL)
1.2 itojun 1405: panic("ifa == NULL in nd6_dad_ns_input");
1406:
1407: ia = (struct in6_ifaddr *)ifa;
1408: taddr6 = &ia->ia_addr.sin6_addr;
1409: duplicate = 0;
1410: dp = nd6_dad_find(ifa);
1411:
1412: /* Quickhack - completely ignore DAD NS packets */
1413: if (dad_ignore_ns) {
1.26 itojun 1414: nd6log((LOG_INFO,
1415: "nd6_dad_ns_input: ignoring DAD NS packet for "
1.2 itojun 1416: "address %s(%s)\n", ip6_sprintf(taddr6),
1.26 itojun 1417: if_name(ifa->ifa_ifp)));
1.2 itojun 1418: return;
1419: }
1420:
1421: /*
1422: * if I'm yet to start DAD, someone else started using this address
1423: * first. I have a duplicate and you win.
1424: */
1.62 rpaulo 1425: if (dp == NULL || dp->dad_ns_ocount == 0)
1.2 itojun 1426: duplicate++;
1427:
1428: /* XXX more checks for loopback situation - see nd6_dad_timer too */
1429:
1430: if (duplicate) {
1431: dp = NULL; /* will be freed in nd6_dad_duplicated() */
1432: nd6_dad_duplicated(ifa);
1433: } else {
1434: /*
1435: * not sure if I got a duplicate.
1436: * increment ns count and see what happens.
1437: */
1438: if (dp)
1439: dp->dad_ns_icount++;
1440: }
1441: }
1442:
1.9 itojun 1443: static void
1.72 dyoung 1444: nd6_dad_na_input(struct ifaddr *ifa)
1.2 itojun 1445: {
1446: struct dadq *dp;
1447:
1.62 rpaulo 1448: if (ifa == NULL)
1.2 itojun 1449: panic("ifa == NULL in nd6_dad_na_input");
1450:
1451: dp = nd6_dad_find(ifa);
1452: if (dp)
1453: dp->dad_na_icount++;
1454:
1455: /* remove the address. */
1456: nd6_dad_duplicated(ifa);
1457: }
CVSweb <webmaster@jp.NetBSD.org>