in6_ifattach.c revision 1.47 1 /* $NetBSD: in6_ifattach.c,v 1.47 2002/06/07 04:30: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.47 2002/06/07 04:30: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: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
310 if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
311 in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
312 in6->s6_addr[14], in6->s6_addr[15]));
313 return 0;
314 }
315
316 /*
317 * configure IPv6 interface address. XXX code duplicated with in.c
318 */
319 static int
320 in6_ifattach_addaddr(ifp, ia)
321 struct ifnet *ifp;
322 struct in6_ifaddr *ia;
323 {
324 struct in6_ifaddr *oia;
325 struct ifaddr *ifa;
326 int error;
327 int rtflag;
328 struct in6_addr llsol;
329
330 /*
331 * initialize if_addrlist, if we are the very first one
332 */
333 ifa = TAILQ_FIRST(&ifp->if_addrlist);
334 if (ifa == NULL) {
335 TAILQ_INIT(&ifp->if_addrlist);
336 }
337
338 /*
339 * link the interface address to global list
340 */
341 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
342 IFAREF(&ia->ia_ifa);
343
344 /*
345 * Also link into the IPv6 address chain beginning with in6_ifaddr.
346 * kazu opposed it, but itojun & jinmei wanted.
347 */
348 if ((oia = in6_ifaddr) != NULL) {
349 for (; oia->ia_next; oia = oia->ia_next)
350 continue;
351 oia->ia_next = ia;
352 } else
353 in6_ifaddr = ia;
354 IFAREF(&ia->ia_ifa);
355
356 /*
357 * give the interface a chance to initialize, in case this
358 * is the first address to be added.
359 */
360 if (ifp->if_ioctl != NULL) {
361 int s;
362 s = splnet();
363 error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
364 splx(s);
365 } else
366 error = 0;
367 if (error) {
368 switch (error) {
369 case EAFNOSUPPORT:
370 printf("%s: IPv6 not supported\n", if_name(ifp));
371 break;
372 default:
373 printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
374 error);
375 break;
376 }
377
378 /* undo changes */
379 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
380 IFAFREE(&ia->ia_ifa);
381 if (oia)
382 oia->ia_next = ia->ia_next;
383 else
384 in6_ifaddr = ia->ia_next;
385 IFAFREE(&ia->ia_ifa);
386 return -1;
387 }
388
389 /* configure link-layer address resolution */
390 rtflag = 0;
391 if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
392 rtflag = RTF_HOST;
393 else {
394 switch (ifp->if_type) {
395 case IFT_LOOP:
396 #ifdef IFT_STF
397 case IFT_STF:
398 #endif
399 rtflag = 0;
400 break;
401 default:
402 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
403 ia->ia_ifa.ifa_flags |= RTF_CLONING;
404 rtflag = RTF_CLONING;
405 break;
406 }
407 }
408
409 /* add route to the interface. */
410 rtrequest(RTM_ADD,
411 (struct sockaddr *)&ia->ia_addr,
412 (struct sockaddr *)&ia->ia_addr,
413 (struct sockaddr *)&ia->ia_prefixmask,
414 RTF_UP | rtflag,
415 (struct rtentry **)0);
416 ia->ia_flags |= IFA_ROUTE;
417
418 if ((rtflag & RTF_CLONING) != 0 &&
419 (ifp->if_flags & IFF_MULTICAST) != 0) {
420 /* Restore saved multicast addresses (if any). */
421 in6_restoremkludge(ia, ifp);
422
423 /*
424 * join solicited multicast address
425 */
426 bzero(&llsol, sizeof(llsol));
427 llsol.s6_addr16[0] = htons(0xff02);
428 llsol.s6_addr16[1] = htons(ifp->if_index);
429 llsol.s6_addr32[1] = 0;
430 llsol.s6_addr32[2] = htonl(1);
431 llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
432 llsol.s6_addr8[12] = 0xff;
433 if (!in6_addmulti(&llsol, ifp, &error)) {
434 nd6log((LOG_ERR, "%s: failed to join %s (errno=%d)\n",
435 if_name(ifp), ip6_sprintf(&llsol), error));
436 }
437
438 if (in6if_do_dad(ifp)) {
439 /* mark the address TENTATIVE, if needed. */
440 ia->ia6_flags |= IN6_IFF_TENTATIVE;
441 /* nd6_dad_start() will be called in in6_if_up */
442 }
443 }
444
445 return 0;
446 }
447
448 static int
449 in6_ifattach_linklocal(ifp, altifp)
450 struct ifnet *ifp;
451 struct ifnet *altifp; /*secondary EUI64 source*/
452 {
453 struct in6_ifaddr *ia;
454
455 /*
456 * configure link-local address
457 */
458 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
459 bzero((caddr_t)ia, sizeof(*ia));
460 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
461 if (ifp->if_flags & IFF_POINTOPOINT)
462 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
463 else
464 ia->ia_ifa.ifa_dstaddr = NULL;
465 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
466 ia->ia_ifp = ifp;
467
468 bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
469 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
470 ia->ia_prefixmask.sin6_family = AF_INET6;
471 ia->ia_prefixmask.sin6_addr = in6mask64;
472
473 /* just in case */
474 bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
475 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
476 ia->ia_dstaddr.sin6_family = AF_INET6;
477
478 bzero(&ia->ia_addr, sizeof(ia->ia_addr));
479 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
480 ia->ia_addr.sin6_family = AF_INET6;
481 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
482 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
483 ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
484 if (ifp->if_flags & IFF_LOOPBACK) {
485 ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
486 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
487 } else {
488 if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
489 nd6log((LOG_ERR,
490 "%s: no ifid available\n", if_name(ifp)));
491 free(ia, M_IFADDR);
492 return -1;
493 }
494 }
495
496 ia->ia_ifa.ifa_metric = ifp->if_metric;
497
498 if (in6_ifattach_addaddr(ifp, ia) != 0) {
499 /* ia will be freed on failure */
500 return -1;
501 }
502
503 return 0;
504 }
505
506 static int
507 in6_ifattach_loopback(ifp)
508 struct ifnet *ifp; /* must be IFT_LOOP */
509 {
510 struct in6_ifaddr *ia;
511
512 /*
513 * configure link-local address
514 */
515 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
516 bzero((caddr_t)ia, sizeof(*ia));
517 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
518 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
519 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
520 ia->ia_ifp = ifp;
521
522 bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
523 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
524 ia->ia_prefixmask.sin6_family = AF_INET6;
525 ia->ia_prefixmask.sin6_addr = in6mask128;
526
527 /*
528 * Always initialize ia_dstaddr (= broadcast address) to loopback
529 * address, to make getifaddr happier.
530 *
531 * For BSDI, it is mandatory. The BSDI version of
532 * ifa_ifwithroute() rejects to add a route to the loopback
533 * interface. Even for other systems, loopback looks somewhat
534 * special.
535 */
536 bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
537 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
538 ia->ia_dstaddr.sin6_family = AF_INET6;
539 ia->ia_dstaddr.sin6_addr = in6addr_loopback;
540
541 bzero(&ia->ia_addr, sizeof(ia->ia_addr));
542 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
543 ia->ia_addr.sin6_family = AF_INET6;
544 ia->ia_addr.sin6_addr = in6addr_loopback;
545
546 ia->ia_ifa.ifa_metric = ifp->if_metric;
547
548 if (in6_ifattach_addaddr(ifp, ia) != 0) {
549 /* ia will be freed on failure */
550 return -1;
551 }
552
553 return 0;
554 }
555
556 /*
557 * XXX multiple loopback interface needs more care. for instance,
558 * nodelocal address needs to be configured onto only one of them.
559 * XXX multiple link-local address case
560 */
561 void
562 in6_ifattach(ifp, altifp)
563 struct ifnet *ifp;
564 struct ifnet *altifp; /* secondary EUI64 source */
565 {
566 struct sockaddr_in6 mltaddr;
567 struct sockaddr_in6 mltmask;
568 struct sockaddr_in6 gate;
569 struct sockaddr_in6 mask;
570 struct in6_ifaddr *ia;
571 struct in6_addr in6;
572
573 /* some of the interfaces are inherently not IPv6 capable */
574 switch (ifp->if_type) {
575 case IFT_BRIDGE:
576 return;
577 }
578
579 /*
580 * if link mtu is too small, don't try to configure IPv6.
581 * remember there could be some link-layer that has special
582 * fragmentation logic.
583 */
584 if (ifp->if_mtu < IPV6_MMTU)
585 return;
586
587 /* create a multicast kludge storage (if we have not had one) */
588 in6_createmkludge(ifp);
589
590 /*
591 * quirks based on interface type
592 */
593 switch (ifp->if_type) {
594 #ifdef IFT_STF
595 case IFT_STF:
596 /*
597 * 6to4 interface is a very special kind of beast.
598 * no multicast, no linklocal. RFC2529 specifies how to make
599 * linklocals for 6to4 interface, but there's no use and
600 * it is rather harmful to have one.
601 */
602 return;
603 #endif
604 default:
605 break;
606 }
607
608 /*
609 * usually, we require multicast capability to the interface
610 */
611 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
612 log(LOG_INFO, "in6_ifattach: "
613 "%s is not multicast capable, IPv6 not enabled\n",
614 if_name(ifp));
615 return;
616 }
617
618 /*
619 * assign link-local address, if there's none
620 */
621 ia = in6ifa_ifpforlinklocal(ifp, 0);
622 if (ia == NULL) {
623 if (in6_ifattach_linklocal(ifp, altifp) != 0)
624 return;
625 ia = in6ifa_ifpforlinklocal(ifp, 0);
626
627 if (ia == NULL) {
628 printf("%s: failed to add link-local address\n",
629 if_name(ifp));
630
631 /* we can't initialize multicasts without link-local */
632 return;
633 }
634 }
635
636 if (ifp->if_flags & IFF_POINTOPOINT) {
637 /*
638 * route local address to loopback
639 */
640 bzero(&gate, sizeof(gate));
641 gate.sin6_len = sizeof(struct sockaddr_in6);
642 gate.sin6_family = AF_INET6;
643 gate.sin6_addr = in6addr_loopback;
644 bzero(&mask, sizeof(mask));
645 mask.sin6_len = sizeof(struct sockaddr_in6);
646 mask.sin6_family = AF_INET6;
647 mask.sin6_addr = in6mask64;
648 rtrequest(RTM_ADD,
649 (struct sockaddr *)&ia->ia_addr,
650 (struct sockaddr *)&gate,
651 (struct sockaddr *)&mask,
652 RTF_UP|RTF_HOST,
653 (struct rtentry **)0);
654 }
655
656 /*
657 * assign loopback address for loopback interface
658 * XXX multiple loopback interface case
659 */
660 in6 = in6addr_loopback;
661 if (ifp->if_flags & IFF_LOOPBACK) {
662 if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
663 if (in6_ifattach_loopback(ifp) != 0)
664 return;
665 }
666 }
667
668 #ifdef DIAGNOSTIC
669 if (!ia) {
670 panic("ia == NULL in in6_ifattach");
671 /*NOTREACHED*/
672 }
673 #endif
674
675 /*
676 * join multicast
677 */
678 if (ifp->if_flags & IFF_MULTICAST) {
679 int error; /* not used */
680 struct in6_multi *in6m;
681
682 /* Restore saved multicast addresses (if any). */
683 in6_restoremkludge(ia, ifp);
684
685 bzero(&mltmask, sizeof(mltmask));
686 mltmask.sin6_len = sizeof(struct sockaddr_in6);
687 mltmask.sin6_family = AF_INET6;
688 mltmask.sin6_addr = in6mask32;
689
690 /*
691 * join link-local all-nodes address
692 */
693 bzero(&mltaddr, sizeof(mltaddr));
694 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
695 mltaddr.sin6_family = AF_INET6;
696 mltaddr.sin6_addr = in6addr_linklocal_allnodes;
697 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
698
699 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
700 if (in6m == NULL) {
701 rtrequest(RTM_ADD,
702 (struct sockaddr *)&mltaddr,
703 (struct sockaddr *)&ia->ia_addr,
704 (struct sockaddr *)&mltmask,
705 RTF_UP|RTF_CLONING, /* xxx */
706 (struct rtentry **)0);
707 if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) {
708 nd6log((LOG_ERR, "%s: failed to join %s "
709 "(errno=%d)\n", if_name(ifp),
710 ip6_sprintf(&mltaddr.sin6_addr),
711 error));
712 }
713 }
714
715 if (ifp->if_flags & IFF_LOOPBACK) {
716 in6 = in6addr_loopback;
717 ia = in6ifa_ifpwithaddr(ifp, &in6);
718 /*
719 * join node-local all-nodes address, on loopback
720 */
721 mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
722
723 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
724 if (in6m == NULL && ia != NULL) {
725 rtrequest(RTM_ADD,
726 (struct sockaddr *)&mltaddr,
727 (struct sockaddr *)&ia->ia_addr,
728 (struct sockaddr *)&mltmask,
729 RTF_UP,
730 (struct rtentry **)0);
731 if (!in6_addmulti(&mltaddr.sin6_addr, ifp,
732 &error)) {
733 nd6log((LOG_ERR, "%s: failed to join "
734 "%s (errno=%d)\n", if_name(ifp),
735 ip6_sprintf(&mltaddr.sin6_addr),
736 error));
737 }
738 }
739 }
740 }
741 }
742
743 /*
744 * NOTE: in6_ifdetach() does not support loopback if at this moment.
745 * We don't need this function in bsdi, because interfaces are never removed
746 * from the ifnet list in bsdi.
747 */
748 void
749 in6_ifdetach(ifp)
750 struct ifnet *ifp;
751 {
752 struct in6_ifaddr *ia, *oia;
753 struct ifaddr *ifa, *next;
754 struct rtentry *rt;
755 short rtflags;
756 struct sockaddr_in6 sin6;
757
758 /* nuke prefix list. this may try to remove some of ifaddrs as well */
759 in6_purgeprefix(ifp);
760
761 /* remove neighbor management table */
762 nd6_purge(ifp);
763
764 /* nuke any of IPv6 addresses we have */
765 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
766 {
767 next = ifa->ifa_list.tqe_next;
768 if (ifa->ifa_addr->sa_family != AF_INET6)
769 continue;
770 in6_purgeaddr(ifa, ifp);
771 }
772
773 /* undo everything done by in6_ifattach(), just in case */
774 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
775 {
776 next = ifa->ifa_list.tqe_next;
777
778
779 if (ifa->ifa_addr->sa_family != AF_INET6
780 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
781 continue;
782 }
783
784 ia = (struct in6_ifaddr *)ifa;
785
786 /* remove from the routing table */
787 if ((ia->ia_flags & IFA_ROUTE)
788 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
789 rtflags = rt->rt_flags;
790 rtfree(rt);
791 rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
792 (struct sockaddr *)&ia->ia_addr,
793 (struct sockaddr *)&ia->ia_prefixmask,
794 rtflags, (struct rtentry **)0);
795 }
796
797 /* remove from the linked list */
798 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
799 IFAFREE(&ia->ia_ifa);
800
801 /* also remove from the IPv6 address chain(itojun&jinmei) */
802 oia = ia;
803 if (oia == (ia = in6_ifaddr))
804 in6_ifaddr = ia->ia_next;
805 else {
806 while (ia->ia_next && (ia->ia_next != oia))
807 ia = ia->ia_next;
808 if (ia->ia_next)
809 ia->ia_next = oia->ia_next;
810 else {
811 nd6log((LOG_ERR,
812 "%s: didn't unlink in6ifaddr from list\n",
813 if_name(ifp)));
814 }
815 }
816
817 IFAFREE(&oia->ia_ifa);
818 }
819
820 /* cleanup multicast address kludge table, if there is any */
821 in6_purgemkludge(ifp);
822
823 /*
824 * remove neighbor management table. we call it twice just to make
825 * sure we nuke everything. maybe we need just one call.
826 * XXX: since the first call did not release addresses, some prefixes
827 * might remain. We should call nd6_purge() again to release the
828 * prefixes after removing all addresses above.
829 * (Or can we just delay calling nd6_purge until at this point?)
830 */
831 nd6_purge(ifp);
832
833 /* remove route to link-local allnodes multicast (ff02::1) */
834 bzero(&sin6, sizeof(sin6));
835 sin6.sin6_len = sizeof(struct sockaddr_in6);
836 sin6.sin6_family = AF_INET6;
837 sin6.sin6_addr = in6addr_linklocal_allnodes;
838 sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
839 rt = rtalloc1((struct sockaddr *)&sin6, 0);
840 if (rt && rt->rt_ifp == ifp) {
841 rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
842 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
843 rtfree(rt);
844 }
845 }
846