in6_ifattach.c revision 1.1.2.2 1 /*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 #include <sys/socket.h>
34 #include <sys/sockio.h>
35 #include <sys/kernel.h>
36 #ifdef __bsdi__
37 #include <crypto/md5.h>
38 #elif defined(__OpenBSD__)
39 #include <sys/md5k.h>
40 #else
41 #include <sys/md5.h>
42 #endif
43
44 #include <net/if.h>
45 #include <net/if_dl.h>
46 #include <net/if_types.h>
47 #include <net/route.h>
48
49 #include <netinet/in.h>
50 #include <netinet/in_var.h>
51 #ifndef __NetBSD__
52 #include <netinet/if_ether.h>
53 #endif
54
55 #include <netinet6/ip6.h>
56 #include <netinet6/ip6_var.h>
57 #include <netinet6/in6_ifattach.h>
58 #include <netinet6/ip6.h>
59 #include <netinet6/ip6_var.h>
60 #include <netinet6/nd6.h>
61
62 #include <net/net_osdep.h>
63
64 static struct in6_addr llsol;
65
66 struct in6_ifstat **in6_ifstat = NULL;
67 struct icmp6_ifstat **icmp6_ifstat = NULL;
68 size_t in6_ifstatmax = 0;
69 size_t icmp6_ifstatmax = 0;
70 unsigned long in6_maxmtu = 0;
71
72 int found_first_ifid = 0;
73 #define IFID_LEN 8
74 static char first_ifid[IFID_LEN];
75
76 static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t));
77 static int gen_rand_eui64 __P((u_int8_t *));
78
79 static int
80 laddr_to_eui64(dst, src, len)
81 u_int8_t *dst;
82 u_int8_t *src;
83 size_t len;
84 {
85 static u_int8_t zero[8];
86
87 bzero(zero, sizeof(zero));
88
89 switch (len) {
90 case 6:
91 if (bcmp(zero, src, 6) == 0)
92 return EINVAL;
93 dst[0] = src[0];
94 dst[1] = src[1];
95 dst[2] = src[2];
96 dst[3] = 0xff;
97 dst[4] = 0xfe;
98 dst[5] = src[3];
99 dst[6] = src[4];
100 dst[7] = src[5];
101 break;
102 case 8:
103 if (bcmp(zero, src, 8) == 0)
104 return EINVAL;
105 bcopy(src, dst, len);
106 break;
107 default:
108 return EINVAL;
109 }
110
111 return 0;
112 }
113
114 /*
115 * Generate a last-resort interface identifier, when the machine has no
116 * IEEE802/EUI64 address sources.
117 * The address should be random, and should not change across reboot.
118 */
119 static int
120 gen_rand_eui64(dst)
121 u_int8_t *dst;
122 {
123 MD5_CTX ctxt;
124 u_int8_t digest[16];
125 #ifdef __FreeBSD__
126 int hostnamelen = strlen(hostname);
127 #endif
128
129 /* generate 8bytes of pseudo-random value. */
130 bzero(&ctxt, sizeof(ctxt));
131 MD5Init(&ctxt);
132 MD5Update(&ctxt, hostname, hostnamelen);
133 MD5Final(digest, &ctxt);
134
135 /* assumes sizeof(digest) > sizeof(first_ifid) */
136 bcopy(digest, dst, 8);
137
138 /* make sure to set "u" bit to local, and "g" bit to individual. */
139 dst[0] &= 0xfe;
140 dst[0] |= 0x02; /* EUI64 "local" */
141
142 return 0;
143 }
144
145 /*
146 * Find first ifid on list of interfaces.
147 * This is assumed that ifp0's interface token (for example, IEEE802 MAC)
148 * is globally unique. We may need to have a flag parameter in the future.
149 */
150 int
151 in6_ifattach_getifid(ifp0)
152 struct ifnet *ifp0;
153 {
154 struct ifnet *ifp;
155 struct ifaddr *ifa;
156 u_int8_t *addr = NULL;
157 int addrlen = 0;
158 struct sockaddr_dl *sdl;
159
160 if (found_first_ifid)
161 return 0;
162
163 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
164 for (ifp = ifnet; ifp; ifp = ifp->if_next)
165 #else
166 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
167 #endif
168 {
169 if (ifp0 != NULL && ifp0 != ifp)
170 continue;
171 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
172 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
173 #else
174 for (ifa = ifp->if_addrlist.tqh_first;
175 ifa;
176 ifa = ifa->ifa_list.tqe_next)
177 #endif
178 {
179 if (ifa->ifa_addr->sa_family != AF_LINK)
180 continue;
181 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
182 if (sdl == NULL)
183 continue;
184 if (sdl->sdl_alen == 0)
185 continue;
186 switch (ifp->if_type) {
187 case IFT_ETHER:
188 case IFT_FDDI:
189 case IFT_ATM:
190 /* IEEE802/EUI64 cases - what others? */
191 addr = LLADDR(sdl);
192 addrlen = sdl->sdl_alen;
193 /*
194 * to copy ifid from IEEE802/EUI64 interface,
195 * u bit of the source needs to be 0.
196 */
197 if ((addr[0] & 0x02) != 0)
198 break;
199 goto found;
200 case IFT_ARCNET:
201 /*
202 * ARCnet interface token cannot be used as
203 * globally unique identifier due to its
204 * small bitwidth.
205 */
206 break;
207 default:
208 break;
209 }
210 }
211 }
212 #ifdef DEBUG
213 printf("in6_ifattach_getifid: failed to get EUI64");
214 #endif
215 return EADDRNOTAVAIL;
216
217 found:
218 if (laddr_to_eui64(first_ifid, addr, addrlen) == 0)
219 found_first_ifid = 1;
220
221 if (found_first_ifid) {
222 printf("%s: supplying EUI64: "
223 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
224 if_name(ifp),
225 first_ifid[0] & 0xff, first_ifid[1] & 0xff,
226 first_ifid[2] & 0xff, first_ifid[3] & 0xff,
227 first_ifid[4] & 0xff, first_ifid[5] & 0xff,
228 first_ifid[6] & 0xff, first_ifid[7] & 0xff);
229
230 /* invert u bit to convert EUI64 to RFC2373 interface ID. */
231 first_ifid[0] ^= 0x02;
232
233 return 0;
234 } else {
235 #ifdef DEBUG
236 printf("in6_ifattach_getifid: failed to get EUI64");
237 #endif
238 return EADDRNOTAVAIL;
239 }
240 }
241
242 /*
243 * add link-local address to *pseudo* p2p interfaces.
244 * get called when the first MAC address is made available in in6_ifattach().
245 *
246 * XXX I start considering this loop as a bad idea. (itojun)
247 */
248 void
249 in6_ifattach_p2p()
250 {
251 struct ifnet *ifp;
252
253 /* prevent infinite loop. just in case. */
254 if (found_first_ifid == 0)
255 return;
256
257 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
258 for (ifp = ifnet; ifp; ifp = ifp->if_next)
259 #else
260 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
261 #endif
262 {
263 switch (ifp->if_type) {
264 case IFT_GIF:
265 /* pseudo interfaces - safe to initialize here */
266 in6_ifattach(ifp, IN6_IFT_P2P, 0, 0);
267 break;
268 case IFT_DUMMY:
269 case IFT_FAITH:
270 /* this mistakingly becomes IFF_UP */
271 break;
272 case IFT_SLIP:
273 /* IPv6 is not supported */
274 break;
275 case IFT_PPP:
276 /* this is not a pseudo interface, skip it */
277 break;
278 default:
279 break;
280 }
281 }
282 }
283
284 void
285 in6_ifattach(ifp, type, laddr, noloop)
286 struct ifnet *ifp;
287 u_int type;
288 caddr_t laddr;
289 /* size_t laddrlen; */
290 int noloop;
291 {
292 static size_t if_indexlim = 8;
293 struct sockaddr_in6 mltaddr;
294 struct sockaddr_in6 mltmask;
295 struct sockaddr_in6 gate;
296 struct sockaddr_in6 mask;
297 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
298 struct ifaddr **ifap;
299 #endif
300
301 struct in6_ifaddr *ia, *ib, *oia;
302 struct ifaddr *ifa;
303 int rtflag = 0;
304
305 if (type == IN6_IFT_P2P && found_first_ifid == 0) {
306 printf("%s: no ifid available for IPv6 link-local address\n",
307 if_name(ifp));
308 #if 0
309 return;
310 #else
311 /* last resort */
312 if (gen_rand_eui64(first_ifid) == 0) {
313 printf("%s: using random value as EUI64: "
314 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
315 if_name(ifp),
316 first_ifid[0] & 0xff, first_ifid[1] & 0xff,
317 first_ifid[2] & 0xff, first_ifid[3] & 0xff,
318 first_ifid[4] & 0xff, first_ifid[5] & 0xff,
319 first_ifid[6] & 0xff, first_ifid[7] & 0xff);
320 /*
321 * invert u bit to convert EUI64 to RFC2373 interface
322 * ID.
323 */
324 first_ifid[0] ^= 0x02;
325
326 found_first_ifid = 1;
327 }
328 #endif
329 }
330
331 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
332 printf("%s: not multicast capable, IPv6 not enabled\n",
333 if_name(ifp));
334 return;
335 }
336
337 /*
338 * We have some arrays that should be indexed by if_index.
339 * since if_index will grow dynamically, they should grow too.
340 * struct in6_ifstat **in6_ifstat
341 * struct icmp6_ifstat **icmp6_ifstat
342 */
343 if (in6_ifstat == NULL || icmp6_ifstat == NULL
344 || if_index >= if_indexlim) {
345 size_t n;
346 caddr_t q;
347 size_t olim;
348
349 olim = if_indexlim;
350 while (if_index >= if_indexlim)
351 if_indexlim <<= 1;
352
353 /* grow in6_ifstat */
354 n = if_indexlim * sizeof(struct in6_ifstat *);
355 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
356 bzero(q, n);
357 if (in6_ifstat) {
358 bcopy((caddr_t)in6_ifstat, q,
359 olim * sizeof(struct in6_ifstat *));
360 free((caddr_t)in6_ifstat, M_IFADDR);
361 }
362 in6_ifstat = (struct in6_ifstat **)q;
363 in6_ifstatmax = if_indexlim;
364
365 /* grow icmp6_ifstat */
366 n = if_indexlim * sizeof(struct icmp6_ifstat *);
367 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
368 bzero(q, n);
369 if (icmp6_ifstat) {
370 bcopy((caddr_t)icmp6_ifstat, q,
371 olim * sizeof(struct icmp6_ifstat *));
372 free((caddr_t)icmp6_ifstat, M_IFADDR);
373 }
374 icmp6_ifstat = (struct icmp6_ifstat **)q;
375 icmp6_ifstatmax = if_indexlim;
376 }
377
378 /*
379 * To prevent to assign link-local address to PnP network
380 * cards multiple times.
381 * This is lengthy for P2P and LOOP but works.
382 */
383 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
384 ifa = ifp->if_addrlist;
385 if (ifa != NULL) {
386 for ( ; ifa; ifa = ifa->ifa_next) {
387 ifap = &ifa->ifa_next;
388 if (ifa->ifa_addr->sa_family != AF_INET6)
389 continue;
390 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
391 return;
392 }
393 } else
394 ifap = &ifp->if_addrlist;
395 #else
396 ifa = TAILQ_FIRST(&ifp->if_addrlist);
397 if (ifa != NULL) {
398 for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
399 if (ifa->ifa_addr->sa_family != AF_INET6)
400 continue;
401 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
402 return;
403 }
404 } else {
405 TAILQ_INIT(&ifp->if_addrlist);
406 }
407 #endif
408
409 /*
410 * link-local address
411 */
412 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
413 bzero((caddr_t)ia, sizeof(*ia));
414 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
415 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
416 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
417 ia->ia_ifp = ifp;
418 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
419 *ifap = (struct ifaddr *)ia;
420 #else
421 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
422 #endif
423 /*
424 * Also link into the IPv6 address chain beginning with in6_ifaddr.
425 * kazu opposed it, but itojun & jinmei wanted.
426 */
427 if ((oia = in6_ifaddr) != NULL) {
428 for (; oia->ia_next; oia = oia->ia_next)
429 continue;
430 oia->ia_next = ia;
431 } else
432 in6_ifaddr = ia;
433
434 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
435 ia->ia_prefixmask.sin6_family = AF_INET6;
436 ia->ia_prefixmask.sin6_addr = in6mask64;
437
438 bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
439 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
440 ia->ia_addr.sin6_family = AF_INET6;
441 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
442 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
443 ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
444
445 switch (type) {
446 case IN6_IFT_LOOP:
447 ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
448 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
449 break;
450 case IN6_IFT_802:
451 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
452 ia->ia_ifa.ifa_flags |= RTF_CLONING;
453 rtflag = RTF_CLONING;
454 /* fall through */
455 case IN6_IFT_P2P802:
456 if (laddr == NULL)
457 break;
458 /* XXX use laddrlen */
459 if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8],
460 laddr, 6) != 0) {
461 break;
462 }
463 /* invert u bit to convert EUI64 to RFC2373 interface ID. */
464 ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02;
465 if (found_first_ifid == 0) {
466 if (in6_ifattach_getifid(ifp) == 0)
467 in6_ifattach_p2p();
468 }
469 break;
470 case IN6_IFT_P2P:
471 bcopy((caddr_t)first_ifid,
472 (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
473 IFID_LEN);
474 break;
475 case IN6_IFT_ARCNET:
476 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
477 ia->ia_ifa.ifa_flags |= RTF_CLONING;
478 rtflag = RTF_CLONING;
479 if (laddr == NULL)
480 break;
481
482 /* make non-global IF id out of link-level address */
483 bzero(&ia->ia_addr.sin6_addr.s6_addr8[8], 7);
484 ia->ia_addr.sin6_addr.s6_addr8[15] = *laddr;
485 }
486
487 ia->ia_ifa.ifa_metric = ifp->if_metric;
488
489 if (ifp->if_ioctl != NULL) {
490 int s;
491 int error;
492
493 /*
494 * give the interface a chance to initialize, in case this
495 * is the first address to be added.
496 */
497 s = splimp();
498 error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
499 splx(s);
500
501 if (error) {
502 switch (error) {
503 case EAFNOSUPPORT:
504 printf("%s: IPv6 not supported\n",
505 if_name(ifp));
506 break;
507 default:
508 printf("%s: SIOCSIFADDR error %d\n",
509 if_name(ifp), error);
510 break;
511 }
512
513 /* undo changes */
514 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
515 *ifap = NULL;
516 #else
517 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
518 #endif
519 if (oia)
520 oia->ia_next = ia->ia_next;
521 else
522 in6_ifaddr = ia->ia_next;
523 free(ia, M_IFADDR);
524 return;
525 }
526 }
527
528 /* add route to the interface. */
529 rtrequest(RTM_ADD,
530 (struct sockaddr *)&ia->ia_addr,
531 (struct sockaddr *)&ia->ia_addr,
532 (struct sockaddr *)&ia->ia_prefixmask,
533 RTF_UP|rtflag,
534 (struct rtentry **)0);
535 ia->ia_flags |= IFA_ROUTE;
536
537 if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
538 /*
539 * route local address to loopback
540 */
541 bzero(&gate, sizeof(gate));
542 gate.sin6_len = sizeof(struct sockaddr_in6);
543 gate.sin6_family = AF_INET6;
544 gate.sin6_addr = in6addr_loopback;
545 bzero(&mask, sizeof(mask));
546 mask.sin6_len = sizeof(struct sockaddr_in6);
547 mask.sin6_family = AF_INET6;
548 mask.sin6_addr = in6mask64;
549 rtrequest(RTM_ADD,
550 (struct sockaddr *)&ia->ia_addr,
551 (struct sockaddr *)&gate,
552 (struct sockaddr *)&mask,
553 RTF_UP|RTF_HOST,
554 (struct rtentry **)0);
555 }
556
557 /*
558 * loopback address
559 */
560 ib = (struct in6_ifaddr *)NULL;
561 if (type == IN6_IFT_LOOP) {
562 ib = (struct in6_ifaddr *)
563 malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
564 bzero((caddr_t)ib, sizeof(*ib));
565 ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
566 ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
567 ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
568 ib->ia_ifp = ifp;
569
570 ia->ia_next = ib;
571 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
572 ia->ia_ifa.ifa_next = (struct ifaddr *)ib;
573 #else
574 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
575 ifa_list);
576 #endif
577
578 ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
579 ib->ia_prefixmask.sin6_family = AF_INET6;
580 ib->ia_prefixmask.sin6_addr = in6mask128;
581 ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
582 ib->ia_addr.sin6_family = AF_INET6;
583 ib->ia_addr.sin6_addr = in6addr_loopback;
584 #ifdef __bsdi__
585 /*
586 * It is necessary to set the loopback address to the dstaddr
587 * field at least for BSDI. Without this setting, the BSDI
588 * version of ifa_ifwithroute() rejects to add a route
589 * to the loopback interface.
590 */
591 ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
592 ib->ia_dstaddr.sin6_family = AF_INET6;
593 ib->ia_dstaddr.sin6_addr = in6addr_loopback;
594 #endif /* __bsdi__ */
595
596 ib->ia_ifa.ifa_metric = ifp->if_metric;
597
598 rtrequest(RTM_ADD,
599 (struct sockaddr *)&ib->ia_addr,
600 (struct sockaddr *)&ib->ia_addr,
601 (struct sockaddr *)&ib->ia_prefixmask,
602 RTF_UP|RTF_HOST,
603 (struct rtentry **)0);
604
605 ib->ia_flags |= IFA_ROUTE;
606 }
607
608 /*
609 * join multicast
610 */
611 if (ifp->if_flags & IFF_MULTICAST) {
612 int error; /* not used */
613
614 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
615 /* Restore saved multicast addresses(if any). */
616 in6_restoremkludge(ia, ifp);
617 #endif
618
619 bzero(&mltmask, sizeof(mltmask));
620 mltmask.sin6_len = sizeof(struct sockaddr_in6);
621 mltmask.sin6_family = AF_INET6;
622 mltmask.sin6_addr = in6mask32;
623
624 /*
625 * join link-local all-nodes address
626 */
627 bzero(&mltaddr, sizeof(mltaddr));
628 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
629 mltaddr.sin6_family = AF_INET6;
630 mltaddr.sin6_addr = in6addr_linklocal_allnodes;
631 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
632 rtrequest(RTM_ADD,
633 (struct sockaddr *)&mltaddr,
634 (struct sockaddr *)&ia->ia_addr,
635 (struct sockaddr *)&mltmask,
636 RTF_UP|RTF_CLONING, /* xxx */
637 (struct rtentry **)0);
638 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
639
640 if (type == IN6_IFT_LOOP) {
641 /*
642 * join node-local all-nodes address
643 */
644 mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
645 rtrequest(RTM_ADD,
646 (struct sockaddr *)&mltaddr,
647 (struct sockaddr *)&ib->ia_addr,
648 (struct sockaddr *)&mltmask,
649 RTF_UP,
650 (struct rtentry **)0);
651 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
652 } else {
653 /*
654 * join solicited multicast address
655 */
656 bzero(&llsol, sizeof(llsol));
657 llsol.s6_addr16[0] = htons(0xff02);
658 llsol.s6_addr16[1] = htons(ifp->if_index);
659 llsol.s6_addr32[1] = 0;
660 llsol.s6_addr32[2] = htonl(1);
661 llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
662 llsol.s6_addr8[12] = 0xff;
663 (void)in6_addmulti(&llsol, ifp, &error);
664 }
665 }
666
667 /* update dynamically. */
668 if (in6_maxmtu < ifp->if_mtu)
669 in6_maxmtu = ifp->if_mtu;
670
671 if (in6_ifstat[ifp->if_index] == NULL) {
672 in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
673 malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
674 bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
675 }
676 if (icmp6_ifstat[ifp->if_index] == NULL) {
677 icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
678 malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
679 bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
680 }
681
682 /* initialize NDP variables */
683 nd6_ifattach(ifp);
684
685 /* mark the address TENTATIVE, if needed. */
686 switch (ifp->if_type) {
687 case IFT_ARCNET:
688 case IFT_ETHER:
689 case IFT_FDDI:
690 #if 0
691 case IFT_ATM:
692 case IFT_SLIP:
693 case IFT_PPP:
694 #endif
695 ia->ia6_flags |= IN6_IFF_TENTATIVE;
696 /* nd6_dad_start() will be called in in6_if_up */
697 break;
698 case IFT_DUMMY:
699 case IFT_GIF: /*XXX*/
700 case IFT_LOOP:
701 case IFT_FAITH:
702 default:
703 break;
704 }
705
706 return;
707 }
708
709 void
710 in6_ifdetach(ifp)
711 struct ifnet *ifp;
712 {
713 struct in6_ifaddr *ia, *oia;
714 struct ifaddr *ifa;
715 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
716 struct ifaddr *ifaprev = NULL;
717 #endif
718 struct rtentry *rt;
719 short rtflags;
720
721 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
722 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
723 #else
724 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
725 #endif
726 {
727 if (ifa->ifa_addr->sa_family != AF_INET6
728 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
729 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
730 ifaprev = ifa;
731 #endif
732 continue;
733 }
734
735 ia = (struct in6_ifaddr *)ifa;
736
737 /* remove from the routing table */
738 if ((ia->ia_flags & IFA_ROUTE)
739 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0
740 #ifdef __FreeBSD__
741 , 0UL
742 #endif
743 ))) {
744 rtflags = rt->rt_flags;
745 rtfree(rt);
746 rtrequest(RTM_DELETE,
747 (struct sockaddr *)&ia->ia_addr,
748 (struct sockaddr *)&ia->ia_addr,
749 (struct sockaddr *)&ia->ia_prefixmask,
750 rtflags, (struct rtentry **)0);
751 }
752
753 /* remove from the linked list */
754 #if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
755 if (ifaprev)
756 ifaprev->ifa_next = ifa->ifa_next;
757 else
758 ifp->if_addrlist = ifa->ifa_next;
759 #else
760 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
761 #endif
762
763 /* also remove from the IPv6 address chain(itojun&jinmei) */
764 oia = ia;
765 if (oia == (ia = in6_ifaddr))
766 in6_ifaddr = ia->ia_next;
767 else {
768 while (ia->ia_next && (ia->ia_next != oia))
769 ia = ia->ia_next;
770 if (ia->ia_next)
771 ia->ia_next = oia->ia_next;
772 #ifdef DEBUG
773 else
774 printf("%s: didn't unlink in6ifaddr from "
775 "list\n", if_name(ifp));
776 #endif
777 }
778
779 free(ia, M_IFADDR);
780 }
781 }
782