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