]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/nd6_nbr.c
xnu-792.21.3.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
9bccf70c 219 rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
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
370 MGETHDR(m, M_DONTWAIT, MT_DATA);
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;
779 int s;
780
781 in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
55e303ae
A
782
783 /*
784 * Lock to protect the default router list.
785 * XXX: this might be unnecessary, since this function
786 * is only called under the network software interrupt
787 * context. However, we keep it just for safety.
788 */
91447636 789 lck_mtx_lock(nd6_mutex);
1c79356b 790 dr = defrouter_lookup(in6, rt->rt_ifp);
91447636
A
791 if (dr) {
792 defrtrlist_del(dr, 1);
793 lck_mtx_unlock(nd6_mutex);
794 }
795 else {
796 lck_mtx_unlock(nd6_mutex);
797 if (!ip6_forwarding && (ip6_accept_rtadv || (rt->rt_ifp->if_eflags & IFEF_ACCEPT_RTADVD))) {
798 /*
799 * Even if the neighbor is not in the default
800 * router list, the neighbor may be used
801 * as a next hop for some destinations
802 * (e.g. redirect case). So we must
803 * call rt6_flush explicitly.
804 */
805 rt6_flush(&ip6->ip6_src, rt->rt_ifp);
806 }
1c79356b 807 }
1c79356b
A
808 }
809 ln->ln_router = is_router;
810 }
811 rt->rt_flags &= ~RTF_REJECT;
812 ln->ln_asked = 0;
813 if (ln->ln_hold) {
9bccf70c 814 /*
55e303ae 815 * we assume ifp is not a loopback here, so just set the 2nd
9bccf70c
A
816 * argument as the 1st one.
817 */
818 nd6_output(ifp, ifp, ln->ln_hold,
91447636 819 (struct sockaddr_in6 *)rt_key(rt), rt, 0);
1c79356b
A
820 ln->ln_hold = 0;
821 }
822
823 freeit:
824 m_freem(m);
9bccf70c
A
825 return;
826
827 bad:
828 icmp6stat.icp6s_badna++;
829 m_freem(m);
1c79356b
A
830}
831
832/*
833 * Neighbor advertisement output handling.
834 *
835 * Based on RFC 2461
836 *
837 * the following items are not implemented yet:
838 * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
839 * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
840 */
841void
91447636
A
842nd6_na_output(
843 struct ifnet *ifp,
844 const struct in6_addr *daddr6,
845 const struct in6_addr *taddr6,
846 u_long flags,
847 int tlladdr, /* 1 if include target link-layer address */
848 struct sockaddr *sdl0) /* sockaddr_dl (= proxy NA) or NULL */
1c79356b
A
849{
850 struct mbuf *m;
851 struct ip6_hdr *ip6;
852 struct nd_neighbor_advert *nd_na;
853 struct in6_ifaddr *ia = NULL;
854 struct ip6_moptions im6o;
855 int icmp6len;
856 int maxlen;
55e303ae 857 caddr_t mac = NULL;
1c79356b
A
858 struct ifnet *outif = NULL;
859
860 /* estimate the size of message */
861 maxlen = sizeof(*ip6) + sizeof(*nd_na);
862 maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
863 if (max_linkhdr + maxlen >= MCLBYTES) {
9bccf70c 864#if DIAGNOSTIC
1c79356b
A
865 printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
866 "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
867#endif
868 return;
869 }
870
871 MGETHDR(m, M_DONTWAIT, MT_DATA);
872 if (m && max_linkhdr + maxlen >= MHLEN) {
873 MCLGET(m, M_DONTWAIT);
874 if ((m->m_flags & M_EXT) == 0) {
875 m_free(m);
876 m = NULL;
877 }
878 }
879 if (m == NULL)
880 return;
9bccf70c 881 m->m_pkthdr.rcvif = NULL;
1c79356b
A
882
883 if (IN6_IS_ADDR_MULTICAST(daddr6)) {
884 m->m_flags |= M_MCAST;
885 im6o.im6o_multicast_ifp = ifp;
886 im6o.im6o_multicast_hlim = 255;
887 im6o.im6o_multicast_loop = 0;
888 }
889
890 icmp6len = sizeof(*nd_na);
891 m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
55e303ae 892 m->m_data += max_linkhdr; /* or MH_ALIGN() equivalent? */
1c79356b
A
893
894 /* fill neighbor advertisement packet */
895 ip6 = mtod(m, struct ip6_hdr *);
896 ip6->ip6_flow = 0;
897 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
898 ip6->ip6_vfc |= IPV6_VERSION;
899 ip6->ip6_nxt = IPPROTO_ICMPV6;
900 ip6->ip6_hlim = 255;
901 if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
902 /* reply to DAD */
903 ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
904 ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
905 ip6->ip6_dst.s6_addr32[1] = 0;
906 ip6->ip6_dst.s6_addr32[2] = 0;
907 ip6->ip6_dst.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
908 flags &= ~ND_NA_FLAG_SOLICITED;
909 } else
910 ip6->ip6_dst = *daddr6;
911
912 /*
913 * Select a source whose scope is the same as that of the dest.
914 */
915 ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
916 if (ia == NULL) {
917 m_freem(m);
918 return;
919 }
920 ip6->ip6_src = ia->ia_addr.sin6_addr;
921 nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
922 nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
923 nd_na->nd_na_code = 0;
924 nd_na->nd_na_target = *taddr6;
925 if (IN6_IS_SCOPE_LINKLOCAL(&nd_na->nd_na_target))
926 nd_na->nd_na_target.s6_addr16[1] = 0;
927
928 /*
929 * "tlladdr" indicates NS's condition for adding tlladdr or not.
930 * see nd6_ns_input() for details.
931 * Basically, if NS packet is sent to unicast/anycast addr,
932 * target lladdr option SHOULD NOT be included.
933 */
934 if (tlladdr) {
1c79356b
A
935 /*
936 * sdl0 != NULL indicates proxy NA. If we do proxy, use
937 * lladdr in sdl0. If we are not proxying (sending NA for
938 * my address) use lladdr configured for the interface.
939 */
940 if (sdl0 == NULL)
941 mac = nd6_ifptomac(ifp);
942 else if (sdl0->sa_family == AF_LINK) {
943 struct sockaddr_dl *sdl;
944 sdl = (struct sockaddr_dl *)sdl0;
945 if (sdl->sdl_alen == ifp->if_addrlen)
946 mac = LLADDR(sdl);
947 }
948 }
949 if (tlladdr && mac) {
950 int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
951 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
952
953 /* roundup to 8 bytes alignment! */
954 optlen = (optlen + 7) & ~7;
955
956 m->m_pkthdr.len += optlen;
957 m->m_len += optlen;
958 icmp6len += optlen;
959 bzero((caddr_t)nd_opt, optlen);
960 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
961 nd_opt->nd_opt_len = optlen >> 3;
962 bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
963 } else
964 flags &= ~ND_NA_FLAG_OVERRIDE;
965
966 ip6->ip6_plen = htons((u_short)icmp6len);
967 nd_na->nd_na_flags_reserved = flags;
968 nd_na->nd_na_cksum = 0;
969 nd_na->nd_na_cksum =
970 in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
971
972#if IPSEC
973 /* Don't lookup socket */
9bccf70c
A
974 if (ipsec_bypass == 0)
975 (void)ipsec_setsocket(m, NULL);
1c79356b 976#endif
91447636 977 ip6_output(m, NULL, NULL, 0, &im6o, &outif, 0);
1c79356b
A
978 if (outif) {
979 icmp6_ifstat_inc(outif, ifs6_out_msg);
980 icmp6_ifstat_inc(outif, ifs6_out_neighboradvert);
981 }
982 icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
983}
984
985caddr_t
91447636
A
986nd6_ifptomac(
987 struct ifnet *ifp)
1c79356b 988{
91447636 989 return ((caddr_t)ifnet_lladdr(ifp));
1c79356b
A
990}
991
992TAILQ_HEAD(dadq_head, dadq);
993struct dadq {
994 TAILQ_ENTRY(dadq) dad_list;
995 struct ifaddr *dad_ifa;
996 int dad_count; /* max NS to send */
997 int dad_ns_tcount; /* # of trials to send NS */
998 int dad_ns_ocount; /* NS sent so far */
999 int dad_ns_icount;
1000 int dad_na_icount;
1c79356b
A
1001};
1002
1003static struct dadq_head dadq;
9bccf70c 1004static int dad_init = 0;
1c79356b
A
1005
1006static struct dadq *
91447636
A
1007nd6_dad_find(
1008 struct ifaddr *ifa)
1c79356b
A
1009{
1010 struct dadq *dp;
91447636 1011 lck_mtx_lock(dad6_mutex);
1c79356b 1012 for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {
91447636
A
1013 if (dp->dad_ifa == ifa) {
1014 lck_mtx_unlock(dad6_mutex);
1c79356b 1015 return dp;
91447636 1016 }
1c79356b 1017 }
91447636 1018 lck_mtx_unlock(dad6_mutex);
1c79356b
A
1019 return NULL;
1020}
1021
9bccf70c
A
1022#ifdef __APPLE__
1023void
91447636
A
1024nd6_dad_stoptimer(
1025 struct ifaddr *ifa)
9bccf70c
A
1026{
1027
91447636 1028 untimeout((void (*)(void *))nd6_dad_timer, (void *)ifa);
9bccf70c
A
1029}
1030#else
1031static void
91447636
A
1032nd6_dad_starttimer(
1033 struct dadq *dp,
1034 int ticks)
9bccf70c
A
1035{
1036
1037 callout_reset(&dp->dad_timer_ch, ticks,
91447636 1038 (void (*)(void *))nd6_dad_timer, (void *)dp->dad_ifa);
9bccf70c 1039}
55e303ae 1040
9bccf70c 1041static void
91447636
A
1042nd6_dad_stoptimer(
1043 struct dadq *dp)
9bccf70c
A
1044{
1045
1046 callout_stop(&dp->dad_timer_ch);
1047}
1048#endif
1049
1c79356b
A
1050/*
1051 * Start Duplicated Address Detection (DAD) for specified interface address.
1052 */
1053void
91447636
A
1054nd6_dad_start(
1055 struct ifaddr *ifa,
1056 int *tick) /* minimum delay ticks for IFF_UP event */
1c79356b
A
1057{
1058 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1059 struct dadq *dp;
1c79356b
A
1060
1061 if (!dad_init) {
1062 TAILQ_INIT(&dadq);
1063 dad_init++;
1064 }
1065
1066 /*
1067 * If we don't need DAD, don't do it.
1068 * There are several cases:
1069 * - DAD is disabled (ip6_dad_count == 0)
1070 * - the interface address is anycast
1071 */
1072 if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
1073 log(LOG_DEBUG,
1074 "nd6_dad_start: called with non-tentative address "
1075 "%s(%s)\n",
1076 ip6_sprintf(&ia->ia_addr.sin6_addr),
1077 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1078 return;
1079 }
1080 if (ia->ia6_flags & IN6_IFF_ANYCAST) {
1081 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1082 return;
1083 }
1084 if (!ip6_dad_count) {
1085 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1086 return;
1087 }
1088 if (!ifa->ifa_ifp)
1089 panic("nd6_dad_start: ifa->ifa_ifp == NULL");
1090 if (!(ifa->ifa_ifp->if_flags & IFF_UP))
1091 return;
1092 if (nd6_dad_find(ifa) != NULL) {
1093 /* DAD already in progress */
1094 return;
1095 }
1096
1097 dp = _MALLOC(sizeof(*dp), M_IP6NDP, M_NOWAIT);
1098 if (dp == NULL) {
1099 log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
1100 "%s(%s)\n",
1101 ip6_sprintf(&ia->ia_addr.sin6_addr),
1102 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1103 return;
1104 }
1105 bzero(dp, sizeof(*dp));
91447636 1106 lck_mtx_lock(dad6_mutex);
1c79356b 1107 TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
91447636 1108 lck_mtx_unlock(dad6_mutex);
1c79356b 1109
9bccf70c
A
1110 nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
1111 ip6_sprintf(&ia->ia_addr.sin6_addr)));
1c79356b
A
1112
1113 /*
1114 * Send NS packet for DAD, ip6_dad_count times.
1115 * Note that we must delay the first transmission, if this is the
1116 * first packet to be sent from the interface after interface
1117 * (re)initialization.
1118 */
1119 dp->dad_ifa = ifa;
9bccf70c 1120 ifaref(ifa); /*just for safety*/
1c79356b
A
1121 dp->dad_count = ip6_dad_count;
1122 dp->dad_ns_icount = dp->dad_na_icount = 0;
1123 dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
55e303ae 1124 if (tick == NULL) {
1c79356b 1125 nd6_dad_ns_output(dp, ifa);
91447636 1126 timeout((void (*)(void *))nd6_dad_timer, (void *)ifa,
1c79356b
A
1127 nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
1128 } else {
1129 int ntick;
1130
1131 if (*tick == 0)
1132 ntick = random() % (MAX_RTR_SOLICITATION_DELAY * hz);
1133 else
1134 ntick = *tick + random() % (hz / 2);
1135 *tick = ntick;
91447636 1136 timeout((void (*)(void *))nd6_dad_timer, (void *)ifa,
1c79356b
A
1137 ntick);
1138 }
1139}
1140
9bccf70c
A
1141/*
1142 * terminate DAD unconditionally. used for address removals.
1143 */
1144void
91447636
A
1145nd6_dad_stop(
1146 struct ifaddr *ifa)
9bccf70c
A
1147{
1148 struct dadq *dp;
1149
1150 if (!dad_init)
1151 return;
1152 dp = nd6_dad_find(ifa);
1153 if (!dp) {
1154 /* DAD wasn't started yet */
1155 return;
1156 }
1157
91447636 1158 untimeout((void (*)(void *))nd6_dad_timer, (void *)ifa);
9bccf70c 1159
91447636 1160 lck_mtx_lock(dad6_mutex);
9bccf70c 1161 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
91447636 1162 lck_mtx_unlock(dad6_mutex);
9bccf70c
A
1163 FREE(dp, M_IP6NDP);
1164 dp = NULL;
1165 ifafree(ifa);
1166}
1167
1168
1c79356b 1169static void
91447636
A
1170nd6_dad_timer(
1171 struct ifaddr *ifa)
1c79356b
A
1172{
1173 int s;
1174 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1175 struct dadq *dp;
1176
55e303ae 1177 s = splnet(); /* XXX */
1c79356b
A
1178
1179 /* Sanity check */
1180 if (ia == NULL) {
1181 log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
1182 goto done;
1183 }
1184 dp = nd6_dad_find(ifa);
1185 if (dp == NULL) {
1186 log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
1187 goto done;
1188 }
1189 if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
1190 log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
1191 "%s(%s)\n",
1192 ip6_sprintf(&ia->ia_addr.sin6_addr),
1193 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1194 goto done;
1195 }
1196 if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
1197 log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
1198 "%s(%s)\n",
1199 ip6_sprintf(&ia->ia_addr.sin6_addr),
1200 ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1201 goto done;
1202 }
1203
1204 /* timeouted with IFF_{RUNNING,UP} check */
1205 if (dp->dad_ns_tcount > dad_maxtry) {
9bccf70c
A
1206 nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
1207 if_name(ifa->ifa_ifp)));
1c79356b 1208
91447636 1209 lck_mtx_lock(dad6_mutex);
1c79356b 1210 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
91447636 1211 lck_mtx_unlock(dad6_mutex);
9bccf70c 1212 FREE(dp, M_IP6NDP);
1c79356b 1213 dp = NULL;
9bccf70c 1214 ifafree(ifa);
1c79356b
A
1215 goto done;
1216 }
1217
1218 /* Need more checks? */
1219 if (dp->dad_ns_ocount < dp->dad_count) {
1220 /*
1221 * We have more NS to go. Send NS packet for DAD.
1222 */
1223 nd6_dad_ns_output(dp, ifa);
91447636 1224 timeout((void (*)(void *))nd6_dad_timer, (void *)ifa,
1c79356b
A
1225 nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);
1226 } else {
1227 /*
1228 * We have transmitted sufficient number of DAD packets.
1229 * See what we've got.
1230 */
1231 int duplicate;
1232
1233 duplicate = 0;
1234
1235 if (dp->dad_na_icount) {
1236 /*
1237 * the check is in nd6_dad_na_input(),
1238 * but just in case
1239 */
1240 duplicate++;
1241 }
1242
1243 if (dp->dad_ns_icount) {
55e303ae 1244#if 0 /* heuristics */
1c79356b
A
1245 /*
1246 * if
1247 * - we have sent many(?) DAD NS, and
1248 * - the number of NS we sent equals to the
1249 * number of NS we've got, and
1250 * - we've got no NA
1251 * we may have a faulty network card/driver which
1252 * loops back multicasts to myself.
1253 */
1254 if (3 < dp->dad_count
1255 && dp->dad_ns_icount == dp->dad_count
1256 && dp->dad_na_icount == 0) {
1257 log(LOG_INFO, "DAD questionable for %s(%s): "
1258 "network card loops back multicast?\n",
1259 ip6_sprintf(&ia->ia_addr.sin6_addr),
1260 if_name(ifa->ifa_ifp));
1261 /* XXX consider it a duplicate or not? */
1262 /* duplicate++; */
1263 } else {
1264 /* We've seen NS, means DAD has failed. */
1265 duplicate++;
1266 }
1267#else
1268 /* We've seen NS, means DAD has failed. */
1269 duplicate++;
1270#endif
1271 }
1272
1273 if (duplicate) {
1274 /* (*dp) will be freed in nd6_dad_duplicated() */
1275 dp = NULL;
1276 nd6_dad_duplicated(ifa);
1277 } else {
1278 /*
1279 * We are done with DAD. No NA came, no NS came.
1280 * duplicated address found.
1281 */
1282 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1283
9bccf70c 1284 nd6log((LOG_DEBUG,
1c79356b
A
1285 "%s: DAD complete for %s - no duplicates found\n",
1286 if_name(ifa->ifa_ifp),
9bccf70c 1287 ip6_sprintf(&ia->ia_addr.sin6_addr)));
1c79356b 1288
91447636 1289 lck_mtx_lock(dad6_mutex);
1c79356b 1290 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
91447636
A
1291 lck_mtx_unlock(dad6_mutex);
1292 in6_post_msg(ia->ia_ifp, KEV_INET6_NEW_USER_ADDR, ia);
9bccf70c 1293 FREE(dp, M_IP6NDP);
1c79356b 1294 dp = NULL;
9bccf70c 1295 ifafree(ifa);
1c79356b
A
1296 }
1297 }
1298
1299done:
1300 splx(s);
1c79356b
A
1301}
1302
1303void
91447636
A
1304nd6_dad_duplicated(
1305 struct ifaddr *ifa)
1c79356b
A
1306{
1307 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1308 struct dadq *dp;
1309
1310 dp = nd6_dad_find(ifa);
1311 if (dp == NULL) {
1312 log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
1313 return;
1314 }
1315
9bccf70c
A
1316 log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
1317 "NS in/out=%d/%d, NA in=%d\n",
1318 if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
1319 dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
1c79356b
A
1320
1321 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
1322 ia->ia6_flags |= IN6_IFF_DUPLICATED;
1323
1324 /* We are done with DAD, with duplicated address found. (failure) */
91447636 1325 untimeout((void (*)(void *))nd6_dad_timer, (void *)ifa);
9bccf70c 1326
1c79356b
A
1327
1328 log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
1329 if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
1330 log(LOG_ERR, "%s: manual intervention required\n",
1331 if_name(ifa->ifa_ifp));
1332
91447636 1333 lck_mtx_lock(dad6_mutex);
1c79356b 1334 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
91447636 1335 lck_mtx_unlock(dad6_mutex);
9bccf70c 1336 FREE(dp, M_IP6NDP);
1c79356b 1337 dp = NULL;
9bccf70c 1338 ifafree(ifa);
1c79356b
A
1339}
1340
1341static void
91447636
A
1342nd6_dad_ns_output(
1343 struct dadq *dp,
1344 struct ifaddr *ifa)
1c79356b
A
1345{
1346 struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1347 struct ifnet *ifp = ifa->ifa_ifp;
1348
1349 dp->dad_ns_tcount++;
1350 if ((ifp->if_flags & IFF_UP) == 0) {
1351#if 0
1352 printf("%s: interface down?\n", if_name(ifp));
1353#endif
1354 return;
1355 }
1356 if ((ifp->if_flags & IFF_RUNNING) == 0) {
1357#if 0
1358 printf("%s: interface not running?\n", if_name(ifp));
1359#endif
1360 return;
1361 }
1362
1363 dp->dad_ns_ocount++;
91447636 1364 nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1, 0);
1c79356b
A
1365}
1366
1367static void
91447636
A
1368nd6_dad_ns_input(
1369 struct ifaddr *ifa)
1c79356b
A
1370{
1371 struct in6_ifaddr *ia;
9bccf70c 1372 const struct in6_addr *taddr6;
1c79356b
A
1373 struct dadq *dp;
1374 int duplicate;
1375
1376 if (!ifa)
1377 panic("ifa == NULL in nd6_dad_ns_input");
1378
1379 ia = (struct in6_ifaddr *)ifa;
1c79356b
A
1380 taddr6 = &ia->ia_addr.sin6_addr;
1381 duplicate = 0;
1382 dp = nd6_dad_find(ifa);
1383
1c79356b
A
1384 /* Quickhack - completely ignore DAD NS packets */
1385 if (dad_ignore_ns) {
9bccf70c
A
1386 nd6log((LOG_INFO,
1387 "nd6_dad_ns_input: ignoring DAD NS packet for "
1c79356b 1388 "address %s(%s)\n", ip6_sprintf(taddr6),
9bccf70c 1389 if_name(ifa->ifa_ifp)));
1c79356b
A
1390 return;
1391 }
1392
1393 /*
1394 * if I'm yet to start DAD, someone else started using this address
1395 * first. I have a duplicate and you win.
1396 */
1397 if (!dp || dp->dad_ns_ocount == 0)
1398 duplicate++;
1399
1400 /* XXX more checks for loopback situation - see nd6_dad_timer too */
1401
1402 if (duplicate) {
1403 dp = NULL; /* will be freed in nd6_dad_duplicated() */
1404 nd6_dad_duplicated(ifa);
1405 } else {
1406 /*
1407 * not sure if I got a duplicate.
1408 * increment ns count and see what happens.
1409 */
1410 if (dp)
1411 dp->dad_ns_icount++;
1412 }
1413}
1414
1415static void
91447636
A
1416nd6_dad_na_input(
1417 struct ifaddr *ifa)
1c79356b
A
1418{
1419 struct dadq *dp;
1420
1421 if (!ifa)
1422 panic("ifa == NULL in nd6_dad_na_input");
1423
1424 dp = nd6_dad_find(ifa);
1425 if (dp)
1426 dp->dad_na_icount++;
1427
1428 /* remove the address. */
1429 nd6_dad_duplicated(ifa);
1430}