in6_ifattach.c revision 1.26 1 /* $NetBSD: in6_ifattach.c,v 1.26 2000/04/13 16:21:25 itojun Exp $ */
2 /* $KAME: in6_ifattach.c,v 1.48 2000/04/12 03:51:29 itojun 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/param.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/kernel.h>
39 #include <sys/md5.h>
40
41 #include <net/if.h>
42 #include <net/if_dl.h>
43 #include <net/if_types.h>
44 #include <net/route.h>
45
46 #include <netinet/in.h>
47 #include <netinet/in_var.h>
48
49 #include <netinet/ip6.h>
50 #include <netinet6/ip6_var.h>
51 #include <netinet6/in6_ifattach.h>
52 #include <netinet6/ip6_var.h>
53 #include <netinet6/nd6.h>
54
55 #include <net/net_osdep.h>
56
57 struct in6_ifstat **in6_ifstat = NULL;
58 struct icmp6_ifstat **icmp6_ifstat = NULL;
59 size_t in6_ifstatmax = 0;
60 size_t icmp6_ifstatmax = 0;
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 /* IEEE802/EUI64 cases - what others? */
165
166 /* look at IEEE802/EUI64 only */
167 if (addrlen != 8 && addrlen != 6)
168 return -1;
169
170 /*
171 * check for invalid MAC address - on bsdi, we see it a lot
172 * since wildboar configures all-zero MAC on pccard before
173 * card insertion.
174 */
175 if (bcmp(addr, allzero, addrlen) == 0)
176 return -1;
177 if (bcmp(addr, allone, addrlen) == 0)
178 return -1;
179
180 /* make EUI64 address */
181 if (addrlen == 8)
182 bcopy(addr, &in6->s6_addr[8], 8);
183 else if (addrlen == 6) {
184 in6->s6_addr[8] = addr[0];
185 in6->s6_addr[9] = addr[1];
186 in6->s6_addr[10] = addr[2];
187 in6->s6_addr[11] = 0xff;
188 in6->s6_addr[12] = 0xfe;
189 in6->s6_addr[13] = addr[3];
190 in6->s6_addr[14] = addr[4];
191 in6->s6_addr[15] = addr[5];
192 }
193 break;
194
195 case IFT_ARCNET:
196 if (addrlen != 1)
197 return -1;
198 if (!addr[0])
199 return -1;
200
201 bzero(&in6->s6_addr[8], 8);
202 in6->s6_addr[15] = addr[0];
203
204 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
205 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
206 break;
207
208 case IFT_GIF:
209 #ifdef IFT_STF
210 case IFT_STF:
211 #endif
212 /*
213 * mech-05/6to4-05: use IPv4 address as ifid source.
214 * the specification does not survive IPv4 renumbering.
215 * I'd rather not implement it, or make it optional (itojun).
216 */
217 return -1;
218
219 default:
220 return -1;
221 }
222
223 /* sanity check: g bit must not indicate "group" */
224 if (EUI64_GROUP(in6))
225 return -1;
226
227 /* convert EUI64 into IPv6 interface identifier */
228 EUI64_TO_IFID(in6);
229
230 /*
231 * sanity check: ifid must not be all zero, avoid conflict with
232 * subnet router anycast
233 */
234 if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
235 bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
236 return -1;
237 }
238
239 return 0;
240 }
241
242 /*
243 * Get interface identifier for the specified interface. If it is not
244 * available on ifp0, borrow interface identifier from other information
245 * sources.
246 */
247 static int
248 get_ifid(ifp0, altifp, in6)
249 struct ifnet *ifp0;
250 struct ifnet *altifp; /*secondary EUI64 source*/
251 struct in6_addr *in6;
252 {
253 struct ifnet *ifp;
254
255 /* first, try to get it from the interface itself */
256 if (get_hw_ifid(ifp0, in6) == 0) {
257 #ifdef ND6_DEBUG
258 printf("%s: got interface identifier from itself\n",
259 if_name(ifp0));
260 #endif
261 goto success;
262 }
263
264 /* try secondary EUI64 source. this basically is for ATM PVC */
265 if (altifp && get_hw_ifid(altifp, in6) == 0) {
266 #ifdef ND6_DEBUG
267 printf("%s: got interface identifier from %s\n",
268 if_name(ifp0), ifname(altifp));
269 #endif
270 goto success;
271 }
272
273 /* next, try to get it from some other hardware interface */
274 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
275 {
276 if (ifp == ifp0)
277 continue;
278 if (get_hw_ifid(ifp, in6) != 0)
279 continue;
280 /*
281 * to borrow ifid from other interface, ifid needs to be
282 * globally unique
283 */
284 if (IFID_UNIVERSAL(in6)) {
285
286 #ifdef ND6_DEBUG
287 printf("%s: borrow interface identifier from %s\n",
288 if_name(ifp0), if_name(ifp));
289 #endif
290 goto success;
291 }
292 }
293
294 /* last resort: get from random number source */
295 if (get_rand_ifid(ifp, in6) == 0) {
296 #ifdef ND6_DEBUG
297 printf("%s: interface identifier generated by random number\n",
298 if_name(ifp0));
299 #endif
300 goto success;
301 }
302
303 printf("%s: failed to get interface identifier", if_name(ifp0));
304 return -1;
305
306 success:
307 #ifdef ND6_DEBUG
308 printf("%s: ifid: "
309 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
310 if_name(ifp0),
311 in6->s6_addr[8], in6->s6_addr[9],
312 in6->s6_addr[10], in6->s6_addr[11],
313 in6->s6_addr[12], in6->s6_addr[13],
314 in6->s6_addr[14], in6->s6_addr[15]);
315 #endif
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 ia->ia_ifa.ifa_refcnt++;
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 ia->ia_ifa.ifa_refcnt++;
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 = splimp();
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 if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
394 rtflag = RTF_HOST;
395 else {
396 switch (ifp->if_type) {
397 case IFT_LOOP:
398 #ifdef IFT_STF
399 case IFT_STF:
400 #endif
401 rtflag = 0;
402 break;
403 #if 1
404 case IFT_ARCNET:
405 case IFT_ETHER:
406 case IFT_FDDI:
407 #else
408 default:
409 #endif
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 (void)in6_addmulti(&llsol, ifp, &error);
442
443 /* XXX should we run DAD on other interface types? */
444 switch (ifp->if_type) {
445 #if 1
446 case IFT_ARCNET:
447 case IFT_ETHER:
448 case IFT_FDDI:
449 #else
450 default:
451 #endif
452 /* mark the address TENTATIVE, if needed. */
453 ia->ia6_flags |= IN6_IFF_TENTATIVE;
454 /* nd6_dad_start() will be called in in6_if_up */
455 }
456 }
457
458 return 0;
459 }
460
461 static int
462 in6_ifattach_linklocal(ifp, altifp)
463 struct ifnet *ifp;
464 struct ifnet *altifp; /*secondary EUI64 source*/
465 {
466 struct in6_ifaddr *ia;
467
468 /*
469 * configure link-local address
470 */
471 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
472 bzero((caddr_t)ia, sizeof(*ia));
473 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
474 if (ifp->if_flags & IFF_POINTOPOINT)
475 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
476 else
477 ia->ia_ifa.ifa_dstaddr = NULL;
478 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
479 ia->ia_ifp = ifp;
480
481 bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
482 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
483 ia->ia_prefixmask.sin6_family = AF_INET6;
484 ia->ia_prefixmask.sin6_addr = in6mask64;
485
486 /* just in case */
487 bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
488 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
489 ia->ia_dstaddr.sin6_family = AF_INET6;
490
491 bzero(&ia->ia_addr, sizeof(ia->ia_addr));
492 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
493 ia->ia_addr.sin6_family = AF_INET6;
494 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
495 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
496 ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
497 if (ifp->if_flags & IFF_LOOPBACK) {
498 ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
499 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
500 } else {
501 if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
502 #ifdef ND6_DEBUG
503 printf("%s: no ifid available\n", if_name(ifp));
504 #endif
505 free(ia, M_IFADDR);
506 return -1;
507 }
508 }
509
510 ia->ia_ifa.ifa_metric = ifp->if_metric;
511
512 if (in6_ifattach_addaddr(ifp, ia) != 0) {
513 /* ia will be freed on failure */
514 return -1;
515 }
516
517 return 0;
518 }
519
520 static int
521 in6_ifattach_loopback(ifp)
522 struct ifnet *ifp; /* must be IFT_LOOP */
523 {
524 struct in6_ifaddr *ia;
525
526 /*
527 * configure link-local address
528 */
529 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
530 bzero((caddr_t)ia, sizeof(*ia));
531 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
532 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
533 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
534 ia->ia_ifp = ifp;
535
536 bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
537 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
538 ia->ia_prefixmask.sin6_family = AF_INET6;
539 ia->ia_prefixmask.sin6_addr = in6mask128;
540
541 /*
542 * Always initialize ia_dstaddr (= broadcast address) to loopback
543 * address, to make getifaddr happier.
544 *
545 * For BSDI, it is mandatory. The BSDI version of
546 * ifa_ifwithroute() rejects to add a route to the loopback
547 * interface. Even for other systems, loopback looks somewhat
548 * special.
549 */
550 bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
551 ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
552 ia->ia_dstaddr.sin6_family = AF_INET6;
553 ia->ia_dstaddr.sin6_addr = in6addr_loopback;
554
555 bzero(&ia->ia_addr, sizeof(ia->ia_addr));
556 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
557 ia->ia_addr.sin6_family = AF_INET6;
558 ia->ia_addr.sin6_addr = in6addr_loopback;
559
560 ia->ia_ifa.ifa_metric = ifp->if_metric;
561
562 if (in6_ifattach_addaddr(ifp, ia) != 0) {
563 /* ia will be freed on failure */
564 return -1;
565 }
566
567 return 0;
568 }
569
570 /*
571 * XXX multiple loopback interface needs more care. for instance,
572 * nodelocal address needs to be configured onto only one of them.
573 * XXX multiple link-local address case
574 */
575 void
576 in6_ifattach(ifp, altifp)
577 struct ifnet *ifp;
578 struct ifnet *altifp; /* secondary EUI64 source */
579 {
580 static size_t if_indexlim = 8;
581 struct sockaddr_in6 mltaddr;
582 struct sockaddr_in6 mltmask;
583 struct sockaddr_in6 gate;
584 struct sockaddr_in6 mask;
585 struct in6_ifaddr *ia;
586 struct in6_addr in6;
587
588 /*
589 * We have some arrays that should be indexed by if_index.
590 * since if_index will grow dynamically, they should grow too.
591 * struct in6_ifstat **in6_ifstat
592 * struct icmp6_ifstat **icmp6_ifstat
593 */
594 if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
595 if_index >= if_indexlim) {
596 size_t n;
597 caddr_t q;
598 size_t olim;
599
600 olim = if_indexlim;
601 while (if_index >= if_indexlim)
602 if_indexlim <<= 1;
603
604 /* grow in6_ifstat */
605 n = if_indexlim * sizeof(struct in6_ifstat *);
606 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
607 bzero(q, n);
608 if (in6_ifstat) {
609 bcopy((caddr_t)in6_ifstat, q,
610 olim * sizeof(struct in6_ifstat *));
611 free((caddr_t)in6_ifstat, M_IFADDR);
612 }
613 in6_ifstat = (struct in6_ifstat **)q;
614 in6_ifstatmax = if_indexlim;
615
616 /* grow icmp6_ifstat */
617 n = if_indexlim * sizeof(struct icmp6_ifstat *);
618 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
619 bzero(q, n);
620 if (icmp6_ifstat) {
621 bcopy((caddr_t)icmp6_ifstat, q,
622 olim * sizeof(struct icmp6_ifstat *));
623 free((caddr_t)icmp6_ifstat, M_IFADDR);
624 }
625 icmp6_ifstat = (struct icmp6_ifstat **)q;
626 icmp6_ifstatmax = if_indexlim;
627 }
628
629 /*
630 * quirks based on interface type
631 */
632 switch (ifp->if_type) {
633 #ifdef IFT_STF
634 case IFT_STF:
635 /*
636 * 6to4 interface is a very speical kind of beast.
637 * no multicast, no linklocal (based on 03 draft).
638 */
639 goto statinit;
640 #endif
641 default:
642 break;
643 }
644
645 /*
646 * usually, we require multicast capability to the interface
647 */
648 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
649 printf("%s: not multicast capable, IPv6 not enabled\n",
650 if_name(ifp));
651 return;
652 }
653
654 /*
655 * assign link-local address, if there's none
656 */
657 ia = in6ifa_ifpforlinklocal(ifp, 0);
658 if (ia == NULL) {
659 if (in6_ifattach_linklocal(ifp, altifp) != 0)
660 return;
661 ia = in6ifa_ifpforlinklocal(ifp, 0);
662
663 if (ia == NULL) {
664 printf("%s: failed to add link-local address",
665 if_name(ifp));
666
667 /* we can't initialize multicasts without link-local */
668 goto statinit;
669 }
670 }
671
672 if (ifp->if_flags & IFF_POINTOPOINT) {
673 /*
674 * route local address to loopback
675 */
676 bzero(&gate, sizeof(gate));
677 gate.sin6_len = sizeof(struct sockaddr_in6);
678 gate.sin6_family = AF_INET6;
679 gate.sin6_addr = in6addr_loopback;
680 bzero(&mask, sizeof(mask));
681 mask.sin6_len = sizeof(struct sockaddr_in6);
682 mask.sin6_family = AF_INET6;
683 mask.sin6_addr = in6mask64;
684 rtrequest(RTM_ADD,
685 (struct sockaddr *)&ia->ia_addr,
686 (struct sockaddr *)&gate,
687 (struct sockaddr *)&mask,
688 RTF_UP|RTF_HOST,
689 (struct rtentry **)0);
690 }
691
692 /*
693 * assign loopback address for loopback interface
694 * XXX multiple loopback interface case
695 */
696 in6 = in6addr_loopback;
697 if (ifp->if_flags & IFF_LOOPBACK) {
698 if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
699 if (in6_ifattach_loopback(ifp) != 0)
700 return;
701 }
702 }
703
704 #ifdef DIAGNOSTIC
705 if (!ia) {
706 panic("ia == NULL in in6_ifattach");
707 /*NOTREACHED*/
708 }
709 #endif
710
711 /*
712 * join multicast
713 */
714 if (ifp->if_flags & IFF_MULTICAST) {
715 int error; /* not used */
716 struct in6_multi *in6m;
717
718 /* Restore saved multicast addresses (if any). */
719 in6_restoremkludge(ia, ifp);
720
721 bzero(&mltmask, sizeof(mltmask));
722 mltmask.sin6_len = sizeof(struct sockaddr_in6);
723 mltmask.sin6_family = AF_INET6;
724 mltmask.sin6_addr = in6mask32;
725
726 /*
727 * join link-local all-nodes address
728 */
729 bzero(&mltaddr, sizeof(mltaddr));
730 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
731 mltaddr.sin6_family = AF_INET6;
732 mltaddr.sin6_addr = in6addr_linklocal_allnodes;
733 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
734
735 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
736 if (in6m == NULL) {
737 rtrequest(RTM_ADD,
738 (struct sockaddr *)&mltaddr,
739 (struct sockaddr *)&ia->ia_addr,
740 (struct sockaddr *)&mltmask,
741 RTF_UP|RTF_CLONING, /* xxx */
742 (struct rtentry **)0);
743 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
744 }
745
746 if (ifp->if_flags & IFF_LOOPBACK) {
747 in6 = in6addr_loopback;
748 ia = in6ifa_ifpwithaddr(ifp, &in6);
749 /*
750 * join node-local all-nodes address, on loopback
751 */
752 mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
753
754 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
755 if (in6m == NULL && ia != NULL) {
756 rtrequest(RTM_ADD,
757 (struct sockaddr *)&mltaddr,
758 (struct sockaddr *)&ia->ia_addr,
759 (struct sockaddr *)&mltmask,
760 RTF_UP,
761 (struct rtentry **)0);
762 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
763 }
764 }
765 }
766
767 statinit:;
768
769 /* update dynamically. */
770 if (in6_maxmtu < ifp->if_mtu)
771 in6_maxmtu = ifp->if_mtu;
772
773 if (in6_ifstat[ifp->if_index] == NULL) {
774 in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
775 malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
776 bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
777 }
778 if (icmp6_ifstat[ifp->if_index] == NULL) {
779 icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
780 malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
781 bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
782 }
783
784 /* initialize NDP variables */
785 nd6_ifattach(ifp);
786 }
787
788 /*
789 * NOTE: in6_ifdetach() does not support loopback if at this moment.
790 */
791 void
792 in6_ifdetach(ifp)
793 struct ifnet *ifp;
794 {
795 struct in6_ifaddr *ia, *oia;
796 struct ifaddr *ifa;
797 struct rtentry *rt;
798 short rtflags;
799 struct sockaddr_in6 sin6;
800
801 /* nuke prefix list. this may try to remove some of ifaddrs as well */
802 in6_purgeprefix(ifp);
803
804 /* remove neighbor management table */
805 nd6_purge(ifp);
806
807 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
808 {
809 if (ifa->ifa_addr->sa_family != AF_INET6
810 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
811 continue;
812 }
813
814 ia = (struct in6_ifaddr *)ifa;
815
816 /* remove from the routing table */
817 if ((ia->ia_flags & IFA_ROUTE)
818 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
819 rtflags = rt->rt_flags;
820 rtfree(rt);
821 rtrequest(RTM_DELETE,
822 (struct sockaddr *)&ia->ia_addr,
823 (struct sockaddr *)&ia->ia_addr,
824 (struct sockaddr *)&ia->ia_prefixmask,
825 rtflags, (struct rtentry **)0);
826 }
827
828 /* remove from the linked list */
829 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
830
831 /* also remove from the IPv6 address chain(itojun&jinmei) */
832 oia = ia;
833 if (oia == (ia = in6_ifaddr))
834 in6_ifaddr = ia->ia_next;
835 else {
836 while (ia->ia_next && (ia->ia_next != oia))
837 ia = ia->ia_next;
838 if (ia->ia_next)
839 ia->ia_next = oia->ia_next;
840 #ifdef ND6_DEBUG
841 else
842 printf("%s: didn't unlink in6ifaddr from "
843 "list\n", if_name(ifp));
844 #endif
845 }
846
847 free(ia, M_IFADDR);
848 }
849
850 /* cleanup multicast address kludge table, if there is any */
851 in6_purgemkludge(ifp);
852
853 /* remove route to link-local allnodes multicast (ff02::1) */
854 bzero(&sin6, sizeof(sin6));
855 sin6.sin6_len = sizeof(struct sockaddr_in6);
856 sin6.sin6_family = AF_INET6;
857 sin6.sin6_addr = in6addr_linklocal_allnodes;
858 sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
859 if ((rt = rtalloc1((struct sockaddr *)&sin6, 0)) != NULL) {
860 rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
861 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
862 rtfree(rt);
863 }
864 }
865