in6_ifattach.c revision 160981
1171169Smlaier/* $FreeBSD: head/sys/netinet6/in6_ifattach.c 160981 2006-08-04 21:27:40Z brooks $ */ 2171169Smlaier/* $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $ */ 3171169Smlaier 4171169Smlaier/*- 5171169Smlaier * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6171169Smlaier * All rights reserved. 7171169Smlaier * 8171169Smlaier * Redistribution and use in source and binary forms, with or without 9171169Smlaier * modification, are permitted provided that the following conditions 10171169Smlaier * are met: 11171169Smlaier * 1. Redistributions of source code must retain the above copyright 12171169Smlaier * notice, this list of conditions and the following disclaimer. 13171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright 14171169Smlaier * notice, this list of conditions and the following disclaimer in the 15171169Smlaier * documentation and/or other materials provided with the distribution. 16171169Smlaier * 3. Neither the name of the project nor the names of its contributors 17171169Smlaier * may be used to endorse or promote products derived from this software 18171169Smlaier * without specific prior written permission. 19171169Smlaier * 20171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21171169Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22171169Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23171169Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24171169Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25171169Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26171169Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27171169Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28171169Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29171169Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30171169Smlaier * SUCH DAMAGE. 31171169Smlaier */ 32171169Smlaier 33171169Smlaier#include <sys/param.h> 34171169Smlaier#include <sys/systm.h> 35171169Smlaier#include <sys/malloc.h> 36171169Smlaier#include <sys/socket.h> 37171169Smlaier#include <sys/sockio.h> 38171169Smlaier#include <sys/kernel.h> 39171169Smlaier#include <sys/syslog.h> 40171169Smlaier#include <sys/md5.h> 41171169Smlaier 42171169Smlaier#include <net/if.h> 43171169Smlaier#include <net/if_dl.h> 44171169Smlaier#include <net/if_types.h> 45171169Smlaier#include <net/route.h> 46171169Smlaier 47171169Smlaier#include <netinet/in.h> 48171169Smlaier#include <netinet/in_var.h> 49171169Smlaier#include <netinet/if_ether.h> 50171169Smlaier#include <netinet/in_pcb.h> 51171169Smlaier 52171169Smlaier#include <netinet/ip6.h> 53171169Smlaier#include <netinet6/ip6_var.h> 54171169Smlaier#include <netinet6/in6_var.h> 55171169Smlaier#include <netinet6/in6_pcb.h> 56171169Smlaier#include <netinet6/in6_ifattach.h> 57171169Smlaier#include <netinet6/ip6_var.h> 58171169Smlaier#include <netinet6/nd6.h> 59171169Smlaier#include <netinet6/scope6_var.h> 60171169Smlaier 61171169Smlaierunsigned long in6_maxmtu = 0; 62171169Smlaier 63171169Smlaier#ifdef IP6_AUTO_LINKLOCAL 64171169Smlaierint ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; 65171169Smlaier#else 66171169Smlaierint ip6_auto_linklocal = 1; /* enable by default */ 67171169Smlaier#endif 68171169Smlaier 69171169Smlaierstruct callout in6_tmpaddrtimer_ch; 70171169Smlaier 71171169Smlaierextern struct inpcbinfo udbinfo; 72171169Smlaierextern struct inpcbinfo ripcbinfo; 73171169Smlaier 74171169Smlaierstatic int get_rand_ifid __P((struct ifnet *, struct in6_addr *)); 75171169Smlaierstatic int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *)); 76171169Smlaierstatic int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *)); 77171169Smlaierstatic int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *)); 78171169Smlaierstatic int in6_ifattach_loopback __P((struct ifnet *)); 79171169Smlaier 80171169Smlaier#define EUI64_GBIT 0x01 81171169Smlaier#define EUI64_UBIT 0x02 82171169Smlaier#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) 83171169Smlaier#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) 84171169Smlaier#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) 85171169Smlaier#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) 86171169Smlaier#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) 87171169Smlaier 88171169Smlaier#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) 89171169Smlaier#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) 90171169Smlaier 91171169Smlaier/* 92171169Smlaier * Generate a last-resort interface identifier, when the machine has no 93171169Smlaier * IEEE802/EUI64 address sources. 94171169Smlaier * The goal here is to get an interface identifier that is 95171169Smlaier * (1) random enough and (2) does not change across reboot. 96171169Smlaier * We currently use MD5(hostname) for it. 97171169Smlaier */ 98171169Smlaierstatic int 99171169Smlaierget_rand_ifid(ifp, in6) 100171169Smlaier struct ifnet *ifp; 101171169Smlaier struct in6_addr *in6; /* upper 64bits are preserved */ 102171169Smlaier{ 103171169Smlaier MD5_CTX ctxt; 104171169Smlaier u_int8_t digest[16]; 105171169Smlaier int hostnamelen = strlen(hostname); 106171169Smlaier 107171169Smlaier#if 0 108171169Smlaier /* we need at least several letters as seed for ifid */ 109171169Smlaier if (hostnamelen < 3) 110171169Smlaier return -1; 111171169Smlaier#endif 112171169Smlaier 113171169Smlaier /* generate 8 bytes of pseudo-random value. */ 114171169Smlaier bzero(&ctxt, sizeof(ctxt)); 115171169Smlaier MD5Init(&ctxt); 116171169Smlaier MD5Update(&ctxt, hostname, hostnamelen); 117171169Smlaier MD5Final(digest, &ctxt); 118171169Smlaier 119171169Smlaier /* assumes sizeof(digest) > sizeof(ifid) */ 120171169Smlaier bcopy(digest, &in6->s6_addr[8], 8); 121171169Smlaier 122171169Smlaier /* make sure to set "u" bit to local, and "g" bit to individual. */ 123171169Smlaier in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 124171169Smlaier in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 125171169Smlaier 126171169Smlaier /* convert EUI64 into IPv6 interface identifier */ 127171169Smlaier EUI64_TO_IFID(in6); 128171169Smlaier 129171169Smlaier return 0; 130171169Smlaier} 131171169Smlaier 132171169Smlaierstatic int 133171169Smlaiergenerate_tmp_ifid(seed0, seed1, ret) 134171169Smlaier u_int8_t *seed0, *ret; 135171169Smlaier const u_int8_t *seed1; 136171169Smlaier{ 137171169Smlaier MD5_CTX ctxt; 138171169Smlaier u_int8_t seed[16], digest[16], nullbuf[8]; 139171169Smlaier u_int32_t val32; 140171169Smlaier 141171169Smlaier /* If there's no hisotry, start with a random seed. */ 142171169Smlaier bzero(nullbuf, sizeof(nullbuf)); 143171169Smlaier if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { 144171169Smlaier int i; 145171169Smlaier 146171169Smlaier for (i = 0; i < 2; i++) { 147171169Smlaier val32 = arc4random(); 148171169Smlaier bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32)); 149171169Smlaier } 150171169Smlaier } else 151171169Smlaier bcopy(seed0, seed, 8); 152171169Smlaier 153171169Smlaier /* copy the right-most 64-bits of the given address */ 154171169Smlaier /* XXX assumption on the size of IFID */ 155171169Smlaier bcopy(seed1, &seed[8], 8); 156171169Smlaier 157171169Smlaier if (0) { /* for debugging purposes only */ 158171169Smlaier int i; 159171169Smlaier 160171169Smlaier printf("generate_tmp_ifid: new randomized ID from: "); 161171169Smlaier for (i = 0; i < 16; i++) 162171169Smlaier printf("%02x", seed[i]); 163171169Smlaier printf(" "); 164171169Smlaier } 165171169Smlaier 166171169Smlaier /* generate 16 bytes of pseudo-random value. */ 167171169Smlaier bzero(&ctxt, sizeof(ctxt)); 168171169Smlaier MD5Init(&ctxt); 169171169Smlaier MD5Update(&ctxt, seed, sizeof(seed)); 170171169Smlaier MD5Final(digest, &ctxt); 171171169Smlaier 172171169Smlaier /* 173171169Smlaier * RFC 3041 3.2.1. (3) 174171169Smlaier * Take the left-most 64-bits of the MD5 digest and set bit 6 (the 175171169Smlaier * left-most bit is numbered 0) to zero. 176171169Smlaier */ 177171169Smlaier bcopy(digest, ret, 8); 178171169Smlaier ret[0] &= ~EUI64_UBIT; 179171169Smlaier 180171169Smlaier /* 181171169Smlaier * XXX: we'd like to ensure that the generated value is not zero 182171169Smlaier * for simplicity. If the caclculated digest happens to be zero, 183171169Smlaier * use a random non-zero value as the last resort. 184171169Smlaier */ 185171169Smlaier if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { 186171169Smlaier nd6log((LOG_INFO, 187171169Smlaier "generate_tmp_ifid: computed MD5 value is zero.\n")); 188171169Smlaier 189171169Smlaier val32 = arc4random(); 190171169Smlaier val32 = 1 + (val32 % (0xffffffff - 1)); 191171169Smlaier } 192171169Smlaier 193171169Smlaier /* 194171169Smlaier * RFC 3041 3.2.1. (4) 195171169Smlaier * Take the rightmost 64-bits of the MD5 digest and save them in 196171169Smlaier * stable storage as the history value to be used in the next 197171169Smlaier * iteration of the algorithm. 198171169Smlaier */ 199171169Smlaier bcopy(&digest[8], seed0, 8); 200171169Smlaier 201171169Smlaier if (0) { /* for debugging purposes only */ 202171169Smlaier int i; 203171169Smlaier 204171169Smlaier printf("to: "); 205171169Smlaier for (i = 0; i < 16; i++) 206171169Smlaier printf("%02x", digest[i]); 207171169Smlaier printf("\n"); 208171169Smlaier } 209171169Smlaier 210171169Smlaier return 0; 211171169Smlaier} 212171169Smlaier 213171169Smlaier/* 214171169Smlaier * Get interface identifier for the specified interface. 215171169Smlaier * XXX assumes single sockaddr_dl (AF_LINK address) per an interface 216171169Smlaier */ 217171169Smlaierint 218171169Smlaierin6_get_hw_ifid(ifp, in6) 219171169Smlaier struct ifnet *ifp; 220171169Smlaier struct in6_addr *in6; /* upper 64bits are preserved */ 221171169Smlaier{ 222171169Smlaier struct ifaddr *ifa; 223171169Smlaier struct sockaddr_dl *sdl; 224171169Smlaier u_int8_t *addr; 225171169Smlaier size_t addrlen; 226171169Smlaier static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 227171169Smlaier static u_int8_t allone[8] = 228171169Smlaier { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 229171169Smlaier 230171169Smlaier for (ifa = ifp->if_addrlist.tqh_first; 231171169Smlaier ifa; 232171169Smlaier ifa = ifa->ifa_list.tqe_next) { 233171169Smlaier if (ifa->ifa_addr->sa_family != AF_LINK) 234171169Smlaier continue; 235171169Smlaier sdl = (struct sockaddr_dl *)ifa->ifa_addr; 236171169Smlaier if (sdl == NULL) 237171169Smlaier continue; 238171169Smlaier if (sdl->sdl_alen == 0) 239171169Smlaier continue; 240171169Smlaier 241171169Smlaier goto found; 242171169Smlaier } 243171169Smlaier 244171169Smlaier return -1; 245171169Smlaier 246171169Smlaierfound: 247171169Smlaier addr = LLADDR(sdl); 248171169Smlaier addrlen = sdl->sdl_alen; 249171169Smlaier 250171169Smlaier /* get EUI64 */ 251171169Smlaier switch (ifp->if_type) { 252171169Smlaier case IFT_ETHER: 253171169Smlaier case IFT_FDDI: 254171169Smlaier case IFT_ISO88025: 255171169Smlaier case IFT_ATM: 256171169Smlaier case IFT_IEEE1394: 257171169Smlaier#ifdef IFT_IEEE80211 258171169Smlaier case IFT_IEEE80211: 259171169Smlaier#endif 260171169Smlaier /* IEEE802/EUI64 cases - what others? */ 261171169Smlaier /* IEEE1394 uses 16byte length address starting with EUI64 */ 262171169Smlaier if (addrlen > 8) 263171169Smlaier addrlen = 8; 264171169Smlaier 265171169Smlaier /* look at IEEE802/EUI64 only */ 266171169Smlaier if (addrlen != 8 && addrlen != 6) 267171169Smlaier return -1; 268171169Smlaier 269171169Smlaier /* 270171169Smlaier * check for invalid MAC address - on bsdi, we see it a lot 271171169Smlaier * since wildboar configures all-zero MAC on pccard before 272171169Smlaier * card insertion. 273171169Smlaier */ 274171169Smlaier if (bcmp(addr, allzero, addrlen) == 0) 275171169Smlaier return -1; 276171169Smlaier if (bcmp(addr, allone, addrlen) == 0) 277171169Smlaier return -1; 278171169Smlaier 279171169Smlaier /* make EUI64 address */ 280171169Smlaier if (addrlen == 8) 281171169Smlaier bcopy(addr, &in6->s6_addr[8], 8); 282171169Smlaier else if (addrlen == 6) { 283171169Smlaier in6->s6_addr[8] = addr[0]; 284171169Smlaier in6->s6_addr[9] = addr[1]; 285171169Smlaier in6->s6_addr[10] = addr[2]; 286171169Smlaier in6->s6_addr[11] = 0xff; 287171169Smlaier in6->s6_addr[12] = 0xfe; 288171169Smlaier in6->s6_addr[13] = addr[3]; 289171169Smlaier in6->s6_addr[14] = addr[4]; 290171169Smlaier in6->s6_addr[15] = addr[5]; 291171169Smlaier } 292171169Smlaier break; 293171169Smlaier 294171169Smlaier case IFT_ARCNET: 295171169Smlaier if (addrlen != 1) 296171169Smlaier return -1; 297171169Smlaier if (!addr[0]) 298171169Smlaier return -1; 299171169Smlaier 300171169Smlaier bzero(&in6->s6_addr[8], 8); 301171169Smlaier in6->s6_addr[15] = addr[0]; 302171169Smlaier 303171169Smlaier /* 304171169Smlaier * due to insufficient bitwidth, we mark it local. 305171169Smlaier */ 306171169Smlaier in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 307171169Smlaier in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 308171169Smlaier break; 309171169Smlaier 310171169Smlaier case IFT_GIF: 311171169Smlaier#ifdef IFT_STF 312171169Smlaier case IFT_STF: 313171169Smlaier#endif 314171169Smlaier /* 315171169Smlaier * RFC2893 says: "SHOULD use IPv4 address as ifid source". 316171169Smlaier * however, IPv4 address is not very suitable as unique 317171169Smlaier * identifier source (can be renumbered). 318171169Smlaier * we don't do this. 319171169Smlaier */ 320171169Smlaier return -1; 321171169Smlaier 322171169Smlaier default: 323171169Smlaier return -1; 324171169Smlaier } 325171169Smlaier 326171169Smlaier /* sanity check: g bit must not indicate "group" */ 327171169Smlaier if (EUI64_GROUP(in6)) 328171169Smlaier return -1; 329171169Smlaier 330171169Smlaier /* convert EUI64 into IPv6 interface identifier */ 331171169Smlaier EUI64_TO_IFID(in6); 332171169Smlaier 333171169Smlaier /* 334171169Smlaier * sanity check: ifid must not be all zero, avoid conflict with 335171169Smlaier * subnet router anycast 336171169Smlaier */ 337171169Smlaier if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && 338171169Smlaier bcmp(&in6->s6_addr[9], allzero, 7) == 0) { 339171169Smlaier return -1; 340171169Smlaier } 341171169Smlaier 342171169Smlaier return 0; 343171169Smlaier} 344171169Smlaier 345171169Smlaier/* 346171169Smlaier * Get interface identifier for the specified interface. If it is not 347171169Smlaier * available on ifp0, borrow interface identifier from other information 348171169Smlaier * sources. 349171169Smlaier */ 350171169Smlaierstatic int 351171169Smlaierget_ifid(ifp0, altifp, in6) 352171169Smlaier struct ifnet *ifp0; 353171169Smlaier struct ifnet *altifp; /* secondary EUI64 source */ 354171169Smlaier struct in6_addr *in6; 355171169Smlaier{ 356171169Smlaier struct ifnet *ifp; 357171169Smlaier 358171169Smlaier /* first, try to get it from the interface itself */ 359171169Smlaier if (in6_get_hw_ifid(ifp0, in6) == 0) { 360171169Smlaier nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", 361171169Smlaier if_name(ifp0))); 362171169Smlaier goto success; 363171169Smlaier } 364171169Smlaier 365171169Smlaier /* try secondary EUI64 source. this basically is for ATM PVC */ 366171169Smlaier if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { 367171169Smlaier nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", 368171169Smlaier if_name(ifp0), if_name(altifp))); 369171169Smlaier goto success; 370171169Smlaier } 371171169Smlaier 372171169Smlaier /* next, try to get it from some other hardware interface */ 373171169Smlaier IFNET_RLOCK(); 374171169Smlaier for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) { 375171169Smlaier if (ifp == ifp0) 376171169Smlaier continue; 377171169Smlaier if (in6_get_hw_ifid(ifp, in6) != 0) 378171169Smlaier continue; 379171169Smlaier 380171169Smlaier /* 381171169Smlaier * to borrow ifid from other interface, ifid needs to be 382171169Smlaier * globally unique 383171169Smlaier */ 384171169Smlaier if (IFID_UNIVERSAL(in6)) { 385171169Smlaier nd6log((LOG_DEBUG, 386171169Smlaier "%s: borrow interface identifier from %s\n", 387171169Smlaier if_name(ifp0), if_name(ifp))); 388171169Smlaier IFNET_RUNLOCK(); 389171169Smlaier goto success; 390171169Smlaier } 391171169Smlaier } 392171169Smlaier IFNET_RUNLOCK(); 393171169Smlaier 394171169Smlaier /* last resort: get from random number source */ 395171169Smlaier if (get_rand_ifid(ifp, in6) == 0) { 396171169Smlaier nd6log((LOG_DEBUG, 397171169Smlaier "%s: interface identifier generated by random number\n", 398171169Smlaier if_name(ifp0))); 399171169Smlaier goto success; 400171169Smlaier } 401171169Smlaier 402171169Smlaier printf("%s: failed to get interface identifier\n", if_name(ifp0)); 403171169Smlaier return -1; 404171169Smlaier 405171169Smlaiersuccess: 406171169Smlaier nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 407171169Smlaier if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10], 408171169Smlaier in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13], 409171169Smlaier in6->s6_addr[14], in6->s6_addr[15])); 410171169Smlaier return 0; 411171169Smlaier} 412171169Smlaier 413171169Smlaierstatic int 414171169Smlaierin6_ifattach_linklocal(ifp, altifp) 415171169Smlaier struct ifnet *ifp; 416171169Smlaier struct ifnet *altifp; /* secondary EUI64 source */ 417171169Smlaier{ 418171169Smlaier struct in6_ifaddr *ia; 419171169Smlaier struct in6_aliasreq ifra; 420171169Smlaier struct nd_prefixctl pr0; 421171169Smlaier int i, error; 422171169Smlaier 423171169Smlaier /* 424171169Smlaier * configure link-local address. 425171169Smlaier */ 426171169Smlaier bzero(&ifra, sizeof(ifra)); 427171169Smlaier 428171169Smlaier /* 429171169Smlaier * in6_update_ifa() does not use ifra_name, but we accurately set it 430171169Smlaier * for safety. 431171169Smlaier */ 432171169Smlaier strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 433171169Smlaier 434171169Smlaier ifra.ifra_addr.sin6_family = AF_INET6; 435171169Smlaier ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 436171169Smlaier ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000); 437171169Smlaier ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; 438171169Smlaier if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 439171169Smlaier ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; 440171169Smlaier ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); 441171169Smlaier } else { 442171169Smlaier if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { 443171169Smlaier nd6log((LOG_ERR, 444171169Smlaier "%s: no ifid available\n", if_name(ifp))); 445171169Smlaier return (-1); 446171169Smlaier } 447171169Smlaier } 448171169Smlaier if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) 449171169Smlaier return (-1); 450171169Smlaier 451171169Smlaier ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 452171169Smlaier ifra.ifra_prefixmask.sin6_family = AF_INET6; 453171169Smlaier ifra.ifra_prefixmask.sin6_addr = in6mask64; 454171169Smlaier /* link-local addresses should NEVER expire. */ 455171169Smlaier ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 456171169Smlaier ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 457171169Smlaier 458171169Smlaier /* 459171169Smlaier * Now call in6_update_ifa() to do a bunch of procedures to configure 460171169Smlaier * a link-local address. We can set the 3rd argument to NULL, because 461171169Smlaier * we know there's no other link-local address on the interface 462171169Smlaier * and therefore we are adding one (instead of updating one). 463171169Smlaier */ 464171169Smlaier if ((error = in6_update_ifa(ifp, &ifra, NULL, 465171169Smlaier IN6_IFAUPDATE_DADDELAY)) != 0) { 466171169Smlaier /* 467171169Smlaier * XXX: When the interface does not support IPv6, this call 468171169Smlaier * would fail in the SIOCSIFADDR ioctl. I believe the 469171169Smlaier * notification is rather confusing in this case, so just 470171169Smlaier * suppress it. (jinmei@kame.net 20010130) 471171169Smlaier */ 472171169Smlaier if (error != EAFNOSUPPORT) 473171169Smlaier nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to " 474171169Smlaier "configure a link-local address on %s " 475171169Smlaier "(errno=%d)\n", 476171169Smlaier if_name(ifp), error)); 477171169Smlaier return (-1); 478171169Smlaier } 479171169Smlaier 480171169Smlaier ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ 481171169Smlaier#ifdef DIAGNOSTIC 482171169Smlaier if (!ia) { 483171169Smlaier panic("ia == NULL in in6_ifattach_linklocal"); 484171169Smlaier /* NOTREACHED */ 485171169Smlaier } 486171169Smlaier#endif 487171169Smlaier 488171169Smlaier /* 489171169Smlaier * Make the link-local prefix (fe80::%link/64) as on-link. 490171169Smlaier * Since we'd like to manage prefixes separately from addresses, 491171169Smlaier * we make an ND6 prefix structure for the link-local prefix, 492171169Smlaier * and add it to the prefix list as a never-expire prefix. 493171169Smlaier * XXX: this change might affect some existing code base... 494171169Smlaier */ 495171169Smlaier bzero(&pr0, sizeof(pr0)); 496171169Smlaier pr0.ndpr_ifp = ifp; 497171169Smlaier /* this should be 64 at this moment. */ 498171169Smlaier pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); 499171169Smlaier pr0.ndpr_prefix = ifra.ifra_addr; 500171169Smlaier /* apply the mask for safety. (nd6_prelist_add will apply it again) */ 501171169Smlaier for (i = 0; i < 4; i++) { 502171169Smlaier pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= 503171169Smlaier in6mask64.s6_addr32[i]; 504171169Smlaier } 505171169Smlaier /* 506171169Smlaier * Initialize parameters. The link-local prefix must always be 507171169Smlaier * on-link, and its lifetimes never expire. 508171169Smlaier */ 509171169Smlaier pr0.ndpr_raf_onlink = 1; 510171169Smlaier pr0.ndpr_raf_auto = 1; /* probably meaningless */ 511171169Smlaier pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; 512171169Smlaier pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; 513171169Smlaier /* 514171169Smlaier * Since there is no other link-local addresses, nd6_prefix_lookup() 515171169Smlaier * probably returns NULL. However, we cannot always expect the result. 516171169Smlaier * For example, if we first remove the (only) existing link-local 517171169Smlaier * address, and then reconfigure another one, the prefix is still 518171169Smlaier * valid with referring to the old link-local address. 519171169Smlaier */ 520171169Smlaier if (nd6_prefix_lookup(&pr0) == NULL) { 521171169Smlaier if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) 522171169Smlaier return (error); 523171169Smlaier } 524171169Smlaier 525171169Smlaier return 0; 526171169Smlaier} 527171169Smlaier 528171169Smlaierstatic int 529171169Smlaierin6_ifattach_loopback(ifp) 530171169Smlaier struct ifnet *ifp; /* must be IFT_LOOP */ 531171169Smlaier{ 532171169Smlaier struct in6_aliasreq ifra; 533171169Smlaier int error; 534171169Smlaier 535171169Smlaier bzero(&ifra, sizeof(ifra)); 536171169Smlaier 537171169Smlaier /* 538171169Smlaier * in6_update_ifa() does not use ifra_name, but we accurately set it 539171169Smlaier * for safety. 540171169Smlaier */ 541171169Smlaier strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 542171169Smlaier 543171169Smlaier ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 544171169Smlaier ifra.ifra_prefixmask.sin6_family = AF_INET6; 545171169Smlaier ifra.ifra_prefixmask.sin6_addr = in6mask128; 546171169Smlaier 547171169Smlaier /* 548171169Smlaier * Always initialize ia_dstaddr (= broadcast address) to loopback 549171169Smlaier * address. Follows IPv4 practice - see in_ifinit(). 550171169Smlaier */ 551171169Smlaier ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 552171169Smlaier ifra.ifra_dstaddr.sin6_family = AF_INET6; 553171169Smlaier ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; 554171169Smlaier 555171169Smlaier ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 556171169Smlaier ifra.ifra_addr.sin6_family = AF_INET6; 557171169Smlaier ifra.ifra_addr.sin6_addr = in6addr_loopback; 558171169Smlaier 559171169Smlaier /* the loopback address should NEVER expire. */ 560171169Smlaier ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 561171169Smlaier ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 562171169Smlaier 563171169Smlaier /* we don't need to perform DAD on loopback interfaces. */ 564171169Smlaier ifra.ifra_flags |= IN6_IFF_NODAD; 565171169Smlaier 566171169Smlaier /* skip registration to the prefix list. XXX should be temporary. */ 567171169Smlaier ifra.ifra_flags |= IN6_IFF_NOPFX; 568171169Smlaier 569171169Smlaier /* 570171169Smlaier * We are sure that this is a newly assigned address, so we can set 571171169Smlaier * NULL to the 3rd arg. 572171169Smlaier */ 573171169Smlaier if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) { 574171169Smlaier nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " 575171169Smlaier "the loopback address on %s (errno=%d)\n", 576171169Smlaier if_name(ifp), error)); 577171169Smlaier return (-1); 578171169Smlaier } 579171169Smlaier 580171169Smlaier return 0; 581171169Smlaier} 582171169Smlaier 583171169Smlaier/* 584171169Smlaier * compute NI group address, based on the current hostname setting. 585171169Smlaier * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later). 586171169Smlaier * 587171169Smlaier * when ifp == NULL, the caller is responsible for filling scopeid. 588171169Smlaier */ 589171169Smlaierint 590171169Smlaierin6_nigroup(ifp, name, namelen, in6) 591171169Smlaier struct ifnet *ifp; 592171169Smlaier const char *name; 593171169Smlaier int namelen; 594171169Smlaier struct in6_addr *in6; 595171169Smlaier{ 596171169Smlaier const char *p; 597171169Smlaier u_char *q; 598171169Smlaier MD5_CTX ctxt; 599171169Smlaier u_int8_t digest[16]; 600171169Smlaier char l; 601171169Smlaier char n[64]; /* a single label must not exceed 63 chars */ 602171169Smlaier 603171169Smlaier if (!namelen || !name) 604171169Smlaier return -1; 605171169Smlaier 606171169Smlaier p = name; 607171169Smlaier while (p && *p && *p != '.' && p - name < namelen) 608171169Smlaier p++; 609171169Smlaier if (p - name > sizeof(n) - 1) 610171169Smlaier return -1; /* label too long */ 611171169Smlaier l = p - name; 612171169Smlaier strncpy(n, name, l); 613171169Smlaier n[(int)l] = '\0'; 614171169Smlaier for (q = n; *q; q++) { 615171169Smlaier if ('A' <= *q && *q <= 'Z') 616171169Smlaier *q = *q - 'A' + 'a'; 617171169Smlaier } 618171169Smlaier 619171169Smlaier /* generate 8 bytes of pseudo-random value. */ 620171169Smlaier bzero(&ctxt, sizeof(ctxt)); 621171169Smlaier MD5Init(&ctxt); 622171169Smlaier MD5Update(&ctxt, &l, sizeof(l)); 623171169Smlaier MD5Update(&ctxt, n, l); 624171169Smlaier MD5Final(digest, &ctxt); 625171169Smlaier 626171169Smlaier bzero(in6, sizeof(*in6)); 627171169Smlaier in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL; 628171169Smlaier in6->s6_addr8[11] = 2; 629171169Smlaier bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3])); 630171169Smlaier if (in6_setscope(in6, ifp, NULL)) 631171169Smlaier return (-1); /* XXX: should not fail */ 632171169Smlaier 633171169Smlaier return 0; 634171169Smlaier} 635171169Smlaier 636171169Smlaier/* 637171169Smlaier * XXX multiple loopback interface needs more care. for instance, 638171169Smlaier * nodelocal address needs to be configured onto only one of them. 639171169Smlaier * XXX multiple link-local address case 640171169Smlaier */ 641171169Smlaiervoid 642171169Smlaierin6_ifattach(ifp, altifp) 643171169Smlaier struct ifnet *ifp; 644171169Smlaier struct ifnet *altifp; /* secondary EUI64 source */ 645171169Smlaier{ 646171169Smlaier struct in6_ifaddr *ia; 647171169Smlaier struct in6_addr in6; 648171169Smlaier 649171169Smlaier /* some of the interfaces are inherently not IPv6 capable */ 650171169Smlaier switch (ifp->if_type) { 651171169Smlaier case IFT_PFLOG: 652171169Smlaier case IFT_PFSYNC: 653171169Smlaier case IFT_CARP: 654171169Smlaier return; 655171169Smlaier } 656171169Smlaier 657171169Smlaier /* 658171169Smlaier * quirks based on interface type 659171169Smlaier */ 660171169Smlaier switch (ifp->if_type) { 661171169Smlaier#ifdef IFT_STF 662171169Smlaier case IFT_STF: 663171169Smlaier /* 664171169Smlaier * 6to4 interface is a very special kind of beast. 665171169Smlaier * no multicast, no linklocal. RFC2529 specifies how to make 666171169Smlaier * linklocals for 6to4 interface, but there's no use and 667171169Smlaier * it is rather harmful to have one. 668171169Smlaier */ 669171169Smlaier goto statinit; 670171169Smlaier#endif 671171169Smlaier default: 672171169Smlaier break; 673171169Smlaier } 674171169Smlaier 675171169Smlaier /* 676171169Smlaier * usually, we require multicast capability to the interface 677171169Smlaier */ 678171169Smlaier if ((ifp->if_flags & IFF_MULTICAST) == 0) { 679171169Smlaier nd6log((LOG_INFO, "in6_ifattach: " 680171169Smlaier "%s is not multicast capable, IPv6 not enabled\n", 681171169Smlaier if_name(ifp))); 682171169Smlaier return; 683171169Smlaier } 684171169Smlaier 685171169Smlaier /* 686171169Smlaier * assign loopback address for loopback interface. 687171169Smlaier * XXX multiple loopback interface case. 688171169Smlaier */ 689171169Smlaier if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 690171169Smlaier in6 = in6addr_loopback; 691171169Smlaier if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { 692171169Smlaier if (in6_ifattach_loopback(ifp) != 0) 693171169Smlaier return; 694171169Smlaier } 695171169Smlaier } 696171169Smlaier 697171169Smlaier /* 698171169Smlaier * assign a link-local address, if there's none. 699171169Smlaier */ 700171169Smlaier if (ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) { 701171169Smlaier ia = in6ifa_ifpforlinklocal(ifp, 0); 702171169Smlaier if (ia == NULL) { 703171169Smlaier if (in6_ifattach_linklocal(ifp, altifp) == 0) { 704171169Smlaier /* linklocal address assigned */ 705171169Smlaier } else { 706171169Smlaier /* failed to assign linklocal address. bark? */ 707171169Smlaier } 708171169Smlaier } 709171169Smlaier } 710171169Smlaier 711171169Smlaier#ifdef IFT_STF /* XXX */ 712171169Smlaierstatinit: 713171169Smlaier#endif 714171169Smlaier 715171169Smlaier /* update dynamically. */ 716171169Smlaier if (in6_maxmtu < ifp->if_mtu) 717171169Smlaier in6_maxmtu = ifp->if_mtu; 718171169Smlaier} 719171169Smlaier 720171169Smlaier/* 721171169Smlaier * NOTE: in6_ifdetach() does not support loopback if at this moment. 722171169Smlaier * We don't need this function in bsdi, because interfaces are never removed 723171169Smlaier * from the ifnet list in bsdi. 724171169Smlaier */ 725171169Smlaiervoid 726171169Smlaierin6_ifdetach(ifp) 727171169Smlaier struct ifnet *ifp; 728171169Smlaier{ 729171169Smlaier struct in6_ifaddr *ia, *oia; 730171169Smlaier struct ifaddr *ifa, *next; 731171169Smlaier struct rtentry *rt; 732171169Smlaier short rtflags; 733171169Smlaier struct sockaddr_in6 sin6; 734171169Smlaier struct in6_multi *in6m; 735171169Smlaier struct in6_multi *in6m_next; 736171169Smlaier 737171169Smlaier /* remove neighbor management table */ 738171169Smlaier nd6_purge(ifp); 739171169Smlaier 740171169Smlaier /* nuke any of IPv6 addresses we have */ 741171169Smlaier for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 742171169Smlaier next = ifa->ifa_list.tqe_next; 743171169Smlaier if (ifa->ifa_addr->sa_family != AF_INET6) 744171169Smlaier continue; 745171169Smlaier in6_purgeaddr(ifa); 746171169Smlaier } 747171169Smlaier 748171169Smlaier /* undo everything done by in6_ifattach(), just in case */ 749171169Smlaier for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) { 750171169Smlaier next = ifa->ifa_list.tqe_next; 751171169Smlaier 752171169Smlaier if (ifa->ifa_addr->sa_family != AF_INET6 753171169Smlaier || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 754171169Smlaier continue; 755171169Smlaier } 756171169Smlaier 757171169Smlaier ia = (struct in6_ifaddr *)ifa; 758171169Smlaier 759171169Smlaier /* remove from the routing table */ 760171169Smlaier if ((ia->ia_flags & IFA_ROUTE) && 761171169Smlaier (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { 762171169Smlaier rtflags = rt->rt_flags; 763171169Smlaier rtfree(rt); 764171169Smlaier rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr, 765171169Smlaier (struct sockaddr *)&ia->ia_addr, 766171169Smlaier (struct sockaddr *)&ia->ia_prefixmask, 767171169Smlaier rtflags, (struct rtentry **)0); 768171169Smlaier } 769171169Smlaier 770171169Smlaier /* remove from the linked list */ 771171169Smlaier TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 772171169Smlaier IFAFREE(&ia->ia_ifa); 773171169Smlaier 774171169Smlaier /* also remove from the IPv6 address chain(itojun&jinmei) */ 775171169Smlaier oia = ia; 776171169Smlaier if (oia == (ia = in6_ifaddr)) 777171169Smlaier in6_ifaddr = ia->ia_next; 778171169Smlaier else { 779171169Smlaier while (ia->ia_next && (ia->ia_next != oia)) 780171169Smlaier ia = ia->ia_next; 781171169Smlaier if (ia->ia_next) 782171169Smlaier ia->ia_next = oia->ia_next; 783171169Smlaier else { 784171169Smlaier nd6log((LOG_ERR, 785171169Smlaier "%s: didn't unlink in6ifaddr from list\n", 786171169Smlaier if_name(ifp))); 787171169Smlaier } 788171169Smlaier } 789171169Smlaier 790171169Smlaier IFAFREE(&oia->ia_ifa); 791171169Smlaier } 792171169Smlaier 793171169Smlaier /* leave from all multicast groups joined */ 794171169Smlaier 795171169Smlaier in6_pcbpurgeif0(&udbinfo, ifp); 796171169Smlaier in6_pcbpurgeif0(&ripcbinfo, ifp); 797171169Smlaier 798171169Smlaier for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) { 799171169Smlaier in6m_next = LIST_NEXT(in6m, in6m_entry); 800171169Smlaier if (in6m->in6m_ifp != ifp) 801171169Smlaier continue; 802171169Smlaier in6_delmulti(in6m); 803171169Smlaier in6m = NULL; 804171169Smlaier } 805171169Smlaier 806171169Smlaier /* 807171169Smlaier * remove neighbor management table. we call it twice just to make 808171169Smlaier * sure we nuke everything. maybe we need just one call. 809171169Smlaier * XXX: since the first call did not release addresses, some prefixes 810171169Smlaier * might remain. We should call nd6_purge() again to release the 811171169Smlaier * prefixes after removing all addresses above. 812171169Smlaier * (Or can we just delay calling nd6_purge until at this point?) 813171169Smlaier */ 814171169Smlaier nd6_purge(ifp); 815171169Smlaier 816171169Smlaier /* remove route to link-local allnodes multicast (ff02::1) */ 817171169Smlaier bzero(&sin6, sizeof(sin6)); 818171169Smlaier sin6.sin6_len = sizeof(struct sockaddr_in6); 819171169Smlaier sin6.sin6_family = AF_INET6; 820171169Smlaier sin6.sin6_addr = in6addr_linklocal_allnodes; 821171169Smlaier if (in6_setscope(&sin6.sin6_addr, ifp, NULL)) 822171169Smlaier /* XXX: should not fail */ 823171169Smlaier return; 824171169Smlaier /* XXX grab lock first to avoid LOR */ 825171169Smlaier if (rt_tables[AF_INET6] != NULL) { 826171169Smlaier RADIX_NODE_HEAD_LOCK(rt_tables[AF_INET6]); 827171169Smlaier rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); 828171169Smlaier if (rt) { 829171169Smlaier if (rt->rt_ifp == ifp) 830171169Smlaier rtexpunge(rt); 831171169Smlaier RTFREE_LOCKED(rt); 832171169Smlaier } 833171169Smlaier RADIX_NODE_HEAD_UNLOCK(rt_tables[AF_INET6]); 834171169Smlaier } 835171169Smlaier} 836171169Smlaier 837171169Smlaierint 838171169Smlaierin6_get_tmpifid(ifp, retbuf, baseid, generate) 839171169Smlaier struct ifnet *ifp; 840171169Smlaier u_int8_t *retbuf; 841171169Smlaier const u_int8_t *baseid; 842171169Smlaier int generate; 843171169Smlaier{ 844171169Smlaier u_int8_t nullbuf[8]; 845171169Smlaier struct nd_ifinfo *ndi = ND_IFINFO(ifp); 846171169Smlaier 847171169Smlaier bzero(nullbuf, sizeof(nullbuf)); 848171169Smlaier if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { 849171169Smlaier /* we've never created a random ID. Create a new one. */ 850171169Smlaier generate = 1; 851171169Smlaier } 852171169Smlaier 853171169Smlaier if (generate) { 854171169Smlaier bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); 855171169Smlaier 856171169Smlaier /* generate_tmp_ifid will update seedn and buf */ 857171169Smlaier (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, 858171169Smlaier ndi->randomid); 859171169Smlaier } 860171169Smlaier bcopy(ndi->randomid, retbuf, 8); 861171169Smlaier 862171169Smlaier return (0); 863171169Smlaier} 864171169Smlaier 865171169Smlaiervoid 866171169Smlaierin6_tmpaddrtimer(ignored_arg) 867171169Smlaier void *ignored_arg; 868171169Smlaier{ 869171169Smlaier struct nd_ifinfo *ndi; 870171169Smlaier u_int8_t nullbuf[8]; 871171169Smlaier struct ifnet *ifp; 872171169Smlaier int s = splnet(); 873171169Smlaier 874171169Smlaier callout_reset(&in6_tmpaddrtimer_ch, 875171169Smlaier (ip6_temp_preferred_lifetime - ip6_desync_factor - 876171169Smlaier ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL); 877171169Smlaier 878171169Smlaier bzero(nullbuf, sizeof(nullbuf)); 879 for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { 880 ndi = ND_IFINFO(ifp); 881 if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { 882 /* 883 * We've been generating a random ID on this interface. 884 * Create a new one. 885 */ 886 (void)generate_tmp_ifid(ndi->randomseed0, 887 ndi->randomseed1, ndi->randomid); 888 } 889 } 890 891 splx(s); 892} 893