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