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 * $FreeBSD$ 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 #include <sys/md5.h> 39 40 #include <net/if.h> 41 #include <net/if_dl.h> 42 #include <net/if_types.h> 43 #include <net/route.h> 44 45 #include <netinet/in.h> 46 #include <netinet/in_var.h> 47 #include <netinet/if_ether.h> 48 49 #include <netinet6/in6.h> 50 #include <netinet6/ip6.h> 51 #include <netinet6/ip6_var.h> 52 #include <netinet6/in6_ifattach.h> 53 #include <netinet6/ip6.h> 54 #include <netinet6/ip6_var.h> 55 #include <netinet6/nd6.h> 56 57 #include <net/net_osdep.h> 58 59 static struct in6_addr llsol; 60 61 struct in6_ifstat **in6_ifstat = NULL; 62 struct icmp6_ifstat **icmp6_ifstat = NULL; 63 size_t in6_ifstatmax = 0; 64 size_t icmp6_ifstatmax = 0; 65 unsigned long in6_maxmtu = 0; 66 67 int found_first_ifid = 0; 68 #define IFID_LEN 8 69 static char first_ifid[IFID_LEN]; 70 71 static int laddr_to_eui64 __P((u_int8_t *, u_int8_t *, size_t)); 72 static int gen_rand_eui64 __P((u_int8_t *)); 73 74 static int 75 laddr_to_eui64(dst, src, len) 76 u_int8_t *dst; 77 u_int8_t *src; 78 size_t len; 79 { 80 static u_int8_t zero[8]; 81 82 bzero(zero, sizeof(zero)); 83 84 switch (len) { 85 case 6: 86 if (bcmp(zero, src, 6) == 0) 87 return EINVAL; 88 dst[0] = src[0]; 89 dst[1] = src[1]; 90 dst[2] = src[2]; 91 dst[3] = 0xff; 92 dst[4] = 0xfe; 93 dst[5] = src[3]; 94 dst[6] = src[4]; 95 dst[7] = src[5]; 96 break; 97 case 8: 98 if (bcmp(zero, src, 8) == 0) 99 return EINVAL; 100 bcopy(src, dst, len); 101 break; 102 default: 103 return EINVAL; 104 } 105 106 return 0; 107 } 108 109 /* 110 * Generate a last-resort interface identifier, when the machine has no 111 * IEEE802/EUI64 address sources. 112 * The address should be random, and should not change across reboot. 113 */ 114 static int 115 gen_rand_eui64(dst) 116 u_int8_t *dst; 117 { 118 MD5_CTX ctxt; 119 u_int8_t digest[16]; 120 int hostnamelen = strlen(hostname); 121 122 /* generate 8bytes of pseudo-random value. */ 123 bzero(&ctxt, sizeof(ctxt)); 124 MD5Init(&ctxt); 125 MD5Update(&ctxt, hostname, hostnamelen); 126 MD5Final(digest, &ctxt); 127 128 /* assumes sizeof(digest) > sizeof(first_ifid) */ 129 bcopy(digest, dst, 8); 130 131 /* make sure to set "u" bit to local, and "g" bit to individual. */ 132 dst[0] &= 0xfe; 133 dst[0] |= 0x02; /* EUI64 "local" */ 134 135 return 0; 136 } 137 138 /* 139 * Find first ifid on list of interfaces. 140 * This is assumed that ifp0's interface token (for example, IEEE802 MAC) 141 * is globally unique. We may need to have a flag parameter in the future. 142 */ 143 int 144 in6_ifattach_getifid(ifp0) 145 struct ifnet *ifp0; 146 { 147 struct ifnet *ifp; 148 struct ifaddr *ifa; 149 u_int8_t *addr = NULL; 150 int addrlen = 0; 151 struct sockaddr_dl *sdl; 152 153 if (found_first_ifid) 154 return 0; 155 156 TAILQ_FOREACH(ifp, &ifnet, if_list) 157 { 158 if (ifp0 != NULL && ifp0 != ifp) 159 continue; 160 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 161 { 162 if (ifa->ifa_addr->sa_family != AF_LINK) 163 continue; 164 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 165 if (sdl == NULL) 166 continue; 167 if (sdl->sdl_alen == 0) 168 continue; 169 switch (ifp->if_type) { 170 case IFT_ETHER: 171 case IFT_FDDI: 172 case IFT_ATM: 173 /* IEEE802/EUI64 cases - what others? */ 174 addr = LLADDR(sdl); 175 addrlen = sdl->sdl_alen; 176 /* 177 * to copy ifid from IEEE802/EUI64 interface, 178 * u bit of the source needs to be 0. 179 */ 180 if ((addr[0] & 0x02) != 0) 181 break; 182 goto found; 183 case IFT_ARCNET: 184 /* 185 * ARCnet interface token cannot be used as 186 * globally unique identifier due to its 187 * small bitwidth. 188 */ 189 break; 190 default: 191 break; 192 } 193 } 194 } 195 #ifdef DEBUG 196 printf("in6_ifattach_getifid: failed to get EUI64"); 197 #endif 198 return EADDRNOTAVAIL; 199 200 found: 201 if (laddr_to_eui64(first_ifid, addr, addrlen) == 0) 202 found_first_ifid = 1; 203 204 if (found_first_ifid) { 205 printf("%s: supplying EUI64: " 206 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 207 if_name(ifp), 208 first_ifid[0] & 0xff, first_ifid[1] & 0xff, 209 first_ifid[2] & 0xff, first_ifid[3] & 0xff, 210 first_ifid[4] & 0xff, first_ifid[5] & 0xff, 211 first_ifid[6] & 0xff, first_ifid[7] & 0xff); 212 213 /* invert u bit to convert EUI64 to RFC2373 interface ID. */ 214 first_ifid[0] ^= 0x02; 215 216 return 0; 217 } else { 218 #ifdef DEBUG 219 printf("in6_ifattach_getifid: failed to get EUI64"); 220 #endif 221 return EADDRNOTAVAIL; 222 } 223 } 224 225 /* 226 * add link-local address to *pseudo* p2p interfaces. 227 * get called when the first MAC address is made available in in6_ifattach(). 228 * 229 * XXX I start considering this loop as a bad idea. (itojun) 230 */ 231 void 232 in6_ifattach_p2p() 233 { 234 struct ifnet *ifp; 235 236 /* prevent infinite loop. just in case. */ 237 if (found_first_ifid == 0) 238 return; 239 240 TAILQ_FOREACH(ifp, &ifnet, if_list) 241 { 242 switch (ifp->if_type) { 243 case IFT_GIF: 244 /* pseudo interfaces - safe to initialize here */ 245 in6_ifattach(ifp, IN6_IFT_P2P, 0, 0); 246 break; 247 #ifdef IFT_DUMMY 248 case IFT_DUMMY: 249 #endif 250 case IFT_FAITH: 251 /* this mistakingly becomes IFF_UP */ 252 break; 253 case IFT_SLIP: 254 /* IPv6 is not supported */ 255 break; 256 case IFT_PPP: 257 /* this is not a pseudo interface, skip it */ 258 break; 259 default: 260 break; 261 } 262 } 263 } 264 265 void 266 in6_ifattach(ifp, type, laddr, noloop) 267 struct ifnet *ifp; 268 u_int type; 269 caddr_t laddr; 270 /* size_t laddrlen; */ 271 int noloop; 272 { 273 static size_t if_indexlim = 8; 274 struct sockaddr_in6 mltaddr; 275 struct sockaddr_in6 mltmask; 276 struct sockaddr_in6 gate; 277 struct sockaddr_in6 mask; 278 279 struct in6_ifaddr *ia, *ib, *oia; 280 struct ifaddr *ifa; 281 int rtflag = 0; 282 283 if (type == IN6_IFT_P2P && found_first_ifid == 0) { 284 printf("%s: no ifid available for IPv6 link-local address\n", 285 if_name(ifp)); 286 /* last resort */ 287 if (gen_rand_eui64(first_ifid) == 0) { 288 printf("%s: using random value as EUI64: " 289 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 290 if_name(ifp), 291 first_ifid[0] & 0xff, first_ifid[1] & 0xff, 292 first_ifid[2] & 0xff, first_ifid[3] & 0xff, 293 first_ifid[4] & 0xff, first_ifid[5] & 0xff, 294 first_ifid[6] & 0xff, first_ifid[7] & 0xff); 295 /* 296 * invert u bit to convert EUI64 to RFC2373 interface 297 * ID. 298 */ 299 first_ifid[0] ^= 0x02; 300 301 found_first_ifid = 1; 302 } 303 } 304 305 if ((ifp->if_flags & IFF_MULTICAST) == 0) { 306 printf("%s: not multicast capable, IPv6 not enabled\n", 307 if_name(ifp)); 308 return; 309 } 310 311 /* 312 * We have some arrays that should be indexed by if_index. 313 * since if_index will grow dynamically, they should grow too. 314 * struct in6_ifstat **in6_ifstat 315 * struct icmp6_ifstat **icmp6_ifstat 316 */ 317 if (in6_ifstat == NULL || icmp6_ifstat == NULL 318 || if_index >= if_indexlim) { 319 size_t n; 320 caddr_t q; 321 size_t olim; 322 323 olim = if_indexlim; 324 while (if_index >= if_indexlim) 325 if_indexlim <<= 1; 326 327 /* grow in6_ifstat */ 328 n = if_indexlim * sizeof(struct in6_ifstat *); 329 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); 330 bzero(q, n); 331 if (in6_ifstat) { 332 bcopy((caddr_t)in6_ifstat, q, 333 olim * sizeof(struct in6_ifstat *)); 334 free((caddr_t)in6_ifstat, M_IFADDR); 335 } 336 in6_ifstat = (struct in6_ifstat **)q; 337 in6_ifstatmax = if_indexlim; 338 339 /* grow icmp6_ifstat */ 340 n = if_indexlim * sizeof(struct icmp6_ifstat *); 341 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); 342 bzero(q, n); 343 if (icmp6_ifstat) { 344 bcopy((caddr_t)icmp6_ifstat, q, 345 olim * sizeof(struct icmp6_ifstat *)); 346 free((caddr_t)icmp6_ifstat, M_IFADDR); 347 } 348 icmp6_ifstat = (struct icmp6_ifstat **)q; 349 icmp6_ifstatmax = if_indexlim; 350 } 351 352 /* 353 * To prevent to assign link-local address to PnP network 354 * cards multiple times. 355 * This is lengthy for P2P and LOOP but works. 356 */ 357 ifa = TAILQ_FIRST(&ifp->if_addrlist); 358 if (ifa != NULL) { 359 for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) { 360 if (ifa->ifa_addr->sa_family != AF_INET6) 361 continue; 362 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr)) 363 return; 364 } 365 } else { 366 TAILQ_INIT(&ifp->if_addrlist); 367 } 368 369 /* 370 * link-local address 371 */ 372 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 373 bzero((caddr_t)ia, sizeof(*ia)); 374 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 375 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 376 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 377 ia->ia_ifp = ifp; 378 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 379 /* 380 * Also link into the IPv6 address chain beginning with in6_ifaddr. 381 * kazu opposed it, but itojun & jinmei wanted. 382 */ 383 if ((oia = in6_ifaddr) != NULL) { 384 for (; oia->ia_next; oia = oia->ia_next) 385 continue; 386 oia->ia_next = ia; 387 } else 388 in6_ifaddr = ia; 389 390 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 391 ia->ia_prefixmask.sin6_family = AF_INET6; 392 ia->ia_prefixmask.sin6_addr = in6mask64; 393 394 bzero(&ia->ia_addr, sizeof(struct sockaddr_in6)); 395 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); 396 ia->ia_addr.sin6_family = AF_INET6; 397 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); 398 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 399 ia->ia_addr.sin6_addr.s6_addr32[1] = 0; 400 401 switch (type) { 402 case IN6_IFT_LOOP: 403 ia->ia_addr.sin6_addr.s6_addr32[2] = 0; 404 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1); 405 break; 406 case IN6_IFT_802: 407 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 408 ia->ia_ifa.ifa_flags |= RTF_CLONING; 409 rtflag = RTF_CLONING; 410 /* fall through */ 411 case IN6_IFT_P2P802: 412 if (laddr == NULL) 413 break; 414 /* XXX use laddrlen */ 415 if (laddr_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8], 416 laddr, 6) != 0) { 417 break; 418 } 419 /* invert u bit to convert EUI64 to RFC2373 interface ID. */ 420 ia->ia_addr.sin6_addr.s6_addr8[8] ^= 0x02; 421 if (found_first_ifid == 0) { 422 if (in6_ifattach_getifid(ifp) == 0) 423 in6_ifattach_p2p(); 424 } 425 break; 426 case IN6_IFT_P2P: 427 bcopy((caddr_t)first_ifid, 428 (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8], 429 IFID_LEN); 430 break; 431 case IN6_IFT_ARCNET: 432 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 433 ia->ia_ifa.ifa_flags |= RTF_CLONING; 434 rtflag = RTF_CLONING; 435 if (laddr == NULL) 436 break; 437 438 /* make non-global IF id out of link-level address */ 439 bzero(&ia->ia_addr.sin6_addr.s6_addr8[8], 7); 440 ia->ia_addr.sin6_addr.s6_addr8[15] = *laddr; 441 } 442 443 ia->ia_ifa.ifa_metric = ifp->if_metric; 444 445 if (ifp->if_ioctl != NULL) { 446 int s; 447 int error; 448 449 /* 450 * give the interface a chance to initialize, in case this 451 * is the first address to be added. 452 */ 453 s = splimp(); 454 error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 455 splx(s); 456 457 if (error) { 458 switch (error) { 459 case EAFNOSUPPORT: 460 printf("%s: IPv6 not supported\n", 461 if_name(ifp)); 462 break; 463 default: 464 printf("%s: SIOCSIFADDR error %d\n", 465 if_name(ifp), error); 466 break; 467 } 468 469 /* undo changes */ 470 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 471 if (oia) 472 oia->ia_next = ia->ia_next; 473 else 474 in6_ifaddr = ia->ia_next; 475 free(ia, M_IFADDR); 476 return; 477 } 478 } 479 480 /* add route to the interface. */ 481 rtrequest(RTM_ADD, 482 (struct sockaddr *)&ia->ia_addr, 483 (struct sockaddr *)&ia->ia_addr, 484 (struct sockaddr *)&ia->ia_prefixmask, 485 RTF_UP|rtflag, 486 (struct rtentry **)0); 487 ia->ia_flags |= IFA_ROUTE; 488 489 if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) { 490 /* 491 * route local address to loopback 492 */ 493 bzero(&gate, sizeof(gate)); 494 gate.sin6_len = sizeof(struct sockaddr_in6); 495 gate.sin6_family = AF_INET6; 496 gate.sin6_addr = in6addr_loopback; 497 bzero(&mask, sizeof(mask)); 498 mask.sin6_len = sizeof(struct sockaddr_in6); 499 mask.sin6_family = AF_INET6; 500 mask.sin6_addr = in6mask64; 501 rtrequest(RTM_ADD, 502 (struct sockaddr *)&ia->ia_addr, 503 (struct sockaddr *)&gate, 504 (struct sockaddr *)&mask, 505 RTF_UP|RTF_HOST, 506 (struct rtentry **)0); 507 } 508 509 /* 510 * loopback address 511 */ 512 ib = (struct in6_ifaddr *)NULL; 513 if (type == IN6_IFT_LOOP) { 514 ib = (struct in6_ifaddr *) 515 malloc(sizeof(*ib), M_IFADDR, M_WAITOK); 516 bzero((caddr_t)ib, sizeof(*ib)); 517 ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr; 518 ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr; 519 ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask; 520 ib->ia_ifp = ifp; 521 522 ia->ia_next = ib; 523 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib, 524 ifa_list); 525 526 ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 527 ib->ia_prefixmask.sin6_family = AF_INET6; 528 ib->ia_prefixmask.sin6_addr = in6mask128; 529 ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6); 530 ib->ia_addr.sin6_family = AF_INET6; 531 ib->ia_addr.sin6_addr = in6addr_loopback; 532 ib->ia_ifa.ifa_metric = ifp->if_metric; 533 534 rtrequest(RTM_ADD, 535 (struct sockaddr *)&ib->ia_addr, 536 (struct sockaddr *)&ib->ia_addr, 537 (struct sockaddr *)&ib->ia_prefixmask, 538 RTF_UP|RTF_HOST, 539 (struct rtentry **)0); 540 541 ib->ia_flags |= IFA_ROUTE; 542 } 543 544 /* 545 * join multicast 546 */ 547 if (ifp->if_flags & IFF_MULTICAST) { 548 int error; /* not used */ 549 550 bzero(&mltmask, sizeof(mltmask)); 551 mltmask.sin6_len = sizeof(struct sockaddr_in6); 552 mltmask.sin6_family = AF_INET6; 553 mltmask.sin6_addr = in6mask32; 554 555 /* 556 * join link-local all-nodes address 557 */ 558 bzero(&mltaddr, sizeof(mltaddr)); 559 mltaddr.sin6_len = sizeof(struct sockaddr_in6); 560 mltaddr.sin6_family = AF_INET6; 561 mltaddr.sin6_addr = in6addr_linklocal_allnodes; 562 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 563 rtrequest(RTM_ADD, 564 (struct sockaddr *)&mltaddr, 565 (struct sockaddr *)&ia->ia_addr, 566 (struct sockaddr *)&mltmask, 567 RTF_UP|RTF_CLONING, /* xxx */ 568 (struct rtentry **)0); 569 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 570 571 if (type == IN6_IFT_LOOP) { 572 /* 573 * join node-local all-nodes address 574 */ 575 mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 576 rtrequest(RTM_ADD, 577 (struct sockaddr *)&mltaddr, 578 (struct sockaddr *)&ib->ia_addr, 579 (struct sockaddr *)&mltmask, 580 RTF_UP, 581 (struct rtentry **)0); 582 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 583 } else { 584 /* 585 * join solicited multicast address 586 */ 587 bzero(&llsol, sizeof(llsol)); 588 llsol.s6_addr16[0] = htons(0xff02); 589 llsol.s6_addr16[1] = htons(ifp->if_index); 590 llsol.s6_addr32[1] = 0; 591 llsol.s6_addr32[2] = htonl(1); 592 llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; 593 llsol.s6_addr8[12] = 0xff; 594 (void)in6_addmulti(&llsol, ifp, &error); 595 } 596 } 597 598 /* update dynamically. */ 599 if (in6_maxmtu < ifp->if_mtu) 600 in6_maxmtu = ifp->if_mtu; 601 602 if (in6_ifstat[ifp->if_index] == NULL) { 603 in6_ifstat[ifp->if_index] = (struct in6_ifstat *) 604 malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK); 605 bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat)); 606 } 607 if (icmp6_ifstat[ifp->if_index] == NULL) { 608 icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *) 609 malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK); 610 bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat)); 611 } 612 613 /* initialize NDP variables */ 614 nd6_ifattach(ifp); 615 616 /* mark the address TENTATIVE, if needed. */ 617 switch (ifp->if_type) { 618 case IFT_ARCNET: 619 case IFT_ETHER: 620 case IFT_FDDI: 621 ia->ia6_flags |= IN6_IFF_TENTATIVE; 622 /* nd6_dad_start() will be called in in6_if_up */ 623 break; 624 #ifdef IFT_DUMMY 625 case IFT_DUMMY: 626 #endif 627 case IFT_GIF: /*XXX*/ 628 case IFT_LOOP: 629 case IFT_FAITH: 630 default: 631 break; 632 } 633 634 return; 635 } 636 637 void 638 in6_ifdetach(ifp) 639 struct ifnet *ifp; 640 { 641 struct in6_ifaddr *ia, *oia; 642 struct ifaddr *ifa; 643 struct rtentry *rt; 644 short rtflags; 645 646 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 647 { 648 if (ifa->ifa_addr->sa_family != AF_INET6 649 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 650 continue; 651 } 652 653 ia = (struct in6_ifaddr *)ifa; 654 655 /* remove from the routing table */ 656 if ((ia->ia_flags & IFA_ROUTE) 657 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { 658 rtflags = rt->rt_flags; 659 rtfree(rt); 660 rtrequest(RTM_DELETE, 661 (struct sockaddr *)&ia->ia_addr, 662 (struct sockaddr *)&ia->ia_addr, 663 (struct sockaddr *)&ia->ia_prefixmask, 664 rtflags, (struct rtentry **)0); 665 } 666 667 /* remove from the linked list */ 668 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 669 670 /* also remove from the IPv6 address chain(itojun&jinmei) */ 671 oia = ia; 672 if (oia == (ia = in6_ifaddr)) 673 in6_ifaddr = ia->ia_next; 674 else { 675 while (ia->ia_next && (ia->ia_next != oia)) 676 ia = ia->ia_next; 677 if (ia->ia_next) 678 ia->ia_next = oia->ia_next; 679 #ifdef DEBUG 680 else 681 printf("%s: didn't unlink in6ifaddr from " 682 "list\n", if_name(ifp)); 683 #endif 684 } 685 686 free(ia, M_IFADDR); 687 } 688 } 689