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