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