in6_ifattach.c revision 181888
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: head/sys/netinet6/in6_ifattach.c 181888 2008-08-20 01:24:55Z julian $"); 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> 4053541Sshin#include <sys/kernel.h> 4178064Sume#include <sys/syslog.h> 4253541Sshin#include <sys/md5.h> 43181803Sbz#include <sys/vimage.h> 4453541Sshin 4553541Sshin#include <net/if.h> 4653541Sshin#include <net/if_dl.h> 4753541Sshin#include <net/if_types.h> 4853541Sshin#include <net/route.h> 4953541Sshin 5053541Sshin#include <netinet/in.h> 5153541Sshin#include <netinet/in_var.h> 5253541Sshin#include <netinet/if_ether.h> 5381127Sume#include <netinet/in_pcb.h> 5453541Sshin 5562587Sitojun#include <netinet/ip6.h> 5653541Sshin#include <netinet6/ip6_var.h> 5778064Sume#include <netinet6/in6_var.h> 5881127Sume#include <netinet6/in6_pcb.h> 5953541Sshin#include <netinet6/in6_ifattach.h> 6053541Sshin#include <netinet6/ip6_var.h> 6153541Sshin#include <netinet6/nd6.h> 6262587Sitojun#include <netinet6/scope6_var.h> 6353541Sshin 6462587Sitojununsigned long in6_maxmtu = 0; 6553541Sshin 6678064Sume#ifdef IP6_AUTO_LINKLOCAL 6778064Sumeint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; 6878064Sume#else 69163306Sumeint ip6_auto_linklocal = 1; /* enable by default */ 7078064Sume#endif 7178064Sume 7278064Sumestruct callout in6_tmpaddrtimer_ch; 7378064Sume 7481127Sumeextern struct inpcbinfo udbinfo; 7581127Sumeextern struct inpcbinfo ripcbinfo; 7681127Sume 77175162Sobrienstatic int get_rand_ifid(struct ifnet *, struct in6_addr *); 78175162Sobrienstatic int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *); 79175162Sobrienstatic int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *); 80175162Sobrienstatic int in6_ifattach_linklocal(struct ifnet *, struct ifnet *); 81175162Sobrienstatic int in6_ifattach_loopback(struct ifnet *); 82175162Sobrienstatic void in6_purgemaddrs(struct ifnet *); 8353541Sshin 8462587Sitojun#define EUI64_GBIT 0x01 8562587Sitojun#define EUI64_UBIT 0x02 8662587Sitojun#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) 8762587Sitojun#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) 8862587Sitojun#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) 8962587Sitojun#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) 9062587Sitojun#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) 9153541Sshin 9262587Sitojun#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) 9362587Sitojun#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) 9453541Sshin 9553541Sshin/* 9653541Sshin * Generate a last-resort interface identifier, when the machine has no 9753541Sshin * IEEE802/EUI64 address sources. 9862587Sitojun * The goal here is to get an interface identifier that is 9962587Sitojun * (1) random enough and (2) does not change across reboot. 10062587Sitojun * We currently use MD5(hostname) for it. 101171259Sdelphij * 102171259Sdelphij * in6 - upper 64bits are preserved 10353541Sshin */ 10453541Sshinstatic int 105171259Sdelphijget_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) 10653541Sshin{ 10753541Sshin MD5_CTX ctxt; 10853541Sshin u_int8_t digest[16]; 109180291Srwatson int hostnamelen; 11053541Sshin 111180291Srwatson mtx_lock(&hostname_mtx); 112181803Sbz hostnamelen = strlen(V_hostname); 11362587Sitojun#if 0 11462587Sitojun /* we need at least several letters as seed for ifid */ 11562587Sitojun if (hostnamelen < 3) 11662587Sitojun return -1; 11762587Sitojun#endif 11862587Sitojun 11962587Sitojun /* generate 8 bytes of pseudo-random value. */ 12053541Sshin bzero(&ctxt, sizeof(ctxt)); 12153541Sshin MD5Init(&ctxt); 122181803Sbz MD5Update(&ctxt, V_hostname, hostnamelen); 123180291Srwatson mtx_unlock(&hostname_mtx); 12453541Sshin MD5Final(digest, &ctxt); 12553541Sshin 12662587Sitojun /* assumes sizeof(digest) > sizeof(ifid) */ 12762587Sitojun bcopy(digest, &in6->s6_addr[8], 8); 12853541Sshin 12953541Sshin /* make sure to set "u" bit to local, and "g" bit to individual. */ 13062587Sitojun in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 13162587Sitojun in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 13253541Sshin 13362587Sitojun /* convert EUI64 into IPv6 interface identifier */ 13462587Sitojun EUI64_TO_IFID(in6); 13562587Sitojun 13653541Sshin return 0; 13753541Sshin} 13853541Sshin 13978064Sumestatic int 140171259Sdelphijgenerate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret) 14178064Sume{ 14278064Sume MD5_CTX ctxt; 14378064Sume u_int8_t seed[16], digest[16], nullbuf[8]; 14478064Sume u_int32_t val32; 14578064Sume 146171259Sdelphij /* If there's no history, start with a random seed. */ 14778064Sume bzero(nullbuf, sizeof(nullbuf)); 14878064Sume if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { 14978064Sume int i; 15078064Sume 15178064Sume for (i = 0; i < 2; i++) { 152121807Sume val32 = arc4random(); 15378064Sume bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); 15478064Sume } 155120913Sume } else 15678064Sume bcopy(seed0, seed, 8); 15778064Sume 15878064Sume /* copy the right-most 64-bits of the given address */ 15978064Sume /* XXX assumption on the size of IFID */ 16078064Sume bcopy(seed1, &seed[8], 8); 16178064Sume 16278064Sume if (0) { /* for debugging purposes only */ 16378064Sume int i; 16478064Sume 16578064Sume printf("generate_tmp_ifid: new randomized ID from: "); 16678064Sume for (i = 0; i < 16; i++) 16778064Sume printf("%02x", seed[i]); 16878064Sume printf(" "); 16978064Sume } 17078064Sume 17178064Sume /* generate 16 bytes of pseudo-random value. */ 17278064Sume bzero(&ctxt, sizeof(ctxt)); 17378064Sume MD5Init(&ctxt); 17478064Sume MD5Update(&ctxt, seed, sizeof(seed)); 17578064Sume MD5Final(digest, &ctxt); 17678064Sume 17778064Sume /* 17878064Sume * RFC 3041 3.2.1. (3) 17978064Sume * Take the left-most 64-bits of the MD5 digest and set bit 6 (the 18078064Sume * left-most bit is numbered 0) to zero. 18178064Sume */ 18278064Sume bcopy(digest, ret, 8); 18378064Sume ret[0] &= ~EUI64_UBIT; 18478064Sume 18578064Sume /* 18678064Sume * XXX: we'd like to ensure that the generated value is not zero 18778064Sume * for simplicity. If the caclculated digest happens to be zero, 18878064Sume * use a random non-zero value as the last resort. 18978064Sume */ 19078064Sume if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { 191151465Ssuz nd6log((LOG_INFO, 192151465Ssuz "generate_tmp_ifid: computed MD5 value is zero.\n")); 19378064Sume 194121807Sume val32 = arc4random(); 19578064Sume val32 = 1 + (val32 % (0xffffffff - 1)); 19678064Sume } 19778064Sume 19878064Sume /* 19978064Sume * RFC 3041 3.2.1. (4) 20078064Sume * Take the rightmost 64-bits of the MD5 digest and save them in 20178064Sume * stable storage as the history value to be used in the next 202120913Sume * iteration of the algorithm. 20378064Sume */ 20478064Sume bcopy(&digest[8], seed0, 8); 20578064Sume 20678064Sume if (0) { /* for debugging purposes only */ 20778064Sume int i; 20878064Sume 20978064Sume printf("to: "); 21078064Sume for (i = 0; i < 16; i++) 21178064Sume printf("%02x", digest[i]); 21278064Sume printf("\n"); 21378064Sume } 21478064Sume 21578064Sume return 0; 21678064Sume} 21778064Sume 21853541Sshin/* 21962587Sitojun * Get interface identifier for the specified interface. 22062587Sitojun * XXX assumes single sockaddr_dl (AF_LINK address) per an interface 221171259Sdelphij * 222171259Sdelphij * in6 - upper 64bits are preserved 22353541Sshin */ 224151477Ssuzint 225171259Sdelphijin6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) 22653541Sshin{ 22753541Sshin struct ifaddr *ifa; 22853541Sshin struct sockaddr_dl *sdl; 22962587Sitojun u_int8_t *addr; 23062587Sitojun size_t addrlen; 23162587Sitojun static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 23262587Sitojun static u_int8_t allone[8] = 23362587Sitojun { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 23453541Sshin 23562587Sitojun for (ifa = ifp->if_addrlist.tqh_first; 23662587Sitojun ifa; 237120913Sume ifa = ifa->ifa_list.tqe_next) { 23862587Sitojun if (ifa->ifa_addr->sa_family != AF_LINK) 23953541Sshin continue; 24062587Sitojun sdl = (struct sockaddr_dl *)ifa->ifa_addr; 24162587Sitojun if (sdl == NULL) 24262587Sitojun continue; 24362587Sitojun if (sdl->sdl_alen == 0) 24462587Sitojun continue; 24562587Sitojun 24662587Sitojun goto found; 24753541Sshin } 24853541Sshin 24962587Sitojun return -1; 25062587Sitojun 25153541Sshinfound: 25262587Sitojun addr = LLADDR(sdl); 25362587Sitojun addrlen = sdl->sdl_alen; 25453541Sshin 25562587Sitojun /* get EUI64 */ 25662587Sitojun switch (ifp->if_type) { 25762587Sitojun case IFT_ETHER: 25862587Sitojun case IFT_FDDI: 259120049Smdodd case IFT_ISO88025: 26062587Sitojun case IFT_ATM: 26178064Sume case IFT_IEEE1394: 26278064Sume#ifdef IFT_IEEE80211 26378064Sume case IFT_IEEE80211: 26478064Sume#endif 26562587Sitojun /* IEEE802/EUI64 cases - what others? */ 26678064Sume /* IEEE1394 uses 16byte length address starting with EUI64 */ 26778064Sume if (addrlen > 8) 26878064Sume addrlen = 8; 26953541Sshin 27062587Sitojun /* look at IEEE802/EUI64 only */ 27162587Sitojun if (addrlen != 8 && addrlen != 6) 27262587Sitojun return -1; 27353541Sshin 27462587Sitojun /* 27562587Sitojun * check for invalid MAC address - on bsdi, we see it a lot 27662587Sitojun * since wildboar configures all-zero MAC on pccard before 27762587Sitojun * card insertion. 27862587Sitojun */ 27962587Sitojun if (bcmp(addr, allzero, addrlen) == 0) 28062587Sitojun return -1; 28162587Sitojun if (bcmp(addr, allone, addrlen) == 0) 28262587Sitojun return -1; 28362587Sitojun 28462587Sitojun /* make EUI64 address */ 28562587Sitojun if (addrlen == 8) 28662587Sitojun bcopy(addr, &in6->s6_addr[8], 8); 28762587Sitojun else if (addrlen == 6) { 28862587Sitojun in6->s6_addr[8] = addr[0]; 28962587Sitojun in6->s6_addr[9] = addr[1]; 29062587Sitojun in6->s6_addr[10] = addr[2]; 29162587Sitojun in6->s6_addr[11] = 0xff; 29262587Sitojun in6->s6_addr[12] = 0xfe; 29362587Sitojun in6->s6_addr[13] = addr[3]; 29462587Sitojun in6->s6_addr[14] = addr[4]; 29562587Sitojun in6->s6_addr[15] = addr[5]; 29662587Sitojun } 29762587Sitojun break; 29862587Sitojun 29962587Sitojun case IFT_ARCNET: 30062587Sitojun if (addrlen != 1) 30162587Sitojun return -1; 30262587Sitojun if (!addr[0]) 30362587Sitojun return -1; 30462587Sitojun 30562587Sitojun bzero(&in6->s6_addr[8], 8); 30662587Sitojun in6->s6_addr[15] = addr[0]; 30762587Sitojun 30862587Sitojun /* 30962587Sitojun * due to insufficient bitwidth, we mark it local. 31062587Sitojun */ 31162587Sitojun in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 31262587Sitojun in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 31362587Sitojun break; 31462587Sitojun 31562587Sitojun case IFT_GIF: 31662587Sitojun#ifdef IFT_STF 31762587Sitojun case IFT_STF: 31853541Sshin#endif 31962587Sitojun /* 32078064Sume * RFC2893 says: "SHOULD use IPv4 address as ifid source". 32162587Sitojun * however, IPv4 address is not very suitable as unique 32262587Sitojun * identifier source (can be renumbered). 32362587Sitojun * we don't do this. 32462587Sitojun */ 32562587Sitojun return -1; 32662587Sitojun 32762587Sitojun default: 32862587Sitojun return -1; 32953541Sshin } 33062587Sitojun 33162587Sitojun /* sanity check: g bit must not indicate "group" */ 33262587Sitojun if (EUI64_GROUP(in6)) 33362587Sitojun return -1; 33462587Sitojun 33562587Sitojun /* convert EUI64 into IPv6 interface identifier */ 33662587Sitojun EUI64_TO_IFID(in6); 33762587Sitojun 33862587Sitojun /* 33962587Sitojun * sanity check: ifid must not be all zero, avoid conflict with 34062587Sitojun * subnet router anycast 34162587Sitojun */ 34262587Sitojun if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && 34362587Sitojun bcmp(&in6->s6_addr[9], allzero, 7) == 0) { 34462587Sitojun return -1; 34562587Sitojun } 34662587Sitojun 34762587Sitojun return 0; 34853541Sshin} 34953541Sshin 35053541Sshin/* 35162587Sitojun * Get interface identifier for the specified interface. If it is not 35262587Sitojun * available on ifp0, borrow interface identifier from other information 35362587Sitojun * sources. 354171259Sdelphij * 355171259Sdelphij * altifp - secondary EUI64 source 35653541Sshin */ 35762587Sitojunstatic int 358171259Sdelphijget_ifid(struct ifnet *ifp0, struct ifnet *altifp, 359171259Sdelphij struct in6_addr *in6) 36053541Sshin{ 36153541Sshin struct ifnet *ifp; 36253541Sshin 36362587Sitojun /* first, try to get it from the interface itself */ 364151477Ssuz if (in6_get_hw_ifid(ifp0, in6) == 0) { 36578064Sume nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", 36678064Sume if_name(ifp0))); 36762587Sitojun goto success; 36862587Sitojun } 36953541Sshin 37062587Sitojun /* try secondary EUI64 source. this basically is for ATM PVC */ 371151477Ssuz if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { 37278064Sume nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", 37378064Sume if_name(ifp0), if_name(altifp))); 37462587Sitojun goto success; 37562587Sitojun } 37662587Sitojun 37762587Sitojun /* next, try to get it from some other hardware interface */ 378108172Shsu IFNET_RLOCK(); 379181803Sbz for (ifp = V_ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { 38062587Sitojun if (ifp == ifp0) 38162587Sitojun continue; 382151477Ssuz if (in6_get_hw_ifid(ifp, in6) != 0) 38362587Sitojun continue; 38462587Sitojun 38562587Sitojun /* 38662587Sitojun * to borrow ifid from other interface, ifid needs to be 38762587Sitojun * globally unique 38862587Sitojun */ 38962587Sitojun if (IFID_UNIVERSAL(in6)) { 39078064Sume nd6log((LOG_DEBUG, 39178064Sume "%s: borrow interface identifier from %s\n", 39278064Sume if_name(ifp0), if_name(ifp))); 393108172Shsu IFNET_RUNLOCK(); 39462587Sitojun goto success; 39562587Sitojun } 39662587Sitojun } 397108172Shsu IFNET_RUNLOCK(); 39862587Sitojun 39962587Sitojun /* last resort: get from random number source */ 40062587Sitojun if (get_rand_ifid(ifp, in6) == 0) { 40178064Sume nd6log((LOG_DEBUG, 40278064Sume "%s: interface identifier generated by random number\n", 40378064Sume if_name(ifp0))); 40462587Sitojun goto success; 40562587Sitojun } 40662587Sitojun 40766504Sitojun printf("%s: failed to get interface identifier\n", if_name(ifp0)); 40862587Sitojun return -1; 40962587Sitojun 41062587Sitojunsuccess: 411120913Sume nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 412120913Sume if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10], 413120913Sume in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13], 414120913Sume in6->s6_addr[14], in6->s6_addr[15])); 41562587Sitojun return 0; 41662587Sitojun} 41762587Sitojun 418171259Sdelphij/* 419171259Sdelphij * altifp - secondary EUI64 source 420171259Sdelphij */ 42162587Sitojunstatic int 422171259Sdelphijin6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp) 42378064Sume{ 42462587Sitojun struct in6_ifaddr *ia; 42578064Sume struct in6_aliasreq ifra; 426151539Ssuz struct nd_prefixctl pr0; 42778064Sume int i, error; 42862587Sitojun 42962587Sitojun /* 43078064Sume * configure link-local address. 43162587Sitojun */ 43278064Sume bzero(&ifra, sizeof(ifra)); 43362587Sitojun 43462587Sitojun /* 43578064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 43678064Sume * for safety. 43762587Sitojun */ 43878064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 43962587Sitojun 44078064Sume ifra.ifra_addr.sin6_family = AF_INET6; 44178064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 442148385Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000); 44378064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; 44478064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 44578064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; 44678064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); 44778064Sume } else { 44878064Sume if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { 44978064Sume nd6log((LOG_ERR, 45078064Sume "%s: no ifid available\n", if_name(ifp))); 451120913Sume return (-1); 45262587Sitojun } 45362587Sitojun } 454148385Sume if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) 455148385Sume return (-1); 45662587Sitojun 45778064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 45878064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 45978064Sume ifra.ifra_prefixmask.sin6_addr = in6mask64; 46078064Sume /* link-local addresses should NEVER expire. */ 46178064Sume ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 46278064Sume ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 46362587Sitojun 46478064Sume /* 46578064Sume * Now call in6_update_ifa() to do a bunch of procedures to configure 466151465Ssuz * a link-local address. We can set the 3rd argument to NULL, because 46795023Ssuz * we know there's no other link-local address on the interface 46895023Ssuz * and therefore we are adding one (instead of updating one). 46978064Sume */ 470151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, 471151539Ssuz IN6_IFAUPDATE_DADDELAY)) != 0) { 47262587Sitojun /* 47378064Sume * XXX: When the interface does not support IPv6, this call 47478064Sume * would fail in the SIOCSIFADDR ioctl. I believe the 47578064Sume * notification is rather confusing in this case, so just 476120913Sume * suppress it. (jinmei@kame.net 20010130) 47762587Sitojun */ 47878064Sume if (error != EAFNOSUPPORT) 479151465Ssuz nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to " 48078064Sume "configure a link-local address on %s " 48178064Sume "(errno=%d)\n", 482151465Ssuz if_name(ifp), error)); 483120856Sume return (-1); 48462587Sitojun } 48562587Sitojun 48678064Sume ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ 48778064Sume#ifdef DIAGNOSTIC 48878064Sume if (!ia) { 48978064Sume panic("ia == NULL in in6_ifattach_linklocal"); 49095023Ssuz /* NOTREACHED */ 49178064Sume } 49262587Sitojun#endif 49353541Sshin 49478064Sume /* 495120913Sume * Make the link-local prefix (fe80::%link/64) as on-link. 49678064Sume * Since we'd like to manage prefixes separately from addresses, 49778064Sume * we make an ND6 prefix structure for the link-local prefix, 49878064Sume * and add it to the prefix list as a never-expire prefix. 49978064Sume * XXX: this change might affect some existing code base... 50078064Sume */ 50178064Sume bzero(&pr0, sizeof(pr0)); 50278064Sume pr0.ndpr_ifp = ifp; 50378064Sume /* this should be 64 at this moment. */ 50478064Sume pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); 50578064Sume pr0.ndpr_prefix = ifra.ifra_addr; 50678064Sume /* apply the mask for safety. (nd6_prelist_add will apply it again) */ 50778064Sume for (i = 0; i < 4; i++) { 50878064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 509120913Sume in6mask64.s6_addr32[i]; 51062587Sitojun } 51178064Sume /* 51278064Sume * Initialize parameters. The link-local prefix must always be 51378064Sume * on-link, and its lifetimes never expire. 51478064Sume */ 51578064Sume pr0.ndpr_raf_onlink = 1; 51678064Sume pr0.ndpr_raf_auto = 1; /* probably meaningless */ 51778064Sume pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; 51878064Sume pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; 51978064Sume /* 52078064Sume * Since there is no other link-local addresses, nd6_prefix_lookup() 52178064Sume * probably returns NULL. However, we cannot always expect the result. 52278064Sume * For example, if we first remove the (only) existing link-local 52378064Sume * address, and then reconfigure another one, the prefix is still 52478064Sume * valid with referring to the old link-local address. 52578064Sume */ 52678064Sume if (nd6_prefix_lookup(&pr0) == NULL) { 52778064Sume if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) 528120856Sume return (error); 52978064Sume } 53062587Sitojun 53162587Sitojun return 0; 53262587Sitojun} 53362587Sitojun 534171259Sdelphij/* 535171259Sdelphij * ifp - must be IFT_LOOP 536171259Sdelphij */ 53762587Sitojunstatic int 538171259Sdelphijin6_ifattach_loopback(struct ifnet *ifp) 53962587Sitojun{ 54078064Sume struct in6_aliasreq ifra; 54178064Sume int error; 54262587Sitojun 54378064Sume bzero(&ifra, sizeof(ifra)); 54478064Sume 54562587Sitojun /* 54678064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 54778064Sume * for safety. 54862587Sitojun */ 54978064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 55062587Sitojun 55178064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 55278064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 55378064Sume ifra.ifra_prefixmask.sin6_addr = in6mask128; 55462587Sitojun 55562587Sitojun /* 55662587Sitojun * Always initialize ia_dstaddr (= broadcast address) to loopback 55778064Sume * address. Follows IPv4 practice - see in_ifinit(). 55862587Sitojun */ 55978064Sume ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 56078064Sume ifra.ifra_dstaddr.sin6_family = AF_INET6; 56178064Sume ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; 56262587Sitojun 56378064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 56478064Sume ifra.ifra_addr.sin6_family = AF_INET6; 56578064Sume ifra.ifra_addr.sin6_addr = in6addr_loopback; 56662587Sitojun 56778064Sume /* the loopback address should NEVER expire. */ 56878064Sume ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 56978064Sume ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 57062587Sitojun 57195023Ssuz /* we don't need to perform DAD on loopback interfaces. */ 57278064Sume ifra.ifra_flags |= IN6_IFF_NODAD; 57378064Sume 57478064Sume /* skip registration to the prefix list. XXX should be temporary. */ 57578064Sume ifra.ifra_flags |= IN6_IFF_NOPFX; 57678064Sume 57778064Sume /* 57895023Ssuz * We are sure that this is a newly assigned address, so we can set 57995023Ssuz * NULL to the 3rd arg. 58078064Sume */ 581151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) { 582151465Ssuz nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " 58378064Sume "the loopback address on %s (errno=%d)\n", 584151465Ssuz if_name(ifp), error)); 585120856Sume return (-1); 58662587Sitojun } 58762587Sitojun 58862587Sitojun return 0; 58962587Sitojun} 59062587Sitojun 59162587Sitojun/* 59262587Sitojun * compute NI group address, based on the current hostname setting. 59362587Sitojun * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later). 59462587Sitojun * 59562587Sitojun * when ifp == NULL, the caller is responsible for filling scopeid. 59662587Sitojun */ 59778064Sumeint 598171259Sdelphijin6_nigroup(struct ifnet *ifp, const char *name, int namelen, 599171259Sdelphij struct in6_addr *in6) 60062587Sitojun{ 60162587Sitojun const char *p; 60278064Sume u_char *q; 60362587Sitojun MD5_CTX ctxt; 60462587Sitojun u_int8_t digest[16]; 60562587Sitojun char l; 60678064Sume char n[64]; /* a single label must not exceed 63 chars */ 60762587Sitojun 60862587Sitojun if (!namelen || !name) 60962587Sitojun return -1; 61062587Sitojun 61162587Sitojun p = name; 61262587Sitojun while (p && *p && *p != '.' && p - name < namelen) 61362587Sitojun p++; 61478064Sume if (p - name > sizeof(n) - 1) 61595023Ssuz return -1; /* label too long */ 61662587Sitojun l = p - name; 61778064Sume strncpy(n, name, l); 61878064Sume n[(int)l] = '\0'; 61978064Sume for (q = n; *q; q++) { 62078064Sume if ('A' <= *q && *q <= 'Z') 62178064Sume *q = *q - 'A' + 'a'; 62278064Sume } 62362587Sitojun 62462587Sitojun /* generate 8 bytes of pseudo-random value. */ 62562587Sitojun bzero(&ctxt, sizeof(ctxt)); 62662587Sitojun MD5Init(&ctxt); 62762587Sitojun MD5Update(&ctxt, &l, sizeof(l)); 62878064Sume MD5Update(&ctxt, n, l); 62962587Sitojun MD5Final(digest, &ctxt); 63062587Sitojun 63162587Sitojun bzero(in6, sizeof(*in6)); 632151465Ssuz in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL; 63362587Sitojun in6->s6_addr8[11] = 2; 63462587Sitojun bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3])); 635148385Sume if (in6_setscope(in6, ifp, NULL)) 636148385Sume return (-1); /* XXX: should not fail */ 63762587Sitojun 63862587Sitojun return 0; 63962587Sitojun} 64062587Sitojun 64162587Sitojun/* 64262587Sitojun * XXX multiple loopback interface needs more care. for instance, 64362587Sitojun * nodelocal address needs to be configured onto only one of them. 64462587Sitojun * XXX multiple link-local address case 645171259Sdelphij * 646171259Sdelphij * altifp - secondary EUI64 source 64762587Sitojun */ 64862587Sitojunvoid 649171259Sdelphijin6_ifattach(struct ifnet *ifp, struct ifnet *altifp) 65062587Sitojun{ 65162587Sitojun struct in6_ifaddr *ia; 65262587Sitojun struct in6_addr in6; 65362587Sitojun 65478064Sume /* some of the interfaces are inherently not IPv6 capable */ 65578064Sume switch (ifp->if_type) { 656126263Smlaier case IFT_PFLOG: 657126263Smlaier case IFT_PFSYNC: 658142215Sglebius case IFT_CARP: 65978064Sume return; 66078064Sume } 66178064Sume 66253541Sshin /* 66362587Sitojun * quirks based on interface type 66453541Sshin */ 66562587Sitojun switch (ifp->if_type) { 66662587Sitojun#ifdef IFT_STF 66762587Sitojun case IFT_STF: 66862587Sitojun /* 66995023Ssuz * 6to4 interface is a very special kind of beast. 67095023Ssuz * no multicast, no linklocal. RFC2529 specifies how to make 67195023Ssuz * linklocals for 6to4 interface, but there's no use and 67295023Ssuz * it is rather harmful to have one. 67362587Sitojun */ 67462587Sitojun goto statinit; 67562587Sitojun#endif 67662587Sitojun default: 67762587Sitojun break; 67853541Sshin } 67953541Sshin 68053541Sshin /* 68162587Sitojun * usually, we require multicast capability to the interface 68253541Sshin */ 68362587Sitojun if ((ifp->if_flags & IFF_MULTICAST) == 0) { 684151465Ssuz nd6log((LOG_INFO, "in6_ifattach: " 68578064Sume "%s is not multicast capable, IPv6 not enabled\n", 686151465Ssuz if_name(ifp))); 68762587Sitojun return; 68862587Sitojun } 68962587Sitojun 69053541Sshin /* 69178064Sume * assign loopback address for loopback interface. 69278064Sume * XXX multiple loopback interface case. 69353541Sshin */ 69478064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 69578064Sume in6 = in6addr_loopback; 69662587Sitojun if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { 69762587Sitojun if (in6_ifattach_loopback(ifp) != 0) 69862587Sitojun return; 69962587Sitojun } 70062587Sitojun } 70153541Sshin 70253541Sshin /* 703120913Sume * assign a link-local address, if there's none. 70453541Sshin */ 705181803Sbz if (V_ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) { 70678064Sume ia = in6ifa_ifpforlinklocal(ifp, 0); 70778064Sume if (ia == NULL) { 70878064Sume if (in6_ifattach_linklocal(ifp, altifp) == 0) { 70978064Sume /* linklocal address assigned */ 71078064Sume } else { 71178064Sume /* failed to assign linklocal address. bark? */ 71262587Sitojun } 71362587Sitojun } 71453541Sshin } 71553541Sshin 71678064Sume#ifdef IFT_STF /* XXX */ 717120913Sumestatinit: 71878064Sume#endif 71962587Sitojun 72053541Sshin /* update dynamically. */ 721181803Sbz if (V_in6_maxmtu < ifp->if_mtu) 722181803Sbz V_in6_maxmtu = ifp->if_mtu; 72353541Sshin} 72453541Sshin 72562587Sitojun/* 72662587Sitojun * NOTE: in6_ifdetach() does not support loopback if at this moment. 72778064Sume * We don't need this function in bsdi, because interfaces are never removed 72878064Sume * from the ifnet list in bsdi. 72962587Sitojun */ 73053541Sshinvoid 731171259Sdelphijin6_ifdetach(struct ifnet *ifp) 73253541Sshin{ 73353541Sshin struct in6_ifaddr *ia, *oia; 73462587Sitojun struct ifaddr *ifa, *next; 73553541Sshin struct rtentry *rt; 73653541Sshin short rtflags; 73762587Sitojun struct sockaddr_in6 sin6; 738170202Sjinmei struct in6_multi_mship *imm; 73953541Sshin 74062587Sitojun /* remove neighbor management table */ 74162587Sitojun nd6_purge(ifp); 74262587Sitojun 74362587Sitojun /* nuke any of IPv6 addresses we have */ 744120913Sume for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 74562587Sitojun next = ifa->ifa_list.tqe_next; 74662587Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 74762587Sitojun continue; 74878064Sume in6_purgeaddr(ifa); 74962587Sitojun } 75062587Sitojun 75162587Sitojun /* undo everything done by in6_ifattach(), just in case */ 752120913Sume for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 75362587Sitojun next = ifa->ifa_list.tqe_next; 75462587Sitojun 75553541Sshin if (ifa->ifa_addr->sa_family != AF_INET6 75653541Sshin || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 75753541Sshin continue; 75853541Sshin } 75953541Sshin 76053541Sshin ia = (struct in6_ifaddr *)ifa; 76153541Sshin 762170202Sjinmei /* 763170202Sjinmei * leave from multicast groups we have joined for the interface 764170202Sjinmei */ 765170202Sjinmei while ((imm = ia->ia6_memberships.lh_first) != NULL) { 766170202Sjinmei LIST_REMOVE(imm, i6mm_chain); 767170202Sjinmei in6_leavegroup(imm); 768170202Sjinmei } 769170202Sjinmei 77053541Sshin /* remove from the routing table */ 771120913Sume if ((ia->ia_flags & IFA_ROUTE) && 772120913Sume (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { 77353541Sshin rtflags = rt->rt_flags; 77453541Sshin rtfree(rt); 775120913Sume rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr, 776120913Sume (struct sockaddr *)&ia->ia_addr, 777120913Sume (struct sockaddr *)&ia->ia_prefixmask, 778120913Sume rtflags, (struct rtentry **)0); 77953541Sshin } 78053541Sshin 78153541Sshin /* remove from the linked list */ 78253541Sshin TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 78362587Sitojun IFAFREE(&ia->ia_ifa); 78453541Sshin 78553541Sshin /* also remove from the IPv6 address chain(itojun&jinmei) */ 78653541Sshin oia = ia; 787181803Sbz if (oia == (ia = V_in6_ifaddr)) 788181803Sbz V_in6_ifaddr = ia->ia_next; 78953541Sshin else { 79053541Sshin while (ia->ia_next && (ia->ia_next != oia)) 79153541Sshin ia = ia->ia_next; 79253541Sshin if (ia->ia_next) 79353541Sshin ia->ia_next = oia->ia_next; 79478064Sume else { 795120913Sume nd6log((LOG_ERR, 796120913Sume "%s: didn't unlink in6ifaddr from list\n", 797120913Sume if_name(ifp))); 79878064Sume } 79953541Sshin } 80053541Sshin 80162587Sitojun IFAFREE(&oia->ia_ifa); 80253541Sshin } 80362587Sitojun 804181803Sbz in6_pcbpurgeif0(&V_udbinfo, ifp); 805181803Sbz in6_pcbpurgeif0(&V_ripcbinfo, ifp); 806170613Sbms /* leave from all multicast groups joined */ 807170613Sbms in6_purgemaddrs(ifp); 808120913Sume 80978064Sume /* 81078064Sume * remove neighbor management table. we call it twice just to make 81178064Sume * sure we nuke everything. maybe we need just one call. 81278064Sume * XXX: since the first call did not release addresses, some prefixes 81378064Sume * might remain. We should call nd6_purge() again to release the 81478064Sume * prefixes after removing all addresses above. 81578064Sume * (Or can we just delay calling nd6_purge until at this point?) 81678064Sume */ 81762587Sitojun nd6_purge(ifp); 81862587Sitojun 81962587Sitojun /* remove route to link-local allnodes multicast (ff02::1) */ 82062587Sitojun bzero(&sin6, sizeof(sin6)); 82162587Sitojun sin6.sin6_len = sizeof(struct sockaddr_in6); 82262587Sitojun sin6.sin6_family = AF_INET6; 82362587Sitojun sin6.sin6_addr = in6addr_linklocal_allnodes; 824148385Sume if (in6_setscope(&sin6.sin6_addr, ifp, NULL)) 825148385Sume /* XXX: should not fail */ 826148385Sume return; 827121770Ssam /* XXX grab lock first to avoid LOR */ 828181803Sbz if (V_rt_tables[0][AF_INET6] != NULL) { 829181803Sbz RADIX_NODE_HEAD_LOCK(V_rt_tables[0][AF_INET6]); 830124333Struckman rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 831124333Struckman if (rt) { 832124333Struckman if (rt->rt_ifp == ifp) 833124333Struckman rtexpunge(rt); 834124333Struckman RTFREE_LOCKED(rt); 835124333Struckman } 836181803Sbz RADIX_NODE_HEAD_UNLOCK(V_rt_tables[0][AF_INET6]); 83762587Sitojun } 83853541Sshin} 83978064Sume 840151539Ssuzint 841171259Sdelphijin6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf, 842171259Sdelphij const u_int8_t *baseid, int generate) 84378064Sume{ 84478064Sume u_int8_t nullbuf[8]; 845121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 84678064Sume 84778064Sume bzero(nullbuf, sizeof(nullbuf)); 84878064Sume if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { 84978064Sume /* we've never created a random ID. Create a new one. */ 85078064Sume generate = 1; 85178064Sume } 85278064Sume 85378064Sume if (generate) { 85478064Sume bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); 85578064Sume 85678064Sume /* generate_tmp_ifid will update seedn and buf */ 85778064Sume (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, 858120913Sume ndi->randomid); 85978064Sume } 86078064Sume bcopy(ndi->randomid, retbuf, 8); 861151539Ssuz 862151539Ssuz return (0); 86378064Sume} 86478064Sume 86578064Sumevoid 866171259Sdelphijin6_tmpaddrtimer(void *ignored_arg) 86778064Sume{ 86878064Sume struct nd_ifinfo *ndi; 86978064Sume u_int8_t nullbuf[8]; 870121161Sume struct ifnet *ifp; 87178064Sume 872181803Sbz callout_reset(&V_in6_tmpaddrtimer_ch, 873181803Sbz (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor - 874181803Sbz V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL); 87578064Sume 87678064Sume bzero(nullbuf, sizeof(nullbuf)); 877181887Sjulian for (ifp = TAILQ_FIRST(&V_ifnet); ifp; 878181888Sjulian ifp = TAILQ_NEXT(ifp, if_list)) { 879121161Sume ndi = ND_IFINFO(ifp); 88078064Sume if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { 88178064Sume /* 88278064Sume * We've been generating a random ID on this interface. 88378064Sume * Create a new one. 88478064Sume */ 88578064Sume (void)generate_tmp_ifid(ndi->randomseed0, 886120913Sume ndi->randomseed1, ndi->randomid); 88778064Sume } 88878064Sume } 88978064Sume 89078064Sume} 891170613Sbms 892170613Sbmsstatic void 893171259Sdelphijin6_purgemaddrs(struct ifnet *ifp) 894170613Sbms{ 895170613Sbms struct in6_multi *in6m; 896170613Sbms struct in6_multi *oin6m; 897170613Sbms 898170613Sbms#ifdef DIAGNOSTIC 899170613Sbms printf("%s: purging ifp %p\n", __func__, ifp); 900170613Sbms#endif 901170613Sbms 902170613Sbms IFF_LOCKGIANT(ifp); 903170613Sbms LIST_FOREACH_SAFE(in6m, &in6_multihead, in6m_entry, oin6m) { 904170613Sbms if (in6m->in6m_ifp == ifp) 905170613Sbms in6_delmulti(in6m); 906170613Sbms } 907170613Sbms IFF_UNLOCKGIANT(ifp); 908170613Sbms} 909