1686cdd19SJun-ichiro itojun Hagino /* $FreeBSD$ */ 2de9c893eSJun-ichiro itojun Hagino /* $KAME: in6_ifattach.c,v 1.67 2000/10/01 10:51:54 itojun Exp $ */ 3686cdd19SJun-ichiro itojun Hagino 482cd038dSYoshinobu Inoue /* 582cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 682cd038dSYoshinobu Inoue * All rights reserved. 782cd038dSYoshinobu Inoue * 882cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 982cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 1082cd038dSYoshinobu Inoue * are met: 1182cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1282cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1382cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1482cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1582cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1682cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1782cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1882cd038dSYoshinobu Inoue * without specific prior written permission. 1982cd038dSYoshinobu Inoue * 2082cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2182cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2282cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2382cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2482cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2582cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2682cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2782cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2882cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2982cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3082cd038dSYoshinobu Inoue * SUCH DAMAGE. 3182cd038dSYoshinobu Inoue */ 3282cd038dSYoshinobu Inoue 3382cd038dSYoshinobu Inoue #include <sys/param.h> 3482cd038dSYoshinobu Inoue #include <sys/systm.h> 3582cd038dSYoshinobu Inoue #include <sys/malloc.h> 3682cd038dSYoshinobu Inoue #include <sys/socket.h> 3782cd038dSYoshinobu Inoue #include <sys/sockio.h> 3882cd038dSYoshinobu Inoue #include <sys/kernel.h> 3982cd038dSYoshinobu Inoue #include <sys/md5.h> 4082cd038dSYoshinobu Inoue 4182cd038dSYoshinobu Inoue #include <net/if.h> 4282cd038dSYoshinobu Inoue #include <net/if_dl.h> 4382cd038dSYoshinobu Inoue #include <net/if_types.h> 4482cd038dSYoshinobu Inoue #include <net/route.h> 4582cd038dSYoshinobu Inoue 4682cd038dSYoshinobu Inoue #include <netinet/in.h> 4782cd038dSYoshinobu Inoue #include <netinet/in_var.h> 4882cd038dSYoshinobu Inoue #include <netinet/if_ether.h> 4982cd038dSYoshinobu Inoue 50686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 5182cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 5282cd038dSYoshinobu Inoue #include <netinet6/in6_ifattach.h> 5382cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 5482cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 55686cdd19SJun-ichiro itojun Hagino #include <netinet6/scope6_var.h> 5682cd038dSYoshinobu Inoue 5782cd038dSYoshinobu Inoue #include <net/net_osdep.h> 5882cd038dSYoshinobu Inoue 5982cd038dSYoshinobu Inoue struct in6_ifstat **in6_ifstat = NULL; 6082cd038dSYoshinobu Inoue struct icmp6_ifstat **icmp6_ifstat = NULL; 6182cd038dSYoshinobu Inoue size_t in6_ifstatmax = 0; 6282cd038dSYoshinobu Inoue size_t icmp6_ifstatmax = 0; 6382cd038dSYoshinobu Inoue unsigned long in6_maxmtu = 0; 6482cd038dSYoshinobu Inoue 65686cdd19SJun-ichiro itojun Hagino static int get_rand_ifid __P((struct ifnet *, struct in6_addr *)); 66686cdd19SJun-ichiro itojun Hagino static int get_hw_ifid __P((struct ifnet *, struct in6_addr *)); 67686cdd19SJun-ichiro itojun Hagino static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *)); 68686cdd19SJun-ichiro itojun Hagino static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *)); 69686cdd19SJun-ichiro itojun Hagino static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *)); 70686cdd19SJun-ichiro itojun Hagino static int in6_ifattach_loopback __P((struct ifnet *)); 71686cdd19SJun-ichiro itojun Hagino static int nigroup __P((struct ifnet *, const char *, int, struct in6_addr *)); 7282cd038dSYoshinobu Inoue 73686cdd19SJun-ichiro itojun Hagino #define EUI64_GBIT 0x01 74686cdd19SJun-ichiro itojun Hagino #define EUI64_UBIT 0x02 75686cdd19SJun-ichiro itojun Hagino #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) 76686cdd19SJun-ichiro itojun Hagino #define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT) 77686cdd19SJun-ichiro itojun Hagino #define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6)) 78686cdd19SJun-ichiro itojun Hagino #define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT) 79686cdd19SJun-ichiro itojun Hagino #define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6)) 8082cd038dSYoshinobu Inoue 81686cdd19SJun-ichiro itojun Hagino #define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) 82686cdd19SJun-ichiro itojun Hagino #define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) 8382cd038dSYoshinobu Inoue 8482cd038dSYoshinobu Inoue /* 8582cd038dSYoshinobu Inoue * Generate a last-resort interface identifier, when the machine has no 8682cd038dSYoshinobu Inoue * IEEE802/EUI64 address sources. 87686cdd19SJun-ichiro itojun Hagino * The goal here is to get an interface identifier that is 88686cdd19SJun-ichiro itojun Hagino * (1) random enough and (2) does not change across reboot. 89686cdd19SJun-ichiro itojun Hagino * We currently use MD5(hostname) for it. 9082cd038dSYoshinobu Inoue */ 9182cd038dSYoshinobu Inoue static int 92686cdd19SJun-ichiro itojun Hagino get_rand_ifid(ifp, in6) 93686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 94686cdd19SJun-ichiro itojun Hagino struct in6_addr *in6; /*upper 64bits are preserved */ 9582cd038dSYoshinobu Inoue { 9682cd038dSYoshinobu Inoue MD5_CTX ctxt; 9782cd038dSYoshinobu Inoue u_int8_t digest[16]; 9882cd038dSYoshinobu Inoue int hostnamelen = strlen(hostname); 9982cd038dSYoshinobu Inoue 100686cdd19SJun-ichiro itojun Hagino #if 0 101686cdd19SJun-ichiro itojun Hagino /* we need at least several letters as seed for ifid */ 102686cdd19SJun-ichiro itojun Hagino if (hostnamelen < 3) 103686cdd19SJun-ichiro itojun Hagino return -1; 104686cdd19SJun-ichiro itojun Hagino #endif 105686cdd19SJun-ichiro itojun Hagino 10682cd038dSYoshinobu Inoue /* generate 8 bytes of pseudo-random value. */ 10782cd038dSYoshinobu Inoue bzero(&ctxt, sizeof(ctxt)); 10882cd038dSYoshinobu Inoue MD5Init(&ctxt); 10982cd038dSYoshinobu Inoue MD5Update(&ctxt, hostname, hostnamelen); 11082cd038dSYoshinobu Inoue MD5Final(digest, &ctxt); 11182cd038dSYoshinobu Inoue 112686cdd19SJun-ichiro itojun Hagino /* assumes sizeof(digest) > sizeof(ifid) */ 113686cdd19SJun-ichiro itojun Hagino bcopy(digest, &in6->s6_addr[8], 8); 11482cd038dSYoshinobu Inoue 11582cd038dSYoshinobu Inoue /* make sure to set "u" bit to local, and "g" bit to individual. */ 116686cdd19SJun-ichiro itojun Hagino in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 117686cdd19SJun-ichiro itojun Hagino in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 118686cdd19SJun-ichiro itojun Hagino 119686cdd19SJun-ichiro itojun Hagino /* convert EUI64 into IPv6 interface identifier */ 120686cdd19SJun-ichiro itojun Hagino EUI64_TO_IFID(in6); 12182cd038dSYoshinobu Inoue 12282cd038dSYoshinobu Inoue return 0; 12382cd038dSYoshinobu Inoue } 12482cd038dSYoshinobu Inoue 12582cd038dSYoshinobu Inoue /* 126686cdd19SJun-ichiro itojun Hagino * Get interface identifier for the specified interface. 127686cdd19SJun-ichiro itojun Hagino * XXX assumes single sockaddr_dl (AF_LINK address) per an interface 12882cd038dSYoshinobu Inoue */ 129686cdd19SJun-ichiro itojun Hagino static int 130686cdd19SJun-ichiro itojun Hagino get_hw_ifid(ifp, in6) 13182cd038dSYoshinobu Inoue struct ifnet *ifp; 132686cdd19SJun-ichiro itojun Hagino struct in6_addr *in6; /*upper 64bits are preserved */ 13382cd038dSYoshinobu Inoue { 134686cdd19SJun-ichiro itojun Hagino struct ifaddr *ifa; 135686cdd19SJun-ichiro itojun Hagino struct sockaddr_dl *sdl; 136686cdd19SJun-ichiro itojun Hagino u_int8_t *addr; 137686cdd19SJun-ichiro itojun Hagino size_t addrlen; 138686cdd19SJun-ichiro itojun Hagino static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 139686cdd19SJun-ichiro itojun Hagino static u_int8_t allone[8] = 140686cdd19SJun-ichiro itojun Hagino { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 141686cdd19SJun-ichiro itojun Hagino 142686cdd19SJun-ichiro itojun Hagino for (ifa = ifp->if_addrlist.tqh_first; 143686cdd19SJun-ichiro itojun Hagino ifa; 144686cdd19SJun-ichiro itojun Hagino ifa = ifa->ifa_list.tqe_next) 14582cd038dSYoshinobu Inoue { 14682cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_LINK) 14782cd038dSYoshinobu Inoue continue; 14882cd038dSYoshinobu Inoue sdl = (struct sockaddr_dl *)ifa->ifa_addr; 14982cd038dSYoshinobu Inoue if (sdl == NULL) 15082cd038dSYoshinobu Inoue continue; 15182cd038dSYoshinobu Inoue if (sdl->sdl_alen == 0) 15282cd038dSYoshinobu Inoue continue; 153686cdd19SJun-ichiro itojun Hagino 154686cdd19SJun-ichiro itojun Hagino goto found; 155686cdd19SJun-ichiro itojun Hagino } 156686cdd19SJun-ichiro itojun Hagino 157686cdd19SJun-ichiro itojun Hagino return -1; 158686cdd19SJun-ichiro itojun Hagino 159686cdd19SJun-ichiro itojun Hagino found: 160686cdd19SJun-ichiro itojun Hagino addr = LLADDR(sdl); 161686cdd19SJun-ichiro itojun Hagino addrlen = sdl->sdl_alen; 162686cdd19SJun-ichiro itojun Hagino 163686cdd19SJun-ichiro itojun Hagino /* get EUI64 */ 16482cd038dSYoshinobu Inoue switch (ifp->if_type) { 16582cd038dSYoshinobu Inoue case IFT_ETHER: 16682cd038dSYoshinobu Inoue case IFT_FDDI: 16782cd038dSYoshinobu Inoue case IFT_ATM: 16882cd038dSYoshinobu Inoue /* IEEE802/EUI64 cases - what others? */ 169686cdd19SJun-ichiro itojun Hagino 170686cdd19SJun-ichiro itojun Hagino /* look at IEEE802/EUI64 only */ 171686cdd19SJun-ichiro itojun Hagino if (addrlen != 8 && addrlen != 6) 172686cdd19SJun-ichiro itojun Hagino return -1; 173686cdd19SJun-ichiro itojun Hagino 17482cd038dSYoshinobu Inoue /* 175686cdd19SJun-ichiro itojun Hagino * check for invalid MAC address - on bsdi, we see it a lot 176686cdd19SJun-ichiro itojun Hagino * since wildboar configures all-zero MAC on pccard before 177686cdd19SJun-ichiro itojun Hagino * card insertion. 17882cd038dSYoshinobu Inoue */ 179686cdd19SJun-ichiro itojun Hagino if (bcmp(addr, allzero, addrlen) == 0) 180686cdd19SJun-ichiro itojun Hagino return -1; 181686cdd19SJun-ichiro itojun Hagino if (bcmp(addr, allone, addrlen) == 0) 182686cdd19SJun-ichiro itojun Hagino return -1; 183686cdd19SJun-ichiro itojun Hagino 184686cdd19SJun-ichiro itojun Hagino /* make EUI64 address */ 185686cdd19SJun-ichiro itojun Hagino if (addrlen == 8) 186686cdd19SJun-ichiro itojun Hagino bcopy(addr, &in6->s6_addr[8], 8); 187686cdd19SJun-ichiro itojun Hagino else if (addrlen == 6) { 188686cdd19SJun-ichiro itojun Hagino in6->s6_addr[8] = addr[0]; 189686cdd19SJun-ichiro itojun Hagino in6->s6_addr[9] = addr[1]; 190686cdd19SJun-ichiro itojun Hagino in6->s6_addr[10] = addr[2]; 191686cdd19SJun-ichiro itojun Hagino in6->s6_addr[11] = 0xff; 192686cdd19SJun-ichiro itojun Hagino in6->s6_addr[12] = 0xfe; 193686cdd19SJun-ichiro itojun Hagino in6->s6_addr[13] = addr[3]; 194686cdd19SJun-ichiro itojun Hagino in6->s6_addr[14] = addr[4]; 195686cdd19SJun-ichiro itojun Hagino in6->s6_addr[15] = addr[5]; 196686cdd19SJun-ichiro itojun Hagino } 19782cd038dSYoshinobu Inoue break; 198686cdd19SJun-ichiro itojun Hagino 19982cd038dSYoshinobu Inoue case IFT_ARCNET: 200686cdd19SJun-ichiro itojun Hagino if (addrlen != 1) 201686cdd19SJun-ichiro itojun Hagino return -1; 202686cdd19SJun-ichiro itojun Hagino if (!addr[0]) 203686cdd19SJun-ichiro itojun Hagino return -1; 204686cdd19SJun-ichiro itojun Hagino 205686cdd19SJun-ichiro itojun Hagino bzero(&in6->s6_addr[8], 8); 206686cdd19SJun-ichiro itojun Hagino in6->s6_addr[15] = addr[0]; 207686cdd19SJun-ichiro itojun Hagino 20882cd038dSYoshinobu Inoue /* 209686cdd19SJun-ichiro itojun Hagino * due to insufficient bitwidth, we mark it local. 21082cd038dSYoshinobu Inoue */ 211686cdd19SJun-ichiro itojun Hagino in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ 212686cdd19SJun-ichiro itojun Hagino in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ 21382cd038dSYoshinobu Inoue break; 214686cdd19SJun-ichiro itojun Hagino 215686cdd19SJun-ichiro itojun Hagino case IFT_GIF: 216686cdd19SJun-ichiro itojun Hagino #ifdef IFT_STF 217686cdd19SJun-ichiro itojun Hagino case IFT_STF: 21882cd038dSYoshinobu Inoue #endif 219686cdd19SJun-ichiro itojun Hagino /* 220686cdd19SJun-ichiro itojun Hagino * mech-06 says: "SHOULD use IPv4 address as ifid source". 221686cdd19SJun-ichiro itojun Hagino * however, IPv4 address is not very suitable as unique 222686cdd19SJun-ichiro itojun Hagino * identifier source (can be renumbered). 223686cdd19SJun-ichiro itojun Hagino * we don't do this. 224686cdd19SJun-ichiro itojun Hagino */ 225686cdd19SJun-ichiro itojun Hagino return -1; 22682cd038dSYoshinobu Inoue 227686cdd19SJun-ichiro itojun Hagino default: 228686cdd19SJun-ichiro itojun Hagino return -1; 229686cdd19SJun-ichiro itojun Hagino } 23082cd038dSYoshinobu Inoue 231686cdd19SJun-ichiro itojun Hagino /* sanity check: g bit must not indicate "group" */ 232686cdd19SJun-ichiro itojun Hagino if (EUI64_GROUP(in6)) 233686cdd19SJun-ichiro itojun Hagino return -1; 23482cd038dSYoshinobu Inoue 235686cdd19SJun-ichiro itojun Hagino /* convert EUI64 into IPv6 interface identifier */ 236686cdd19SJun-ichiro itojun Hagino EUI64_TO_IFID(in6); 237686cdd19SJun-ichiro itojun Hagino 238686cdd19SJun-ichiro itojun Hagino /* 239686cdd19SJun-ichiro itojun Hagino * sanity check: ifid must not be all zero, avoid conflict with 240686cdd19SJun-ichiro itojun Hagino * subnet router anycast 241686cdd19SJun-ichiro itojun Hagino */ 242686cdd19SJun-ichiro itojun Hagino if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && 243686cdd19SJun-ichiro itojun Hagino bcmp(&in6->s6_addr[9], allzero, 7) == 0) { 244686cdd19SJun-ichiro itojun Hagino return -1; 245686cdd19SJun-ichiro itojun Hagino } 24682cd038dSYoshinobu Inoue 24782cd038dSYoshinobu Inoue return 0; 248686cdd19SJun-ichiro itojun Hagino } 249686cdd19SJun-ichiro itojun Hagino 250686cdd19SJun-ichiro itojun Hagino /* 251686cdd19SJun-ichiro itojun Hagino * Get interface identifier for the specified interface. If it is not 252686cdd19SJun-ichiro itojun Hagino * available on ifp0, borrow interface identifier from other information 253686cdd19SJun-ichiro itojun Hagino * sources. 254686cdd19SJun-ichiro itojun Hagino */ 255686cdd19SJun-ichiro itojun Hagino static int 256686cdd19SJun-ichiro itojun Hagino get_ifid(ifp0, altifp, in6) 257686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp0; 258686cdd19SJun-ichiro itojun Hagino struct ifnet *altifp; /*secondary EUI64 source*/ 259686cdd19SJun-ichiro itojun Hagino struct in6_addr *in6; 260686cdd19SJun-ichiro itojun Hagino { 261686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 262686cdd19SJun-ichiro itojun Hagino 263686cdd19SJun-ichiro itojun Hagino /* first, try to get it from the interface itself */ 264686cdd19SJun-ichiro itojun Hagino if (get_hw_ifid(ifp0, in6) == 0) { 265686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG 266686cdd19SJun-ichiro itojun Hagino printf("%s: got interface identifier from itself\n", 267686cdd19SJun-ichiro itojun Hagino if_name(ifp0)); 26882cd038dSYoshinobu Inoue #endif 269686cdd19SJun-ichiro itojun Hagino goto success; 270686cdd19SJun-ichiro itojun Hagino } 271686cdd19SJun-ichiro itojun Hagino 272686cdd19SJun-ichiro itojun Hagino /* try secondary EUI64 source. this basically is for ATM PVC */ 273686cdd19SJun-ichiro itojun Hagino if (altifp && get_hw_ifid(altifp, in6) == 0) { 274686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG 275686cdd19SJun-ichiro itojun Hagino printf("%s: got interface identifier from %s\n", 276686cdd19SJun-ichiro itojun Hagino if_name(ifp0), if_name(altifp)); 277686cdd19SJun-ichiro itojun Hagino #endif 278686cdd19SJun-ichiro itojun Hagino goto success; 279686cdd19SJun-ichiro itojun Hagino } 280686cdd19SJun-ichiro itojun Hagino 281686cdd19SJun-ichiro itojun Hagino /* next, try to get it from some other hardware interface */ 282686cdd19SJun-ichiro itojun Hagino for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) 283686cdd19SJun-ichiro itojun Hagino { 284686cdd19SJun-ichiro itojun Hagino if (ifp == ifp0) 285686cdd19SJun-ichiro itojun Hagino continue; 286686cdd19SJun-ichiro itojun Hagino if (get_hw_ifid(ifp, in6) != 0) 287686cdd19SJun-ichiro itojun Hagino continue; 288686cdd19SJun-ichiro itojun Hagino 289686cdd19SJun-ichiro itojun Hagino /* 290686cdd19SJun-ichiro itojun Hagino * to borrow ifid from other interface, ifid needs to be 291686cdd19SJun-ichiro itojun Hagino * globally unique 292686cdd19SJun-ichiro itojun Hagino */ 293686cdd19SJun-ichiro itojun Hagino if (IFID_UNIVERSAL(in6)) { 294686cdd19SJun-ichiro itojun Hagino 295686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG 296686cdd19SJun-ichiro itojun Hagino printf("%s: borrow interface identifier from %s\n", 297686cdd19SJun-ichiro itojun Hagino if_name(ifp0), if_name(ifp)); 298686cdd19SJun-ichiro itojun Hagino #endif 299686cdd19SJun-ichiro itojun Hagino goto success; 300686cdd19SJun-ichiro itojun Hagino } 301686cdd19SJun-ichiro itojun Hagino } 302686cdd19SJun-ichiro itojun Hagino 303686cdd19SJun-ichiro itojun Hagino /* last resort: get from random number source */ 304686cdd19SJun-ichiro itojun Hagino if (get_rand_ifid(ifp, in6) == 0) { 305686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG 306686cdd19SJun-ichiro itojun Hagino printf("%s: interface identifier generated by random number\n", 307686cdd19SJun-ichiro itojun Hagino if_name(ifp0)); 308686cdd19SJun-ichiro itojun Hagino #endif 309686cdd19SJun-ichiro itojun Hagino goto success; 310686cdd19SJun-ichiro itojun Hagino } 311686cdd19SJun-ichiro itojun Hagino 312de9c893eSJun-ichiro itojun Hagino printf("%s: failed to get interface identifier\n", if_name(ifp0)); 313686cdd19SJun-ichiro itojun Hagino return -1; 314686cdd19SJun-ichiro itojun Hagino 315686cdd19SJun-ichiro itojun Hagino success: 316686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG 317686cdd19SJun-ichiro itojun Hagino printf("%s: ifid: " 318686cdd19SJun-ichiro itojun Hagino "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 319686cdd19SJun-ichiro itojun Hagino if_name(ifp0), 320686cdd19SJun-ichiro itojun Hagino in6->s6_addr[8], in6->s6_addr[9], 321686cdd19SJun-ichiro itojun Hagino in6->s6_addr[10], in6->s6_addr[11], 322686cdd19SJun-ichiro itojun Hagino in6->s6_addr[12], in6->s6_addr[13], 323686cdd19SJun-ichiro itojun Hagino in6->s6_addr[14], in6->s6_addr[15]); 324686cdd19SJun-ichiro itojun Hagino #endif 325686cdd19SJun-ichiro itojun Hagino return 0; 326686cdd19SJun-ichiro itojun Hagino } 327686cdd19SJun-ichiro itojun Hagino 328686cdd19SJun-ichiro itojun Hagino /* 329686cdd19SJun-ichiro itojun Hagino * configure IPv6 interface address. XXX code duplicated with in.c 330686cdd19SJun-ichiro itojun Hagino */ 331686cdd19SJun-ichiro itojun Hagino static int 332686cdd19SJun-ichiro itojun Hagino in6_ifattach_addaddr(ifp, ia) 333686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 334686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *ia; 335686cdd19SJun-ichiro itojun Hagino { 336686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *oia; 337686cdd19SJun-ichiro itojun Hagino struct ifaddr *ifa; 338686cdd19SJun-ichiro itojun Hagino int error; 339686cdd19SJun-ichiro itojun Hagino int rtflag; 340686cdd19SJun-ichiro itojun Hagino struct in6_addr llsol; 341686cdd19SJun-ichiro itojun Hagino 342686cdd19SJun-ichiro itojun Hagino /* 343686cdd19SJun-ichiro itojun Hagino * initialize if_addrlist, if we are the very first one 344686cdd19SJun-ichiro itojun Hagino */ 345686cdd19SJun-ichiro itojun Hagino ifa = TAILQ_FIRST(&ifp->if_addrlist); 346686cdd19SJun-ichiro itojun Hagino if (ifa == NULL) { 347686cdd19SJun-ichiro itojun Hagino TAILQ_INIT(&ifp->if_addrlist); 348686cdd19SJun-ichiro itojun Hagino } 349686cdd19SJun-ichiro itojun Hagino 350686cdd19SJun-ichiro itojun Hagino /* 351686cdd19SJun-ichiro itojun Hagino * link the interface address to global list 352686cdd19SJun-ichiro itojun Hagino */ 353686cdd19SJun-ichiro itojun Hagino TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 354686cdd19SJun-ichiro itojun Hagino /* gain a refcnt for the link from if_addrlist */ 355686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_refcnt++; 356686cdd19SJun-ichiro itojun Hagino 357686cdd19SJun-ichiro itojun Hagino /* 358686cdd19SJun-ichiro itojun Hagino * Also link into the IPv6 address chain beginning with in6_ifaddr. 359686cdd19SJun-ichiro itojun Hagino * kazu opposed it, but itojun & jinmei wanted. 360686cdd19SJun-ichiro itojun Hagino */ 361686cdd19SJun-ichiro itojun Hagino if ((oia = in6_ifaddr) != NULL) { 362686cdd19SJun-ichiro itojun Hagino for (; oia->ia_next; oia = oia->ia_next) 363686cdd19SJun-ichiro itojun Hagino continue; 364686cdd19SJun-ichiro itojun Hagino oia->ia_next = ia; 365686cdd19SJun-ichiro itojun Hagino } else 366686cdd19SJun-ichiro itojun Hagino in6_ifaddr = ia; 367686cdd19SJun-ichiro itojun Hagino /* gain another refcnt for the link from in6_ifaddr */ 368686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_refcnt++; 369686cdd19SJun-ichiro itojun Hagino 370686cdd19SJun-ichiro itojun Hagino /* 371686cdd19SJun-ichiro itojun Hagino * give the interface a chance to initialize, in case this 372686cdd19SJun-ichiro itojun Hagino * is the first address to be added. 373686cdd19SJun-ichiro itojun Hagino */ 374686cdd19SJun-ichiro itojun Hagino if (ifp->if_ioctl != NULL) { 375686cdd19SJun-ichiro itojun Hagino int s; 376686cdd19SJun-ichiro itojun Hagino s = splimp(); 377686cdd19SJun-ichiro itojun Hagino error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); 378686cdd19SJun-ichiro itojun Hagino splx(s); 379686cdd19SJun-ichiro itojun Hagino } else 380686cdd19SJun-ichiro itojun Hagino error = 0; 381686cdd19SJun-ichiro itojun Hagino if (error) { 382686cdd19SJun-ichiro itojun Hagino switch (error) { 383686cdd19SJun-ichiro itojun Hagino case EAFNOSUPPORT: 384686cdd19SJun-ichiro itojun Hagino printf("%s: IPv6 not supported\n", if_name(ifp)); 385686cdd19SJun-ichiro itojun Hagino break; 386686cdd19SJun-ichiro itojun Hagino default: 387686cdd19SJun-ichiro itojun Hagino printf("%s: SIOCSIFADDR error %d\n", if_name(ifp), 388686cdd19SJun-ichiro itojun Hagino error); 389686cdd19SJun-ichiro itojun Hagino break; 390686cdd19SJun-ichiro itojun Hagino } 391686cdd19SJun-ichiro itojun Hagino 392686cdd19SJun-ichiro itojun Hagino /* undo changes */ 393686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 394686cdd19SJun-ichiro itojun Hagino IFAFREE(&ia->ia_ifa); 395686cdd19SJun-ichiro itojun Hagino if (oia) 396686cdd19SJun-ichiro itojun Hagino oia->ia_next = ia->ia_next; 397686cdd19SJun-ichiro itojun Hagino else 398686cdd19SJun-ichiro itojun Hagino in6_ifaddr = ia->ia_next; 399686cdd19SJun-ichiro itojun Hagino IFAFREE(&ia->ia_ifa); 400686cdd19SJun-ichiro itojun Hagino return -1; 401686cdd19SJun-ichiro itojun Hagino } 402686cdd19SJun-ichiro itojun Hagino 403686cdd19SJun-ichiro itojun Hagino /* configure link-layer address resolution */ 404686cdd19SJun-ichiro itojun Hagino rtflag = 0; 405686cdd19SJun-ichiro itojun Hagino if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128)) 406686cdd19SJun-ichiro itojun Hagino rtflag = RTF_HOST; 407686cdd19SJun-ichiro itojun Hagino else { 408686cdd19SJun-ichiro itojun Hagino switch (ifp->if_type) { 409686cdd19SJun-ichiro itojun Hagino case IFT_LOOP: 410686cdd19SJun-ichiro itojun Hagino #ifdef IFT_STF 411686cdd19SJun-ichiro itojun Hagino case IFT_STF: 412686cdd19SJun-ichiro itojun Hagino #endif 413686cdd19SJun-ichiro itojun Hagino rtflag = 0; 414686cdd19SJun-ichiro itojun Hagino break; 415686cdd19SJun-ichiro itojun Hagino default: 416686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; 417686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_flags |= RTF_CLONING; 418686cdd19SJun-ichiro itojun Hagino rtflag = RTF_CLONING; 419686cdd19SJun-ichiro itojun Hagino break; 420686cdd19SJun-ichiro itojun Hagino } 421686cdd19SJun-ichiro itojun Hagino } 422686cdd19SJun-ichiro itojun Hagino 423686cdd19SJun-ichiro itojun Hagino /* add route to the interface. */ 424686cdd19SJun-ichiro itojun Hagino { 425686cdd19SJun-ichiro itojun Hagino int e; 426686cdd19SJun-ichiro itojun Hagino 427686cdd19SJun-ichiro itojun Hagino e = rtrequest(RTM_ADD, 428686cdd19SJun-ichiro itojun Hagino (struct sockaddr *)&ia->ia_addr, 429686cdd19SJun-ichiro itojun Hagino (struct sockaddr *)&ia->ia_addr, 430686cdd19SJun-ichiro itojun Hagino (struct sockaddr *)&ia->ia_prefixmask, 431686cdd19SJun-ichiro itojun Hagino RTF_UP | rtflag, 432686cdd19SJun-ichiro itojun Hagino (struct rtentry **)0); 433686cdd19SJun-ichiro itojun Hagino if (e) { 434686cdd19SJun-ichiro itojun Hagino printf("in6_ifattach_addaddr: rtrequest failed. errno = %d\n", e); 435686cdd19SJun-ichiro itojun Hagino } 436686cdd19SJun-ichiro itojun Hagino } 437686cdd19SJun-ichiro itojun Hagino ia->ia_flags |= IFA_ROUTE; 438686cdd19SJun-ichiro itojun Hagino 439686cdd19SJun-ichiro itojun Hagino if ((rtflag & RTF_CLONING) != 0 && 440686cdd19SJun-ichiro itojun Hagino (ifp->if_flags & IFF_MULTICAST) != 0) { 441686cdd19SJun-ichiro itojun Hagino /* 442686cdd19SJun-ichiro itojun Hagino * join solicited multicast address 443686cdd19SJun-ichiro itojun Hagino */ 444686cdd19SJun-ichiro itojun Hagino bzero(&llsol, sizeof(llsol)); 445686cdd19SJun-ichiro itojun Hagino llsol.s6_addr16[0] = htons(0xff02); 446686cdd19SJun-ichiro itojun Hagino llsol.s6_addr16[1] = htons(ifp->if_index); 447686cdd19SJun-ichiro itojun Hagino llsol.s6_addr32[1] = 0; 448686cdd19SJun-ichiro itojun Hagino llsol.s6_addr32[2] = htonl(1); 449686cdd19SJun-ichiro itojun Hagino llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; 450686cdd19SJun-ichiro itojun Hagino llsol.s6_addr8[12] = 0xff; 451686cdd19SJun-ichiro itojun Hagino (void)in6_addmulti(&llsol, ifp, &error); 452686cdd19SJun-ichiro itojun Hagino 453686cdd19SJun-ichiro itojun Hagino /* XXX should we run DAD on other interface types? */ 454686cdd19SJun-ichiro itojun Hagino switch (ifp->if_type) { 455686cdd19SJun-ichiro itojun Hagino #if 1 456686cdd19SJun-ichiro itojun Hagino case IFT_ARCNET: 457686cdd19SJun-ichiro itojun Hagino case IFT_ETHER: 458686cdd19SJun-ichiro itojun Hagino case IFT_FDDI: 459686cdd19SJun-ichiro itojun Hagino #else 460686cdd19SJun-ichiro itojun Hagino default: 461686cdd19SJun-ichiro itojun Hagino #endif 462686cdd19SJun-ichiro itojun Hagino /* mark the address TENTATIVE, if needed. */ 463686cdd19SJun-ichiro itojun Hagino ia->ia6_flags |= IN6_IFF_TENTATIVE; 464686cdd19SJun-ichiro itojun Hagino /* nd6_dad_start() will be called in in6_if_up */ 465686cdd19SJun-ichiro itojun Hagino } 466686cdd19SJun-ichiro itojun Hagino } 467686cdd19SJun-ichiro itojun Hagino 468686cdd19SJun-ichiro itojun Hagino return 0; 469686cdd19SJun-ichiro itojun Hagino } 470686cdd19SJun-ichiro itojun Hagino 471686cdd19SJun-ichiro itojun Hagino static int 472686cdd19SJun-ichiro itojun Hagino in6_ifattach_linklocal(ifp, altifp) 473686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 474686cdd19SJun-ichiro itojun Hagino struct ifnet *altifp; /*secondary EUI64 source*/ 475686cdd19SJun-ichiro itojun Hagino { 476686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *ia; 477686cdd19SJun-ichiro itojun Hagino 478686cdd19SJun-ichiro itojun Hagino /* 479686cdd19SJun-ichiro itojun Hagino * configure link-local address 480686cdd19SJun-ichiro itojun Hagino */ 481686cdd19SJun-ichiro itojun Hagino ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 482686cdd19SJun-ichiro itojun Hagino bzero((caddr_t)ia, sizeof(*ia)); 483686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 484686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_POINTOPOINT) 485686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 486686cdd19SJun-ichiro itojun Hagino else 487686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_dstaddr = NULL; 488686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 489686cdd19SJun-ichiro itojun Hagino ia->ia_ifp = ifp; 490686cdd19SJun-ichiro itojun Hagino 491686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 492686cdd19SJun-ichiro itojun Hagino ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 493686cdd19SJun-ichiro itojun Hagino ia->ia_prefixmask.sin6_family = AF_INET6; 494686cdd19SJun-ichiro itojun Hagino #ifdef SCOPEDROUTING 495686cdd19SJun-ichiro itojun Hagino /* take into accound the sin6_scope_id field for routing */ 496686cdd19SJun-ichiro itojun Hagino ia->ia_prefixmask.sin6_scope_id = 0xffffffff; 497686cdd19SJun-ichiro itojun Hagino #endif 498686cdd19SJun-ichiro itojun Hagino ia->ia_prefixmask.sin6_addr = in6mask64; 499686cdd19SJun-ichiro itojun Hagino 500686cdd19SJun-ichiro itojun Hagino /* just in case */ 501686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); 502686cdd19SJun-ichiro itojun Hagino ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 503686cdd19SJun-ichiro itojun Hagino ia->ia_dstaddr.sin6_family = AF_INET6; 504686cdd19SJun-ichiro itojun Hagino 505686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_addr, sizeof(ia->ia_addr)); 506686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); 507686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_family = AF_INET6; 508686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); 509686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 510686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_addr.s6_addr32[1] = 0; 511686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_LOOPBACK) { 512686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_addr.s6_addr32[2] = 0; 513686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1); 514686cdd19SJun-ichiro itojun Hagino } else { 515686cdd19SJun-ichiro itojun Hagino if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) { 516686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG 517686cdd19SJun-ichiro itojun Hagino printf("%s: no ifid available\n", if_name(ifp)); 518686cdd19SJun-ichiro itojun Hagino #endif 519686cdd19SJun-ichiro itojun Hagino free(ia, M_IFADDR); 520686cdd19SJun-ichiro itojun Hagino return -1; 521686cdd19SJun-ichiro itojun Hagino } 522686cdd19SJun-ichiro itojun Hagino } 523686cdd19SJun-ichiro itojun Hagino #ifdef SCOPEDROUTING 524686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_scope_id = in6_addr2scopeid(ifp, 525686cdd19SJun-ichiro itojun Hagino &ia->ia_addr.sin6_addr); 526686cdd19SJun-ichiro itojun Hagino #endif 527686cdd19SJun-ichiro itojun Hagino 528686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_metric = ifp->if_metric; 529686cdd19SJun-ichiro itojun Hagino 530686cdd19SJun-ichiro itojun Hagino if (in6_ifattach_addaddr(ifp, ia) != 0) { 531686cdd19SJun-ichiro itojun Hagino /* ia will be freed on failure */ 532686cdd19SJun-ichiro itojun Hagino return -1; 533686cdd19SJun-ichiro itojun Hagino } 534686cdd19SJun-ichiro itojun Hagino 535686cdd19SJun-ichiro itojun Hagino return 0; 536686cdd19SJun-ichiro itojun Hagino } 537686cdd19SJun-ichiro itojun Hagino 538686cdd19SJun-ichiro itojun Hagino static int 539686cdd19SJun-ichiro itojun Hagino in6_ifattach_loopback(ifp) 540686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; /* must be IFT_LOOP */ 541686cdd19SJun-ichiro itojun Hagino { 542686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *ia; 543686cdd19SJun-ichiro itojun Hagino 544686cdd19SJun-ichiro itojun Hagino /* 545686cdd19SJun-ichiro itojun Hagino * configure link-local address 546686cdd19SJun-ichiro itojun Hagino */ 547686cdd19SJun-ichiro itojun Hagino ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK); 548686cdd19SJun-ichiro itojun Hagino bzero((caddr_t)ia, sizeof(*ia)); 549686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 550686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 551686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 552686cdd19SJun-ichiro itojun Hagino ia->ia_ifp = ifp; 553686cdd19SJun-ichiro itojun Hagino 554686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); 555686cdd19SJun-ichiro itojun Hagino ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 556686cdd19SJun-ichiro itojun Hagino ia->ia_prefixmask.sin6_family = AF_INET6; 557686cdd19SJun-ichiro itojun Hagino ia->ia_prefixmask.sin6_addr = in6mask128; 558686cdd19SJun-ichiro itojun Hagino 559686cdd19SJun-ichiro itojun Hagino /* 560686cdd19SJun-ichiro itojun Hagino * Always initialize ia_dstaddr (= broadcast address) to loopback 561686cdd19SJun-ichiro itojun Hagino * address, to make getifaddr happier. 562686cdd19SJun-ichiro itojun Hagino * 563686cdd19SJun-ichiro itojun Hagino * For BSDI, it is mandatory. The BSDI version of 564686cdd19SJun-ichiro itojun Hagino * ifa_ifwithroute() rejects to add a route to the loopback 565686cdd19SJun-ichiro itojun Hagino * interface. Even for other systems, loopback looks somewhat 566686cdd19SJun-ichiro itojun Hagino * special. 567686cdd19SJun-ichiro itojun Hagino */ 568686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr)); 569686cdd19SJun-ichiro itojun Hagino ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6); 570686cdd19SJun-ichiro itojun Hagino ia->ia_dstaddr.sin6_family = AF_INET6; 571686cdd19SJun-ichiro itojun Hagino ia->ia_dstaddr.sin6_addr = in6addr_loopback; 572686cdd19SJun-ichiro itojun Hagino 573686cdd19SJun-ichiro itojun Hagino bzero(&ia->ia_addr, sizeof(ia->ia_addr)); 574686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); 575686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_family = AF_INET6; 576686cdd19SJun-ichiro itojun Hagino ia->ia_addr.sin6_addr = in6addr_loopback; 577686cdd19SJun-ichiro itojun Hagino 578686cdd19SJun-ichiro itojun Hagino ia->ia_ifa.ifa_metric = ifp->if_metric; 579686cdd19SJun-ichiro itojun Hagino 580686cdd19SJun-ichiro itojun Hagino if (in6_ifattach_addaddr(ifp, ia) != 0) { 581686cdd19SJun-ichiro itojun Hagino /* ia will be freed on failure */ 582686cdd19SJun-ichiro itojun Hagino return -1; 583686cdd19SJun-ichiro itojun Hagino } 584686cdd19SJun-ichiro itojun Hagino 585686cdd19SJun-ichiro itojun Hagino return 0; 586686cdd19SJun-ichiro itojun Hagino } 587686cdd19SJun-ichiro itojun Hagino 588686cdd19SJun-ichiro itojun Hagino /* 589686cdd19SJun-ichiro itojun Hagino * compute NI group address, based on the current hostname setting. 590686cdd19SJun-ichiro itojun Hagino * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later). 591686cdd19SJun-ichiro itojun Hagino * 592686cdd19SJun-ichiro itojun Hagino * when ifp == NULL, the caller is responsible for filling scopeid. 593686cdd19SJun-ichiro itojun Hagino */ 594686cdd19SJun-ichiro itojun Hagino static int 595686cdd19SJun-ichiro itojun Hagino nigroup(ifp, name, namelen, in6) 596686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 597686cdd19SJun-ichiro itojun Hagino const char *name; 598686cdd19SJun-ichiro itojun Hagino int namelen; 599686cdd19SJun-ichiro itojun Hagino struct in6_addr *in6; 600686cdd19SJun-ichiro itojun Hagino { 601686cdd19SJun-ichiro itojun Hagino const char *p; 602686cdd19SJun-ichiro itojun Hagino MD5_CTX ctxt; 603686cdd19SJun-ichiro itojun Hagino u_int8_t digest[16]; 604686cdd19SJun-ichiro itojun Hagino char l; 605686cdd19SJun-ichiro itojun Hagino 606686cdd19SJun-ichiro itojun Hagino if (!namelen || !name) 607686cdd19SJun-ichiro itojun Hagino return -1; 608686cdd19SJun-ichiro itojun Hagino 609686cdd19SJun-ichiro itojun Hagino p = name; 610686cdd19SJun-ichiro itojun Hagino while (p && *p && *p != '.' && p - name < namelen) 611686cdd19SJun-ichiro itojun Hagino p++; 612686cdd19SJun-ichiro itojun Hagino if (p - name > 63) 613686cdd19SJun-ichiro itojun Hagino return -1; /*label too long*/ 614686cdd19SJun-ichiro itojun Hagino l = p - name; 615686cdd19SJun-ichiro itojun Hagino 616686cdd19SJun-ichiro itojun Hagino /* generate 8 bytes of pseudo-random value. */ 617686cdd19SJun-ichiro itojun Hagino bzero(&ctxt, sizeof(ctxt)); 618686cdd19SJun-ichiro itojun Hagino MD5Init(&ctxt); 619686cdd19SJun-ichiro itojun Hagino MD5Update(&ctxt, &l, sizeof(l)); 620686cdd19SJun-ichiro itojun Hagino /* LINTED const cast */ 621686cdd19SJun-ichiro itojun Hagino MD5Update(&ctxt, (void *)name, p - name); 622686cdd19SJun-ichiro itojun Hagino MD5Final(digest, &ctxt); 623686cdd19SJun-ichiro itojun Hagino 624686cdd19SJun-ichiro itojun Hagino bzero(in6, sizeof(*in6)); 625686cdd19SJun-ichiro itojun Hagino in6->s6_addr16[0] = htons(0xff02); 626686cdd19SJun-ichiro itojun Hagino if (ifp) 627686cdd19SJun-ichiro itojun Hagino in6->s6_addr16[1] = htons(ifp->if_index); 628686cdd19SJun-ichiro itojun Hagino in6->s6_addr8[11] = 2; 629686cdd19SJun-ichiro itojun Hagino bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3])); 630686cdd19SJun-ichiro itojun Hagino 631686cdd19SJun-ichiro itojun Hagino return 0; 632686cdd19SJun-ichiro itojun Hagino } 633686cdd19SJun-ichiro itojun Hagino 634686cdd19SJun-ichiro itojun Hagino void 635686cdd19SJun-ichiro itojun Hagino in6_nigroup_attach(name, namelen) 636686cdd19SJun-ichiro itojun Hagino const char *name; 637686cdd19SJun-ichiro itojun Hagino int namelen; 638686cdd19SJun-ichiro itojun Hagino { 639686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 640686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 mltaddr; 641686cdd19SJun-ichiro itojun Hagino struct in6_multi *in6m; 642686cdd19SJun-ichiro itojun Hagino int error; 643686cdd19SJun-ichiro itojun Hagino 644686cdd19SJun-ichiro itojun Hagino bzero(&mltaddr, sizeof(mltaddr)); 645686cdd19SJun-ichiro itojun Hagino mltaddr.sin6_family = AF_INET6; 646686cdd19SJun-ichiro itojun Hagino mltaddr.sin6_len = sizeof(struct sockaddr_in6); 647686cdd19SJun-ichiro itojun Hagino if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) 648686cdd19SJun-ichiro itojun Hagino return; 649686cdd19SJun-ichiro itojun Hagino 650686cdd19SJun-ichiro itojun Hagino for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) 651686cdd19SJun-ichiro itojun Hagino { 652686cdd19SJun-ichiro itojun Hagino mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 653686cdd19SJun-ichiro itojun Hagino IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 654686cdd19SJun-ichiro itojun Hagino if (!in6m) 655686cdd19SJun-ichiro itojun Hagino (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 656686cdd19SJun-ichiro itojun Hagino } 657686cdd19SJun-ichiro itojun Hagino } 658686cdd19SJun-ichiro itojun Hagino 659686cdd19SJun-ichiro itojun Hagino void 660686cdd19SJun-ichiro itojun Hagino in6_nigroup_detach(name, namelen) 661686cdd19SJun-ichiro itojun Hagino const char *name; 662686cdd19SJun-ichiro itojun Hagino int namelen; 663686cdd19SJun-ichiro itojun Hagino { 664686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 665686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 mltaddr; 666686cdd19SJun-ichiro itojun Hagino struct in6_multi *in6m; 667686cdd19SJun-ichiro itojun Hagino 668686cdd19SJun-ichiro itojun Hagino bzero(&mltaddr, sizeof(mltaddr)); 669686cdd19SJun-ichiro itojun Hagino mltaddr.sin6_family = AF_INET6; 670686cdd19SJun-ichiro itojun Hagino mltaddr.sin6_len = sizeof(struct sockaddr_in6); 671686cdd19SJun-ichiro itojun Hagino if (nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0) 672686cdd19SJun-ichiro itojun Hagino return; 673686cdd19SJun-ichiro itojun Hagino 674686cdd19SJun-ichiro itojun Hagino for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) 675686cdd19SJun-ichiro itojun Hagino { 676686cdd19SJun-ichiro itojun Hagino mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 677686cdd19SJun-ichiro itojun Hagino IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 678686cdd19SJun-ichiro itojun Hagino if (in6m) 679686cdd19SJun-ichiro itojun Hagino in6_delmulti(in6m); 68082cd038dSYoshinobu Inoue } 68182cd038dSYoshinobu Inoue } 68282cd038dSYoshinobu Inoue 68382cd038dSYoshinobu Inoue /* 684686cdd19SJun-ichiro itojun Hagino * XXX multiple loopback interface needs more care. for instance, 685686cdd19SJun-ichiro itojun Hagino * nodelocal address needs to be configured onto only one of them. 686686cdd19SJun-ichiro itojun Hagino * XXX multiple link-local address case 68782cd038dSYoshinobu Inoue */ 68882cd038dSYoshinobu Inoue void 689686cdd19SJun-ichiro itojun Hagino in6_ifattach(ifp, altifp) 69082cd038dSYoshinobu Inoue struct ifnet *ifp; 691686cdd19SJun-ichiro itojun Hagino struct ifnet *altifp; /* secondary EUI64 source */ 69282cd038dSYoshinobu Inoue { 69382cd038dSYoshinobu Inoue static size_t if_indexlim = 8; 69482cd038dSYoshinobu Inoue struct sockaddr_in6 mltaddr; 69582cd038dSYoshinobu Inoue struct sockaddr_in6 mltmask; 69682cd038dSYoshinobu Inoue struct sockaddr_in6 gate; 69782cd038dSYoshinobu Inoue struct sockaddr_in6 mask; 698686cdd19SJun-ichiro itojun Hagino struct in6_ifaddr *ia; 699686cdd19SJun-ichiro itojun Hagino struct in6_addr in6; 700686cdd19SJun-ichiro itojun Hagino int hostnamelen = strlen(hostname); 70182cd038dSYoshinobu Inoue 70282cd038dSYoshinobu Inoue /* 70382cd038dSYoshinobu Inoue * We have some arrays that should be indexed by if_index. 70482cd038dSYoshinobu Inoue * since if_index will grow dynamically, they should grow too. 70582cd038dSYoshinobu Inoue * struct in6_ifstat **in6_ifstat 70682cd038dSYoshinobu Inoue * struct icmp6_ifstat **icmp6_ifstat 70782cd038dSYoshinobu Inoue */ 708686cdd19SJun-ichiro itojun Hagino if (in6_ifstat == NULL || icmp6_ifstat == NULL || 709686cdd19SJun-ichiro itojun Hagino if_index >= if_indexlim) { 71082cd038dSYoshinobu Inoue size_t n; 71182cd038dSYoshinobu Inoue caddr_t q; 71282cd038dSYoshinobu Inoue size_t olim; 71382cd038dSYoshinobu Inoue 71482cd038dSYoshinobu Inoue olim = if_indexlim; 71582cd038dSYoshinobu Inoue while (if_index >= if_indexlim) 71682cd038dSYoshinobu Inoue if_indexlim <<= 1; 71782cd038dSYoshinobu Inoue 71882cd038dSYoshinobu Inoue /* grow in6_ifstat */ 71982cd038dSYoshinobu Inoue n = if_indexlim * sizeof(struct in6_ifstat *); 72082cd038dSYoshinobu Inoue q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); 72182cd038dSYoshinobu Inoue bzero(q, n); 72282cd038dSYoshinobu Inoue if (in6_ifstat) { 72382cd038dSYoshinobu Inoue bcopy((caddr_t)in6_ifstat, q, 72482cd038dSYoshinobu Inoue olim * sizeof(struct in6_ifstat *)); 72582cd038dSYoshinobu Inoue free((caddr_t)in6_ifstat, M_IFADDR); 72682cd038dSYoshinobu Inoue } 72782cd038dSYoshinobu Inoue in6_ifstat = (struct in6_ifstat **)q; 72882cd038dSYoshinobu Inoue in6_ifstatmax = if_indexlim; 72982cd038dSYoshinobu Inoue 73082cd038dSYoshinobu Inoue /* grow icmp6_ifstat */ 73182cd038dSYoshinobu Inoue n = if_indexlim * sizeof(struct icmp6_ifstat *); 73282cd038dSYoshinobu Inoue q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK); 73382cd038dSYoshinobu Inoue bzero(q, n); 73482cd038dSYoshinobu Inoue if (icmp6_ifstat) { 73582cd038dSYoshinobu Inoue bcopy((caddr_t)icmp6_ifstat, q, 73682cd038dSYoshinobu Inoue olim * sizeof(struct icmp6_ifstat *)); 73782cd038dSYoshinobu Inoue free((caddr_t)icmp6_ifstat, M_IFADDR); 73882cd038dSYoshinobu Inoue } 73982cd038dSYoshinobu Inoue icmp6_ifstat = (struct icmp6_ifstat **)q; 74082cd038dSYoshinobu Inoue icmp6_ifstatmax = if_indexlim; 74182cd038dSYoshinobu Inoue } 74282cd038dSYoshinobu Inoue 743686cdd19SJun-ichiro itojun Hagino /* initialize scope identifiers */ 744686cdd19SJun-ichiro itojun Hagino scope6_ifattach(ifp); 74582cd038dSYoshinobu Inoue 74682cd038dSYoshinobu Inoue /* 747686cdd19SJun-ichiro itojun Hagino * quirks based on interface type 74882cd038dSYoshinobu Inoue */ 749686cdd19SJun-ichiro itojun Hagino switch (ifp->if_type) { 750686cdd19SJun-ichiro itojun Hagino #ifdef IFT_STF 751686cdd19SJun-ichiro itojun Hagino case IFT_STF: 75282cd038dSYoshinobu Inoue /* 753686cdd19SJun-ichiro itojun Hagino * 6to4 interface is a very speical kind of beast. 754686cdd19SJun-ichiro itojun Hagino * no multicast, no linklocal (based on 03 draft). 75582cd038dSYoshinobu Inoue */ 756686cdd19SJun-ichiro itojun Hagino goto statinit; 757686cdd19SJun-ichiro itojun Hagino #endif 75882cd038dSYoshinobu Inoue default: 75982cd038dSYoshinobu Inoue break; 76082cd038dSYoshinobu Inoue } 76182cd038dSYoshinobu Inoue 762686cdd19SJun-ichiro itojun Hagino /* 763686cdd19SJun-ichiro itojun Hagino * usually, we require multicast capability to the interface 764686cdd19SJun-ichiro itojun Hagino */ 765686cdd19SJun-ichiro itojun Hagino if ((ifp->if_flags & IFF_MULTICAST) == 0) { 766686cdd19SJun-ichiro itojun Hagino printf("%s: not multicast capable, IPv6 not enabled\n", 767686cdd19SJun-ichiro itojun Hagino if_name(ifp)); 76882cd038dSYoshinobu Inoue return; 76982cd038dSYoshinobu Inoue } 770686cdd19SJun-ichiro itojun Hagino 771686cdd19SJun-ichiro itojun Hagino /* 772686cdd19SJun-ichiro itojun Hagino * assign link-local address, if there's none 773686cdd19SJun-ichiro itojun Hagino */ 774686cdd19SJun-ichiro itojun Hagino ia = in6ifa_ifpforlinklocal(ifp, 0); 775686cdd19SJun-ichiro itojun Hagino if (ia == NULL) { 776686cdd19SJun-ichiro itojun Hagino if (in6_ifattach_linklocal(ifp, altifp) != 0) 777686cdd19SJun-ichiro itojun Hagino return; 778686cdd19SJun-ichiro itojun Hagino ia = in6ifa_ifpforlinklocal(ifp, 0); 779686cdd19SJun-ichiro itojun Hagino 780686cdd19SJun-ichiro itojun Hagino if (ia == NULL) { 781de9c893eSJun-ichiro itojun Hagino printf("%s: failed to add link-local address\n", 782686cdd19SJun-ichiro itojun Hagino if_name(ifp)); 783686cdd19SJun-ichiro itojun Hagino 784686cdd19SJun-ichiro itojun Hagino /* we can't initialize multicasts without link-local */ 785686cdd19SJun-ichiro itojun Hagino goto statinit; 786686cdd19SJun-ichiro itojun Hagino } 78782cd038dSYoshinobu Inoue } 78882cd038dSYoshinobu Inoue 789686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_POINTOPOINT) { 79082cd038dSYoshinobu Inoue /* 79182cd038dSYoshinobu Inoue * route local address to loopback 79282cd038dSYoshinobu Inoue */ 79382cd038dSYoshinobu Inoue bzero(&gate, sizeof(gate)); 79482cd038dSYoshinobu Inoue gate.sin6_len = sizeof(struct sockaddr_in6); 79582cd038dSYoshinobu Inoue gate.sin6_family = AF_INET6; 79682cd038dSYoshinobu Inoue gate.sin6_addr = in6addr_loopback; 79782cd038dSYoshinobu Inoue bzero(&mask, sizeof(mask)); 79882cd038dSYoshinobu Inoue mask.sin6_len = sizeof(struct sockaddr_in6); 79982cd038dSYoshinobu Inoue mask.sin6_family = AF_INET6; 80082cd038dSYoshinobu Inoue mask.sin6_addr = in6mask64; 80182cd038dSYoshinobu Inoue rtrequest(RTM_ADD, 80282cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_addr, 80382cd038dSYoshinobu Inoue (struct sockaddr *)&gate, 80482cd038dSYoshinobu Inoue (struct sockaddr *)&mask, 80582cd038dSYoshinobu Inoue RTF_UP|RTF_HOST, 80682cd038dSYoshinobu Inoue (struct rtentry **)0); 80782cd038dSYoshinobu Inoue } 80882cd038dSYoshinobu Inoue 80982cd038dSYoshinobu Inoue /* 810686cdd19SJun-ichiro itojun Hagino * assign loopback address for loopback interface 811686cdd19SJun-ichiro itojun Hagino * XXX multiple loopback interface case 81282cd038dSYoshinobu Inoue */ 813686cdd19SJun-ichiro itojun Hagino in6 = in6addr_loopback; 814686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_LOOPBACK) { 815686cdd19SJun-ichiro itojun Hagino if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) { 816686cdd19SJun-ichiro itojun Hagino if (in6_ifattach_loopback(ifp) != 0) 817686cdd19SJun-ichiro itojun Hagino return; 81882cd038dSYoshinobu Inoue } 819686cdd19SJun-ichiro itojun Hagino } 820686cdd19SJun-ichiro itojun Hagino 821686cdd19SJun-ichiro itojun Hagino #ifdef DIAGNOSTIC 822686cdd19SJun-ichiro itojun Hagino if (!ia) { 823686cdd19SJun-ichiro itojun Hagino panic("ia == NULL in in6_ifattach"); 824686cdd19SJun-ichiro itojun Hagino /*NOTREACHED*/ 825686cdd19SJun-ichiro itojun Hagino } 826686cdd19SJun-ichiro itojun Hagino #endif 82782cd038dSYoshinobu Inoue 82882cd038dSYoshinobu Inoue /* 82982cd038dSYoshinobu Inoue * join multicast 83082cd038dSYoshinobu Inoue */ 83182cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_MULTICAST) { 83282cd038dSYoshinobu Inoue int error; /* not used */ 833686cdd19SJun-ichiro itojun Hagino struct in6_multi *in6m; 83482cd038dSYoshinobu Inoue 83582cd038dSYoshinobu Inoue bzero(&mltmask, sizeof(mltmask)); 83682cd038dSYoshinobu Inoue mltmask.sin6_len = sizeof(struct sockaddr_in6); 83782cd038dSYoshinobu Inoue mltmask.sin6_family = AF_INET6; 83882cd038dSYoshinobu Inoue mltmask.sin6_addr = in6mask32; 83982cd038dSYoshinobu Inoue 84082cd038dSYoshinobu Inoue /* 84182cd038dSYoshinobu Inoue * join link-local all-nodes address 84282cd038dSYoshinobu Inoue */ 84382cd038dSYoshinobu Inoue bzero(&mltaddr, sizeof(mltaddr)); 84482cd038dSYoshinobu Inoue mltaddr.sin6_len = sizeof(struct sockaddr_in6); 84582cd038dSYoshinobu Inoue mltaddr.sin6_family = AF_INET6; 84682cd038dSYoshinobu Inoue mltaddr.sin6_addr = in6addr_linklocal_allnodes; 84782cd038dSYoshinobu Inoue mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 848686cdd19SJun-ichiro itojun Hagino 849686cdd19SJun-ichiro itojun Hagino IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 850686cdd19SJun-ichiro itojun Hagino if (in6m == NULL) { 85182cd038dSYoshinobu Inoue rtrequest(RTM_ADD, 85282cd038dSYoshinobu Inoue (struct sockaddr *)&mltaddr, 85382cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_addr, 85482cd038dSYoshinobu Inoue (struct sockaddr *)&mltmask, 85582cd038dSYoshinobu Inoue RTF_UP|RTF_CLONING, /* xxx */ 85682cd038dSYoshinobu Inoue (struct rtentry **)0); 85782cd038dSYoshinobu Inoue (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 858686cdd19SJun-ichiro itojun Hagino } 85982cd038dSYoshinobu Inoue 86082cd038dSYoshinobu Inoue /* 861686cdd19SJun-ichiro itojun Hagino * join node information group address 862686cdd19SJun-ichiro itojun Hagino */ 863686cdd19SJun-ichiro itojun Hagino if (nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr) 864686cdd19SJun-ichiro itojun Hagino == 0) { 865686cdd19SJun-ichiro itojun Hagino IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 866686cdd19SJun-ichiro itojun Hagino if (in6m == NULL && ia != NULL) { 867686cdd19SJun-ichiro itojun Hagino (void)in6_addmulti(&mltaddr.sin6_addr, 868686cdd19SJun-ichiro itojun Hagino ifp, &error); 869686cdd19SJun-ichiro itojun Hagino } 870686cdd19SJun-ichiro itojun Hagino } 871686cdd19SJun-ichiro itojun Hagino 872686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_LOOPBACK) { 873686cdd19SJun-ichiro itojun Hagino in6 = in6addr_loopback; 874686cdd19SJun-ichiro itojun Hagino ia = in6ifa_ifpwithaddr(ifp, &in6); 875686cdd19SJun-ichiro itojun Hagino /* 876686cdd19SJun-ichiro itojun Hagino * join node-local all-nodes address, on loopback 87782cd038dSYoshinobu Inoue */ 87882cd038dSYoshinobu Inoue mltaddr.sin6_addr = in6addr_nodelocal_allnodes; 879686cdd19SJun-ichiro itojun Hagino 880686cdd19SJun-ichiro itojun Hagino IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m); 881686cdd19SJun-ichiro itojun Hagino if (in6m == NULL && ia != NULL) { 88282cd038dSYoshinobu Inoue rtrequest(RTM_ADD, 88382cd038dSYoshinobu Inoue (struct sockaddr *)&mltaddr, 884686cdd19SJun-ichiro itojun Hagino (struct sockaddr *)&ia->ia_addr, 88582cd038dSYoshinobu Inoue (struct sockaddr *)&mltmask, 88682cd038dSYoshinobu Inoue RTF_UP, 88782cd038dSYoshinobu Inoue (struct rtentry **)0); 88882cd038dSYoshinobu Inoue (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error); 88982cd038dSYoshinobu Inoue } 89082cd038dSYoshinobu Inoue } 891686cdd19SJun-ichiro itojun Hagino } 892686cdd19SJun-ichiro itojun Hagino 893686cdd19SJun-ichiro itojun Hagino statinit:; 89482cd038dSYoshinobu Inoue 89582cd038dSYoshinobu Inoue /* update dynamically. */ 89682cd038dSYoshinobu Inoue if (in6_maxmtu < ifp->if_mtu) 89782cd038dSYoshinobu Inoue in6_maxmtu = ifp->if_mtu; 89882cd038dSYoshinobu Inoue 89982cd038dSYoshinobu Inoue if (in6_ifstat[ifp->if_index] == NULL) { 90082cd038dSYoshinobu Inoue in6_ifstat[ifp->if_index] = (struct in6_ifstat *) 90182cd038dSYoshinobu Inoue malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK); 90282cd038dSYoshinobu Inoue bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat)); 90382cd038dSYoshinobu Inoue } 90482cd038dSYoshinobu Inoue if (icmp6_ifstat[ifp->if_index] == NULL) { 90582cd038dSYoshinobu Inoue icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *) 90682cd038dSYoshinobu Inoue malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK); 90782cd038dSYoshinobu Inoue bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat)); 90882cd038dSYoshinobu Inoue } 90982cd038dSYoshinobu Inoue 91082cd038dSYoshinobu Inoue /* initialize NDP variables */ 91182cd038dSYoshinobu Inoue nd6_ifattach(ifp); 91282cd038dSYoshinobu Inoue } 91382cd038dSYoshinobu Inoue 914686cdd19SJun-ichiro itojun Hagino /* 915686cdd19SJun-ichiro itojun Hagino * NOTE: in6_ifdetach() does not support loopback if at this moment. 916686cdd19SJun-ichiro itojun Hagino */ 91782cd038dSYoshinobu Inoue void 91882cd038dSYoshinobu Inoue in6_ifdetach(ifp) 91982cd038dSYoshinobu Inoue struct ifnet *ifp; 92082cd038dSYoshinobu Inoue { 92182cd038dSYoshinobu Inoue struct in6_ifaddr *ia, *oia; 922686cdd19SJun-ichiro itojun Hagino struct ifaddr *ifa, *next; 92382cd038dSYoshinobu Inoue struct rtentry *rt; 92482cd038dSYoshinobu Inoue short rtflags; 925686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 sin6; 926686cdd19SJun-ichiro itojun Hagino struct in6_multi *in6m; 927686cdd19SJun-ichiro itojun Hagino struct in6_multi *in6m_next; 92882cd038dSYoshinobu Inoue 929686cdd19SJun-ichiro itojun Hagino /* nuke prefix list. this may try to remove some of ifaddrs as well */ 930686cdd19SJun-ichiro itojun Hagino in6_purgeprefix(ifp); 931686cdd19SJun-ichiro itojun Hagino 932686cdd19SJun-ichiro itojun Hagino /* remove neighbor management table */ 933686cdd19SJun-ichiro itojun Hagino nd6_purge(ifp); 934686cdd19SJun-ichiro itojun Hagino 935686cdd19SJun-ichiro itojun Hagino /* nuke any of IPv6 addresses we have */ 936686cdd19SJun-ichiro itojun Hagino for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) 93782cd038dSYoshinobu Inoue { 938686cdd19SJun-ichiro itojun Hagino next = ifa->ifa_list.tqe_next; 939686cdd19SJun-ichiro itojun Hagino if (ifa->ifa_addr->sa_family != AF_INET6) 940686cdd19SJun-ichiro itojun Hagino continue; 941686cdd19SJun-ichiro itojun Hagino in6_purgeaddr(ifa, ifp); 942686cdd19SJun-ichiro itojun Hagino } 943686cdd19SJun-ichiro itojun Hagino 944686cdd19SJun-ichiro itojun Hagino /* undo everything done by in6_ifattach(), just in case */ 945686cdd19SJun-ichiro itojun Hagino for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) 946686cdd19SJun-ichiro itojun Hagino { 947686cdd19SJun-ichiro itojun Hagino next = ifa->ifa_list.tqe_next; 948686cdd19SJun-ichiro itojun Hagino 949686cdd19SJun-ichiro itojun Hagino 95082cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6 95182cd038dSYoshinobu Inoue || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { 95282cd038dSYoshinobu Inoue continue; 95382cd038dSYoshinobu Inoue } 95482cd038dSYoshinobu Inoue 95582cd038dSYoshinobu Inoue ia = (struct in6_ifaddr *)ifa; 95682cd038dSYoshinobu Inoue 95782cd038dSYoshinobu Inoue /* remove from the routing table */ 95882cd038dSYoshinobu Inoue if ((ia->ia_flags & IFA_ROUTE) 95982cd038dSYoshinobu Inoue && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) { 96082cd038dSYoshinobu Inoue rtflags = rt->rt_flags; 96182cd038dSYoshinobu Inoue rtfree(rt); 96282cd038dSYoshinobu Inoue rtrequest(RTM_DELETE, 96382cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_addr, 96482cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_addr, 96582cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_prefixmask, 96682cd038dSYoshinobu Inoue rtflags, (struct rtentry **)0); 96782cd038dSYoshinobu Inoue } 96882cd038dSYoshinobu Inoue 96982cd038dSYoshinobu Inoue /* remove from the linked list */ 97082cd038dSYoshinobu Inoue TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 971686cdd19SJun-ichiro itojun Hagino IFAFREE(&ia->ia_ifa); 97282cd038dSYoshinobu Inoue 97382cd038dSYoshinobu Inoue /* also remove from the IPv6 address chain(itojun&jinmei) */ 97482cd038dSYoshinobu Inoue oia = ia; 97582cd038dSYoshinobu Inoue if (oia == (ia = in6_ifaddr)) 97682cd038dSYoshinobu Inoue in6_ifaddr = ia->ia_next; 97782cd038dSYoshinobu Inoue else { 97882cd038dSYoshinobu Inoue while (ia->ia_next && (ia->ia_next != oia)) 97982cd038dSYoshinobu Inoue ia = ia->ia_next; 98082cd038dSYoshinobu Inoue if (ia->ia_next) 98182cd038dSYoshinobu Inoue ia->ia_next = oia->ia_next; 982686cdd19SJun-ichiro itojun Hagino #ifdef ND6_DEBUG 98382cd038dSYoshinobu Inoue else 98482cd038dSYoshinobu Inoue printf("%s: didn't unlink in6ifaddr from " 98582cd038dSYoshinobu Inoue "list\n", if_name(ifp)); 98682cd038dSYoshinobu Inoue #endif 98782cd038dSYoshinobu Inoue } 98882cd038dSYoshinobu Inoue 989686cdd19SJun-ichiro itojun Hagino IFAFREE(&oia->ia_ifa); 990686cdd19SJun-ichiro itojun Hagino } 991686cdd19SJun-ichiro itojun Hagino 992686cdd19SJun-ichiro itojun Hagino /* leave from all multicast groups joined */ 993686cdd19SJun-ichiro itojun Hagino for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) { 994686cdd19SJun-ichiro itojun Hagino in6m_next = LIST_NEXT(in6m, in6m_entry); 995686cdd19SJun-ichiro itojun Hagino if (in6m->in6m_ifp != ifp) 996686cdd19SJun-ichiro itojun Hagino continue; 997686cdd19SJun-ichiro itojun Hagino in6_delmulti(in6m); 998686cdd19SJun-ichiro itojun Hagino in6m = NULL; 999686cdd19SJun-ichiro itojun Hagino } 1000686cdd19SJun-ichiro itojun Hagino 1001686cdd19SJun-ichiro itojun Hagino /* remove neighbor management table */ 1002686cdd19SJun-ichiro itojun Hagino nd6_purge(ifp); 1003686cdd19SJun-ichiro itojun Hagino 1004686cdd19SJun-ichiro itojun Hagino /* remove route to link-local allnodes multicast (ff02::1) */ 1005686cdd19SJun-ichiro itojun Hagino bzero(&sin6, sizeof(sin6)); 1006686cdd19SJun-ichiro itojun Hagino sin6.sin6_len = sizeof(struct sockaddr_in6); 1007686cdd19SJun-ichiro itojun Hagino sin6.sin6_family = AF_INET6; 1008686cdd19SJun-ichiro itojun Hagino sin6.sin6_addr = in6addr_linklocal_allnodes; 1009686cdd19SJun-ichiro itojun Hagino sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); 1010686cdd19SJun-ichiro itojun Hagino if ((rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL)) != NULL) 1011686cdd19SJun-ichiro itojun Hagino { 1012686cdd19SJun-ichiro itojun Hagino rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), 1013686cdd19SJun-ichiro itojun Hagino rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); 1014686cdd19SJun-ichiro itojun Hagino rtfree(rt); 101582cd038dSYoshinobu Inoue } 101682cd038dSYoshinobu Inoue } 1017