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