in6_ifattach.c revision 157978
162587Sitojun/* $FreeBSD: head/sys/netinet6/in6_ifattach.c 157978 2006-04-23 15:06:16Z rwatson $ */ 278064Sume/* $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $ */ 362587Sitojun 4139826Simp/*- 553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 653541Sshin * All rights reserved. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms, with or without 953541Sshin * modification, are permitted provided that the following conditions 1053541Sshin * are met: 1153541Sshin * 1. Redistributions of source code must retain the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer. 1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer in the 1553541Sshin * documentation and/or other materials provided with the distribution. 1653541Sshin * 3. Neither the name of the project nor the names of its contributors 1753541Sshin * may be used to endorse or promote products derived from this software 1853541Sshin * without specific prior written permission. 1953541Sshin * 2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2353541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3053541Sshin * SUCH DAMAGE. 3153541Sshin */ 3253541Sshin 3353541Sshin#include <sys/param.h> 3453541Sshin#include <sys/systm.h> 3553541Sshin#include <sys/malloc.h> 3653541Sshin#include <sys/socket.h> 3753541Sshin#include <sys/sockio.h> 3853541Sshin#include <sys/kernel.h> 3978064Sume#include <sys/syslog.h> 4053541Sshin#include <sys/md5.h> 4153541Sshin 4253541Sshin#include <net/if.h> 4353541Sshin#include <net/if_dl.h> 4453541Sshin#include <net/if_types.h> 4553541Sshin#include <net/route.h> 4653541Sshin 4753541Sshin#include <netinet/in.h> 4853541Sshin#include <netinet/in_var.h> 4953541Sshin#include <netinet/if_ether.h> 5081127Sume#include <netinet/in_pcb.h> 5153541Sshin 5262587Sitojun#include <netinet/ip6.h> 5353541Sshin#include <netinet6/ip6_var.h> 5478064Sume#include <netinet6/in6_var.h> 5581127Sume#include <netinet6/in6_pcb.h> 5653541Sshin#include <netinet6/in6_ifattach.h> 5753541Sshin#include <netinet6/ip6_var.h> 5853541Sshin#include <netinet6/nd6.h> 5962587Sitojun#include <netinet6/scope6_var.h> 6053541Sshin 6153541Sshin#include <net/net_osdep.h> 6253541Sshin 6362587Sitojununsigned long in6_maxmtu = 0; 6453541Sshin 6578064Sume#ifdef IP6_AUTO_LINKLOCAL 6678064Sumeint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; 6778064Sume#else 6878064Sumeint ip6_auto_linklocal = 1; /* enable by default */ 6978064Sume#endif 7078064Sume 7178064Sumestruct callout in6_tmpaddrtimer_ch; 7278064Sume 7381127Sumeextern struct inpcbinfo udbinfo; 7481127Sumeextern struct inpcbinfo ripcbinfo; 7581127Sume 7662587Sitojunstatic int get_rand_ifid __P((struct ifnet *, struct in6_addr *)); 7778064Sumestatic int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *)); 7862587Sitojunstatic int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *)); 7962587Sitojunstatic int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *)); 8062587Sitojunstatic int in6_ifattach_loopback __P((struct ifnet *)); 8153541Sshin 8262587Sitojun#define EUI64_GBIT 0x01 8362587Sitojun#define EUI64_UBIT 0x02 8462587Sitojun#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) 8562587Sitojun#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) 8662587Sitojun#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) 8762587Sitojun#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) 8862587Sitojun#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) 8953541Sshin 9062587Sitojun#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) 9162587Sitojun#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) 9253541Sshin 9353541Sshin/* 9453541Sshin * Generate a last-resort interface identifier, when the machine has no 9553541Sshin * IEEE802/EUI64 address sources. 9662587Sitojun * The goal here is to get an interface identifier that is 9762587Sitojun * (1) random enough and (2) does not change across reboot. 9862587Sitojun * We currently use MD5(hostname) for it. 9953541Sshin */ 10053541Sshinstatic int 10162587Sitojunget_rand_ifid(ifp, in6) 10262587Sitojun struct ifnet *ifp; 10395023Ssuz struct in6_addr *in6; /* upper 64bits are preserved */ 10453541Sshin{ 10553541Sshin MD5_CTX ctxt; 10653541Sshin u_int8_t digest[16]; 10753541Sshin int hostnamelen = strlen(hostname); 10853541Sshin 10962587Sitojun#if 0 11062587Sitojun /* we need at least several letters as seed for ifid */ 11162587Sitojun if (hostnamelen < 3) 11262587Sitojun return -1; 11362587Sitojun#endif 11462587Sitojun 11562587Sitojun /* generate 8 bytes of pseudo-random value. */ 11653541Sshin bzero(&ctxt, sizeof(ctxt)); 11753541Sshin MD5Init(&ctxt); 11853541Sshin MD5Update(&ctxt, hostname, hostnamelen); 11953541Sshin MD5Final(digest, &ctxt); 12053541Sshin 12162587Sitojun /* assumes sizeof(digest) > sizeof(ifid) */ 12262587Sitojun bcopy(digest, &in6->s6_addr[8], 8); 12353541Sshin 12453541Sshin /* make sure to set "u" bit to local, and "g" bit to individual. */ 12562587Sitojun in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 12662587Sitojun in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 12753541Sshin 12862587Sitojun /* convert EUI64 into IPv6 interface identifier */ 12962587Sitojun EUI64_TO_IFID(in6); 13062587Sitojun 13153541Sshin return 0; 13253541Sshin} 13353541Sshin 13478064Sumestatic int 13578064Sumegenerate_tmp_ifid(seed0, seed1, ret) 13678064Sume u_int8_t *seed0, *ret; 13778064Sume const u_int8_t *seed1; 13878064Sume{ 13978064Sume MD5_CTX ctxt; 14078064Sume u_int8_t seed[16], digest[16], nullbuf[8]; 14178064Sume u_int32_t val32; 14278064Sume 14378064Sume /* If there's no hisotry, start with a random seed. */ 14478064Sume bzero(nullbuf, sizeof(nullbuf)); 14578064Sume if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { 14678064Sume int i; 14778064Sume 14878064Sume for (i = 0; i < 2; i++) { 149121807Sume val32 = arc4random(); 15078064Sume bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); 15178064Sume } 152120913Sume } else 15378064Sume bcopy(seed0, seed, 8); 15478064Sume 15578064Sume /* copy the right-most 64-bits of the given address */ 15678064Sume /* XXX assumption on the size of IFID */ 15778064Sume bcopy(seed1, &seed[8], 8); 15878064Sume 15978064Sume if (0) { /* for debugging purposes only */ 16078064Sume int i; 16178064Sume 16278064Sume printf("generate_tmp_ifid: new randomized ID from: "); 16378064Sume for (i = 0; i < 16; i++) 16478064Sume printf("%02x", seed[i]); 16578064Sume printf(" "); 16678064Sume } 16778064Sume 16878064Sume /* generate 16 bytes of pseudo-random value. */ 16978064Sume bzero(&ctxt, sizeof(ctxt)); 17078064Sume MD5Init(&ctxt); 17178064Sume MD5Update(&ctxt, seed, sizeof(seed)); 17278064Sume MD5Final(digest, &ctxt); 17378064Sume 17478064Sume /* 17578064Sume * RFC 3041 3.2.1. (3) 17678064Sume * Take the left-most 64-bits of the MD5 digest and set bit 6 (the 17778064Sume * left-most bit is numbered 0) to zero. 17878064Sume */ 17978064Sume bcopy(digest, ret, 8); 18078064Sume ret[0] &= ~EUI64_UBIT; 18178064Sume 18278064Sume /* 18378064Sume * XXX: we'd like to ensure that the generated value is not zero 18478064Sume * for simplicity. If the caclculated digest happens to be zero, 18578064Sume * use a random non-zero value as the last resort. 18678064Sume */ 18778064Sume if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { 188151465Ssuz nd6log((LOG_INFO, 189151465Ssuz "generate_tmp_ifid: computed MD5 value is zero.\n")); 19078064Sume 191121807Sume val32 = arc4random(); 19278064Sume val32 = 1 + (val32 % (0xffffffff - 1)); 19378064Sume } 19478064Sume 19578064Sume /* 19678064Sume * RFC 3041 3.2.1. (4) 19778064Sume * Take the rightmost 64-bits of the MD5 digest and save them in 19878064Sume * stable storage as the history value to be used in the next 199120913Sume * iteration of the algorithm. 20078064Sume */ 20178064Sume bcopy(&digest[8], seed0, 8); 20278064Sume 20378064Sume if (0) { /* for debugging purposes only */ 20478064Sume int i; 20578064Sume 20678064Sume printf("to: "); 20778064Sume for (i = 0; i < 16; i++) 20878064Sume printf("%02x", digest[i]); 20978064Sume printf("\n"); 21078064Sume } 21178064Sume 21278064Sume return 0; 21378064Sume} 21478064Sume 21553541Sshin/* 21662587Sitojun * Get interface identifier for the specified interface. 21762587Sitojun * XXX assumes single sockaddr_dl (AF_LINK address) per an interface 21853541Sshin */ 219151477Ssuzint 220151477Ssuzin6_get_hw_ifid(ifp, in6) 22162587Sitojun struct ifnet *ifp; 22295023Ssuz struct in6_addr *in6; /* upper 64bits are preserved */ 22353541Sshin{ 22453541Sshin struct ifaddr *ifa; 22553541Sshin struct sockaddr_dl *sdl; 22662587Sitojun u_int8_t *addr; 22762587Sitojun size_t addrlen; 22862587Sitojun static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 22962587Sitojun static u_int8_t allone[8] = 23062587Sitojun { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 23153541Sshin 23262587Sitojun for (ifa = ifp->if_addrlist.tqh_first; 23362587Sitojun ifa; 234120913Sume ifa = ifa->ifa_list.tqe_next) { 23562587Sitojun if (ifa->ifa_addr->sa_family != AF_LINK) 23653541Sshin continue; 23762587Sitojun sdl = (struct sockaddr_dl *)ifa->ifa_addr; 23862587Sitojun if (sdl == NULL) 23962587Sitojun continue; 24062587Sitojun if (sdl->sdl_alen == 0) 24162587Sitojun continue; 24262587Sitojun 24362587Sitojun goto found; 24453541Sshin } 24553541Sshin 24662587Sitojun return -1; 24762587Sitojun 24853541Sshinfound: 24962587Sitojun addr = LLADDR(sdl); 25062587Sitojun addrlen = sdl->sdl_alen; 25153541Sshin 25262587Sitojun /* get EUI64 */ 25362587Sitojun switch (ifp->if_type) { 25462587Sitojun case IFT_ETHER: 25562587Sitojun case IFT_FDDI: 256120049Smdodd case IFT_ISO88025: 25762587Sitojun case IFT_ATM: 25878064Sume case IFT_IEEE1394: 25978064Sume#ifdef IFT_IEEE80211 26078064Sume case IFT_IEEE80211: 26178064Sume#endif 26262587Sitojun /* IEEE802/EUI64 cases - what others? */ 26378064Sume /* IEEE1394 uses 16byte length address starting with EUI64 */ 26478064Sume if (addrlen > 8) 26578064Sume addrlen = 8; 26653541Sshin 26762587Sitojun /* look at IEEE802/EUI64 only */ 26862587Sitojun if (addrlen != 8 && addrlen != 6) 26962587Sitojun return -1; 27053541Sshin 27162587Sitojun /* 27262587Sitojun * check for invalid MAC address - on bsdi, we see it a lot 27362587Sitojun * since wildboar configures all-zero MAC on pccard before 27462587Sitojun * card insertion. 27562587Sitojun */ 27662587Sitojun if (bcmp(addr, allzero, addrlen) == 0) 27762587Sitojun return -1; 27862587Sitojun if (bcmp(addr, allone, addrlen) == 0) 27962587Sitojun return -1; 28062587Sitojun 28162587Sitojun /* make EUI64 address */ 28262587Sitojun if (addrlen == 8) 28362587Sitojun bcopy(addr, &in6->s6_addr[8], 8); 28462587Sitojun else if (addrlen == 6) { 28562587Sitojun in6->s6_addr[8] = addr[0]; 28662587Sitojun in6->s6_addr[9] = addr[1]; 28762587Sitojun in6->s6_addr[10] = addr[2]; 28862587Sitojun in6->s6_addr[11] = 0xff; 28962587Sitojun in6->s6_addr[12] = 0xfe; 29062587Sitojun in6->s6_addr[13] = addr[3]; 29162587Sitojun in6->s6_addr[14] = addr[4]; 29262587Sitojun in6->s6_addr[15] = addr[5]; 29362587Sitojun } 29462587Sitojun break; 29562587Sitojun 29662587Sitojun case IFT_ARCNET: 29762587Sitojun if (addrlen != 1) 29862587Sitojun return -1; 29962587Sitojun if (!addr[0]) 30062587Sitojun return -1; 30162587Sitojun 30262587Sitojun bzero(&in6->s6_addr[8], 8); 30362587Sitojun in6->s6_addr[15] = addr[0]; 30462587Sitojun 30562587Sitojun /* 30662587Sitojun * due to insufficient bitwidth, we mark it local. 30762587Sitojun */ 30862587Sitojun in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 30962587Sitojun in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 31062587Sitojun break; 31162587Sitojun 31262587Sitojun case IFT_GIF: 31362587Sitojun#ifdef IFT_STF 31462587Sitojun case IFT_STF: 31553541Sshin#endif 31662587Sitojun /* 31778064Sume * RFC2893 says: "SHOULD use IPv4 address as ifid source". 31862587Sitojun * however, IPv4 address is not very suitable as unique 31962587Sitojun * identifier source (can be renumbered). 32062587Sitojun * we don't do this. 32162587Sitojun */ 32262587Sitojun return -1; 32362587Sitojun 32462587Sitojun default: 32562587Sitojun return -1; 32653541Sshin } 32762587Sitojun 32862587Sitojun /* sanity check: g bit must not indicate "group" */ 32962587Sitojun if (EUI64_GROUP(in6)) 33062587Sitojun return -1; 33162587Sitojun 33262587Sitojun /* convert EUI64 into IPv6 interface identifier */ 33362587Sitojun EUI64_TO_IFID(in6); 33462587Sitojun 33562587Sitojun /* 33662587Sitojun * sanity check: ifid must not be all zero, avoid conflict with 33762587Sitojun * subnet router anycast 33862587Sitojun */ 33962587Sitojun if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && 34062587Sitojun bcmp(&in6->s6_addr[9], allzero, 7) == 0) { 34162587Sitojun return -1; 34262587Sitojun } 34362587Sitojun 34462587Sitojun return 0; 34553541Sshin} 34653541Sshin 34753541Sshin/* 34862587Sitojun * Get interface identifier for the specified interface. If it is not 34962587Sitojun * available on ifp0, borrow interface identifier from other information 35062587Sitojun * sources. 35153541Sshin */ 35262587Sitojunstatic int 35362587Sitojunget_ifid(ifp0, altifp, in6) 35462587Sitojun struct ifnet *ifp0; 35595023Ssuz struct ifnet *altifp; /* secondary EUI64 source */ 35662587Sitojun struct in6_addr *in6; 35753541Sshin{ 35853541Sshin struct ifnet *ifp; 35953541Sshin 36062587Sitojun /* first, try to get it from the interface itself */ 361151477Ssuz if (in6_get_hw_ifid(ifp0, in6) == 0) { 36278064Sume nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", 36378064Sume if_name(ifp0))); 36462587Sitojun goto success; 36562587Sitojun } 36653541Sshin 36762587Sitojun /* try secondary EUI64 source. this basically is for ATM PVC */ 368151477Ssuz if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { 36978064Sume nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", 37078064Sume if_name(ifp0), if_name(altifp))); 37162587Sitojun goto success; 37262587Sitojun } 37362587Sitojun 37462587Sitojun /* next, try to get it from some other hardware interface */ 375108172Shsu IFNET_RLOCK(); 376120913Sume for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { 37762587Sitojun if (ifp == ifp0) 37862587Sitojun continue; 379151477Ssuz if (in6_get_hw_ifid(ifp, in6) != 0) 38062587Sitojun continue; 38162587Sitojun 38262587Sitojun /* 38362587Sitojun * to borrow ifid from other interface, ifid needs to be 38462587Sitojun * globally unique 38562587Sitojun */ 38662587Sitojun if (IFID_UNIVERSAL(in6)) { 38778064Sume nd6log((LOG_DEBUG, 38878064Sume "%s: borrow interface identifier from %s\n", 38978064Sume if_name(ifp0), if_name(ifp))); 390108172Shsu IFNET_RUNLOCK(); 39162587Sitojun goto success; 39262587Sitojun } 39362587Sitojun } 394108172Shsu IFNET_RUNLOCK(); 39562587Sitojun 39662587Sitojun /* last resort: get from random number source */ 39762587Sitojun if (get_rand_ifid(ifp, in6) == 0) { 39878064Sume nd6log((LOG_DEBUG, 39978064Sume "%s: interface identifier generated by random number\n", 40078064Sume if_name(ifp0))); 40162587Sitojun goto success; 40262587Sitojun } 40362587Sitojun 40466504Sitojun printf("%s: failed to get interface identifier\n", if_name(ifp0)); 40562587Sitojun return -1; 40662587Sitojun 40762587Sitojunsuccess: 408120913Sume nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 409120913Sume if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10], 410120913Sume in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13], 411120913Sume in6->s6_addr[14], in6->s6_addr[15])); 41262587Sitojun return 0; 41362587Sitojun} 41462587Sitojun 41562587Sitojunstatic int 41678064Sumein6_ifattach_linklocal(ifp, altifp) 41762587Sitojun struct ifnet *ifp; 41878064Sume struct ifnet *altifp; /* secondary EUI64 source */ 41978064Sume{ 42062587Sitojun struct in6_ifaddr *ia; 42178064Sume struct in6_aliasreq ifra; 422151539Ssuz struct nd_prefixctl pr0; 42378064Sume int i, error; 42462587Sitojun 42562587Sitojun /* 42678064Sume * configure link-local address. 42762587Sitojun */ 42878064Sume bzero(&ifra, sizeof(ifra)); 42962587Sitojun 43062587Sitojun /* 43178064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 43278064Sume * for safety. 43362587Sitojun */ 43478064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 43562587Sitojun 43678064Sume ifra.ifra_addr.sin6_family = AF_INET6; 43778064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 438148385Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000); 43978064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; 44078064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 44178064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; 44278064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); 44378064Sume } else { 44478064Sume if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { 44578064Sume nd6log((LOG_ERR, 44678064Sume "%s: no ifid available\n", if_name(ifp))); 447120913Sume return (-1); 44862587Sitojun } 44962587Sitojun } 450148385Sume if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) 451148385Sume return (-1); 45262587Sitojun 45378064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 45478064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 45578064Sume ifra.ifra_prefixmask.sin6_addr = in6mask64; 45678064Sume /* link-local addresses should NEVER expire. */ 45778064Sume ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 45878064Sume ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 45962587Sitojun 46078064Sume /* 46178064Sume * Now call in6_update_ifa() to do a bunch of procedures to configure 462151465Ssuz * a link-local address. We can set the 3rd argument to NULL, because 46395023Ssuz * we know there's no other link-local address on the interface 46495023Ssuz * and therefore we are adding one (instead of updating one). 46578064Sume */ 466151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, 467151539Ssuz IN6_IFAUPDATE_DADDELAY)) != 0) { 46862587Sitojun /* 46978064Sume * XXX: When the interface does not support IPv6, this call 47078064Sume * would fail in the SIOCSIFADDR ioctl. I believe the 47178064Sume * notification is rather confusing in this case, so just 472120913Sume * suppress it. (jinmei@kame.net 20010130) 47362587Sitojun */ 47478064Sume if (error != EAFNOSUPPORT) 475151465Ssuz nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to " 47678064Sume "configure a link-local address on %s " 47778064Sume "(errno=%d)\n", 478151465Ssuz if_name(ifp), error)); 479120856Sume return (-1); 48062587Sitojun } 48162587Sitojun 48278064Sume ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ 48378064Sume#ifdef DIAGNOSTIC 48478064Sume if (!ia) { 48578064Sume panic("ia == NULL in in6_ifattach_linklocal"); 48695023Ssuz /* NOTREACHED */ 48778064Sume } 48862587Sitojun#endif 48953541Sshin 49078064Sume /* 491120913Sume * Make the link-local prefix (fe80::%link/64) as on-link. 49278064Sume * Since we'd like to manage prefixes separately from addresses, 49378064Sume * we make an ND6 prefix structure for the link-local prefix, 49478064Sume * and add it to the prefix list as a never-expire prefix. 49578064Sume * XXX: this change might affect some existing code base... 49678064Sume */ 49778064Sume bzero(&pr0, sizeof(pr0)); 49878064Sume pr0.ndpr_ifp = ifp; 49978064Sume /* this should be 64 at this moment. */ 50078064Sume pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); 50178064Sume pr0.ndpr_prefix = ifra.ifra_addr; 50278064Sume /* apply the mask for safety. (nd6_prelist_add will apply it again) */ 50378064Sume for (i = 0; i < 4; i++) { 50478064Sume pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 505120913Sume in6mask64.s6_addr32[i]; 50662587Sitojun } 50778064Sume /* 50878064Sume * Initialize parameters. The link-local prefix must always be 50978064Sume * on-link, and its lifetimes never expire. 51078064Sume */ 51178064Sume pr0.ndpr_raf_onlink = 1; 51278064Sume pr0.ndpr_raf_auto = 1; /* probably meaningless */ 51378064Sume pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; 51478064Sume pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; 51578064Sume /* 51678064Sume * Since there is no other link-local addresses, nd6_prefix_lookup() 51778064Sume * probably returns NULL. However, we cannot always expect the result. 51878064Sume * For example, if we first remove the (only) existing link-local 51978064Sume * address, and then reconfigure another one, the prefix is still 52078064Sume * valid with referring to the old link-local address. 52178064Sume */ 52278064Sume if (nd6_prefix_lookup(&pr0) == NULL) { 52378064Sume if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) 524120856Sume return (error); 52578064Sume } 52662587Sitojun 52762587Sitojun return 0; 52862587Sitojun} 52962587Sitojun 53062587Sitojunstatic int 53162587Sitojunin6_ifattach_loopback(ifp) 53262587Sitojun struct ifnet *ifp; /* must be IFT_LOOP */ 53362587Sitojun{ 53478064Sume struct in6_aliasreq ifra; 53578064Sume int error; 53662587Sitojun 53778064Sume bzero(&ifra, sizeof(ifra)); 53878064Sume 53962587Sitojun /* 54078064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 54178064Sume * for safety. 54262587Sitojun */ 54378064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 54462587Sitojun 54578064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 54678064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 54778064Sume ifra.ifra_prefixmask.sin6_addr = in6mask128; 54862587Sitojun 54962587Sitojun /* 55062587Sitojun * Always initialize ia_dstaddr (= broadcast address) to loopback 55178064Sume * address. Follows IPv4 practice - see in_ifinit(). 55262587Sitojun */ 55378064Sume ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 55478064Sume ifra.ifra_dstaddr.sin6_family = AF_INET6; 55578064Sume ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; 55662587Sitojun 55778064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 55878064Sume ifra.ifra_addr.sin6_family = AF_INET6; 55978064Sume ifra.ifra_addr.sin6_addr = in6addr_loopback; 56062587Sitojun 56178064Sume /* the loopback address should NEVER expire. */ 56278064Sume ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 56378064Sume ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 56462587Sitojun 56595023Ssuz /* we don't need to perform DAD on loopback interfaces. */ 56678064Sume ifra.ifra_flags |= IN6_IFF_NODAD; 56778064Sume 56878064Sume /* skip registration to the prefix list. XXX should be temporary. */ 56978064Sume ifra.ifra_flags |= IN6_IFF_NOPFX; 57078064Sume 57178064Sume /* 57295023Ssuz * We are sure that this is a newly assigned address, so we can set 57395023Ssuz * NULL to the 3rd arg. 57478064Sume */ 575151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) { 576151465Ssuz nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " 57778064Sume "the loopback address on %s (errno=%d)\n", 578151465Ssuz if_name(ifp), error)); 579120856Sume return (-1); 58062587Sitojun } 58162587Sitojun 58262587Sitojun return 0; 58362587Sitojun} 58462587Sitojun 58562587Sitojun/* 58662587Sitojun * compute NI group address, based on the current hostname setting. 58762587Sitojun * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later). 58862587Sitojun * 58962587Sitojun * when ifp == NULL, the caller is responsible for filling scopeid. 59062587Sitojun */ 59178064Sumeint 59278064Sumein6_nigroup(ifp, name, namelen, in6) 59362587Sitojun struct ifnet *ifp; 59462587Sitojun const char *name; 59562587Sitojun int namelen; 59662587Sitojun struct in6_addr *in6; 59762587Sitojun{ 59862587Sitojun const char *p; 59978064Sume u_char *q; 60062587Sitojun MD5_CTX ctxt; 60162587Sitojun u_int8_t digest[16]; 60262587Sitojun char l; 60378064Sume char n[64]; /* a single label must not exceed 63 chars */ 60462587Sitojun 60562587Sitojun if (!namelen || !name) 60662587Sitojun return -1; 60762587Sitojun 60862587Sitojun p = name; 60962587Sitojun while (p && *p && *p != '.' && p - name < namelen) 61062587Sitojun p++; 61178064Sume if (p - name > sizeof(n) - 1) 61295023Ssuz return -1; /* label too long */ 61362587Sitojun l = p - name; 61478064Sume strncpy(n, name, l); 61578064Sume n[(int)l] = '\0'; 61678064Sume for (q = n; *q; q++) { 61778064Sume if ('A' <= *q && *q <= 'Z') 61878064Sume *q = *q - 'A' + 'a'; 61978064Sume } 62062587Sitojun 62162587Sitojun /* generate 8 bytes of pseudo-random value. */ 62262587Sitojun bzero(&ctxt, sizeof(ctxt)); 62362587Sitojun MD5Init(&ctxt); 62462587Sitojun MD5Update(&ctxt, &l, sizeof(l)); 62578064Sume MD5Update(&ctxt, n, l); 62662587Sitojun MD5Final(digest, &ctxt); 62762587Sitojun 62862587Sitojun bzero(in6, sizeof(*in6)); 629151465Ssuz in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL; 63062587Sitojun in6->s6_addr8[11] = 2; 63162587Sitojun bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3])); 632148385Sume if (in6_setscope(in6, ifp, NULL)) 633148385Sume return (-1); /* XXX: should not fail */ 63462587Sitojun 63562587Sitojun return 0; 63662587Sitojun} 63762587Sitojun 63862587Sitojun/* 63962587Sitojun * XXX multiple loopback interface needs more care. for instance, 64062587Sitojun * nodelocal address needs to be configured onto only one of them. 64162587Sitojun * XXX multiple link-local address case 64262587Sitojun */ 64362587Sitojunvoid 64462587Sitojunin6_ifattach(ifp, altifp) 64562587Sitojun struct ifnet *ifp; 64662587Sitojun struct ifnet *altifp; /* secondary EUI64 source */ 64762587Sitojun{ 64862587Sitojun struct in6_ifaddr *ia; 64962587Sitojun struct in6_addr in6; 65062587Sitojun 65178064Sume /* some of the interfaces are inherently not IPv6 capable */ 65278064Sume switch (ifp->if_type) { 653126263Smlaier case IFT_PFLOG: 654126263Smlaier case IFT_PFSYNC: 655142215Sglebius case IFT_CARP: 65678064Sume return; 65778064Sume } 65878064Sume 65953541Sshin /* 66062587Sitojun * quirks based on interface type 66153541Sshin */ 66262587Sitojun switch (ifp->if_type) { 66362587Sitojun#ifdef IFT_STF 66462587Sitojun case IFT_STF: 66562587Sitojun /* 66695023Ssuz * 6to4 interface is a very special kind of beast. 66795023Ssuz * no multicast, no linklocal. RFC2529 specifies how to make 66895023Ssuz * linklocals for 6to4 interface, but there's no use and 66995023Ssuz * it is rather harmful to have one. 67062587Sitojun */ 67162587Sitojun goto statinit; 67262587Sitojun#endif 67362587Sitojun default: 67462587Sitojun break; 67553541Sshin } 67653541Sshin 67753541Sshin /* 67862587Sitojun * usually, we require multicast capability to the interface 67953541Sshin */ 68062587Sitojun if ((ifp->if_flags & IFF_MULTICAST) == 0) { 681151465Ssuz nd6log((LOG_INFO, "in6_ifattach: " 68278064Sume "%s is not multicast capable, IPv6 not enabled\n", 683151465Ssuz if_name(ifp))); 68462587Sitojun return; 68562587Sitojun } 68662587Sitojun 68753541Sshin /* 68878064Sume * assign loopback address for loopback interface. 68978064Sume * XXX multiple loopback interface case. 69053541Sshin */ 69178064Sume if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 69278064Sume in6 = in6addr_loopback; 69362587Sitojun if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { 69462587Sitojun if (in6_ifattach_loopback(ifp) != 0) 69562587Sitojun return; 69662587Sitojun } 69762587Sitojun } 69853541Sshin 69953541Sshin /* 700120913Sume * assign a link-local address, if there's none. 70153541Sshin */ 702149829Sthompsa if (ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) { 70378064Sume ia = in6ifa_ifpforlinklocal(ifp, 0); 70478064Sume if (ia == NULL) { 70578064Sume if (in6_ifattach_linklocal(ifp, altifp) == 0) { 70678064Sume /* linklocal address assigned */ 70778064Sume } else { 70878064Sume /* failed to assign linklocal address. bark? */ 70962587Sitojun } 71062587Sitojun } 71153541Sshin } 71253541Sshin 71378064Sume#ifdef IFT_STF /* XXX */ 714120913Sumestatinit: 71578064Sume#endif 71662587Sitojun 71753541Sshin /* update dynamically. */ 71853541Sshin if (in6_maxmtu < ifp->if_mtu) 71953541Sshin in6_maxmtu = ifp->if_mtu; 72053541Sshin} 72153541Sshin 72262587Sitojun/* 72362587Sitojun * NOTE: in6_ifdetach() does not support loopback if at this moment. 72478064Sume * We don't need this function in bsdi, because interfaces are never removed 72578064Sume * from the ifnet list in bsdi. 72662587Sitojun */ 72753541Sshinvoid 72853541Sshinin6_ifdetach(ifp) 72953541Sshin struct ifnet *ifp; 73053541Sshin{ 73153541Sshin struct in6_ifaddr *ia, *oia; 73262587Sitojun struct ifaddr *ifa, *next; 73353541Sshin struct rtentry *rt; 73453541Sshin short rtflags; 73562587Sitojun struct sockaddr_in6 sin6; 73662587Sitojun struct in6_multi *in6m; 73762587Sitojun struct in6_multi *in6m_next; 73853541Sshin 73962587Sitojun /* remove neighbor management table */ 74062587Sitojun nd6_purge(ifp); 74162587Sitojun 74262587Sitojun /* nuke any of IPv6 addresses we have */ 743120913Sume for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 74462587Sitojun next = ifa->ifa_list.tqe_next; 74562587Sitojun if (ifa->ifa_addr->sa_family != AF_INET6) 74662587Sitojun continue; 74778064Sume in6_purgeaddr(ifa); 74862587Sitojun } 74962587Sitojun 75062587Sitojun /* undo everything done by in6_ifattach(), just in case */ 751120913Sume for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 75262587Sitojun next = ifa->ifa_list.tqe_next; 75362587Sitojun 75453541Sshin if (ifa->ifa_addr->sa_family != AF_INET6 75553541Sshin || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 75653541Sshin continue; 75753541Sshin } 75853541Sshin 75953541Sshin ia = (struct in6_ifaddr *)ifa; 76053541Sshin 76153541Sshin /* remove from the routing table */ 762120913Sume if ((ia->ia_flags & IFA_ROUTE) && 763120913Sume (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { 76453541Sshin rtflags = rt->rt_flags; 76553541Sshin rtfree(rt); 766120913Sume rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr, 767120913Sume (struct sockaddr *)&ia->ia_addr, 768120913Sume (struct sockaddr *)&ia->ia_prefixmask, 769120913Sume rtflags, (struct rtentry **)0); 77053541Sshin } 77153541Sshin 77253541Sshin /* remove from the linked list */ 77353541Sshin TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 77462587Sitojun IFAFREE(&ia->ia_ifa); 77553541Sshin 77653541Sshin /* also remove from the IPv6 address chain(itojun&jinmei) */ 77753541Sshin oia = ia; 77853541Sshin if (oia == (ia = in6_ifaddr)) 77953541Sshin in6_ifaddr = ia->ia_next; 78053541Sshin else { 78153541Sshin while (ia->ia_next && (ia->ia_next != oia)) 78253541Sshin ia = ia->ia_next; 78353541Sshin if (ia->ia_next) 78453541Sshin ia->ia_next = oia->ia_next; 78578064Sume else { 786120913Sume nd6log((LOG_ERR, 787120913Sume "%s: didn't unlink in6ifaddr from list\n", 788120913Sume if_name(ifp))); 78978064Sume } 79053541Sshin } 79153541Sshin 79262587Sitojun IFAFREE(&oia->ia_ifa); 79353541Sshin } 79462587Sitojun 79562587Sitojun /* leave from all multicast groups joined */ 796120913Sume 797157978Srwatson in6_pcbpurgeif0(&udbinfo, ifp); 798157978Srwatson in6_pcbpurgeif0(&ripcbinfo, ifp); 799120913Sume 80062587Sitojun for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) { 80162587Sitojun in6m_next = LIST_NEXT(in6m, in6m_entry); 80262587Sitojun if (in6m->in6m_ifp != ifp) 80362587Sitojun continue; 80462587Sitojun in6_delmulti(in6m); 80562587Sitojun in6m = NULL; 80662587Sitojun } 80762587Sitojun 80878064Sume /* 80978064Sume * remove neighbor management table. we call it twice just to make 81078064Sume * sure we nuke everything. maybe we need just one call. 81178064Sume * XXX: since the first call did not release addresses, some prefixes 81278064Sume * might remain. We should call nd6_purge() again to release the 81378064Sume * prefixes after removing all addresses above. 81478064Sume * (Or can we just delay calling nd6_purge until at this point?) 81578064Sume */ 81662587Sitojun nd6_purge(ifp); 81762587Sitojun 81862587Sitojun /* remove route to link-local allnodes multicast (ff02::1) */ 81962587Sitojun bzero(&sin6, sizeof(sin6)); 82062587Sitojun sin6.sin6_len = sizeof(struct sockaddr_in6); 82162587Sitojun sin6.sin6_family = AF_INET6; 82262587Sitojun sin6.sin6_addr = in6addr_linklocal_allnodes; 823148385Sume if (in6_setscope(&sin6.sin6_addr, ifp, NULL)) 824148385Sume /* XXX: should not fail */ 825148385Sume return; 826121770Ssam /* XXX grab lock first to avoid LOR */ 827124333Struckman if (rt_tables[AF_INET6] != NULL) { 828124333Struckman RADIX_NODE_HEAD_LOCK(rt_tables[AF_INET6]); 829124333Struckman rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 830124333Struckman if (rt) { 831124333Struckman if (rt->rt_ifp == ifp) 832124333Struckman rtexpunge(rt); 833124333Struckman RTFREE_LOCKED(rt); 834124333Struckman } 835124333Struckman RADIX_NODE_HEAD_UNLOCK(rt_tables[AF_INET6]); 83662587Sitojun } 83753541Sshin} 83878064Sume 839151539Ssuzint 84078064Sumein6_get_tmpifid(ifp, retbuf, baseid, generate) 84178064Sume struct ifnet *ifp; 84278064Sume u_int8_t *retbuf; 84378064Sume const u_int8_t *baseid; 84478064Sume int generate; 84578064Sume{ 84678064Sume u_int8_t nullbuf[8]; 847121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 84878064Sume 84978064Sume bzero(nullbuf, sizeof(nullbuf)); 85078064Sume if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { 85178064Sume /* we've never created a random ID. Create a new one. */ 85278064Sume generate = 1; 85378064Sume } 85478064Sume 85578064Sume if (generate) { 85678064Sume bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); 85778064Sume 85878064Sume /* generate_tmp_ifid will update seedn and buf */ 85978064Sume (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, 860120913Sume ndi->randomid); 86178064Sume } 86278064Sume bcopy(ndi->randomid, retbuf, 8); 863151539Ssuz 864151539Ssuz return (0); 86578064Sume} 86678064Sume 86778064Sumevoid 86878064Sumein6_tmpaddrtimer(ignored_arg) 86978064Sume void *ignored_arg; 87078064Sume{ 87178064Sume struct nd_ifinfo *ndi; 87278064Sume u_int8_t nullbuf[8]; 873121161Sume struct ifnet *ifp; 87478064Sume int s = splnet(); 87578064Sume 87678064Sume callout_reset(&in6_tmpaddrtimer_ch, 877120913Sume (ip6_temp_preferred_lifetime - ip6_desync_factor - 878120913Sume ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL); 87978064Sume 88078064Sume bzero(nullbuf, sizeof(nullbuf)); 881121161Sume for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { 882121161Sume ndi = ND_IFINFO(ifp); 88378064Sume if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { 88478064Sume /* 88578064Sume * We've been generating a random ID on this interface. 88678064Sume * Create a new one. 88778064Sume */ 88878064Sume (void)generate_tmp_ifid(ndi->randomseed0, 889120913Sume ndi->randomseed1, ndi->randomid); 89078064Sume } 89178064Sume } 89278064Sume 89378064Sume splx(s); 89478064Sume} 895