in6_ifattach.c revision 1.41.10.1 1 /* $NetBSD: in6_ifattach.c,v 1.41.10.1 2003/09/01 07:39:51 tron Exp $ */
2 /* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
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
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.41.10.1 2003/09/01 07:39:51 tron Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
39 #include <sys/socket.h>
40 #include <sys/sockio.h>
41 #include <sys/kernel.h>
42 #include <sys/syslog.h>
43 #include <sys/md5.h>
44
45 #include <net/if.h>
46 #include <net/if_dl.h>
47 #include <net/if_types.h>
48 #include <net/route.h>
49
50 #include <netinet/in.h>
51 #include <netinet/in_var.h>
52
53 #include <netinet/ip6.h>
54 #include <netinet6/ip6_var.h>
55 #include <netinet6/in6_ifattach.h>
56 #include <netinet6/ip6_var.h>
57 #include <netinet6/nd6.h>
58 #include <netinet6/ip6_mroute.h>
59
60 #include <net/net_osdep.h>
61
62 struct in6_ifstat **in6_ifstat = NULL;
63 struct icmp6_ifstat **icmp6_ifstat = NULL;
64 size_t in6_ifstatmax = 0;
65 size_t icmp6_ifstatmax = 0;
66 unsigned long in6_maxmtu = 0;
67
68 static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
69 static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
70 static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
71 static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *));
72 static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
73 static int in6_ifattach_loopback __P((struct ifnet *));
74
75 #define EUI64_GBIT 0x01
76 #define EUI64_UBIT 0x02
77 #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
78 #define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
79 #define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))
80 #define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)
81 #define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))
82
83 #define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
84 #define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
85
86 /*
87 * Generate a last-resort interface identifier, when the machine has no
88 * IEEE802/EUI64 address sources.
89 * The goal here is to get an interface identifier that is
90 * (1) random enough and (2) does not change across reboot.
91 * We currently use MD5(hostname) for it.
92 */
93 static int
94 get_rand_ifid(ifp, in6)
95 struct ifnet *ifp;
96 struct in6_addr *in6; /* upper 64bits are preserved */
97 {
98 MD5_CTX ctxt;
99 u_int8_t digest[16];
100
101 #if 0
102 /* we need at least several letters as seed for ifid */
103 if (hostnamelen < 3)
104 return -1;
105 #endif
106
107 /* generate 8 bytes of pseudo-random value. */
108 bzero(&ctxt, sizeof(ctxt));
109 MD5Init(&ctxt);
110 MD5Update(&ctxt, hostname, hostnamelen);
111 MD5Final(digest, &ctxt);
112
113 /* assumes sizeof(digest) > sizeof(ifid) */
114 bcopy(digest, &in6->s6_addr[8], 8);
115
116 /* make sure to set "u" bit to local, and "g" bit to individual. */
117 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
118 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
119
120 /* convert EUI64 into IPv6 interface identifier */
121 EUI64_TO_IFID(in6);
122
123 return 0;
124 }
125
126 /*
127 * Get interface identifier for the specified interface.
128 * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
129 */
130 static int
131 get_hw_ifid(ifp, in6)
132 struct ifnet *ifp;
133 struct in6_addr *in6; /* upper 64bits are preserved */
134 {
135 struct ifaddr *ifa;
136 struct sockaddr_dl *sdl;
137 u_int8_t *addr;
138 size_t addrlen;
139 static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
140 static u_int8_t allone[8] =
141 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
142
143 for (ifa = ifp->if_addrlist.tqh_first;
144 ifa;
145 ifa = ifa->ifa_list.tqe_next)
146 {
147 if (ifa->ifa_addr->sa_family != AF_LINK)
148 continue;
149 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
150 if (sdl == NULL)
151 continue;
152 if (sdl->sdl_alen == 0)
153 continue;
154
155 goto found;
156 }
157
158 return -1;
159
160 found:
161 addr = LLADDR(sdl);
162 addrlen = sdl->sdl_alen;
163
164 /* get EUI64 */
165 switch (ifp->if_type) {
166 case IFT_ETHER:
167 case IFT_FDDI:
168 case IFT_ATM:
169 case IFT_IEEE1394:
170 /* IEEE802/EUI64 cases - what others? */
171 /* IEEE1394 uses 16byte length address starting with EUI64 */
172 if (addrlen > 8)
173 addrlen = 8;
174
175 /* look at IEEE802/EUI64 only */
176 if (addrlen != 8 && addrlen != 6)
177 return -1;
178
179 /*
180 * check for invalid MAC address - on bsdi, we see it a lot
181 * since wildboar configures all-zero MAC on pccard before
182 * card insertion.
183 */
184 if (bcmp(addr, allzero, addrlen) == 0)
185 return -1;
186 if (bcmp(addr, allone, addrlen) == 0)
187 return -1;
188
189 /* make EUI64 address */
190 if (addrlen == 8)
191 bcopy(addr, &in6->s6_addr[8], 8);
192 else if (addrlen == 6) {
193 in6->s6_addr[8] = addr[0];
194 in6->s6_addr[9] = addr[1];
195 in6->s6_addr[10] = addr[2];
196 in6->s6_addr[11] = 0xff;
197 in6->s6_addr[12] = 0xfe;
198 in6->s6_addr[13] = addr[3];
199 in6->s6_addr[14] = addr[4];
200 in6->s6_addr[15] = addr[5];
201 }
202 break;
203
204 case IFT_ARCNET:
205 if (addrlen != 1)
206 return -1;
207 if (!addr[0])
208 return -1;
209
210 bzero(&in6->s6_addr[8], 8);
211 in6->s6_addr[15] = addr[0];
212
213 /*
214 * due to insufficient bitwidth, we mark it local.
215 */
216 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
217 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
218 break;
219
220 case IFT_GIF:
221 #ifdef IFT_STF
222 case IFT_STF:
223 #endif
224 /*
225 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
226 * however, IPv4 address is not very suitable as unique
227 * identifier source (can be renumbered).
228 * we don't do this.
229 */
230 return -1;
231
232 default:
233 return -1;
234 }
235
236 /* sanity check: g bit must not indicate "group" */
237 if (EUI64_GROUP(in6))
238 return -1;
239
240 /* convert EUI64 into IPv6 interface identifier */
241 EUI64_TO_IFID(in6);
242
243 /*
244 * sanity check: ifid must not be all zero, avoid conflict with
245 * subnet router anycast
246 */
247 if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
248 bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
249 return -1;
250 }
251
252 return 0;
253 }
254
255 /*
256 * Get interface identifier for the specified interface. If it is not
257 * available on ifp0, borrow interface identifier from other information
258 * sources.
259 */
260 static int
261 get_ifid(ifp0, altifp, in6)
262 struct ifnet *ifp0;
263 struct ifnet *altifp; /*secondary EUI64 source*/
264 struct in6_addr *in6;
265 {
266 struct ifnet *ifp;
267
268 /* first, try to get it from the interface itself */
269 if (get_hw_ifid(ifp0, in6) == 0) {
270 nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
271 if_name(ifp0)));
272 goto success;
273 }
274
275 /* try secondary EUI64 source. this basically is for ATM PVC */
276 if (altifp && get_hw_ifid(altifp, in6) == 0) {
277 nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
278 if_name(ifp0), if_name(altifp)));
279 goto success;
280 }
281
282 /* next, try to get it from some other hardware interface */
283 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
284 {
285 if (ifp == ifp0)
286 continue;
287 if (get_hw_ifid(ifp, in6) != 0)
288 continue;
289
290 /*
291 * to borrow ifid from other interface, ifid needs to be
292 * globally unique
293 */
294 if (IFID_UNIVERSAL(in6)) {
295 nd6log((LOG_DEBUG,
296 "%s: borrow interface identifier from %s\n",
297 if_name(ifp0), if_name(ifp)));
298 goto success;
299 }
300 }
301
302 /* last resort: get from random number source */
303 if (get_rand_ifid(ifp, in6) == 0) {
304 nd6log((LOG_DEBUG,
305 "%s: interface identifier generated by random number\n",
306 if_name(ifp0)));
307 goto success;
308 }
309
310 printf("%s: failed to get interface identifier\n", if_name(ifp0));
311 return -1;
312
313 success:
314 nd6log((LOG_INFO, "%s: ifid: "
315 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
316 if_name(ifp0),
317 in6->s6_addr[8], in6->s6_addr[9],
318 in6->s6_addr[10], in6->s6_addr[11],
319 in6->s6_addr[12], in6->s6_addr[13],
320 in6->s6_addr[14], in6->s6_addr[15]));
321 return 0;
322 }
323
324 /*
325 * configure IPv6 interface address. XXX code duplicated with in.c
326 */
327 static int
328 in6_ifattach_addaddr(ifp, ia)
329 struct ifnet *ifp;
330 struct in6_ifaddr *ia;
331 {
332 struct in6_ifaddr *oia;
333 struct ifaddr *ifa;
334 int error;
335 int rtflag;
336 struct in6_addr llsol;
337
338 /*
339 * initialize if_addrlist, if we are the very first one
340 */
341 ifa = TAILQ_FIRST(&ifp->if_addrlist);
342 if (ifa == NULL) {
343 TAILQ_INIT(&ifp->if_addrlist);
344 }
345
346 /*
347 * link the interface address to global list
348 */
349 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
350 IFAREF(&ia->ia_ifa);
351
352 /*
353 * Also link into the IPv6 address chain beginning with in6_ifaddr.
354 * kazu opposed it, but itojun & jinmei wanted.
355 */
356 if ((oia = in6_ifaddr) != NULL) {
357 for (; oia->ia_next; oia = oia->ia_next)
358 continue;
359 oia->ia_next = ia;
360 } else
361 in6_ifaddr = ia;
362 IFAREF(&ia->ia_ifa);
363
364 /*
365 * give the interface a chance to initialize, in case this
366 * is the first address to be added.
367 */
368 if (ifp->if_ioctl != NULL) {
369 int s;
370 s = splnet();
371 error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
372 splx(s);
373 } else
374 error = 0;
375 if (error) {
376 switch (error) {
377 case EAFNOSUPPORT:
378 printf("%s: IPv6 not supported\n", if_name(ifp));
379 break;
380 default:
381 printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
382 error);
383 break;
384 }
385
386 /* undo changes */
387 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
388 IFAFREE(&ia->ia_ifa);
389 if (oia)
390 oia->ia_next = ia->ia_next;
391 else
392 in6_ifaddr = ia->ia_next;
393 IFAFREE(&ia->ia_ifa);
394 return -1;
395 }
396
397 /* configure link-layer address resolution */
398 rtflag = 0;
399 if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
400 rtflag = RTF_HOST;
401 else {
402 switch (ifp->if_type) {
403 case IFT_LOOP:
404 #ifdef IFT_STF
405 case IFT_STF:
406 #endif
407 rtflag = 0;
408 break;
409 default:
410 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
411 ia->ia_ifa.ifa_flags |= RTF_CLONING;
412 rtflag = RTF_CLONING;
413 break;
414 }
415 }
416
417 /* add route to the interface. */
418 rtrequest(RTM_ADD,
419 (struct sockaddr *)&ia->ia_addr,
420 (struct sockaddr *)&ia->ia_addr,
421 (struct sockaddr *)&ia->ia_prefixmask,
422 RTF_UP | rtflag,
423 (struct rtentry **)0);
424 ia->ia_flags |= IFA_ROUTE;
425
426 if ((rtflag & RTF_CLONING) != 0 &&
427 (ifp->if_flags & IFF_MULTICAST) != 0) {
428 /* Restore saved multicast addresses (if any). */
429 in6_restoremkludge(ia, ifp);
430
431 /*
432 * join solicited multicast address
433 */
434 bzero(&llsol, sizeof(llsol));
435 llsol.s6_addr16[0] = htons(0xff02);
436 llsol.s6_addr16[1] = htons(ifp->if_index);
437 llsol.s6_addr32[1] = 0;
438 llsol.s6_addr32[2] = htonl(1);
439 llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
440 llsol.s6_addr8[12] = 0xff;
441 if (!in6_addmulti(&llsol, ifp, &error)) {
442 nd6log((LOG_ERR, "%s: failed to join %s (errno=%d)\n",
443 if_name(ifp), ip6_sprintf(&llsol), error));
444 }
445
446 /* XXX should we run DAD on other interface types? */
447 switch (ifp->if_type) {
448 #if 1
449 case IFT_ARCNET:
450 case IFT_ETHER:
451 case IFT_FDDI:
452 case IFT_IEEE1394:
453 #else
454 default:
455 #endif
456 /* mark the address TENTATIVE, if needed. */
457 ia->ia6_flags |= IN6_IFF_TENTATIVE;
458 /* nd6_dad_start() will be called in in6_if_up */
459 }
460 }
461
462 return 0;
463 }
464
465 static int
466 in6_ifattach_linklocal(ifp, altifp)
467 struct ifnet *ifp;
468 struct ifnet *altifp; /*secondary EUI64 source*/
469 {
470 struct in6_ifaddr *ia;
471
472 /*
473 * configure link-local address
474 */
475 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
476 bzero((caddr_t)ia, sizeof(*ia));
477 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
478 if (ifp->if_flags & IFF_POINTOPOINT)
479 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
480 else
481 ia->ia_ifa.ifa_dstaddr = NULL;
482 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
483 ia->ia_ifp = ifp;
484
485 bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
486 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
487 ia->ia_prefixmask.sin6_family = AF_INET6;
488 ia->ia_prefixmask.sin6_addr = in6mask64;
489
490 /* just in case */
491 bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
492 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
493 ia->ia_dstaddr.sin6_family = AF_INET6;
494
495 bzero(&ia->ia_addr, sizeof(ia->ia_addr));
496 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
497 ia->ia_addr.sin6_family = AF_INET6;
498 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
499 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
500 ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
501 if (ifp->if_flags & IFF_LOOPBACK) {
502 ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
503 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
504 } else {
505 if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
506 nd6log((LOG_ERR,
507 "%s: no ifid available\n", if_name(ifp)));
508 free(ia, M_IFADDR);
509 return -1;
510 }
511 }
512
513 ia->ia_ifa.ifa_metric = ifp->if_metric;
514
515 if (in6_ifattach_addaddr(ifp, ia) != 0) {
516 /* ia will be freed on failure */
517 return -1;
518 }
519
520 return 0;
521 }
522
523 static int
524 in6_ifattach_loopback(ifp)
525 struct ifnet *ifp; /* must be IFT_LOOP */
526 {
527 struct in6_ifaddr *ia;
528
529 /*
530 * configure link-local address
531 */
532 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
533 bzero((caddr_t)ia, sizeof(*ia));
534 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
535 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
536 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
537 ia->ia_ifp = ifp;
538
539 bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
540 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
541 ia->ia_prefixmask.sin6_family = AF_INET6;
542 ia->ia_prefixmask.sin6_addr = in6mask128;
543
544 /*
545 * Always initialize ia_dstaddr (= broadcast address) to loopback
546 * address, to make getifaddr happier.
547 *
548 * For BSDI, it is mandatory. The BSDI version of
549 * ifa_ifwithroute() rejects to add a route to the loopback
550 * interface. Even for other systems, loopback looks somewhat
551 * special.
552 */
553 bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
554 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
555 ia->ia_dstaddr.sin6_family = AF_INET6;
556 ia->ia_dstaddr.sin6_addr = in6addr_loopback;
557
558 bzero(&ia->ia_addr, sizeof(ia->ia_addr));
559 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
560 ia->ia_addr.sin6_family = AF_INET6;
561 ia->ia_addr.sin6_addr = in6addr_loopback;
562
563 ia->ia_ifa.ifa_metric = ifp->if_metric;
564
565 if (in6_ifattach_addaddr(ifp, ia) != 0) {
566 /* ia will be freed on failure */
567 return -1;
568 }
569
570 return 0;
571 }
572
573 /*
574 * XXX multiple loopback interface needs more care. for instance,
575 * nodelocal address needs to be configured onto only one of them.
576 * XXX multiple link-local address case
577 */
578 void
579 in6_ifattach(ifp, altifp)
580 struct ifnet *ifp;
581 struct ifnet *altifp; /* secondary EUI64 source */
582 {
583 static size_t if_indexlim = 8;
584 struct sockaddr_in6 mltaddr;
585 struct sockaddr_in6 mltmask;
586 struct sockaddr_in6 gate;
587 struct sockaddr_in6 mask;
588 struct in6_ifaddr *ia;
589 struct in6_addr in6;
590
591 /* some of the interfaces are inherently not IPv6 capable */
592 switch (ifp->if_type) {
593 case IFT_PROPVIRTUAL:
594 if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
595 '0' <= ifp->if_xname[sizeof("bridge")] &&
596 ifp->if_xname[sizeof("bridge")] <= '9')
597 return;
598 break;
599 }
600
601 /*
602 * We have some arrays that should be indexed by if_index.
603 * since if_index will grow dynamically, they should grow too.
604 * struct in6_ifstat **in6_ifstat
605 * struct icmp6_ifstat **icmp6_ifstat
606 */
607 if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
608 if_index >= if_indexlim) {
609 size_t n;
610 caddr_t q;
611 size_t olim;
612
613 olim = if_indexlim;
614 while (if_index >= if_indexlim)
615 if_indexlim <<= 1;
616
617 /* grow in6_ifstat */
618 n = if_indexlim * sizeof(struct in6_ifstat *);
619 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
620 bzero(q, n);
621 if (in6_ifstat) {
622 bcopy((caddr_t)in6_ifstat, q,
623 olim * sizeof(struct in6_ifstat *));
624 free((caddr_t)in6_ifstat, M_IFADDR);
625 }
626 in6_ifstat = (struct in6_ifstat **)q;
627 in6_ifstatmax = if_indexlim;
628
629 /* grow icmp6_ifstat */
630 n = if_indexlim * sizeof(struct icmp6_ifstat *);
631 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
632 bzero(q, n);
633 if (icmp6_ifstat) {
634 bcopy((caddr_t)icmp6_ifstat, q,
635 olim * sizeof(struct icmp6_ifstat *));
636 free((caddr_t)icmp6_ifstat, M_IFADDR);
637 }
638 icmp6_ifstat = (struct icmp6_ifstat **)q;
639 icmp6_ifstatmax = if_indexlim;
640 }
641
642 /* create a multicast kludge storage (if we have not had one) */
643 in6_createmkludge(ifp);
644
645 /*
646 * quirks based on interface type
647 */
648 switch (ifp->if_type) {
649 #ifdef IFT_STF
650 case IFT_STF:
651 /*
652 * 6to4 interface is a very special kind of beast.
653 * no multicast, no linklocal. RFC2529 specifies how to make
654 * linklocals for 6to4 interface, but there's no use and
655 * it is rather harmful to have one.
656 */
657 goto statinit;
658 #endif
659 default:
660 break;
661 }
662
663 /*
664 * usually, we require multicast capability to the interface
665 */
666 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
667 log(LOG_INFO, "in6_ifattach: "
668 "%s is not multicast capable, IPv6 not enabled\n",
669 if_name(ifp));
670 return;
671 }
672
673 /*
674 * assign link-local address, if there's none
675 */
676 ia = in6ifa_ifpforlinklocal(ifp, 0);
677 if (ia == NULL) {
678 if (in6_ifattach_linklocal(ifp, altifp) != 0)
679 return;
680 ia = in6ifa_ifpforlinklocal(ifp, 0);
681
682 if (ia == NULL) {
683 printf("%s: failed to add link-local address\n",
684 if_name(ifp));
685
686 /* we can't initialize multicasts without link-local */
687 goto statinit;
688 }
689 }
690
691 if (ifp->if_flags & IFF_POINTOPOINT) {
692 /*
693 * route local address to loopback
694 */
695 bzero(&gate, sizeof(gate));
696 gate.sin6_len = sizeof(struct sockaddr_in6);
697 gate.sin6_family = AF_INET6;
698 gate.sin6_addr = in6addr_loopback;
699 bzero(&mask, sizeof(mask));
700 mask.sin6_len = sizeof(struct sockaddr_in6);
701 mask.sin6_family = AF_INET6;
702 mask.sin6_addr = in6mask64;
703 rtrequest(RTM_ADD,
704 (struct sockaddr *)&ia->ia_addr,
705 (struct sockaddr *)&gate,
706 (struct sockaddr *)&mask,
707 RTF_UP|RTF_HOST,
708 (struct rtentry **)0);
709 }
710
711 /*
712 * assign loopback address for loopback interface
713 * XXX multiple loopback interface case
714 */
715 in6 = in6addr_loopback;
716 if (ifp->if_flags & IFF_LOOPBACK) {
717 if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
718 if (in6_ifattach_loopback(ifp) != 0)
719 return;
720 }
721 }
722
723 #ifdef DIAGNOSTIC
724 if (!ia) {
725 panic("ia == NULL in in6_ifattach");
726 /*NOTREACHED*/
727 }
728 #endif
729
730 /*
731 * join multicast
732 */
733 if (ifp->if_flags & IFF_MULTICAST) {
734 int error; /* not used */
735 struct in6_multi *in6m;
736
737 /* Restore saved multicast addresses (if any). */
738 in6_restoremkludge(ia, ifp);
739
740 bzero(&mltmask, sizeof(mltmask));
741 mltmask.sin6_len = sizeof(struct sockaddr_in6);
742 mltmask.sin6_family = AF_INET6;
743 mltmask.sin6_addr = in6mask32;
744
745 /*
746 * join link-local all-nodes address
747 */
748 bzero(&mltaddr, sizeof(mltaddr));
749 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
750 mltaddr.sin6_family = AF_INET6;
751 mltaddr.sin6_addr = in6addr_linklocal_allnodes;
752 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
753
754 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
755 if (in6m == NULL) {
756 rtrequest(RTM_ADD,
757 (struct sockaddr *)&mltaddr,
758 (struct sockaddr *)&ia->ia_addr,
759 (struct sockaddr *)&mltmask,
760 RTF_UP|RTF_CLONING, /* xxx */
761 (struct rtentry **)0);
762 if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) {
763 nd6log((LOG_ERR, "%s: failed to join %s "
764 "(errno=%d)\n", if_name(ifp),
765 ip6_sprintf(&mltaddr.sin6_addr),
766 error));
767 }
768 }
769
770 if (ifp->if_flags & IFF_LOOPBACK) {
771 in6 = in6addr_loopback;
772 ia = in6ifa_ifpwithaddr(ifp, &in6);
773 /*
774 * join node-local all-nodes address, on loopback
775 */
776 mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
777
778 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
779 if (in6m == NULL && ia != NULL) {
780 rtrequest(RTM_ADD,
781 (struct sockaddr *)&mltaddr,
782 (struct sockaddr *)&ia->ia_addr,
783 (struct sockaddr *)&mltmask,
784 RTF_UP,
785 (struct rtentry **)0);
786 if (!in6_addmulti(&mltaddr.sin6_addr, ifp,
787 &error)) {
788 nd6log((LOG_ERR, "%s: failed to join "
789 "%s (errno=%d)\n", if_name(ifp),
790 ip6_sprintf(&mltaddr.sin6_addr),
791 error));
792 }
793 }
794 }
795 }
796
797 statinit:;
798
799 /* update dynamically. */
800 if (in6_maxmtu < ifp->if_mtu)
801 in6_maxmtu = ifp->if_mtu;
802
803 if (in6_ifstat[ifp->if_index] == NULL) {
804 in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
805 malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
806 bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
807 }
808 if (icmp6_ifstat[ifp->if_index] == NULL) {
809 icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
810 malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
811 bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
812 }
813
814 /* initialize NDP variables */
815 nd6_ifattach(ifp);
816 }
817
818 /*
819 * NOTE: in6_ifdetach() does not support loopback if at this moment.
820 * We don't need this function in bsdi, because interfaces are never removed
821 * from the ifnet list in bsdi.
822 */
823 void
824 in6_ifdetach(ifp)
825 struct ifnet *ifp;
826 {
827 struct in6_ifaddr *ia, *oia;
828 struct ifaddr *ifa, *next;
829 struct rtentry *rt;
830 short rtflags;
831 struct sockaddr_in6 sin6;
832
833 /* remove ip6_mrouter stuff */
834 ip6_mrouter_detach(ifp);
835
836 /* nuke prefix list. this may try to remove some of ifaddrs as well */
837 in6_purgeprefix(ifp);
838
839 /* remove neighbor management table */
840 nd6_purge(ifp);
841
842 /* nuke any of IPv6 addresses we have */
843 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
844 {
845 next = ifa->ifa_list.tqe_next;
846 if (ifa->ifa_addr->sa_family != AF_INET6)
847 continue;
848 in6_purgeaddr(ifa, ifp);
849 }
850
851 /* undo everything done by in6_ifattach(), just in case */
852 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
853 {
854 next = ifa->ifa_list.tqe_next;
855
856
857 if (ifa->ifa_addr->sa_family != AF_INET6
858 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
859 continue;
860 }
861
862 ia = (struct in6_ifaddr *)ifa;
863
864 /* remove from the routing table */
865 if ((ia->ia_flags & IFA_ROUTE)
866 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
867 rtflags = rt->rt_flags;
868 rtfree(rt);
869 rtrequest(RTM_DELETE,
870 (struct sockaddr *)&ia->ia_addr,
871 (struct sockaddr *)&ia->ia_addr,
872 (struct sockaddr *)&ia->ia_prefixmask,
873 rtflags, (struct rtentry **)0);
874 }
875
876 /* remove from the linked list */
877 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
878 IFAFREE(&ia->ia_ifa);
879
880 /* also remove from the IPv6 address chain(itojun&jinmei) */
881 oia = ia;
882 if (oia == (ia = in6_ifaddr))
883 in6_ifaddr = ia->ia_next;
884 else {
885 while (ia->ia_next && (ia->ia_next != oia))
886 ia = ia->ia_next;
887 if (ia->ia_next)
888 ia->ia_next = oia->ia_next;
889 else {
890 nd6log((LOG_ERR,
891 "%s: didn't unlink in6ifaddr from "
892 "list\n", if_name(ifp)));
893 }
894 }
895
896 IFAFREE(&oia->ia_ifa);
897 }
898
899 /* cleanup multicast address kludge table, if there is any */
900 in6_purgemkludge(ifp);
901
902 /*
903 * remove neighbor management table. we call it twice just to make
904 * sure we nuke everything. maybe we need just one call.
905 * XXX: since the first call did not release addresses, some prefixes
906 * might remain. We should call nd6_purge() again to release the
907 * prefixes after removing all addresses above.
908 * (Or can we just delay calling nd6_purge until at this point?)
909 */
910 nd6_purge(ifp);
911
912 /* remove route to link-local allnodes multicast (ff02::1) */
913 bzero(&sin6, sizeof(sin6));
914 sin6.sin6_len = sizeof(struct sockaddr_in6);
915 sin6.sin6_family = AF_INET6;
916 sin6.sin6_addr = in6addr_linklocal_allnodes;
917 sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
918 rt = rtalloc1((struct sockaddr *)&sin6, 0);
919 if (rt && rt->rt_ifp == ifp) {
920 rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
921 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
922 rtfree(rt);
923 }
924 }
925