in6_ifattach.c revision 1.45 1 /* $NetBSD: in6_ifattach.c,v 1.45 2002/05/29 02:58:30 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.45 2002/05/29 02:58:30 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 /* create a multicast kludge storage (if we have not had one) */
583 in6_createmkludge(ifp);
584
585 /*
586 * quirks based on interface type
587 */
588 switch (ifp->if_type) {
589 #ifdef IFT_STF
590 case IFT_STF:
591 /*
592 * 6to4 interface is a very special kind of beast.
593 * no multicast, no linklocal. RFC2529 specifies how to make
594 * linklocals for 6to4 interface, but there's no use and
595 * it is rather harmful to have one.
596 */
597 goto statinit;
598 #endif
599 default:
600 break;
601 }
602
603 /*
604 * usually, we require multicast capability to the interface
605 */
606 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
607 log(LOG_INFO, "in6_ifattach: "
608 "%s is not multicast capable, IPv6 not enabled\n",
609 if_name(ifp));
610 return;
611 }
612
613 /*
614 * assign link-local address, if there's none
615 */
616 ia = in6ifa_ifpforlinklocal(ifp, 0);
617 if (ia == NULL) {
618 if (in6_ifattach_linklocal(ifp, altifp) != 0)
619 return;
620 ia = in6ifa_ifpforlinklocal(ifp, 0);
621
622 if (ia == NULL) {
623 printf("%s: failed to add link-local address\n",
624 if_name(ifp));
625
626 /* we can't initialize multicasts without link-local */
627 goto statinit;
628 }
629 }
630
631 if (ifp->if_flags & IFF_POINTOPOINT) {
632 /*
633 * route local address to loopback
634 */
635 bzero(&gate, sizeof(gate));
636 gate.sin6_len = sizeof(struct sockaddr_in6);
637 gate.sin6_family = AF_INET6;
638 gate.sin6_addr = in6addr_loopback;
639 bzero(&mask, sizeof(mask));
640 mask.sin6_len = sizeof(struct sockaddr_in6);
641 mask.sin6_family = AF_INET6;
642 mask.sin6_addr = in6mask64;
643 rtrequest(RTM_ADD,
644 (struct sockaddr *)&ia->ia_addr,
645 (struct sockaddr *)&gate,
646 (struct sockaddr *)&mask,
647 RTF_UP|RTF_HOST,
648 (struct rtentry **)0);
649 }
650
651 /*
652 * assign loopback address for loopback interface
653 * XXX multiple loopback interface case
654 */
655 in6 = in6addr_loopback;
656 if (ifp->if_flags & IFF_LOOPBACK) {
657 if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
658 if (in6_ifattach_loopback(ifp) != 0)
659 return;
660 }
661 }
662
663 #ifdef DIAGNOSTIC
664 if (!ia) {
665 panic("ia == NULL in in6_ifattach");
666 /*NOTREACHED*/
667 }
668 #endif
669
670 /*
671 * join multicast
672 */
673 if (ifp->if_flags & IFF_MULTICAST) {
674 int error; /* not used */
675 struct in6_multi *in6m;
676
677 /* Restore saved multicast addresses (if any). */
678 in6_restoremkludge(ia, ifp);
679
680 bzero(&mltmask, sizeof(mltmask));
681 mltmask.sin6_len = sizeof(struct sockaddr_in6);
682 mltmask.sin6_family = AF_INET6;
683 mltmask.sin6_addr = in6mask32;
684
685 /*
686 * join link-local all-nodes address
687 */
688 bzero(&mltaddr, sizeof(mltaddr));
689 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
690 mltaddr.sin6_family = AF_INET6;
691 mltaddr.sin6_addr = in6addr_linklocal_allnodes;
692 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
693
694 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
695 if (in6m == NULL) {
696 rtrequest(RTM_ADD,
697 (struct sockaddr *)&mltaddr,
698 (struct sockaddr *)&ia->ia_addr,
699 (struct sockaddr *)&mltmask,
700 RTF_UP|RTF_CLONING, /* xxx */
701 (struct rtentry **)0);
702 if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) {
703 nd6log((LOG_ERR, "%s: failed to join %s "
704 "(errno=%d)\n", if_name(ifp),
705 ip6_sprintf(&mltaddr.sin6_addr),
706 error));
707 }
708 }
709
710 if (ifp->if_flags & IFF_LOOPBACK) {
711 in6 = in6addr_loopback;
712 ia = in6ifa_ifpwithaddr(ifp, &in6);
713 /*
714 * join node-local all-nodes address, on loopback
715 */
716 mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
717
718 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
719 if (in6m == NULL && ia != NULL) {
720 rtrequest(RTM_ADD,
721 (struct sockaddr *)&mltaddr,
722 (struct sockaddr *)&ia->ia_addr,
723 (struct sockaddr *)&mltmask,
724 RTF_UP,
725 (struct rtentry **)0);
726 if (!in6_addmulti(&mltaddr.sin6_addr, ifp,
727 &error)) {
728 nd6log((LOG_ERR, "%s: failed to join "
729 "%s (errno=%d)\n", if_name(ifp),
730 ip6_sprintf(&mltaddr.sin6_addr),
731 error));
732 }
733 }
734 }
735 }
736
737 statinit:;
738
739 /* update dynamically. */
740 if (in6_maxmtu < ifp->if_mtu)
741 in6_maxmtu = ifp->if_mtu;
742
743 /* initialize NDP variables */
744 nd6_ifattach(ifp);
745 }
746
747 /*
748 * NOTE: in6_ifdetach() does not support loopback if at this moment.
749 * We don't need this function in bsdi, because interfaces are never removed
750 * from the ifnet list in bsdi.
751 */
752 void
753 in6_ifdetach(ifp)
754 struct ifnet *ifp;
755 {
756 struct in6_ifaddr *ia, *oia;
757 struct ifaddr *ifa, *next;
758 struct rtentry *rt;
759 short rtflags;
760 struct sockaddr_in6 sin6;
761
762 /* nuke prefix list. this may try to remove some of ifaddrs as well */
763 in6_purgeprefix(ifp);
764
765 /* remove neighbor management table */
766 nd6_purge(ifp);
767
768 /* nuke any of IPv6 addresses we have */
769 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
770 {
771 next = ifa->ifa_list.tqe_next;
772 if (ifa->ifa_addr->sa_family != AF_INET6)
773 continue;
774 in6_purgeaddr(ifa, ifp);
775 }
776
777 /* undo everything done by in6_ifattach(), just in case */
778 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
779 {
780 next = ifa->ifa_list.tqe_next;
781
782
783 if (ifa->ifa_addr->sa_family != AF_INET6
784 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
785 continue;
786 }
787
788 ia = (struct in6_ifaddr *)ifa;
789
790 /* remove from the routing table */
791 if ((ia->ia_flags & IFA_ROUTE)
792 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
793 rtflags = rt->rt_flags;
794 rtfree(rt);
795 rtrequest(RTM_DELETE,
796 (struct sockaddr *)&ia->ia_addr,
797 (struct sockaddr *)&ia->ia_addr,
798 (struct sockaddr *)&ia->ia_prefixmask,
799 rtflags, (struct rtentry **)0);
800 }
801
802 /* remove from the linked list */
803 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
804 IFAFREE(&ia->ia_ifa);
805
806 /* also remove from the IPv6 address chain(itojun&jinmei) */
807 oia = ia;
808 if (oia == (ia = in6_ifaddr))
809 in6_ifaddr = ia->ia_next;
810 else {
811 while (ia->ia_next && (ia->ia_next != oia))
812 ia = ia->ia_next;
813 if (ia->ia_next)
814 ia->ia_next = oia->ia_next;
815 else {
816 nd6log((LOG_ERR,
817 "%s: didn't unlink in6ifaddr from "
818 "list\n", if_name(ifp)));
819 }
820 }
821
822 IFAFREE(&oia->ia_ifa);
823 }
824
825 /* cleanup multicast address kludge table, if there is any */
826 in6_purgemkludge(ifp);
827
828 /*
829 * remove neighbor management table. we call it twice just to make
830 * sure we nuke everything. maybe we need just one call.
831 * XXX: since the first call did not release addresses, some prefixes
832 * might remain. We should call nd6_purge() again to release the
833 * prefixes after removing all addresses above.
834 * (Or can we just delay calling nd6_purge until at this point?)
835 */
836 nd6_purge(ifp);
837
838 /* remove route to link-local allnodes multicast (ff02::1) */
839 bzero(&sin6, sizeof(sin6));
840 sin6.sin6_len = sizeof(struct sockaddr_in6);
841 sin6.sin6_family = AF_INET6;
842 sin6.sin6_addr = in6addr_linklocal_allnodes;
843 sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
844 rt = rtalloc1((struct sockaddr *)&sin6, 0);
845 if (rt && rt->rt_ifp == ifp) {
846 rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
847 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
848 rtfree(rt);
849 }
850 }
851