1139826Simp/*- 253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. Neither the name of the project nor the names of its contributors 1453541Sshin * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 1653541Sshin * 1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753541Sshin * SUCH DAMAGE. 28174510Sobrien * 29174510Sobrien * $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $ 3053541Sshin */ 3153541Sshin 32174510Sobrien#include <sys/cdefs.h> 33174510Sobrien__FBSDID("$FreeBSD$"); 34174510Sobrien 3553541Sshin#include <sys/param.h> 3653541Sshin#include <sys/systm.h> 3753541Sshin#include <sys/malloc.h> 3853541Sshin#include <sys/socket.h> 3953541Sshin#include <sys/sockio.h> 40193066Sjamie#include <sys/jail.h> 4153541Sshin#include <sys/kernel.h> 42196019Srwatson#include <sys/proc.h> 4378064Sume#include <sys/syslog.h> 4453541Sshin#include <sys/md5.h> 4553541Sshin 4653541Sshin#include <net/if.h> 4753541Sshin#include <net/if_dl.h> 4853541Sshin#include <net/if_types.h> 4953541Sshin#include <net/route.h> 50185571Sbz#include <net/vnet.h> 5153541Sshin 5253541Sshin#include <netinet/in.h> 5353541Sshin#include <netinet/in_var.h> 5453541Sshin#include <netinet/if_ether.h> 5581127Sume#include <netinet/in_pcb.h> 56195699Srwatson#include <netinet/ip_var.h> 57195699Srwatson#include <netinet/udp.h> 58195699Srwatson#include <netinet/udp_var.h> 5953541Sshin 6062587Sitojun#include <netinet/ip6.h> 6153541Sshin#include <netinet6/ip6_var.h> 6278064Sume#include <netinet6/in6_var.h> 6381127Sume#include <netinet6/in6_pcb.h> 6453541Sshin#include <netinet6/in6_ifattach.h> 6553541Sshin#include <netinet6/ip6_var.h> 6653541Sshin#include <netinet6/nd6.h> 67191672Sbms#include <netinet6/mld6_var.h> 6862587Sitojun#include <netinet6/scope6_var.h> 6953541Sshin 70207369SbzVNET_DEFINE(unsigned long, in6_maxmtu) = 0; 71207369Sbz 72207369Sbz#ifdef IP6_AUTO_LINKLOCAL 73207369SbzVNET_DEFINE(int, ip6_auto_linklocal) = IP6_AUTO_LINKLOCAL; 74207369Sbz#else 75207369SbzVNET_DEFINE(int, ip6_auto_linklocal) = 1; /* enabled by default */ 76207369Sbz#endif 77207369Sbz 78195699SrwatsonVNET_DEFINE(struct callout, in6_tmpaddrtimer_ch); 79195727Srwatson#define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch) 80195699Srwatson 81195699SrwatsonVNET_DECLARE(struct inpcbinfo, ripcbinfo); 82195727Srwatson#define V_ripcbinfo VNET(ripcbinfo) 83195699Srwatson 84175162Sobrienstatic int get_rand_ifid(struct ifnet *, struct in6_addr *); 85175162Sobrienstatic int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *); 86175162Sobrienstatic int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *); 87175162Sobrienstatic int in6_ifattach_linklocal(struct ifnet *, struct ifnet *); 88175162Sobrienstatic int in6_ifattach_loopback(struct ifnet *); 89175162Sobrienstatic void in6_purgemaddrs(struct ifnet *); 9053541Sshin 9162587Sitojun#define EUI64_GBIT 0x01 9262587Sitojun#define EUI64_UBIT 0x02 9362587Sitojun#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) 9462587Sitojun#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) 9562587Sitojun#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) 9662587Sitojun#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) 9762587Sitojun#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) 9853541Sshin 9962587Sitojun#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) 10062587Sitojun#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) 10153541Sshin 10253541Sshin/* 10353541Sshin * Generate a last-resort interface identifier, when the machine has no 10453541Sshin * IEEE802/EUI64 address sources. 10562587Sitojun * The goal here is to get an interface identifier that is 10662587Sitojun * (1) random enough and (2) does not change across reboot. 10762587Sitojun * We currently use MD5(hostname) for it. 108171259Sdelphij * 109171259Sdelphij * in6 - upper 64bits are preserved 11053541Sshin */ 11153541Sshinstatic int 112171259Sdelphijget_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) 11353541Sshin{ 11453541Sshin MD5_CTX ctxt; 115193066Sjamie struct prison *pr; 11653541Sshin u_int8_t digest[16]; 117180291Srwatson int hostnamelen; 11853541Sshin 119193066Sjamie pr = curthread->td_ucred->cr_prison; 120193066Sjamie mtx_lock(&pr->pr_mtx); 121194118Sjamie hostnamelen = strlen(pr->pr_hostname); 12262587Sitojun#if 0 12362587Sitojun /* we need at least several letters as seed for ifid */ 124193066Sjamie if (hostnamelen < 3) { 125193066Sjamie mtx_unlock(&pr->pr_mtx); 12662587Sitojun return -1; 127193066Sjamie } 12862587Sitojun#endif 12962587Sitojun 13062587Sitojun /* generate 8 bytes of pseudo-random value. */ 13153541Sshin bzero(&ctxt, sizeof(ctxt)); 13253541Sshin MD5Init(&ctxt); 133194118Sjamie MD5Update(&ctxt, pr->pr_hostname, hostnamelen); 134193066Sjamie mtx_unlock(&pr->pr_mtx); 13553541Sshin MD5Final(digest, &ctxt); 13653541Sshin 13762587Sitojun /* assumes sizeof(digest) > sizeof(ifid) */ 13862587Sitojun bcopy(digest, &in6->s6_addr[8], 8); 13953541Sshin 14053541Sshin /* make sure to set "u" bit to local, and "g" bit to individual. */ 14162587Sitojun in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 14262587Sitojun in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 14353541Sshin 14462587Sitojun /* convert EUI64 into IPv6 interface identifier */ 14562587Sitojun EUI64_TO_IFID(in6); 14662587Sitojun 14753541Sshin return 0; 14853541Sshin} 14953541Sshin 15078064Sumestatic int 151171259Sdelphijgenerate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret) 15278064Sume{ 15378064Sume MD5_CTX ctxt; 15478064Sume u_int8_t seed[16], digest[16], nullbuf[8]; 15578064Sume u_int32_t val32; 15678064Sume 157171259Sdelphij /* If there's no history, start with a random seed. */ 15878064Sume bzero(nullbuf, sizeof(nullbuf)); 15978064Sume if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { 16078064Sume int i; 16178064Sume 16278064Sume for (i = 0; i < 2; i++) { 163121807Sume val32 = arc4random(); 16478064Sume bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); 16578064Sume } 166120913Sume } else 16778064Sume bcopy(seed0, seed, 8); 16878064Sume 16978064Sume /* copy the right-most 64-bits of the given address */ 17078064Sume /* XXX assumption on the size of IFID */ 17178064Sume bcopy(seed1, &seed[8], 8); 17278064Sume 17378064Sume if (0) { /* for debugging purposes only */ 17478064Sume int i; 17578064Sume 17678064Sume printf("generate_tmp_ifid: new randomized ID from: "); 17778064Sume for (i = 0; i < 16; i++) 17878064Sume printf("%02x", seed[i]); 17978064Sume printf(" "); 18078064Sume } 18178064Sume 18278064Sume /* generate 16 bytes of pseudo-random value. */ 18378064Sume bzero(&ctxt, sizeof(ctxt)); 18478064Sume MD5Init(&ctxt); 18578064Sume MD5Update(&ctxt, seed, sizeof(seed)); 18678064Sume MD5Final(digest, &ctxt); 18778064Sume 18878064Sume /* 18978064Sume * RFC 3041 3.2.1. (3) 19078064Sume * Take the left-most 64-bits of the MD5 digest and set bit 6 (the 19178064Sume * left-most bit is numbered 0) to zero. 19278064Sume */ 19378064Sume bcopy(digest, ret, 8); 19478064Sume ret[0] &= ~EUI64_UBIT; 19578064Sume 19678064Sume /* 19778064Sume * XXX: we'd like to ensure that the generated value is not zero 19878064Sume * for simplicity. If the caclculated digest happens to be zero, 19978064Sume * use a random non-zero value as the last resort. 20078064Sume */ 20178064Sume if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { 202151465Ssuz nd6log((LOG_INFO, 203151465Ssuz "generate_tmp_ifid: computed MD5 value is zero.\n")); 20478064Sume 205121807Sume val32 = arc4random(); 20678064Sume val32 = 1 + (val32 % (0xffffffff - 1)); 20778064Sume } 20878064Sume 20978064Sume /* 21078064Sume * RFC 3041 3.2.1. (4) 21178064Sume * Take the rightmost 64-bits of the MD5 digest and save them in 21278064Sume * stable storage as the history value to be used in the next 213120913Sume * iteration of the algorithm. 21478064Sume */ 21578064Sume bcopy(&digest[8], seed0, 8); 21678064Sume 21778064Sume if (0) { /* for debugging purposes only */ 21878064Sume int i; 21978064Sume 22078064Sume printf("to: "); 22178064Sume for (i = 0; i < 16; i++) 22278064Sume printf("%02x", digest[i]); 22378064Sume printf("\n"); 22478064Sume } 22578064Sume 22678064Sume return 0; 22778064Sume} 22878064Sume 22953541Sshin/* 23062587Sitojun * Get interface identifier for the specified interface. 23162587Sitojun * XXX assumes single sockaddr_dl (AF_LINK address) per an interface 232171259Sdelphij * 233171259Sdelphij * in6 - upper 64bits are preserved 23453541Sshin */ 235151477Ssuzint 236171259Sdelphijin6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) 23753541Sshin{ 23853541Sshin struct ifaddr *ifa; 23953541Sshin struct sockaddr_dl *sdl; 24062587Sitojun u_int8_t *addr; 24162587Sitojun size_t addrlen; 24262587Sitojun static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 24362587Sitojun static u_int8_t allone[8] = 24462587Sitojun { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 24553541Sshin 246229621Sjhb IF_ADDR_RLOCK(ifp); 247191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 24862587Sitojun if (ifa->ifa_addr->sa_family != AF_LINK) 24953541Sshin continue; 25062587Sitojun sdl = (struct sockaddr_dl *)ifa->ifa_addr; 25162587Sitojun if (sdl == NULL) 25262587Sitojun continue; 25362587Sitojun if (sdl->sdl_alen == 0) 25462587Sitojun continue; 25562587Sitojun 25662587Sitojun goto found; 25753541Sshin } 258229621Sjhb IF_ADDR_RUNLOCK(ifp); 25953541Sshin 26062587Sitojun return -1; 26162587Sitojun 26253541Sshinfound: 263194760Srwatson IF_ADDR_LOCK_ASSERT(ifp); 26462587Sitojun addr = LLADDR(sdl); 26562587Sitojun addrlen = sdl->sdl_alen; 26653541Sshin 26762587Sitojun /* get EUI64 */ 26862587Sitojun switch (ifp->if_type) { 269252511Shrs case IFT_BRIDGE: 27062587Sitojun case IFT_ETHER: 271216650Sjhay case IFT_L2VLAN: 27262587Sitojun case IFT_FDDI: 273120049Smdodd case IFT_ISO88025: 27462587Sitojun case IFT_ATM: 27578064Sume case IFT_IEEE1394: 27678064Sume#ifdef IFT_IEEE80211 27778064Sume case IFT_IEEE80211: 27878064Sume#endif 27962587Sitojun /* IEEE802/EUI64 cases - what others? */ 28078064Sume /* IEEE1394 uses 16byte length address starting with EUI64 */ 28178064Sume if (addrlen > 8) 28278064Sume addrlen = 8; 28353541Sshin 28462587Sitojun /* look at IEEE802/EUI64 only */ 285191337Srwatson if (addrlen != 8 && addrlen != 6) { 286229621Sjhb IF_ADDR_RUNLOCK(ifp); 28762587Sitojun return -1; 288191337Srwatson } 28953541Sshin 29062587Sitojun /* 29162587Sitojun * check for invalid MAC address - on bsdi, we see it a lot 29262587Sitojun * since wildboar configures all-zero MAC on pccard before 29362587Sitojun * card insertion. 29462587Sitojun */ 295191337Srwatson if (bcmp(addr, allzero, addrlen) == 0) { 296229621Sjhb IF_ADDR_RUNLOCK(ifp); 29762587Sitojun return -1; 298191337Srwatson } 299191337Srwatson if (bcmp(addr, allone, addrlen) == 0) { 300229621Sjhb IF_ADDR_RUNLOCK(ifp); 30162587Sitojun return -1; 302191337Srwatson } 30362587Sitojun 30462587Sitojun /* make EUI64 address */ 30562587Sitojun if (addrlen == 8) 30662587Sitojun bcopy(addr, &in6->s6_addr[8], 8); 30762587Sitojun else if (addrlen == 6) { 30862587Sitojun in6->s6_addr[8] = addr[0]; 30962587Sitojun in6->s6_addr[9] = addr[1]; 31062587Sitojun in6->s6_addr[10] = addr[2]; 31162587Sitojun in6->s6_addr[11] = 0xff; 31262587Sitojun in6->s6_addr[12] = 0xfe; 31362587Sitojun in6->s6_addr[13] = addr[3]; 31462587Sitojun in6->s6_addr[14] = addr[4]; 31562587Sitojun in6->s6_addr[15] = addr[5]; 31662587Sitojun } 31762587Sitojun break; 31862587Sitojun 31962587Sitojun case IFT_ARCNET: 320191337Srwatson if (addrlen != 1) { 321229621Sjhb IF_ADDR_RUNLOCK(ifp); 32262587Sitojun return -1; 323191337Srwatson } 324191337Srwatson if (!addr[0]) { 325229621Sjhb IF_ADDR_RUNLOCK(ifp); 32662587Sitojun return -1; 327191337Srwatson } 32862587Sitojun 32962587Sitojun bzero(&in6->s6_addr[8], 8); 33062587Sitojun in6->s6_addr[15] = addr[0]; 33162587Sitojun 33262587Sitojun /* 33362587Sitojun * due to insufficient bitwidth, we mark it local. 33462587Sitojun */ 33562587Sitojun in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 33662587Sitojun in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 33762587Sitojun break; 33862587Sitojun 33962587Sitojun case IFT_GIF: 34062587Sitojun#ifdef IFT_STF 34162587Sitojun case IFT_STF: 34253541Sshin#endif 34362587Sitojun /* 34478064Sume * RFC2893 says: "SHOULD use IPv4 address as ifid source". 34562587Sitojun * however, IPv4 address is not very suitable as unique 34662587Sitojun * identifier source (can be renumbered). 34762587Sitojun * we don't do this. 34862587Sitojun */ 349229621Sjhb IF_ADDR_RUNLOCK(ifp); 35062587Sitojun return -1; 35162587Sitojun 35262587Sitojun default: 353229621Sjhb IF_ADDR_RUNLOCK(ifp); 35462587Sitojun return -1; 35553541Sshin } 35662587Sitojun 35762587Sitojun /* sanity check: g bit must not indicate "group" */ 358191337Srwatson if (EUI64_GROUP(in6)) { 359229621Sjhb IF_ADDR_RUNLOCK(ifp); 36062587Sitojun return -1; 361191337Srwatson } 36262587Sitojun 36362587Sitojun /* convert EUI64 into IPv6 interface identifier */ 36462587Sitojun EUI64_TO_IFID(in6); 36562587Sitojun 36662587Sitojun /* 36762587Sitojun * sanity check: ifid must not be all zero, avoid conflict with 36862587Sitojun * subnet router anycast 36962587Sitojun */ 37062587Sitojun if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && 37162587Sitojun bcmp(&in6->s6_addr[9], allzero, 7) == 0) { 372229621Sjhb IF_ADDR_RUNLOCK(ifp); 37362587Sitojun return -1; 37462587Sitojun } 37562587Sitojun 376229621Sjhb IF_ADDR_RUNLOCK(ifp); 37762587Sitojun return 0; 37853541Sshin} 37953541Sshin 38053541Sshin/* 38162587Sitojun * Get interface identifier for the specified interface. If it is not 38262587Sitojun * available on ifp0, borrow interface identifier from other information 38362587Sitojun * sources. 384171259Sdelphij * 385171259Sdelphij * altifp - secondary EUI64 source 38653541Sshin */ 38762587Sitojunstatic int 388171259Sdelphijget_ifid(struct ifnet *ifp0, struct ifnet *altifp, 389171259Sdelphij struct in6_addr *in6) 39053541Sshin{ 39153541Sshin struct ifnet *ifp; 39253541Sshin 39362587Sitojun /* first, try to get it from the interface itself */ 394151477Ssuz if (in6_get_hw_ifid(ifp0, in6) == 0) { 39578064Sume nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", 39678064Sume if_name(ifp0))); 39762587Sitojun goto success; 39862587Sitojun } 39953541Sshin 40062587Sitojun /* try secondary EUI64 source. this basically is for ATM PVC */ 401151477Ssuz if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { 40278064Sume nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", 40378064Sume if_name(ifp0), if_name(altifp))); 40462587Sitojun goto success; 40562587Sitojun } 40662587Sitojun 40762587Sitojun /* next, try to get it from some other hardware interface */ 408196481Srwatson IFNET_RLOCK_NOSLEEP(); 409228966Sjhb TAILQ_FOREACH(ifp, &V_ifnet, if_list) { 41062587Sitojun if (ifp == ifp0) 41162587Sitojun continue; 412151477Ssuz if (in6_get_hw_ifid(ifp, in6) != 0) 41362587Sitojun continue; 41462587Sitojun 41562587Sitojun /* 41662587Sitojun * to borrow ifid from other interface, ifid needs to be 41762587Sitojun * globally unique 41862587Sitojun */ 41962587Sitojun if (IFID_UNIVERSAL(in6)) { 42078064Sume nd6log((LOG_DEBUG, 42178064Sume "%s: borrow interface identifier from %s\n", 42278064Sume if_name(ifp0), if_name(ifp))); 423196481Srwatson IFNET_RUNLOCK_NOSLEEP(); 42462587Sitojun goto success; 42562587Sitojun } 42662587Sitojun } 427196481Srwatson IFNET_RUNLOCK_NOSLEEP(); 42862587Sitojun 42962587Sitojun /* last resort: get from random number source */ 43062587Sitojun if (get_rand_ifid(ifp, in6) == 0) { 43178064Sume nd6log((LOG_DEBUG, 43278064Sume "%s: interface identifier generated by random number\n", 43378064Sume if_name(ifp0))); 43462587Sitojun goto success; 43562587Sitojun } 43662587Sitojun 43766504Sitojun printf("%s: failed to get interface identifier\n", if_name(ifp0)); 43862587Sitojun return -1; 43962587Sitojun 44062587Sitojunsuccess: 441120913Sume nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 442120913Sume if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10], 443120913Sume in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13], 444120913Sume in6->s6_addr[14], in6->s6_addr[15])); 44562587Sitojun return 0; 44662587Sitojun} 44762587Sitojun 448171259Sdelphij/* 449171259Sdelphij * altifp - secondary EUI64 source 450171259Sdelphij */ 45162587Sitojunstatic int 452171259Sdelphijin6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp) 45378064Sume{ 45462587Sitojun struct in6_ifaddr *ia; 45578064Sume struct in6_aliasreq ifra; 456151539Ssuz struct nd_prefixctl pr0; 45778064Sume int i, error; 45862587Sitojun 45962587Sitojun /* 46078064Sume * configure link-local address. 46162587Sitojun */ 46278064Sume bzero(&ifra, sizeof(ifra)); 46362587Sitojun 46462587Sitojun /* 46578064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 46678064Sume * for safety. 46762587Sitojun */ 46878064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 46962587Sitojun 47078064Sume ifra.ifra_addr.sin6_family = AF_INET6; 47178064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 472148385Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000); 47378064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; 47478064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 47578064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; 47678064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); 47778064Sume } else { 47878064Sume if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { 47978064Sume nd6log((LOG_ERR, 48078064Sume "%s: no ifid available\n", if_name(ifp))); 481120913Sume return (-1); 48262587Sitojun } 48362587Sitojun } 484148385Sume if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) 485148385Sume return (-1); 48662587Sitojun 48778064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 48878064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 48978064Sume ifra.ifra_prefixmask.sin6_addr = in6mask64; 49078064Sume /* link-local addresses should NEVER expire. */ 49178064Sume ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 49278064Sume ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 49362587Sitojun 49478064Sume /* 49578064Sume * Now call in6_update_ifa() to do a bunch of procedures to configure 496151465Ssuz * a link-local address. We can set the 3rd argument to NULL, because 49795023Ssuz * we know there's no other link-local address on the interface 49895023Ssuz * and therefore we are adding one (instead of updating one). 49978064Sume */ 500151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, 501151539Ssuz IN6_IFAUPDATE_DADDELAY)) != 0) { 50262587Sitojun /* 50378064Sume * XXX: When the interface does not support IPv6, this call 50478064Sume * would fail in the SIOCSIFADDR ioctl. I believe the 50578064Sume * notification is rather confusing in this case, so just 506120913Sume * suppress it. (jinmei@kame.net 20010130) 50762587Sitojun */ 50878064Sume if (error != EAFNOSUPPORT) 509151465Ssuz nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to " 51078064Sume "configure a link-local address on %s " 51178064Sume "(errno=%d)\n", 512151465Ssuz if_name(ifp), error)); 513120856Sume return (-1); 51462587Sitojun } 51562587Sitojun 51678064Sume ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ 517229546Sbz KASSERT(ia != NULL, ("%s: ia == NULL, ifp=%p", __func__, ifp)); 518229546Sbz 519194760Srwatson ifa_free(&ia->ia_ifa); 52053541Sshin 52178064Sume /* 522120913Sume * Make the link-local prefix (fe80::%link/64) as on-link. 52378064Sume * Since we'd like to manage prefixes separately from addresses, 52478064Sume * we make an ND6 prefix structure for the link-local prefix, 52578064Sume * and add it to the prefix list as a never-expire prefix. 52678064Sume * XXX: this change might affect some existing code base... 52778064Sume */ 52878064Sume bzero(&pr0, sizeof(pr0)); 52978064Sume pr0.ndpr_ifp = ifp; 53078064Sume /* this should be 64 at this moment. */ 53178064Sume pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); 53278064Sume pr0.ndpr_prefix = ifra.ifra_addr; 53378064Sume /* apply the mask for safety. (nd6_prelist_add will apply it again) */ 53478064Sume for (i = 0; i < 4; i++) { 53578064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 536120913Sume in6mask64.s6_addr32[i]; 53762587Sitojun } 53878064Sume /* 53978064Sume * Initialize parameters. The link-local prefix must always be 54078064Sume * on-link, and its lifetimes never expire. 54178064Sume */ 54278064Sume pr0.ndpr_raf_onlink = 1; 54378064Sume pr0.ndpr_raf_auto = 1; /* probably meaningless */ 54478064Sume pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; 54578064Sume pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; 54678064Sume /* 54778064Sume * Since there is no other link-local addresses, nd6_prefix_lookup() 54878064Sume * probably returns NULL. However, we cannot always expect the result. 54978064Sume * For example, if we first remove the (only) existing link-local 55078064Sume * address, and then reconfigure another one, the prefix is still 55178064Sume * valid with referring to the old link-local address. 55278064Sume */ 55378064Sume if (nd6_prefix_lookup(&pr0) == NULL) { 55478064Sume if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) 555120856Sume return (error); 55678064Sume } 55762587Sitojun 55862587Sitojun return 0; 55962587Sitojun} 56062587Sitojun 561171259Sdelphij/* 562171259Sdelphij * ifp - must be IFT_LOOP 563171259Sdelphij */ 56462587Sitojunstatic int 565171259Sdelphijin6_ifattach_loopback(struct ifnet *ifp) 56662587Sitojun{ 56778064Sume struct in6_aliasreq ifra; 56878064Sume int error; 56962587Sitojun 57078064Sume bzero(&ifra, sizeof(ifra)); 57178064Sume 57262587Sitojun /* 57378064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 57478064Sume * for safety. 57562587Sitojun */ 57678064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 57762587Sitojun 57878064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 57978064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 58078064Sume ifra.ifra_prefixmask.sin6_addr = in6mask128; 58162587Sitojun 58262587Sitojun /* 58362587Sitojun * Always initialize ia_dstaddr (= broadcast address) to loopback 58478064Sume * address. Follows IPv4 practice - see in_ifinit(). 58562587Sitojun */ 58678064Sume ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 58778064Sume ifra.ifra_dstaddr.sin6_family = AF_INET6; 58878064Sume ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; 58962587Sitojun 59078064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 59178064Sume ifra.ifra_addr.sin6_family = AF_INET6; 59278064Sume ifra.ifra_addr.sin6_addr = in6addr_loopback; 59362587Sitojun 59478064Sume /* the loopback address should NEVER expire. */ 59578064Sume ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 59678064Sume ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 59762587Sitojun 59878064Sume /* 59995023Ssuz * We are sure that this is a newly assigned address, so we can set 60095023Ssuz * NULL to the 3rd arg. 60178064Sume */ 602151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) { 603151465Ssuz nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " 60478064Sume "the loopback address on %s (errno=%d)\n", 605151465Ssuz if_name(ifp), error)); 606120856Sume return (-1); 60762587Sitojun } 60862587Sitojun 60962587Sitojun return 0; 61062587Sitojun} 61162587Sitojun 61262587Sitojun/* 61362587Sitojun * compute NI group address, based on the current hostname setting. 614250251Shrs * see RFC 4620. 61562587Sitojun * 61662587Sitojun * when ifp == NULL, the caller is responsible for filling scopeid. 617250251Shrs * 618250251Shrs * If oldmcprefix == 1, FF02:0:0:0:0:2::/96 is used for NI group address 619250251Shrs * while it is FF02:0:0:0:0:2:FF00::/104 in RFC 4620. 62062587Sitojun */ 621250251Shrsstatic int 622250251Shrsin6_nigroup0(struct ifnet *ifp, const char *name, int namelen, 623250251Shrs struct in6_addr *in6, int oldmcprefix) 62462587Sitojun{ 625193066Sjamie struct prison *pr; 62662587Sitojun const char *p; 62778064Sume u_char *q; 62862587Sitojun MD5_CTX ctxt; 62962587Sitojun u_int8_t digest[16]; 63062587Sitojun char l; 63178064Sume char n[64]; /* a single label must not exceed 63 chars */ 63262587Sitojun 633192895Sjamie /* 634192895Sjamie * If no name is given and namelen is -1, 635192895Sjamie * we try to do the hostname lookup ourselves. 636192895Sjamie */ 637192895Sjamie if (!name && namelen == -1) { 638193066Sjamie pr = curthread->td_ucred->cr_prison; 639193066Sjamie mtx_lock(&pr->pr_mtx); 640194118Sjamie name = pr->pr_hostname; 641192895Sjamie namelen = strlen(name); 642192895Sjamie } else 643193066Sjamie pr = NULL; 644192895Sjamie if (!name || !namelen) { 645193066Sjamie if (pr != NULL) 646193066Sjamie mtx_unlock(&pr->pr_mtx); 64762587Sitojun return -1; 648192895Sjamie } 64962587Sitojun 65062587Sitojun p = name; 65162587Sitojun while (p && *p && *p != '.' && p - name < namelen) 65262587Sitojun p++; 653192895Sjamie if (p == name || p - name > sizeof(n) - 1) { 654193066Sjamie if (pr != NULL) 655193066Sjamie mtx_unlock(&pr->pr_mtx); 65695023Ssuz return -1; /* label too long */ 657192895Sjamie } 65862587Sitojun l = p - name; 65978064Sume strncpy(n, name, l); 660193066Sjamie if (pr != NULL) 661193066Sjamie mtx_unlock(&pr->pr_mtx); 66278064Sume n[(int)l] = '\0'; 66378064Sume for (q = n; *q; q++) { 66478064Sume if ('A' <= *q && *q <= 'Z') 66578064Sume *q = *q - 'A' + 'a'; 66678064Sume } 66762587Sitojun 668250251Shrs /* generate 16 bytes of pseudo-random value. */ 66962587Sitojun bzero(&ctxt, sizeof(ctxt)); 67062587Sitojun MD5Init(&ctxt); 67162587Sitojun MD5Update(&ctxt, &l, sizeof(l)); 67278064Sume MD5Update(&ctxt, n, l); 67362587Sitojun MD5Final(digest, &ctxt); 67462587Sitojun 67562587Sitojun bzero(in6, sizeof(*in6)); 676151465Ssuz in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL; 67762587Sitojun in6->s6_addr8[11] = 2; 678250251Shrs if (oldmcprefix == 0) { 679250251Shrs in6->s6_addr8[12] = 0xff; 680250251Shrs /* Copy the first 24 bits of 128-bit hash into the address. */ 681250251Shrs bcopy(digest, &in6->s6_addr8[13], 3); 682250251Shrs } else { 683250251Shrs /* Copy the first 32 bits of 128-bit hash into the address. */ 684250251Shrs bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3])); 685250251Shrs } 686148385Sume if (in6_setscope(in6, ifp, NULL)) 687148385Sume return (-1); /* XXX: should not fail */ 68862587Sitojun 68962587Sitojun return 0; 69062587Sitojun} 69162587Sitojun 692250251Shrsint 693250251Shrsin6_nigroup(struct ifnet *ifp, const char *name, int namelen, 694250251Shrs struct in6_addr *in6) 695250251Shrs{ 696250251Shrs 697250251Shrs return (in6_nigroup0(ifp, name, namelen, in6, 0)); 698250251Shrs} 699250251Shrs 700250251Shrsint 701250251Shrsin6_nigroup_oldmcprefix(struct ifnet *ifp, const char *name, int namelen, 702250251Shrs struct in6_addr *in6) 703250251Shrs{ 704250251Shrs 705250251Shrs return (in6_nigroup0(ifp, name, namelen, in6, 1)); 706250251Shrs} 707250251Shrs 70862587Sitojun/* 70962587Sitojun * XXX multiple loopback interface needs more care. for instance, 71062587Sitojun * nodelocal address needs to be configured onto only one of them. 71162587Sitojun * XXX multiple link-local address case 712171259Sdelphij * 713171259Sdelphij * altifp - secondary EUI64 source 71462587Sitojun */ 71562587Sitojunvoid 716171259Sdelphijin6_ifattach(struct ifnet *ifp, struct ifnet *altifp) 71762587Sitojun{ 71862587Sitojun struct in6_ifaddr *ia; 71962587Sitojun struct in6_addr in6; 72062587Sitojun 721253841Shrs if (ifp->if_afdata[AF_INET6] == NULL) 72278064Sume return; 72353541Sshin /* 72462587Sitojun * quirks based on interface type 72553541Sshin */ 72662587Sitojun switch (ifp->if_type) { 72762587Sitojun case IFT_STF: 72862587Sitojun /* 72995023Ssuz * 6to4 interface is a very special kind of beast. 73095023Ssuz * no multicast, no linklocal. RFC2529 specifies how to make 73195023Ssuz * linklocals for 6to4 interface, but there's no use and 73295023Ssuz * it is rather harmful to have one. 73362587Sitojun */ 734252511Shrs ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL; 735252511Shrs break; 73662587Sitojun default: 73762587Sitojun break; 73853541Sshin } 73953541Sshin 74053541Sshin /* 74162587Sitojun * usually, we require multicast capability to the interface 74253541Sshin */ 74362587Sitojun if ((ifp->if_flags & IFF_MULTICAST) == 0) { 744151465Ssuz nd6log((LOG_INFO, "in6_ifattach: " 74578064Sume "%s is not multicast capable, IPv6 not enabled\n", 746151465Ssuz if_name(ifp))); 74762587Sitojun return; 74862587Sitojun } 74962587Sitojun 75053541Sshin /* 75178064Sume * assign loopback address for loopback interface. 75278064Sume * XXX multiple loopback interface case. 75353541Sshin */ 75478064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 755194760Srwatson struct ifaddr *ifa; 756194760Srwatson 75778064Sume in6 = in6addr_loopback; 758194760Srwatson ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &in6); 759194760Srwatson if (ifa == NULL) { 76062587Sitojun if (in6_ifattach_loopback(ifp) != 0) 76162587Sitojun return; 762194760Srwatson } else 763194760Srwatson ifa_free(ifa); 76462587Sitojun } 76553541Sshin 76653541Sshin /* 767120913Sume * assign a link-local address, if there's none. 76853541Sshin */ 769252511Shrs if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && 770197138Shrs ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) { 771197138Shrs int error; 772197138Shrs 77378064Sume ia = in6ifa_ifpforlinklocal(ifp, 0); 77478064Sume if (ia == NULL) { 775197138Shrs error = in6_ifattach_linklocal(ifp, altifp); 776197996Shrs#if 0 777197138Shrs if (error) 778197138Shrs log(LOG_NOTICE, "in6_ifattach_linklocal: " 779197138Shrs "failed to add a link-local addr to %s\n", 780197138Shrs if_name(ifp)); 781197996Shrs#endif 782194760Srwatson } else 783194760Srwatson ifa_free(&ia->ia_ifa); 78453541Sshin } 78553541Sshin 78653541Sshin /* update dynamically. */ 787181803Sbz if (V_in6_maxmtu < ifp->if_mtu) 788181803Sbz V_in6_maxmtu = ifp->if_mtu; 78953541Sshin} 79053541Sshin 79162587Sitojun/* 79262587Sitojun * NOTE: in6_ifdetach() does not support loopback if at this moment. 79378064Sume * We don't need this function in bsdi, because interfaces are never removed 79478064Sume * from the ifnet list in bsdi. 79562587Sitojun */ 79653541Sshinvoid 797171259Sdelphijin6_ifdetach(struct ifnet *ifp) 79853541Sshin{ 799194907Srwatson struct in6_ifaddr *ia; 80062587Sitojun struct ifaddr *ifa, *next; 801193232Sbz struct radix_node_head *rnh; 80253541Sshin struct rtentry *rt; 80362587Sitojun struct sockaddr_in6 sin6; 804170202Sjinmei struct in6_multi_mship *imm; 80553541Sshin 806256258Shrs if (ifp->if_afdata[AF_INET6] == NULL) 807256258Shrs return; 808256258Shrs 80962587Sitojun /* remove neighbor management table */ 81062587Sitojun nd6_purge(ifp); 81162587Sitojun 81262587Sitojun /* nuke any of IPv6 addresses we have */ 813191340Srwatson TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { 81462587Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 81562587Sitojun continue; 81678064Sume in6_purgeaddr(ifa); 81762587Sitojun } 81862587Sitojun 81962587Sitojun /* undo everything done by in6_ifattach(), just in case */ 820191340Srwatson TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { 82153541Sshin if (ifa->ifa_addr->sa_family != AF_INET6 82253541Sshin || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 82353541Sshin continue; 82453541Sshin } 82553541Sshin 82653541Sshin ia = (struct in6_ifaddr *)ifa; 82753541Sshin 828170202Sjinmei /* 829170202Sjinmei * leave from multicast groups we have joined for the interface 830170202Sjinmei */ 831228966Sjhb while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { 832170202Sjinmei LIST_REMOVE(imm, i6mm_chain); 833170202Sjinmei in6_leavegroup(imm); 834170202Sjinmei } 835170202Sjinmei 836231852Sbz /* Remove link-local from the routing table. */ 837231852Sbz if (ia->ia_flags & IFA_ROUTE) 838231852Sbz (void)rtinit(&ia->ia_ifa, RTM_DELETE, ia->ia_flags); 83953541Sshin 84053541Sshin /* remove from the linked list */ 841229621Sjhb IF_ADDR_WLOCK(ifp); 842194907Srwatson TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 843229621Sjhb IF_ADDR_WUNLOCK(ifp); 844194907Srwatson ifa_free(ifa); /* if_addrhead */ 84553541Sshin 846194971Srwatson IN6_IFADDR_WLOCK(); 847194907Srwatson TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link); 848194971Srwatson IN6_IFADDR_WUNLOCK(); 849194907Srwatson ifa_free(ifa); 85053541Sshin } 85162587Sitojun 852181803Sbz in6_pcbpurgeif0(&V_udbinfo, ifp); 853265946Skevlo in6_pcbpurgeif0(&V_ulitecbinfo, ifp); 854181803Sbz in6_pcbpurgeif0(&V_ripcbinfo, ifp); 855170613Sbms /* leave from all multicast groups joined */ 856170613Sbms in6_purgemaddrs(ifp); 857120913Sume 85878064Sume /* 85978064Sume * remove neighbor management table. we call it twice just to make 86078064Sume * sure we nuke everything. maybe we need just one call. 86178064Sume * XXX: since the first call did not release addresses, some prefixes 86278064Sume * might remain. We should call nd6_purge() again to release the 86378064Sume * prefixes after removing all addresses above. 86478064Sume * (Or can we just delay calling nd6_purge until at this point?) 86578064Sume */ 86662587Sitojun nd6_purge(ifp); 86762587Sitojun 868231852Sbz /* 869231852Sbz * Remove route to link-local allnodes multicast (ff02::1). 870231852Sbz * These only get automatically installed for the default FIB. 871231852Sbz */ 87262587Sitojun bzero(&sin6, sizeof(sin6)); 87362587Sitojun sin6.sin6_len = sizeof(struct sockaddr_in6); 87462587Sitojun sin6.sin6_family = AF_INET6; 87562587Sitojun sin6.sin6_addr = in6addr_linklocal_allnodes; 876148385Sume if (in6_setscope(&sin6.sin6_addr, ifp, NULL)) 877148385Sume /* XXX: should not fail */ 878148385Sume return; 879121770Ssam /* XXX grab lock first to avoid LOR */ 880231852Sbz rnh = rt_tables_get_rnh(RT_DEFAULT_FIB, AF_INET6); 881193232Sbz if (rnh != NULL) { 882193232Sbz RADIX_NODE_HEAD_LOCK(rnh); 883231852Sbz rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED, 884231852Sbz RT_DEFAULT_FIB); 885124333Struckman if (rt) { 886124333Struckman if (rt->rt_ifp == ifp) 887124333Struckman rtexpunge(rt); 888124333Struckman RTFREE_LOCKED(rt); 889124333Struckman } 890193232Sbz RADIX_NODE_HEAD_UNLOCK(rnh); 89162587Sitojun } 89253541Sshin} 89378064Sume 894151539Ssuzint 895171259Sdelphijin6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf, 896171259Sdelphij const u_int8_t *baseid, int generate) 89778064Sume{ 89878064Sume u_int8_t nullbuf[8]; 899121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 90078064Sume 90178064Sume bzero(nullbuf, sizeof(nullbuf)); 90278064Sume if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { 90378064Sume /* we've never created a random ID. Create a new one. */ 90478064Sume generate = 1; 90578064Sume } 90678064Sume 90778064Sume if (generate) { 90878064Sume bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); 90978064Sume 91078064Sume /* generate_tmp_ifid will update seedn and buf */ 91178064Sume (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, 912120913Sume ndi->randomid); 91378064Sume } 91478064Sume bcopy(ndi->randomid, retbuf, 8); 915151539Ssuz 916151539Ssuz return (0); 91778064Sume} 91878064Sume 91978064Sumevoid 920191688Szecin6_tmpaddrtimer(void *arg) 92178064Sume{ 922191688Szec CURVNET_SET((struct vnet *) arg); 92378064Sume struct nd_ifinfo *ndi; 92478064Sume u_int8_t nullbuf[8]; 925121161Sume struct ifnet *ifp; 92678064Sume 927181803Sbz callout_reset(&V_in6_tmpaddrtimer_ch, 928181803Sbz (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor - 929191688Szec V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet); 93078064Sume 93178064Sume bzero(nullbuf, sizeof(nullbuf)); 932228966Sjhb TAILQ_FOREACH(ifp, &V_ifnet, if_list) { 933253950Shrs if (ifp->if_afdata[AF_INET6] == NULL) 934253950Shrs continue; 935121161Sume ndi = ND_IFINFO(ifp); 93678064Sume if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { 93778064Sume /* 93878064Sume * We've been generating a random ID on this interface. 93978064Sume * Create a new one. 94078064Sume */ 94178064Sume (void)generate_tmp_ifid(ndi->randomseed0, 942120913Sume ndi->randomseed1, ndi->randomid); 94378064Sume } 94478064Sume } 94578064Sume 946191688Szec CURVNET_RESTORE(); 94778064Sume} 948170613Sbms 949170613Sbmsstatic void 950171259Sdelphijin6_purgemaddrs(struct ifnet *ifp) 951170613Sbms{ 952191672Sbms LIST_HEAD(,in6_multi) purgeinms; 953191672Sbms struct in6_multi *inm, *tinm; 954191672Sbms struct ifmultiaddr *ifma; 955170613Sbms 956191672Sbms LIST_INIT(&purgeinms); 957191672Sbms IN6_MULTI_LOCK(); 958191672Sbms 959191672Sbms /* 960191672Sbms * Extract list of in6_multi associated with the detaching ifp 961191672Sbms * which the PF_INET6 layer is about to release. 962191672Sbms * We need to do this as IF_ADDR_LOCK() may be re-acquired 963191672Sbms * by code further down. 964191672Sbms */ 965229621Sjhb IF_ADDR_RLOCK(ifp); 966191672Sbms TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 967191672Sbms if (ifma->ifma_addr->sa_family != AF_INET6 || 968191672Sbms ifma->ifma_protospec == NULL) 969191672Sbms continue; 970191672Sbms inm = (struct in6_multi *)ifma->ifma_protospec; 971191672Sbms LIST_INSERT_HEAD(&purgeinms, inm, in6m_entry); 972170613Sbms } 973229621Sjhb IF_ADDR_RUNLOCK(ifp); 974191672Sbms 975191672Sbms LIST_FOREACH_SAFE(inm, &purgeinms, in6m_entry, tinm) { 976191672Sbms LIST_REMOVE(inm, in6m_entry); 977191672Sbms in6m_release_locked(inm); 978191672Sbms } 979191672Sbms mld_ifdetach(ifp); 980191672Sbms 981191672Sbms IN6_MULTI_UNLOCK(); 982170613Sbms} 983