in6_ifattach.c revision 178888
1157114Sscottl/*- 2157114Sscottl * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3157114Sscottl * All rights reserved. 4157114Sscottl * 5157114Sscottl * Redistribution and use in source and binary forms, with or without 6157114Sscottl * modification, are permitted provided that the following conditions 7157114Sscottl * are met: 8157114Sscottl * 1. Redistributions of source code must retain the above copyright 9157114Sscottl * notice, this list of conditions and the following disclaimer. 10157114Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11157114Sscottl * notice, this list of conditions and the following disclaimer in the 12157114Sscottl * documentation and/or other materials provided with the distribution. 13157114Sscottl * 3. Neither the name of the project nor the names of its contributors 14157114Sscottl * may be used to endorse or promote products derived from this software 15157114Sscottl * without specific prior written permission. 16157114Sscottl * 17157114Sscottl * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18157114Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19157114Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20157114Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21157114Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22157114Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23157114Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24157114Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25157114Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26171980Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27171980Sscottl * SUCH DAMAGE. 28171980Sscottl * 29171980Sscottl * $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $ 30171980Sscottl */ 31171980Sscottl 32171980Sscottl#include <sys/cdefs.h> 33171980Sscottl__FBSDID("$FreeBSD: head/sys/netinet6/in6_ifattach.c 178888 2008-05-09 23:03:00Z julian $"); 34171980Sscottl 35171980Sscottl#include <sys/param.h> 36171980Sscottl#include <sys/systm.h> 37171980Sscottl#include <sys/malloc.h> 38171980Sscottl#include <sys/socket.h> 39171980Sscottl#include <sys/sockio.h> 40171980Sscottl#include <sys/kernel.h> 41171980Sscottl#include <sys/syslog.h> 42171980Sscottl#include <sys/md5.h> 43171980Sscottl 44171980Sscottl#include <net/if.h> 45171980Sscottl#include <net/if_dl.h> 46171980Sscottl#include <net/if_types.h> 47171980Sscottl#include <net/route.h> 48171980Sscottl 49171980Sscottl#include <netinet/in.h> 50171980Sscottl#include <netinet/in_var.h> 51171980Sscottl#include <netinet/if_ether.h> 52157114Sscottl#include <netinet/in_pcb.h> 53157114Sscottl 54157114Sscottl#include <netinet/ip6.h> 55157114Sscottl#include <netinet6/ip6_var.h> 56157114Sscottl#include <netinet6/in6_var.h> 57157114Sscottl#include <netinet6/in6_pcb.h> 58157114Sscottl#include <netinet6/in6_ifattach.h> 59157114Sscottl#include <netinet6/ip6_var.h> 60157114Sscottl#include <netinet6/nd6.h> 61157114Sscottl#include <netinet6/scope6_var.h> 62157114Sscottl 63157114Sscottlunsigned long in6_maxmtu = 0; 64157114Sscottl 65157114Sscottl#ifdef IP6_AUTO_LINKLOCAL 66157114Sscottlint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; 67233711Sambrisko#else 68157114Sscottlint ip6_auto_linklocal = 1; /* enable by default */ 69157114Sscottl#endif 70157114Sscottl 71157114Sscottlstruct callout in6_tmpaddrtimer_ch; 72157114Sscottl 73157114Sscottlextern struct inpcbinfo udbinfo; 74157114Sscottlextern struct inpcbinfo ripcbinfo; 75157114Sscottl 76157114Sscottlstatic int get_rand_ifid(struct ifnet *, struct in6_addr *); 77157114Sscottlstatic int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *); 78157114Sscottlstatic int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *); 79157114Sscottlstatic int in6_ifattach_linklocal(struct ifnet *, struct ifnet *); 80157114Sscottlstatic int in6_ifattach_loopback(struct ifnet *); 81157114Sscottlstatic void in6_purgemaddrs(struct ifnet *); 82157114Sscottl 83157114Sscottl#define EUI64_GBIT 0x01 84157114Sscottl#define EUI64_UBIT 0x02 85171980Sscottl#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) 86233711Sambrisko#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) 87233711Sambrisko#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) 88233711Sambrisko#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) 89247369Ssmh#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) 90233711Sambrisko 91233711Sambrisko#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) 92233711Sambrisko#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) 93233711Sambrisko 94233711Sambrisko/* 95171980Sscottl * Generate a last-resort interface identifier, when the machine has no 96171980Sscottl * IEEE802/EUI64 address sources. 97171980Sscottl * The goal here is to get an interface identifier that is 98171980Sscottl * (1) random enough and (2) does not change across reboot. 99171980Sscottl * We currently use MD5(hostname) for it. 100171980Sscottl * 101233711Sambrisko * in6 - upper 64bits are preserved 102171980Sscottl */ 103171980Sscottlstatic int 104171980Sscottlget_rand_ifid(struct ifnet *ifp, struct in6_addr *in6) 105233711Sambrisko{ 106233711Sambrisko MD5_CTX ctxt; 107233711Sambrisko u_int8_t digest[16]; 108233711Sambrisko int hostnamelen = strlen(hostname); 109233711Sambrisko 110184897Sambrisko#if 0 111184897Sambrisko /* we need at least several letters as seed for ifid */ 112184897Sambrisko if (hostnamelen < 3) 113184897Sambrisko return -1; 114184897Sambrisko#endif 115184897Sambrisko 116233711Sambrisko /* generate 8 bytes of pseudo-random value. */ 117233711Sambrisko bzero(&ctxt, sizeof(ctxt)); 118233711Sambrisko MD5Init(&ctxt); 119233711Sambrisko MD5Update(&ctxt, hostname, hostnamelen); 120233711Sambrisko MD5Final(digest, &ctxt); 121233711Sambrisko 122233711Sambrisko /* assumes sizeof(digest) > sizeof(ifid) */ 123233711Sambrisko bcopy(digest, &in6->s6_addr[8], 8); 124157114Sscottl 125157114Sscottl /* make sure to set "u" bit to local, and "g" bit to individual. */ 126157114Sscottl in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 127233711Sambrisko in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 128233711Sambrisko 129233711Sambrisko /* convert EUI64 into IPv6 interface identifier */ 130233711Sambrisko EUI64_TO_IFID(in6); 131157114Sscottl 132157114Sscottl return 0; 133157114Sscottl} 134157114Sscottl 135157114Sscottlstatic int 136157114Sscottlgenerate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret) 137157114Sscottl{ 138157114Sscottl MD5_CTX ctxt; 139157114Sscottl u_int8_t seed[16], digest[16], nullbuf[8]; 140157114Sscottl u_int32_t val32; 141224041Sjhb 142157114Sscottl /* If there's no history, start with a random seed. */ 143157114Sscottl bzero(nullbuf, sizeof(nullbuf)); 144157114Sscottl if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { 145157114Sscottl int i; 146157114Sscottl 147157114Sscottl for (i = 0; i < 2; i++) { 148233711Sambrisko val32 = arc4random(); 149233711Sambrisko bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); 150233711Sambrisko } 151157114Sscottl } else 152233711Sambrisko bcopy(seed0, seed, 8); 153233711Sambrisko 154233711Sambrisko /* copy the right-most 64-bits of the given address */ 155233711Sambrisko /* XXX assumption on the size of IFID */ 156233711Sambrisko bcopy(seed1, &seed[8], 8); 157233711Sambrisko 158233711Sambrisko if (0) { /* for debugging purposes only */ 159157114Sscottl int i; 160157114Sscottl 161157114Sscottl printf("generate_tmp_ifid: new randomized ID from: "); 162157114Sscottl for (i = 0; i < 16; i++) 163157114Sscottl printf("%02x", seed[i]); 164157114Sscottl printf(" "); 165157114Sscottl } 166157114Sscottl 167224041Sjhb /* generate 16 bytes of pseudo-random value. */ 168157114Sscottl bzero(&ctxt, sizeof(ctxt)); 169233711Sambrisko MD5Init(&ctxt); 170233711Sambrisko MD5Update(&ctxt, seed, sizeof(seed)); 171233711Sambrisko MD5Final(digest, &ctxt); 172233711Sambrisko 173233711Sambrisko /* 174233711Sambrisko * RFC 3041 3.2.1. (3) 175157114Sscottl * Take the left-most 64-bits of the MD5 digest and set bit 6 (the 176157114Sscottl * left-most bit is numbered 0) to zero. 177157114Sscottl */ 178157114Sscottl bcopy(digest, ret, 8); 179157114Sscottl ret[0] &= ~EUI64_UBIT; 180157114Sscottl 181157114Sscottl /* 182157114Sscottl * XXX: we'd like to ensure that the generated value is not zero 183157114Sscottl * for simplicity. If the caclculated digest happens to be zero, 184157114Sscottl * use a random non-zero value as the last resort. 185157114Sscottl */ 186157114Sscottl if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { 187157114Sscottl nd6log((LOG_INFO, 188157114Sscottl "generate_tmp_ifid: computed MD5 value is zero.\n")); 189157114Sscottl 190157114Sscottl val32 = arc4random(); 191233711Sambrisko val32 = 1 + (val32 % (0xffffffff - 1)); 192163398Sscottl } 193163398Sscottl 194157114Sscottl /* 195255806Ssbruno * RFC 3041 3.2.1. (4) 196255806Ssbruno * Take the rightmost 64-bits of the MD5 digest and save them in 197157114Sscottl * stable storage as the history value to be used in the next 198157114Sscottl * iteration of the algorithm. 199157114Sscottl */ 200157114Sscottl bcopy(&digest[8], seed0, 8); 201196200Sscottl 202196200Sscottl if (0) { /* for debugging purposes only */ 203196200Sscottl int i; 204196200Sscottl 205196200Sscottl printf("to: "); 206196200Sscottl for (i = 0; i < 16; i++) 207196200Sscottl printf("%02x", digest[i]); 208196200Sscottl printf("\n"); 209196200Sscottl } 210196200Sscottl 211196200Sscottl return 0; 212233711Sambrisko} 213196200Sscottl 214196200Sscottl/* 215196200Sscottl * Get interface identifier for the specified interface. 216196200Sscottl * XXX assumes single sockaddr_dl (AF_LINK address) per an interface 217196200Sscottl * 218196200Sscottl * in6 - upper 64bits are preserved 219196200Sscottl */ 220196200Sscottlint 221196200Sscottlin6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) 222233711Sambrisko{ 223233711Sambrisko struct ifaddr *ifa; 224159811Sps struct sockaddr_dl *sdl; 225159811Sps u_int8_t *addr; 226157114Sscottl size_t addrlen; 227159811Sps static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 228196200Sscottl static u_int8_t allone[8] = 229171821Sjhb { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 230163398Sscottl 231163398Sscottl for (ifa = ifp->if_addrlist.tqh_first; 232163398Sscottl ifa; 233196200Sscottl ifa = ifa->ifa_list.tqe_next) { 234233711Sambrisko if (ifa->ifa_addr->sa_family != AF_LINK) 235251516Ssbruno continue; 236251516Ssbruno sdl = (struct sockaddr_dl *)ifa->ifa_addr; 237251516Ssbruno if (sdl == NULL) 238184897Sambrisko continue; 239251516Ssbruno if (sdl->sdl_alen == 0) 240196200Sscottl continue; 241196200Sscottl 242196200Sscottl goto found; 243249257Smarkj } 244249257Smarkj 245249257Smarkj return -1; 246157114Sscottl 247157114Sscottlfound: 248157114Sscottl addr = LLADDR(sdl); 249157114Sscottl addrlen = sdl->sdl_alen; 250157114Sscottl 251157114Sscottl /* get EUI64 */ 252157114Sscottl switch (ifp->if_type) { 253157114Sscottl case IFT_ETHER: 254157114Sscottl case IFT_FDDI: 255157114Sscottl case IFT_ISO88025: 256157114Sscottl case IFT_ATM: 257157114Sscottl case IFT_IEEE1394: 258157114Sscottl#ifdef IFT_IEEE80211 259158737Sambrisko case IFT_IEEE80211: 260157114Sscottl#endif 261157114Sscottl /* IEEE802/EUI64 cases - what others? */ 262157114Sscottl /* IEEE1394 uses 16byte length address starting with EUI64 */ 263157114Sscottl if (addrlen > 8) 264157114Sscottl addrlen = 8; 265157114Sscottl 266157114Sscottl /* look at IEEE802/EUI64 only */ 267157114Sscottl if (addrlen != 8 && addrlen != 6) 268157114Sscottl return -1; 269157114Sscottl 270157114Sscottl /* 271233711Sambrisko * check for invalid MAC address - on bsdi, we see it a lot 272247369Ssmh * since wildboar configures all-zero MAC on pccard before 273247369Ssmh * card insertion. 274247369Ssmh */ 275247369Ssmh if (bcmp(addr, allzero, addrlen) == 0) 276247369Ssmh return -1; 277247369Ssmh if (bcmp(addr, allone, addrlen) == 0) 278247369Ssmh return -1; 279157114Sscottl 280233711Sambrisko /* make EUI64 address */ 281233711Sambrisko if (addrlen == 8) 282233711Sambrisko bcopy(addr, &in6->s6_addr[8], 8); 283233711Sambrisko else if (addrlen == 6) { 284233711Sambrisko in6->s6_addr[8] = addr[0]; 285233711Sambrisko in6->s6_addr[9] = addr[1]; 286233711Sambrisko in6->s6_addr[10] = addr[2]; 287233711Sambrisko in6->s6_addr[11] = 0xff; 288233711Sambrisko in6->s6_addr[12] = 0xfe; 289233711Sambrisko in6->s6_addr[13] = addr[3]; 290233711Sambrisko in6->s6_addr[14] = addr[4]; 291233711Sambrisko in6->s6_addr[15] = addr[5]; 292233711Sambrisko } 293233711Sambrisko break; 294233711Sambrisko 295233711Sambrisko case IFT_ARCNET: 296233711Sambrisko if (addrlen != 1) 297233711Sambrisko return -1; 298233711Sambrisko if (!addr[0]) 299233711Sambrisko return -1; 300233711Sambrisko 301233711Sambrisko bzero(&in6->s6_addr[8], 8); 302233711Sambrisko in6->s6_addr[15] = addr[0]; 303233711Sambrisko 304233711Sambrisko /* 305233711Sambrisko * due to insufficient bitwidth, we mark it local. 306233711Sambrisko */ 307233711Sambrisko in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 308233711Sambrisko in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 309157114Sscottl break; 310157114Sscottl 311157114Sscottl case IFT_GIF: 312157114Sscottl#ifdef IFT_STF 313157114Sscottl case IFT_STF: 314157114Sscottl#endif 315157114Sscottl /* 316157114Sscottl * RFC2893 says: "SHOULD use IPv4 address as ifid source". 317157114Sscottl * however, IPv4 address is not very suitable as unique 318157114Sscottl * identifier source (can be renumbered). 319157114Sscottl * we don't do this. 320157114Sscottl */ 321157114Sscottl return -1; 322157114Sscottl 323157114Sscottl default: 324157114Sscottl return -1; 325157114Sscottl } 326157114Sscottl 327157114Sscottl /* sanity check: g bit must not indicate "group" */ 328157114Sscottl if (EUI64_GROUP(in6)) 329157114Sscottl return -1; 330157114Sscottl 331157114Sscottl /* convert EUI64 into IPv6 interface identifier */ 332157114Sscottl EUI64_TO_IFID(in6); 333157114Sscottl 334157114Sscottl /* 335157114Sscottl * sanity check: ifid must not be all zero, avoid conflict with 336157114Sscottl * subnet router anycast 337157114Sscottl */ 338157114Sscottl if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && 339157114Sscottl bcmp(&in6->s6_addr[9], allzero, 7) == 0) { 340157114Sscottl return -1; 341157114Sscottl } 342157114Sscottl 343157114Sscottl return 0; 344157114Sscottl} 345157114Sscottl 346157114Sscottl/* 347157114Sscottl * Get interface identifier for the specified interface. If it is not 348157114Sscottl * available on ifp0, borrow interface identifier from other information 349157114Sscottl * sources. 350157114Sscottl * 351157114Sscottl * altifp - secondary EUI64 source 352157114Sscottl */ 353157114Sscottlstatic int 354157114Sscottlget_ifid(struct ifnet *ifp0, struct ifnet *altifp, 355157114Sscottl struct in6_addr *in6) 356157114Sscottl{ 357157114Sscottl struct ifnet *ifp; 358157114Sscottl 359157114Sscottl /* first, try to get it from the interface itself */ 360157114Sscottl if (in6_get_hw_ifid(ifp0, in6) == 0) { 361157114Sscottl nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", 362157114Sscottl if_name(ifp0))); 363157114Sscottl goto success; 364157114Sscottl } 365157114Sscottl 366157114Sscottl /* try secondary EUI64 source. this basically is for ATM PVC */ 367157114Sscottl if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { 368196200Sscottl nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", 369196200Sscottl if_name(ifp0), if_name(altifp))); 370196200Sscottl goto success; 371157114Sscottl } 372157114Sscottl 373157114Sscottl /* next, try to get it from some other hardware interface */ 374157114Sscottl IFNET_RLOCK(); 375157114Sscottl for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { 376157114Sscottl if (ifp == ifp0) 377157114Sscottl continue; 378157114Sscottl if (in6_get_hw_ifid(ifp, in6) != 0) 379157114Sscottl continue; 380157114Sscottl 381157114Sscottl /* 382157114Sscottl * to borrow ifid from other interface, ifid needs to be 383157114Sscottl * globally unique 384157114Sscottl */ 385157114Sscottl if (IFID_UNIVERSAL(in6)) { 386157114Sscottl nd6log((LOG_DEBUG, 387157114Sscottl "%s: borrow interface identifier from %s\n", 388157114Sscottl if_name(ifp0), if_name(ifp))); 389157114Sscottl IFNET_RUNLOCK(); 390157114Sscottl goto success; 391157114Sscottl } 392157114Sscottl } 393157114Sscottl IFNET_RUNLOCK(); 394157114Sscottl 395157114Sscottl /* last resort: get from random number source */ 396157114Sscottl if (get_rand_ifid(ifp, in6) == 0) { 397158737Sambrisko nd6log((LOG_DEBUG, 398158737Sambrisko "%s: interface identifier generated by random number\n", 399158737Sambrisko if_name(ifp0))); 400158737Sambrisko goto success; 401158737Sambrisko } 402158737Sambrisko 403158737Sambrisko printf("%s: failed to get interface identifier\n", if_name(ifp0)); 404158737Sambrisko return -1; 405158737Sambrisko 406158737Sambriskosuccess: 407158737Sambrisko nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 408158737Sambrisko if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10], 409158737Sambrisko in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13], 410158737Sambrisko in6->s6_addr[14], in6->s6_addr[15])); 411158737Sambrisko return 0; 412158737Sambrisko} 413158737Sambrisko 414158737Sambrisko/* 415158737Sambrisko * altifp - secondary EUI64 source 416158737Sambrisko */ 417158737Sambriskostatic int 418157114Sscottlin6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp) 419157114Sscottl{ 420233711Sambrisko struct in6_ifaddr *ia; 421233711Sambrisko struct in6_aliasreq ifra; 422233711Sambrisko struct nd_prefixctl pr0; 423235014Sambrisko int i, error; 424233711Sambrisko 425163398Sscottl /* 426163398Sscottl * configure link-local address. 427163398Sscottl */ 428163398Sscottl bzero(&ifra, sizeof(ifra)); 429163398Sscottl 430163398Sscottl /* 431163398Sscottl * in6_update_ifa() does not use ifra_name, but we accurately set it 432163398Sscottl * for safety. 433163398Sscottl */ 434196200Sscottl strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 435163398Sscottl 436196200Sscottl ifra.ifra_addr.sin6_family = AF_INET6; 437196200Sscottl ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 438196200Sscottl ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000); 439196200Sscottl ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; 440196200Sscottl if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 441196200Sscottl ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; 442196200Sscottl ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); 443196200Sscottl } else { 444196200Sscottl if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { 445196200Sscottl nd6log((LOG_ERR, 446163398Sscottl "%s: no ifid available\n", if_name(ifp))); 447163398Sscottl return (-1); 448163398Sscottl } 449163398Sscottl } 450163398Sscottl if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) 451163398Sscottl return (-1); 452233711Sambrisko 453233711Sambrisko ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 454233711Sambrisko ifra.ifra_prefixmask.sin6_family = AF_INET6; 455233711Sambrisko ifra.ifra_prefixmask.sin6_addr = in6mask64; 456233711Sambrisko /* link-local addresses should NEVER expire. */ 457233711Sambrisko ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 458233711Sambrisko ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 459233711Sambrisko 460233711Sambrisko /* 461157114Sscottl * Now call in6_update_ifa() to do a bunch of procedures to configure 462157114Sscottl * a link-local address. We can set the 3rd argument to NULL, because 463157114Sscottl * we know there's no other link-local address on the interface 464157114Sscottl * and therefore we are adding one (instead of updating one). 465157114Sscottl */ 466157114Sscottl if ((error = in6_update_ifa(ifp, &ifra, NULL, 467157114Sscottl IN6_IFAUPDATE_DADDELAY)) != 0) { 468157114Sscottl /* 469157114Sscottl * XXX: When the interface does not support IPv6, this call 470157114Sscottl * would fail in the SIOCSIFADDR ioctl. I believe the 471196200Sscottl * notification is rather confusing in this case, so just 472157114Sscottl * suppress it. (jinmei@kame.net 20010130) 473157114Sscottl */ 474157114Sscottl if (error != EAFNOSUPPORT) 475157114Sscottl nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to " 476247369Ssmh "configure a link-local address on %s " 477247369Ssmh "(errno=%d)\n", 478157114Sscottl if_name(ifp), error)); 479157114Sscottl return (-1); 480157114Sscottl } 481157114Sscottl 482157114Sscottl ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ 483157114Sscottl#ifdef DIAGNOSTIC 484157114Sscottl if (!ia) { 485157114Sscottl panic("ia == NULL in in6_ifattach_linklocal"); 486157114Sscottl /* NOTREACHED */ 487157114Sscottl } 488157114Sscottl#endif 489157114Sscottl 490157114Sscottl /* 491157114Sscottl * Make the link-local prefix (fe80::%link/64) as on-link. 492157114Sscottl * Since we'd like to manage prefixes separately from addresses, 493233711Sambrisko * we make an ND6 prefix structure for the link-local prefix, 494233711Sambrisko * and add it to the prefix list as a never-expire prefix. 495233711Sambrisko * XXX: this change might affect some existing code base... 496233711Sambrisko */ 497233711Sambrisko bzero(&pr0, sizeof(pr0)); 498233711Sambrisko pr0.ndpr_ifp = ifp; 499157114Sscottl /* this should be 64 at this moment. */ 500233711Sambrisko pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); 501233711Sambrisko pr0.ndpr_prefix = ifra.ifra_addr; 502233711Sambrisko /* apply the mask for safety. (nd6_prelist_add will apply it again) */ 503157114Sscottl for (i = 0; i < 4; i++) { 504157114Sscottl pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 505157114Sscottl in6mask64.s6_addr32[i]; 506157114Sscottl } 507157114Sscottl /* 508157114Sscottl * Initialize parameters. The link-local prefix must always be 509157114Sscottl * on-link, and its lifetimes never expire. 510157114Sscottl */ 511157114Sscottl pr0.ndpr_raf_onlink = 1; 512157114Sscottl pr0.ndpr_raf_auto = 1; /* probably meaningless */ 513157114Sscottl pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; 514157114Sscottl pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; 515157114Sscottl /* 516233711Sambrisko * Since there is no other link-local addresses, nd6_prefix_lookup() 517233711Sambrisko * probably returns NULL. However, we cannot always expect the result. 518233711Sambrisko * For example, if we first remove the (only) existing link-local 519233711Sambrisko * address, and then reconfigure another one, the prefix is still 520157114Sscottl * valid with referring to the old link-local address. 521157114Sscottl */ 522175897Sambrisko if (nd6_prefix_lookup(&pr0) == NULL) { 523175897Sambrisko if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) 524157114Sscottl return (error); 525157114Sscottl } 526157114Sscottl 527157114Sscottl return 0; 528157114Sscottl} 529157114Sscottl 530157114Sscottl/* 531157114Sscottl * ifp - must be IFT_LOOP 532157114Sscottl */ 533157114Sscottlstatic int 534233711Sambriskoin6_ifattach_loopback(struct ifnet *ifp) 535233711Sambrisko{ 536233711Sambrisko struct in6_aliasreq ifra; 537233711Sambrisko int error; 538233711Sambrisko 539233711Sambrisko bzero(&ifra, sizeof(ifra)); 540157114Sscottl 541157114Sscottl /* 542233711Sambrisko * in6_update_ifa() does not use ifra_name, but we accurately set it 543233711Sambrisko * for safety. 544233711Sambrisko */ 545233711Sambrisko strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 546233711Sambrisko 547233711Sambrisko ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 548233711Sambrisko ifra.ifra_prefixmask.sin6_family = AF_INET6; 549233711Sambrisko ifra.ifra_prefixmask.sin6_addr = in6mask128; 550233711Sambrisko 551233711Sambrisko /* 552233711Sambrisko * Always initialize ia_dstaddr (= broadcast address) to loopback 553233711Sambrisko * address. Follows IPv4 practice - see in_ifinit(). 554233711Sambrisko */ 555233711Sambrisko ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 556233711Sambrisko ifra.ifra_dstaddr.sin6_family = AF_INET6; 557157114Sscottl ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; 558157114Sscottl 559157114Sscottl ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 560157114Sscottl ifra.ifra_addr.sin6_family = AF_INET6; 561157114Sscottl ifra.ifra_addr.sin6_addr = in6addr_loopback; 562157114Sscottl 563157114Sscottl /* the loopback address should NEVER expire. */ 564157114Sscottl ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 565157114Sscottl ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 566157114Sscottl 567157114Sscottl /* we don't need to perform DAD on loopback interfaces. */ 568157114Sscottl ifra.ifra_flags |= IN6_IFF_NODAD; 569157114Sscottl 570157114Sscottl /* skip registration to the prefix list. XXX should be temporary. */ 571157114Sscottl ifra.ifra_flags |= IN6_IFF_NOPFX; 572157114Sscottl 573157114Sscottl /* 574157114Sscottl * We are sure that this is a newly assigned address, so we can set 575157114Sscottl * NULL to the 3rd arg. 576157114Sscottl */ 577157114Sscottl if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) { 578157114Sscottl nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " 579157114Sscottl "the loopback address on %s (errno=%d)\n", 580157114Sscottl if_name(ifp), error)); 581157114Sscottl return (-1); 582157114Sscottl } 583157114Sscottl 584157114Sscottl return 0; 585157114Sscottl} 586157114Sscottl 587233711Sambrisko/* 588233711Sambrisko * compute NI group address, based on the current hostname setting. 589157114Sscottl * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later). 590157114Sscottl * 591233711Sambrisko * when ifp == NULL, the caller is responsible for filling scopeid. 592157114Sscottl */ 593157114Sscottlint 594157114Sscottlin6_nigroup(struct ifnet *ifp, const char *name, int namelen, 595157114Sscottl struct in6_addr *in6) 596157114Sscottl{ 597157114Sscottl const char *p; 598157114Sscottl u_char *q; 599157114Sscottl MD5_CTX ctxt; 600157114Sscottl u_int8_t digest[16]; 601157114Sscottl char l; 602157114Sscottl char n[64]; /* a single label must not exceed 63 chars */ 603157114Sscottl 604157114Sscottl if (!namelen || !name) 605157114Sscottl return -1; 606157114Sscottl 607157114Sscottl p = name; 608157114Sscottl while (p && *p && *p != '.' && p - name < namelen) 609157114Sscottl p++; 610157114Sscottl if (p - name > sizeof(n) - 1) 611157114Sscottl return -1; /* label too long */ 612157114Sscottl l = p - name; 613157114Sscottl strncpy(n, name, l); 614157114Sscottl n[(int)l] = '\0'; 615157114Sscottl for (q = n; *q; q++) { 616233711Sambrisko if ('A' <= *q && *q <= 'Z') 617157114Sscottl *q = *q - 'A' + 'a'; 618157114Sscottl } 619157114Sscottl 620157114Sscottl /* generate 8 bytes of pseudo-random value. */ 621157114Sscottl bzero(&ctxt, sizeof(ctxt)); 622157114Sscottl MD5Init(&ctxt); 623157114Sscottl MD5Update(&ctxt, &l, sizeof(l)); 624157114Sscottl MD5Update(&ctxt, n, l); 625157114Sscottl MD5Final(digest, &ctxt); 626157114Sscottl 627157114Sscottl bzero(in6, sizeof(*in6)); 628157114Sscottl in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL; 629157114Sscottl in6->s6_addr8[11] = 2; 630157114Sscottl bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3])); 631157114Sscottl if (in6_setscope(in6, ifp, NULL)) 632157114Sscottl return (-1); /* XXX: should not fail */ 633157114Sscottl 634157114Sscottl return 0; 635157114Sscottl} 636157114Sscottl 637157114Sscottl/* 638157114Sscottl * XXX multiple loopback interface needs more care. for instance, 639157114Sscottl * nodelocal address needs to be configured onto only one of them. 640157114Sscottl * XXX multiple link-local address case 641157114Sscottl * 642157114Sscottl * altifp - secondary EUI64 source 643157114Sscottl */ 644157114Sscottlvoid 645157114Sscottlin6_ifattach(struct ifnet *ifp, struct ifnet *altifp) 646157114Sscottl{ 647157114Sscottl struct in6_ifaddr *ia; 648157114Sscottl struct in6_addr in6; 649157114Sscottl 650157114Sscottl /* some of the interfaces are inherently not IPv6 capable */ 651157114Sscottl switch (ifp->if_type) { 652157114Sscottl case IFT_PFLOG: 653157114Sscottl case IFT_PFSYNC: 654157114Sscottl case IFT_CARP: 655157114Sscottl return; 656157114Sscottl } 657157114Sscottl 658157114Sscottl /* 659157114Sscottl * quirks based on interface type 660157114Sscottl */ 661157114Sscottl switch (ifp->if_type) { 662157114Sscottl#ifdef IFT_STF 663157114Sscottl case IFT_STF: 664157114Sscottl /* 665157114Sscottl * 6to4 interface is a very special kind of beast. 666233711Sambrisko * no multicast, no linklocal. RFC2529 specifies how to make 667233711Sambrisko * linklocals for 6to4 interface, but there's no use and 668233711Sambrisko * it is rather harmful to have one. 669233711Sambrisko */ 670233711Sambrisko goto statinit; 671233711Sambrisko#endif 672233711Sambrisko default: 673233711Sambrisko break; 674233711Sambrisko } 675233711Sambrisko 676233711Sambrisko /* 677233711Sambrisko * usually, we require multicast capability to the interface 678233711Sambrisko */ 679233711Sambrisko if ((ifp->if_flags & IFF_MULTICAST) == 0) { 680233711Sambrisko nd6log((LOG_INFO, "in6_ifattach: " 681233711Sambrisko "%s is not multicast capable, IPv6 not enabled\n", 682233711Sambrisko if_name(ifp))); 683233711Sambrisko return; 684233711Sambrisko } 685233711Sambrisko 686233711Sambrisko /* 687233711Sambrisko * assign loopback address for loopback interface. 688233711Sambrisko * XXX multiple loopback interface case. 689233711Sambrisko */ 690233711Sambrisko if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 691233711Sambrisko in6 = in6addr_loopback; 692233711Sambrisko if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { 693233711Sambrisko if (in6_ifattach_loopback(ifp) != 0) 694233711Sambrisko return; 695233711Sambrisko } 696233711Sambrisko } 697233711Sambrisko 698233711Sambrisko /* 699233711Sambrisko * assign a link-local address, if there's none. 700233711Sambrisko */ 701233711Sambrisko if (ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) { 702233711Sambrisko ia = in6ifa_ifpforlinklocal(ifp, 0); 703233711Sambrisko if (ia == NULL) { 704233711Sambrisko if (in6_ifattach_linklocal(ifp, altifp) == 0) { 705233711Sambrisko /* linklocal address assigned */ 706233711Sambrisko } else { 707233711Sambrisko /* failed to assign linklocal address. bark? */ 708233711Sambrisko } 709233711Sambrisko } 710233711Sambrisko } 711233711Sambrisko 712233711Sambrisko#ifdef IFT_STF /* XXX */ 713233711Sambriskostatinit: 714233711Sambrisko#endif 715233711Sambrisko 716233711Sambrisko /* update dynamically. */ 717233711Sambrisko if (in6_maxmtu < ifp->if_mtu) 718233711Sambrisko in6_maxmtu = ifp->if_mtu; 719233711Sambrisko} 720233711Sambrisko 721157114Sscottl/* 722157114Sscottl * NOTE: in6_ifdetach() does not support loopback if at this moment. 723157114Sscottl * We don't need this function in bsdi, because interfaces are never removed 724157114Sscottl * from the ifnet list in bsdi. 725157114Sscottl */ 726157114Sscottlvoid 727157114Sscottlin6_ifdetach(struct ifnet *ifp) 728157114Sscottl{ 729157114Sscottl struct in6_ifaddr *ia, *oia; 730157114Sscottl struct ifaddr *ifa, *next; 731157114Sscottl struct rtentry *rt; 732157114Sscottl short rtflags; 733157114Sscottl struct sockaddr_in6 sin6; 734157114Sscottl struct in6_multi_mship *imm; 735157114Sscottl 736157114Sscottl /* remove neighbor management table */ 737157114Sscottl nd6_purge(ifp); 738157114Sscottl 739157114Sscottl /* nuke any of IPv6 addresses we have */ 740157114Sscottl for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 741157114Sscottl next = ifa->ifa_list.tqe_next; 742157114Sscottl if (ifa->ifa_addr->sa_family != AF_INET6) 743157114Sscottl continue; 744157114Sscottl in6_purgeaddr(ifa); 745157114Sscottl } 746157114Sscottl 747157114Sscottl /* undo everything done by in6_ifattach(), just in case */ 748157114Sscottl for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 749157114Sscottl next = ifa->ifa_list.tqe_next; 750157114Sscottl 751157114Sscottl if (ifa->ifa_addr->sa_family != AF_INET6 752157114Sscottl || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 753157114Sscottl continue; 754157114Sscottl } 755157114Sscottl 756157114Sscottl ia = (struct in6_ifaddr *)ifa; 757157114Sscottl 758157114Sscottl /* 759157114Sscottl * leave from multicast groups we have joined for the interface 760157114Sscottl */ 761157114Sscottl while ((imm = ia->ia6_memberships.lh_first) != NULL) { 762157114Sscottl LIST_REMOVE(imm, i6mm_chain); 763157114Sscottl in6_leavegroup(imm); 764163398Sscottl } 765163398Sscottl 766163398Sscottl /* remove from the routing table */ 767163398Sscottl if ((ia->ia_flags & IFA_ROUTE) && 768163398Sscottl (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { 769163398Sscottl rtflags = rt->rt_flags; 770163398Sscottl rtfree(rt); 771163398Sscottl rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr, 772163398Sscottl (struct sockaddr *)&ia->ia_addr, 773163398Sscottl (struct sockaddr *)&ia->ia_prefixmask, 774163398Sscottl rtflags, (struct rtentry **)0); 775163398Sscottl } 776163398Sscottl 777163398Sscottl /* remove from the linked list */ 778163398Sscottl TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 779163398Sscottl IFAFREE(&ia->ia_ifa); 780163398Sscottl 781163398Sscottl /* also remove from the IPv6 address chain(itojun&jinmei) */ 782163398Sscottl oia = ia; 783163398Sscottl if (oia == (ia = in6_ifaddr)) 784163398Sscottl in6_ifaddr = ia->ia_next; 785163398Sscottl else { 786163398Sscottl while (ia->ia_next && (ia->ia_next != oia)) 787163398Sscottl ia = ia->ia_next; 788163398Sscottl if (ia->ia_next) 789163398Sscottl ia->ia_next = oia->ia_next; 790163398Sscottl else { 791163398Sscottl nd6log((LOG_ERR, 792163398Sscottl "%s: didn't unlink in6ifaddr from list\n", 793163398Sscottl if_name(ifp))); 794163398Sscottl } 795163398Sscottl } 796163398Sscottl 797157114Sscottl IFAFREE(&oia->ia_ifa); 798163398Sscottl } 799163398Sscottl 800163398Sscottl in6_pcbpurgeif0(&udbinfo, ifp); 801163398Sscottl in6_pcbpurgeif0(&ripcbinfo, ifp); 802163398Sscottl /* leave from all multicast groups joined */ 803163398Sscottl in6_purgemaddrs(ifp); 804163398Sscottl 805163398Sscottl /* 806163398Sscottl * remove neighbor management table. we call it twice just to make 807163398Sscottl * sure we nuke everything. maybe we need just one call. 808163398Sscottl * XXX: since the first call did not release addresses, some prefixes 809163398Sscottl * might remain. We should call nd6_purge() again to release the 810157114Sscottl * prefixes after removing all addresses above. 811157114Sscottl * (Or can we just delay calling nd6_purge until at this point?) 812157114Sscottl */ 813157114Sscottl nd6_purge(ifp); 814157114Sscottl 815157114Sscottl /* remove route to link-local allnodes multicast (ff02::1) */ 816157114Sscottl bzero(&sin6, sizeof(sin6)); 817157114Sscottl sin6.sin6_len = sizeof(struct sockaddr_in6); 818157114Sscottl sin6.sin6_family = AF_INET6; 819157114Sscottl sin6.sin6_addr = in6addr_linklocal_allnodes; 820157114Sscottl if (in6_setscope(&sin6.sin6_addr, ifp, NULL)) 821157114Sscottl /* XXX: should not fail */ 822157114Sscottl return; 823157114Sscottl /* XXX grab lock first to avoid LOR */ 824157114Sscottl if (rt_tables[0][AF_INET6] != NULL) { 825157114Sscottl RADIX_NODE_HEAD_LOCK(rt_tables[0][AF_INET6]); 826157114Sscottl rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 827157114Sscottl if (rt) { 828157114Sscottl if (rt->rt_ifp == ifp) 829157114Sscottl rtexpunge(rt); 830157114Sscottl RTFREE_LOCKED(rt); 831157114Sscottl } 832157114Sscottl RADIX_NODE_HEAD_UNLOCK(rt_tables[0][AF_INET6]); 833157114Sscottl } 834157114Sscottl} 835157114Sscottl 836157114Sscottlint 837157114Sscottlin6_get_tmpifid(struct ifnet *ifp, u_int8_t *retbuf, 838157114Sscottl const u_int8_t *baseid, int generate) 839157114Sscottl{ 840157114Sscottl u_int8_t nullbuf[8]; 841157114Sscottl struct nd_ifinfo *ndi = ND_IFINFO(ifp); 842157114Sscottl 843157114Sscottl bzero(nullbuf, sizeof(nullbuf)); 844157114Sscottl if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { 845157114Sscottl /* we've never created a random ID. Create a new one. */ 846157114Sscottl generate = 1; 847157114Sscottl } 848157114Sscottl 849157114Sscottl if (generate) { 850157114Sscottl bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); 851157114Sscottl 852157114Sscottl /* generate_tmp_ifid will update seedn and buf */ 853157114Sscottl (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, 854157114Sscottl ndi->randomid); 855157114Sscottl } 856157114Sscottl bcopy(ndi->randomid, retbuf, 8); 857157114Sscottl 858157114Sscottl return (0); 859157114Sscottl} 860157114Sscottl 861157114Sscottlvoid 862157114Sscottlin6_tmpaddrtimer(void *ignored_arg) 863157114Sscottl{ 864158737Sambrisko struct nd_ifinfo *ndi; 865157114Sscottl u_int8_t nullbuf[8]; 866157114Sscottl struct ifnet *ifp; 867157114Sscottl int s = splnet(); 868157114Sscottl 869157114Sscottl callout_reset(&in6_tmpaddrtimer_ch, 870157114Sscottl (ip6_temp_preferred_lifetime - ip6_desync_factor - 871157114Sscottl ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL); 872157114Sscottl 873157114Sscottl bzero(nullbuf, sizeof(nullbuf)); 874157114Sscottl for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { 875157114Sscottl ndi = ND_IFINFO(ifp); 876157114Sscottl if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { 877157114Sscottl /* 878157114Sscottl * We've been generating a random ID on this interface. 879157114Sscottl * Create a new one. 880157114Sscottl */ 881157114Sscottl (void)generate_tmp_ifid(ndi->randomseed0, 882157114Sscottl ndi->randomseed1, ndi->randomid); 883157114Sscottl } 884157114Sscottl } 885157114Sscottl 886157114Sscottl splx(s); 887157114Sscottl} 888157114Sscottl 889157114Sscottlstatic void 890157114Sscottlin6_purgemaddrs(struct ifnet *ifp) 891157114Sscottl{ 892157114Sscottl struct in6_multi *in6m; 893157114Sscottl struct in6_multi *oin6m; 894157114Sscottl 895157114Sscottl#ifdef DIAGNOSTIC 896157114Sscottl printf("%s: purging ifp %p\n", __func__, ifp); 897157114Sscottl#endif 898157114Sscottl 899157114Sscottl IFF_LOCKGIANT(ifp); 900157114Sscottl LIST_FOREACH_SAFE(in6m, &in6_multihead, in6m_entry, oin6m) { 901157114Sscottl if (in6m->in6m_ifp == ifp) 902157114Sscottl in6_delmulti(in6m); 903157114Sscottl } 904157114Sscottl IFF_UNLOCKGIANT(ifp); 905157114Sscottl} 906157114Sscottl