in6_ifattach.c revision 1.72
1/* $OpenBSD: in6_ifattach.c,v 1.72 2014/07/01 19:37:07 benno Exp $ */ 2/* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei 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/socket.h> 36#include <sys/sockio.h> 37#include <sys/kernel.h> 38#include <sys/syslog.h> 39 40#include <crypto/md5.h> 41 42#include <net/if.h> 43#include <net/if_var.h> 44#include <net/if_dl.h> 45#include <net/if_types.h> 46#include <net/route.h> 47 48#include <netinet/in.h> 49#include <netinet/if_ether.h> 50 51#include <netinet6/in6_var.h> 52#include <netinet/ip6.h> 53#include <netinet6/ip6_var.h> 54#include <netinet6/in6_ifattach.h> 55#include <netinet6/ip6_var.h> 56#include <netinet6/nd6.h> 57#ifdef MROUTING 58#include <netinet6/ip6_mroute.h> 59#endif 60 61#include <dev/rndvar.h> 62 63unsigned long in6_maxmtu = 0; 64 65int ip6_auto_linklocal = 1; /* enable by default */ 66 67int get_last_resort_ifid(struct ifnet *, struct in6_addr *); 68int get_hw_ifid(struct ifnet *, struct in6_addr *); 69int get_ifid(struct ifnet *, struct in6_addr *); 70int in6_ifattach_loopback(struct ifnet *); 71 72#define EUI64_GBIT 0x01 73#define EUI64_UBIT 0x02 74#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) 75#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) 76#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) 77#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) 78#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) 79 80#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) 81#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) 82 83/* 84 * Generate a last-resort interface identifier, when the machine has no 85 * IEEE802/EUI64 address sources. 86 * The goal here is to get an interface identifier that is 87 * (1) random enough and (2) does not change across reboot. 88 * We currently use MD5(hostname) for it. 89 * 90 * in6 - upper 64bits are preserved 91 */ 92int 93get_last_resort_ifid(struct ifnet *ifp, struct in6_addr *in6) 94{ 95 MD5_CTX ctxt; 96 u_int8_t digest[16]; 97 98#if 0 99 /* we need at least several letters as seed for ifid */ 100 if (hostnamelen < 3) 101 return -1; 102#endif 103 104 /* generate 8 bytes of pseudo-random value. */ 105 bzero(&ctxt, sizeof(ctxt)); 106 MD5Init(&ctxt); 107 MD5Update(&ctxt, hostname, hostnamelen); 108 MD5Final(digest, &ctxt); 109 110 /* assumes sizeof(digest) > sizeof(ifid) */ 111 bcopy(digest, &in6->s6_addr[8], 8); 112 113 /* make sure to set "u" bit to local, and "g" bit to individual. */ 114 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 115 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 116 117 /* convert EUI64 into IPv6 interface identifier */ 118 EUI64_TO_IFID(in6); 119 120 return 0; 121} 122 123/* 124 * Generate a random interface identifier. 125 * 126 * in6 - upper 64bits are preserved 127 */ 128void 129in6_get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) 130{ 131 arc4random_buf(&in6->s6_addr32[2], 8); 132 133 /* make sure to set "u" bit to local, and "g" bit to individual. */ 134 in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 135 in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 136 137 /* convert EUI64 into IPv6 interface identifier */ 138 EUI64_TO_IFID(in6); 139} 140 141/* 142 * Get interface identifier for the specified interface. 143 * 144 * in6 - upper 64bits are preserved 145 */ 146int 147get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) 148{ 149 struct sockaddr_dl *sdl; 150 char *addr; 151 size_t addrlen; 152 static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 153 static u_int8_t allone[8] = 154 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 155 156 sdl = (struct sockaddr_dl *)ifp->if_sadl; 157 if (sdl == NULL || sdl->sdl_alen == 0) 158 return -1; 159 160 addr = LLADDR(sdl); 161 addrlen = sdl->sdl_alen; 162 163 switch (ifp->if_type) { 164 case IFT_IEEE1394: 165 case IFT_IEEE80211: 166 /* IEEE1394 uses 16byte length address starting with EUI64 */ 167 if (addrlen > 8) 168 addrlen = 8; 169 break; 170 default: 171 break; 172 } 173 174 /* get EUI64 */ 175 switch (ifp->if_type) { 176 /* IEEE802/EUI64 cases - what others? */ 177 case IFT_ETHER: 178 case IFT_CARP: 179 case IFT_IEEE1394: 180 case IFT_IEEE80211: 181 /* look at IEEE802/EUI64 only */ 182 if (addrlen != 8 && addrlen != 6) 183 return -1; 184 185 /* 186 * check for invalid MAC address - on bsdi, we see it a lot 187 * since wildboar configures all-zero MAC on pccard before 188 * card insertion. 189 */ 190 if (bcmp(addr, allzero, addrlen) == 0) 191 return -1; 192 if (bcmp(addr, allone, addrlen) == 0) 193 return -1; 194 195 /* make EUI64 address */ 196 if (addrlen == 8) 197 bcopy(addr, &in6->s6_addr[8], 8); 198 else if (addrlen == 6) { 199 in6->s6_addr[8] = addr[0]; 200 in6->s6_addr[9] = addr[1]; 201 in6->s6_addr[10] = addr[2]; 202 in6->s6_addr[11] = 0xff; 203 in6->s6_addr[12] = 0xfe; 204 in6->s6_addr[13] = addr[3]; 205 in6->s6_addr[14] = addr[4]; 206 in6->s6_addr[15] = addr[5]; 207 } 208 break; 209 210 case IFT_GIF: 211 /* 212 * RFC2893 says: "SHOULD use IPv4 address as ifid source". 213 * however, IPv4 address is not very suitable as unique 214 * identifier source (can be renumbered). 215 * we don't do this. 216 */ 217 return -1; 218 219 default: 220 return -1; 221 } 222 223 /* sanity check: g bit must not indicate "group" */ 224 if (EUI64_GROUP(in6)) 225 return -1; 226 227 /* convert EUI64 into IPv6 interface identifier */ 228 EUI64_TO_IFID(in6); 229 230 /* 231 * sanity check: ifid must not be all zero, avoid conflict with 232 * subnet router anycast 233 */ 234 if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && 235 bcmp(&in6->s6_addr[9], allzero, 7) == 0) { 236 return -1; 237 } 238 239 return 0; 240} 241 242/* 243 * Get interface identifier for the specified interface. If it is not 244 * available on ifp0, borrow interface identifier from other information 245 * sources. 246 */ 247int 248get_ifid(struct ifnet *ifp0, struct in6_addr *in6) 249{ 250 struct ifnet *ifp; 251 252 /* first, try to get it from the interface itself */ 253 if (get_hw_ifid(ifp0, in6) == 0) { 254 nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", 255 ifp0->if_xname)); 256 goto success; 257 } 258 259 /* next, try to get it from some other hardware interface */ 260 TAILQ_FOREACH(ifp, &ifnet, if_list) { 261 if (ifp == ifp0) 262 continue; 263 if (get_hw_ifid(ifp, in6) != 0) 264 continue; 265 266 /* 267 * to borrow ifid from other interface, ifid needs to be 268 * globally unique 269 */ 270 if (IFID_UNIVERSAL(in6)) { 271 nd6log((LOG_DEBUG, 272 "%s: borrow interface identifier from %s\n", 273 ifp0->if_xname, ifp->if_xname)); 274 goto success; 275 } 276 } 277 278 /* last resort: get from random number source */ 279 if (get_last_resort_ifid(ifp, in6) == 0) { 280 nd6log((LOG_DEBUG, 281 "%s: interface identifier generated by random number\n", 282 ifp0->if_xname)); 283 goto success; 284 } 285 286 printf("%s: failed to get interface identifier\n", ifp0->if_xname); 287 return -1; 288 289success: 290 nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 291 ifp0->if_xname, in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10], 292 in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13], 293 in6->s6_addr[14], in6->s6_addr[15])); 294 return 0; 295} 296 297/* 298 * ifid - used as EUI64 if not NULL, overrides other EUI64 sources 299 */ 300 301int 302in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid) 303{ 304 struct in6_ifaddr *ia6; 305 struct in6_aliasreq ifra; 306 struct nd_prefix pr0; 307 int i, s, error; 308 309 /* 310 * configure link-local address. 311 */ 312 bzero(&ifra, sizeof(ifra)); 313 314 /* 315 * in6_update_ifa() does not use ifra_name, but we accurately set it 316 * for safety. 317 */ 318 strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name)); 319 320 ifra.ifra_addr.sin6_family = AF_INET6; 321 ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 322 ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); 323 ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 324 ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; 325 if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 326 ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; 327 ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); 328 } else if (ifid) { 329 ifra.ifra_addr.sin6_addr = *ifid; 330 ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); 331 ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 332 ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; 333 ifra.ifra_addr.sin6_addr.s6_addr[8] &= ~EUI64_GBIT; 334 ifra.ifra_addr.sin6_addr.s6_addr[8] |= EUI64_UBIT; 335 } else { 336 if (get_ifid(ifp, &ifra.ifra_addr.sin6_addr) != 0) { 337 nd6log((LOG_ERR, 338 "%s: no ifid available\n", ifp->if_xname)); 339 return (-1); 340 } 341 } 342 343 ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 344 ifra.ifra_prefixmask.sin6_family = AF_INET6; 345 ifra.ifra_prefixmask.sin6_addr = in6mask64; 346 /* link-local addresses should NEVER expire. */ 347 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 348 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 349 350 /* 351 * Do not let in6_update_ifa() do DAD, since we need a random delay 352 * before sending an NS at the first time the interface becomes up. 353 * Instead, in6_if_up() will start DAD with a proper random delay. 354 */ 355 ifra.ifra_flags |= IN6_IFF_NODAD; 356 357 /* 358 * Now call in6_update_ifa() to do a bunch of procedures to configure 359 * a link-local address. In the case of CARP, we may be called after 360 * one has already been configured, so check if it's already there 361 * with in6ifa_ifpforlinklocal() and clobber it if it exists. 362 */ 363 s = splsoftnet(); 364 error = in6_update_ifa(ifp, &ifra, in6ifa_ifpforlinklocal(ifp, 0)); 365 splx(s); 366 367 if (error != 0) { 368 /* 369 * XXX: When the interface does not support IPv6, this call 370 * would fail in the SIOCSIFADDR ioctl. I believe the 371 * notification is rather confusing in this case, so just 372 * suppress it. (jinmei@kame.net 20010130) 373 */ 374 if (error != EAFNOSUPPORT) 375 nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to " 376 "configure a link-local address on %s " 377 "(errno=%d)\n", 378 ifp->if_xname, error)); 379 return (-1); 380 } 381 382 /* 383 * Adjust ia6_flags so that in6_if_up will perform DAD. 384 * XXX: Some P2P interfaces seem not to send packets just after 385 * becoming up, so we skip p2p interfaces for safety. 386 */ 387 ia6 = in6ifa_ifpforlinklocal(ifp, 0); /* ia6 must not be NULL */ 388#ifdef DIAGNOSTIC 389 if (!ia6) { 390 panic("ia6 == NULL in in6_ifattach_linklocal"); 391 /* NOTREACHED */ 392 } 393#endif 394 if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) || 395 (ifp->if_type == IFT_CARP)) == 0) { 396 ia6->ia6_flags &= ~IN6_IFF_NODAD; 397 ia6->ia6_flags |= IN6_IFF_TENTATIVE; 398 } 399 400 /* 401 * Make the link-local prefix (fe80::/64%link) as on-link. 402 * Since we'd like to manage prefixes separately from addresses, 403 * we make an ND6 prefix structure for the link-local prefix, 404 * and add it to the prefix list as a never-expire prefix. 405 * XXX: this change might affect some existing code base... 406 */ 407 bzero(&pr0, sizeof(pr0)); 408 pr0.ndpr_ifp = ifp; 409 /* this should be 64 at this moment. */ 410 pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); 411 pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr; 412 pr0.ndpr_prefix = ifra.ifra_addr; 413 /* apply the mask for safety. (nd6_prelist_add will apply it again) */ 414 for (i = 0; i < 4; i++) { 415 pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 416 in6mask64.s6_addr32[i]; 417 } 418 /* 419 * Initialize parameters. The link-local prefix must always be 420 * on-link, and its lifetimes never expire. 421 */ 422 pr0.ndpr_raf_onlink = 1; 423 pr0.ndpr_raf_auto = 1; /* probably meaningless */ 424 pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; 425 pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; 426 /* 427 * Since there is no other link-local addresses, nd6_prefix_lookup() 428 * probably returns NULL. However, we cannot always expect the result. 429 * For example, if we first remove the (only) existing link-local 430 * address, and then reconfigure another one, the prefix is still 431 * valid with referring to the old link-local address. 432 */ 433 if (nd6_prefix_lookup(&pr0) == NULL) { 434 if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) 435 return (error); 436 } 437 438 return 0; 439} 440 441/* 442 * ifp - must be IFT_LOOP 443 */ 444 445int 446in6_ifattach_loopback(struct ifnet *ifp) 447{ 448 struct in6_aliasreq ifra; 449 int error; 450 451 bzero(&ifra, sizeof(ifra)); 452 453 /* 454 * in6_update_ifa() does not use ifra_name, but we accurately set it 455 * for safety. 456 */ 457 strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name)); 458 459 ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 460 ifra.ifra_prefixmask.sin6_family = AF_INET6; 461 ifra.ifra_prefixmask.sin6_addr = in6mask128; 462 463 /* 464 * Always initialize ia_dstaddr (= broadcast address) to loopback 465 * address. Follows IPv4 practice - see in_ifinit(). 466 */ 467 ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 468 ifra.ifra_dstaddr.sin6_family = AF_INET6; 469 ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; 470 471 ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 472 ifra.ifra_addr.sin6_family = AF_INET6; 473 ifra.ifra_addr.sin6_addr = in6addr_loopback; 474 475 /* the loopback address should NEVER expire. */ 476 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 477 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 478 479 /* we don't need to perform DAD on loopback interfaces. */ 480 ifra.ifra_flags |= IN6_IFF_NODAD; 481 482 /* 483 * We are sure that this is a newly assigned address, so we can set 484 * NULL to the 3rd arg. 485 */ 486 if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { 487 nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " 488 "the loopback address on %s (errno=%d)\n", 489 ifp->if_xname, error)); 490 return (-1); 491 } 492 493 return 0; 494} 495 496/* 497 * compute NI group address, based on the current hostname setting. 498 * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later). 499 * 500 * when ifp == NULL, the caller is responsible for filling scopeid. 501 */ 502int 503in6_nigroup(struct ifnet *ifp, const char *name, int namelen, 504 struct sockaddr_in6 *sa6) 505{ 506 const char *p; 507 u_int8_t *q; 508 MD5_CTX ctxt; 509 u_int8_t digest[16]; 510 u_int8_t l; 511 u_int8_t n[64]; /* a single label must not exceed 63 chars */ 512 513 if (!namelen || !name) 514 return -1; 515 516 p = name; 517 while (p && *p && *p != '.' && p - name < namelen) 518 p++; 519 if (p - name > sizeof(n) - 1) 520 return -1; /* label too long */ 521 l = p - name; 522 strncpy((char *)n, name, l); 523 n[(int)l] = '\0'; 524 for (q = n; *q; q++) { 525 if ('A' <= *q && *q <= 'Z') 526 *q = *q - 'A' + 'a'; 527 } 528 529 /* generate 8 bytes of pseudo-random value. */ 530 bzero(&ctxt, sizeof(ctxt)); 531 MD5Init(&ctxt); 532 MD5Update(&ctxt, &l, sizeof(l)); 533 MD5Update(&ctxt, n, l); 534 MD5Final(digest, &ctxt); 535 536 bzero(sa6, sizeof(*sa6)); 537 sa6->sin6_family = AF_INET6; 538 sa6->sin6_len = sizeof(*sa6); 539 sa6->sin6_addr.s6_addr16[0] = htons(0xff02); 540 sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index); 541 sa6->sin6_addr.s6_addr8[11] = 2; 542 bcopy(digest, &sa6->sin6_addr.s6_addr32[3], 543 sizeof(sa6->sin6_addr.s6_addr32[3])); 544 545 return 0; 546} 547 548/* 549 * XXX multiple loopback interface needs more care. for instance, 550 * nodelocal address needs to be configured onto only one of them. 551 * XXX multiple link-local address case 552 */ 553void 554in6_ifattach(struct ifnet *ifp) 555{ 556 struct in6_ifaddr *ia6; 557 struct in6_addr in6; 558 559 /* some of the interfaces are inherently not IPv6 capable */ 560 switch (ifp->if_type) { 561 case IFT_BRIDGE: 562 case IFT_ENC: 563 case IFT_PFLOG: 564 case IFT_PFSYNC: 565 return; 566 } 567 568 /* 569 * if link mtu is too small, don't try to configure IPv6. 570 * remember there could be some link-layer that has special 571 * fragmentation logic. 572 */ 573 if (ifp->if_mtu < IPV6_MMTU) { 574 nd6log((LOG_INFO, "in6_ifattach: " 575 "%s has too small MTU, IPv6 not enabled\n", 576 ifp->if_xname)); 577 return; 578 } 579 580 /* 581 * usually, we require multicast capability to the interface 582 */ 583 if ((ifp->if_flags & IFF_MULTICAST) == 0) { 584 nd6log((LOG_INFO, "in6_ifattach: " 585 "%s is not multicast capable, IPv6 not enabled\n", 586 ifp->if_xname)); 587 return; 588 } 589 590 /* 591 * assign loopback address for loopback interface. 592 * XXX multiple loopback interface case. 593 */ 594 if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 595 in6 = in6addr_loopback; 596 if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { 597 if (in6_ifattach_loopback(ifp) != 0) 598 return; 599 } 600 } 601 602 /* 603 * assign a link-local address, if there's none. 604 */ 605 if (ip6_auto_linklocal) { 606 ia6 = in6ifa_ifpforlinklocal(ifp, 0); 607 if (ia6 == NULL) { 608 if (in6_ifattach_linklocal(ifp, NULL) == 0) { 609 /* linklocal address assigned */ 610 } else { 611 /* failed to assign linklocal address. bark? */ 612 } 613 } 614 } 615} 616 617/* 618 * NOTE: in6_ifdetach() does not support loopback if at this moment. 619 */ 620void 621in6_ifdetach(struct ifnet *ifp) 622{ 623 struct ifaddr *ifa, *next; 624 struct rtentry *rt; 625 struct sockaddr_in6 sin6; 626 627#ifdef MROUTING 628 /* remove ip6_mrouter stuff */ 629 ip6_mrouter_detach(ifp); 630#endif 631 632 /* remove neighbor management table */ 633 nd6_purge(ifp); 634 635 /* nuke any of IPv6 addresses we have */ 636 TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) { 637 if (ifa->ifa_addr->sa_family != AF_INET6) 638 continue; 639 in6_purgeaddr(ifa); 640 dohooks(ifp->if_addrhooks, 0); 641 } 642 643 /* 644 * remove neighbor management table. we call it twice just to make 645 * sure we nuke everything. maybe we need just one call. 646 * XXX: since the first call did not release addresses, some prefixes 647 * might remain. We should call nd6_purge() again to release the 648 * prefixes after removing all addresses above. 649 * (Or can we just delay calling nd6_purge until at this point?) 650 */ 651 nd6_purge(ifp); 652 653 /* remove route to interface local allnodes multicast (ff01::1) */ 654 bzero(&sin6, sizeof(sin6)); 655 sin6.sin6_len = sizeof(struct sockaddr_in6); 656 sin6.sin6_family = AF_INET6; 657 sin6.sin6_addr = in6addr_intfacelocal_allnodes; 658 sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 659 rt = rtalloc1(sin6tosa(&sin6), 0, ifp->if_rdomain); 660 if (rt && rt->rt_ifp == ifp) { 661 struct rt_addrinfo info; 662 663 bzero(&info, sizeof(info)); 664 info.rti_flags = rt->rt_flags; 665 info.rti_info[RTAX_DST] = rt_key(rt); 666 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 667 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 668 rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, 669 ifp->if_rdomain); 670 rtfree(rt); 671 } 672 673 /* remove route to link-local allnodes multicast (ff02::1) */ 674 bzero(&sin6, sizeof(sin6)); 675 sin6.sin6_len = sizeof(struct sockaddr_in6); 676 sin6.sin6_family = AF_INET6; 677 sin6.sin6_addr = in6addr_linklocal_allnodes; 678 sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 679 rt = rtalloc1(sin6tosa(&sin6), 0, ifp->if_rdomain); 680 if (rt && rt->rt_ifp == ifp) { 681 struct rt_addrinfo info; 682 683 bzero(&info, sizeof(info)); 684 info.rti_flags = rt->rt_flags; 685 info.rti_info[RTAX_DST] = rt_key(rt); 686 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 687 info.rti_info[RTAX_NETMASK] = rt_mask(rt); 688 rtrequest1(RTM_DELETE, &info, rt->rt_priority, NULL, 689 ifp->if_rdomain); 690 rtfree(rt); 691 } 692} 693