[BACK]Return to in6_ifattach.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/in6_ifattach.c, Revision 1.43

1.43    ! itojun      1: /*     $NetBSD: in6_ifattach.c,v 1.42 2002/05/23 06:25:25 itojun Exp $ */
1.37      itojun      2: /*     $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $  */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.24      itojun      7:  *
1.2       itojun      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the project nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
1.24      itojun     19:  *
1.2       itojun     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
1.39      lukem      32:
                     33: #include <sys/cdefs.h>
1.43    ! itojun     34: __KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.42 2002/05/23 06:25:25 itojun Exp $");
1.2       itojun     35:
                     36: #include <sys/param.h>
                     37: #include <sys/systm.h>
                     38: #include <sys/malloc.h>
                     39: #include <sys/socket.h>
                     40: #include <sys/sockio.h>
1.13      itojun     41: #include <sys/kernel.h>
1.34      itojun     42: #include <sys/syslog.h>
1.13      itojun     43: #include <sys/md5.h>
1.2       itojun     44:
                     45: #include <net/if.h>
                     46: #include <net/if_dl.h>
                     47: #include <net/if_types.h>
                     48: #include <net/route.h>
                     49:
                     50: #include <netinet/in.h>
                     51: #include <netinet/in_var.h>
                     52:
1.19      itojun     53: #include <netinet/ip6.h>
1.2       itojun     54: #include <netinet6/ip6_var.h>
                     55: #include <netinet6/in6_ifattach.h>
                     56: #include <netinet6/ip6_var.h>
                     57: #include <netinet6/nd6.h>
                     58:
1.13      itojun     59: #include <net/net_osdep.h>
                     60:
                     61: struct in6_ifstat **in6_ifstat = NULL;
                     62: struct icmp6_ifstat **icmp6_ifstat = NULL;
                     63: size_t in6_ifstatmax = 0;
                     64: size_t icmp6_ifstatmax = 0;
1.2       itojun     65: unsigned long in6_maxmtu = 0;
                     66:
1.25      itojun     67: static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
                     68: static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
                     69: static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
                     70: static int in6_ifattach_addaddr __P((struct ifnet *, struct in6_ifaddr *));
                     71: static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *));
                     72: static int in6_ifattach_loopback __P((struct ifnet *));
                     73:
                     74: #define EUI64_GBIT     0x01
                     75: #define EUI64_UBIT     0x02
                     76: #define EUI64_TO_IFID(in6)     do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
                     77: #define EUI64_GROUP(in6)       ((in6)->s6_addr[8] & EUI64_GBIT)
                     78: #define EUI64_INDIVIDUAL(in6)  (!EUI64_GROUP(in6))
                     79: #define EUI64_LOCAL(in6)       ((in6)->s6_addr[8] & EUI64_UBIT)
                     80: #define EUI64_UNIVERSAL(in6)   (!EUI64_LOCAL(in6))
                     81:
                     82: #define IFID_LOCAL(in6)                (!EUI64_LOCAL(in6))
                     83: #define IFID_UNIVERSAL(in6)    (!EUI64_UNIVERSAL(in6))
                     84:
                     85: /*
                     86:  * Generate a last-resort interface identifier, when the machine has no
                     87:  * IEEE802/EUI64 address sources.
                     88:  * The goal here is to get an interface identifier that is
                     89:  * (1) random enough and (2) does not change across reboot.
                     90:  * We currently use MD5(hostname) for it.
                     91:  */
                     92: static int
                     93: get_rand_ifid(ifp, in6)
                     94:        struct ifnet *ifp;
1.40      itojun     95:        struct in6_addr *in6;   /* upper 64bits are preserved */
1.25      itojun     96: {
                     97:        MD5_CTX ctxt;
                     98:        u_int8_t digest[16];
                     99:
                    100: #if 0
                    101:        /* we need at least several letters as seed for ifid */
                    102:        if (hostnamelen < 3)
                    103:                return -1;
                    104: #endif
                    105:
                    106:        /* generate 8 bytes of pseudo-random value. */
                    107:        bzero(&ctxt, sizeof(ctxt));
                    108:        MD5Init(&ctxt);
                    109:        MD5Update(&ctxt, hostname, hostnamelen);
                    110:        MD5Final(digest, &ctxt);
                    111:
                    112:        /* assumes sizeof(digest) > sizeof(ifid) */
                    113:        bcopy(digest, &in6->s6_addr[8], 8);
1.2       itojun    114:
1.25      itojun    115:        /* make sure to set "u" bit to local, and "g" bit to individual. */
                    116:        in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
                    117:        in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
                    118:
                    119:        /* convert EUI64 into IPv6 interface identifier */
                    120:        EUI64_TO_IFID(in6);
                    121:
                    122:        return 0;
                    123: }
1.2       itojun    124:
1.25      itojun    125: /*
                    126:  * Get interface identifier for the specified interface.
                    127:  * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
                    128:  */
1.7       itojun    129: static int
1.25      itojun    130: get_hw_ifid(ifp, in6)
                    131:        struct ifnet *ifp;
1.40      itojun    132:        struct in6_addr *in6;   /* upper 64bits are preserved */
1.2       itojun    133: {
1.25      itojun    134:        struct ifaddr *ifa;
                    135:        struct sockaddr_dl *sdl;
                    136:        u_int8_t *addr;
                    137:        size_t addrlen;
                    138:        static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
                    139:        static u_int8_t allone[8] =
                    140:                { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
                    141:
                    142:        for (ifa = ifp->if_addrlist.tqh_first;
                    143:             ifa;
                    144:             ifa = ifa->ifa_list.tqe_next)
                    145:        {
                    146:                if (ifa->ifa_addr->sa_family != AF_LINK)
                    147:                        continue;
                    148:                sdl = (struct sockaddr_dl *)ifa->ifa_addr;
                    149:                if (sdl == NULL)
                    150:                        continue;
                    151:                if (sdl->sdl_alen == 0)
                    152:                        continue;
                    153:
                    154:                goto found;
                    155:        }
                    156:
                    157:        return -1;
                    158:
                    159: found:
                    160:        addr = LLADDR(sdl);
                    161:        addrlen = sdl->sdl_alen;
                    162:
                    163:        /* get EUI64 */
                    164:        switch (ifp->if_type) {
                    165:        case IFT_ETHER:
                    166:        case IFT_FDDI:
                    167:        case IFT_ATM:
1.32      onoe      168:        case IFT_IEEE1394:
1.25      itojun    169:                /* IEEE802/EUI64 cases - what others? */
1.32      onoe      170:                /* IEEE1394 uses 16byte length address starting with EUI64 */
                    171:                if (addrlen > 8)
                    172:                        addrlen = 8;
1.13      itojun    173:
1.25      itojun    174:                /* look at IEEE802/EUI64 only */
                    175:                if (addrlen != 8 && addrlen != 6)
                    176:                        return -1;
1.13      itojun    177:
1.25      itojun    178:                /*
                    179:                 * check for invalid MAC address - on bsdi, we see it a lot
                    180:                 * since wildboar configures all-zero MAC on pccard before
                    181:                 * card insertion.
                    182:                 */
                    183:                if (bcmp(addr, allzero, addrlen) == 0)
                    184:                        return -1;
                    185:                if (bcmp(addr, allone, addrlen) == 0)
                    186:                        return -1;
                    187:
                    188:                /* make EUI64 address */
                    189:                if (addrlen == 8)
                    190:                        bcopy(addr, &in6->s6_addr[8], 8);
                    191:                else if (addrlen == 6) {
                    192:                        in6->s6_addr[8] = addr[0];
                    193:                        in6->s6_addr[9] = addr[1];
                    194:                        in6->s6_addr[10] = addr[2];
                    195:                        in6->s6_addr[11] = 0xff;
1.26      itojun    196:                        in6->s6_addr[12] = 0xfe;
1.25      itojun    197:                        in6->s6_addr[13] = addr[3];
                    198:                        in6->s6_addr[14] = addr[4];
                    199:                        in6->s6_addr[15] = addr[5];
                    200:                }
1.7       itojun    201:                break;
1.25      itojun    202:
                    203:        case IFT_ARCNET:
                    204:                if (addrlen != 1)
                    205:                        return -1;
                    206:                if (!addr[0])
                    207:                        return -1;
                    208:
                    209:                bzero(&in6->s6_addr[8], 8);
                    210:                in6->s6_addr[15] = addr[0];
                    211:
1.27      itojun    212:                /*
                    213:                 * due to insufficient bitwidth, we mark it local.
                    214:                 */
1.25      itojun    215:                in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
                    216:                in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
1.7       itojun    217:                break;
1.25      itojun    218:
                    219:        case IFT_GIF:
                    220: #ifdef IFT_STF
                    221:        case IFT_STF:
                    222: #endif
                    223:                /*
1.34      itojun    224:                 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
1.27      itojun    225:                 * however, IPv4 address is not very suitable as unique
                    226:                 * identifier source (can be renumbered).
                    227:                 * we don't do this.
1.25      itojun    228:                 */
                    229:                return -1;
                    230:
1.7       itojun    231:        default:
1.25      itojun    232:                return -1;
                    233:        }
                    234:
                    235:        /* sanity check: g bit must not indicate "group" */
                    236:        if (EUI64_GROUP(in6))
                    237:                return -1;
                    238:
                    239:        /* convert EUI64 into IPv6 interface identifier */
                    240:        EUI64_TO_IFID(in6);
                    241:
                    242:        /*
                    243:         * sanity check: ifid must not be all zero, avoid conflict with
                    244:         * subnet router anycast
                    245:         */
                    246:        if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
                    247:            bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
                    248:                return -1;
1.7       itojun    249:        }
                    250:
                    251:        return 0;
1.2       itojun    252: }
                    253:
                    254: /*
1.25      itojun    255:  * Get interface identifier for the specified interface.  If it is not
                    256:  * available on ifp0, borrow interface identifier from other information
                    257:  * sources.
1.13      itojun    258:  */
                    259: static int
1.25      itojun    260: get_ifid(ifp0, altifp, in6)
                    261:        struct ifnet *ifp0;
                    262:        struct ifnet *altifp;   /*secondary EUI64 source*/
                    263:        struct in6_addr *in6;
1.13      itojun    264: {
1.25      itojun    265:        struct ifnet *ifp;
                    266:
                    267:        /* first, try to get it from the interface itself */
                    268:        if (get_hw_ifid(ifp0, in6) == 0) {
1.34      itojun    269:                nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
                    270:                    if_name(ifp0)));
1.25      itojun    271:                goto success;
                    272:        }
                    273:
                    274:        /* try secondary EUI64 source. this basically is for ATM PVC */
                    275:        if (altifp && get_hw_ifid(altifp, in6) == 0) {
1.34      itojun    276:                nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
                    277:                    if_name(ifp0), if_name(altifp)));
1.25      itojun    278:                goto success;
                    279:        }
                    280:
                    281:        /* next, try to get it from some other hardware interface */
                    282:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
                    283:        {
                    284:                if (ifp == ifp0)
                    285:                        continue;
                    286:                if (get_hw_ifid(ifp, in6) != 0)
                    287:                        continue;
1.27      itojun    288:
1.25      itojun    289:                /*
                    290:                 * to borrow ifid from other interface, ifid needs to be
                    291:                 * globally unique
                    292:                 */
                    293:                if (IFID_UNIVERSAL(in6)) {
1.34      itojun    294:                        nd6log((LOG_DEBUG,
                    295:                            "%s: borrow interface identifier from %s\n",
                    296:                            if_name(ifp0), if_name(ifp)));
1.25      itojun    297:                        goto success;
                    298:                }
                    299:        }
1.13      itojun    300:
1.25      itojun    301:        /* last resort: get from random number source */
                    302:        if (get_rand_ifid(ifp, in6) == 0) {
1.34      itojun    303:                nd6log((LOG_DEBUG,
                    304:                    "%s: interface identifier generated by random number\n",
                    305:                    if_name(ifp0)));
1.25      itojun    306:                goto success;
                    307:        }
1.13      itojun    308:
1.31      itojun    309:        printf("%s: failed to get interface identifier\n", if_name(ifp0));
1.25      itojun    310:        return -1;
1.13      itojun    311:
1.25      itojun    312: success:
1.34      itojun    313:        nd6log((LOG_INFO, "%s: ifid: "
1.25      itojun    314:                "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
                    315:                if_name(ifp0),
                    316:                in6->s6_addr[8], in6->s6_addr[9],
                    317:                in6->s6_addr[10], in6->s6_addr[11],
                    318:                in6->s6_addr[12], in6->s6_addr[13],
1.34      itojun    319:                in6->s6_addr[14], in6->s6_addr[15]));
1.13      itojun    320:        return 0;
                    321: }
                    322:
                    323: /*
1.25      itojun    324:  * configure IPv6 interface address.  XXX code duplicated with in.c
1.2       itojun    325:  */
1.25      itojun    326: static int
                    327: in6_ifattach_addaddr(ifp, ia)
                    328:        struct ifnet *ifp;
                    329:        struct in6_ifaddr *ia;
1.2       itojun    330: {
1.25      itojun    331:        struct in6_ifaddr *oia;
1.2       itojun    332:        struct ifaddr *ifa;
1.25      itojun    333:        int error;
                    334:        int rtflag;
                    335:        struct in6_addr llsol;
                    336:
                    337:        /*
                    338:         * initialize if_addrlist, if we are the very first one
                    339:         */
                    340:        ifa = TAILQ_FIRST(&ifp->if_addrlist);
                    341:        if (ifa == NULL) {
                    342:                TAILQ_INIT(&ifp->if_addrlist);
                    343:        }
1.2       itojun    344:
1.25      itojun    345:        /*
                    346:         * link the interface address to global list
                    347:         */
                    348:        TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1.27      itojun    349:        IFAREF(&ia->ia_ifa);
1.2       itojun    350:
1.25      itojun    351:        /*
                    352:         * Also link into the IPv6 address chain beginning with in6_ifaddr.
                    353:         * kazu opposed it, but itojun & jinmei wanted.
                    354:         */
                    355:        if ((oia = in6_ifaddr) != NULL) {
                    356:                for (; oia->ia_next; oia = oia->ia_next)
1.2       itojun    357:                        continue;
1.25      itojun    358:                oia->ia_next = ia;
                    359:        } else
                    360:                in6_ifaddr = ia;
1.27      itojun    361:        IFAREF(&ia->ia_ifa);
1.25      itojun    362:
                    363:        /*
                    364:         * give the interface a chance to initialize, in case this
                    365:         * is the first address to be added.
                    366:         */
                    367:        if (ifp->if_ioctl != NULL) {
                    368:                int s;
1.35      thorpej   369:                s = splnet();
1.25      itojun    370:                error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
                    371:                splx(s);
                    372:        } else
                    373:                error = 0;
                    374:        if (error) {
                    375:                switch (error) {
                    376:                case EAFNOSUPPORT:
                    377:                        printf("%s: IPv6 not supported\n", if_name(ifp));
                    378:                        break;
                    379:                default:
                    380:                        printf("%s: SIOCSIFADDR error %d\n", if_name(ifp),
                    381:                            error);
                    382:                        break;
                    383:                }
                    384:
                    385:                /* undo changes */
                    386:                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
                    387:                IFAFREE(&ia->ia_ifa);
                    388:                if (oia)
                    389:                        oia->ia_next = ia->ia_next;
                    390:                else
                    391:                        in6_ifaddr = ia->ia_next;
                    392:                IFAFREE(&ia->ia_ifa);
                    393:                return -1;
                    394:        }
                    395:
                    396:        /* configure link-layer address resolution */
1.27      itojun    397:        rtflag = 0;
1.25      itojun    398:        if (IN6_ARE_ADDR_EQUAL(&ia->ia_prefixmask.sin6_addr, &in6mask128))
                    399:                rtflag = RTF_HOST;
                    400:        else {
                    401:                switch (ifp->if_type) {
                    402:                case IFT_LOOP:
                    403: #ifdef IFT_STF
                    404:                case IFT_STF:
                    405: #endif
                    406:                        rtflag = 0;
                    407:                        break;
                    408:                default:
                    409:                        ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
                    410:                        ia->ia_ifa.ifa_flags |= RTF_CLONING;
                    411:                        rtflag = RTF_CLONING;
                    412:                        break;
1.2       itojun    413:                }
                    414:        }
1.25      itojun    415:
                    416:        /* add route to the interface. */
                    417:        rtrequest(RTM_ADD,
                    418:                  (struct sockaddr *)&ia->ia_addr,
                    419:                  (struct sockaddr *)&ia->ia_addr,
                    420:                  (struct sockaddr *)&ia->ia_prefixmask,
                    421:                  RTF_UP | rtflag,
                    422:                  (struct rtentry **)0);
                    423:        ia->ia_flags |= IFA_ROUTE;
                    424:
                    425:        if ((rtflag & RTF_CLONING) != 0 &&
                    426:            (ifp->if_flags & IFF_MULTICAST) != 0) {
                    427:                /* Restore saved multicast addresses (if any). */
                    428:                in6_restoremkludge(ia, ifp);
                    429:
                    430:                /*
                    431:                 * join solicited multicast address
                    432:                 */
                    433:                bzero(&llsol, sizeof(llsol));
                    434:                llsol.s6_addr16[0] = htons(0xff02);
                    435:                llsol.s6_addr16[1] = htons(ifp->if_index);
                    436:                llsol.s6_addr32[1] = 0;
                    437:                llsol.s6_addr32[2] = htonl(1);
                    438:                llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
                    439:                llsol.s6_addr8[12] = 0xff;
1.36      itojun    440:                if (!in6_addmulti(&llsol, ifp, &error)) {
                    441:                        nd6log((LOG_ERR, "%s: failed to join %s (errno=%d)\n",
                    442:                            if_name(ifp), ip6_sprintf(&llsol), error));
                    443:                }
1.25      itojun    444:
1.43    ! itojun    445:                if (in6if_do_dad(ifp)) {
1.25      itojun    446:                        /* mark the address TENTATIVE, if needed. */
                    447:                        ia->ia6_flags |= IN6_IFF_TENTATIVE;
                    448:                        /* nd6_dad_start() will be called in in6_if_up */
                    449:                }
                    450:        }
                    451:
                    452:        return 0;
                    453: }
                    454:
                    455: static int
                    456: in6_ifattach_linklocal(ifp, altifp)
                    457:        struct ifnet *ifp;
                    458:        struct ifnet *altifp;   /*secondary EUI64 source*/
                    459: {
                    460:        struct in6_ifaddr *ia;
1.2       itojun    461:
1.25      itojun    462:        /*
                    463:         * configure link-local address
                    464:         */
                    465:        ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
                    466:        bzero((caddr_t)ia, sizeof(*ia));
                    467:        ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
                    468:        if (ifp->if_flags & IFF_POINTOPOINT)
                    469:                ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
                    470:        else
                    471:                ia->ia_ifa.ifa_dstaddr = NULL;
                    472:        ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
                    473:        ia->ia_ifp = ifp;
1.2       itojun    474:
1.25      itojun    475:        bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
                    476:        ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
                    477:        ia->ia_prefixmask.sin6_family = AF_INET6;
                    478:        ia->ia_prefixmask.sin6_addr = in6mask64;
1.5       itojun    479:
1.25      itojun    480:        /* just in case */
                    481:        bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
                    482:        ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
                    483:        ia->ia_dstaddr.sin6_family = AF_INET6;
1.5       itojun    484:
1.25      itojun    485:        bzero(&ia->ia_addr, sizeof(ia->ia_addr));
                    486:        ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
                    487:        ia->ia_addr.sin6_family = AF_INET6;
                    488:        ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
                    489:        ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
                    490:        ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
                    491:        if (ifp->if_flags & IFF_LOOPBACK) {
                    492:                ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
                    493:                ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
1.2       itojun    494:        } else {
1.25      itojun    495:                if (get_ifid(ifp, altifp, &ia->ia_addr.sin6_addr) != 0) {
1.34      itojun    496:                        nd6log((LOG_ERR,
                    497:                            "%s: no ifid available\n", if_name(ifp)));
1.25      itojun    498:                        free(ia, M_IFADDR);
                    499:                        return -1;
                    500:                }
                    501:        }
                    502:
                    503:        ia->ia_ifa.ifa_metric = ifp->if_metric;
                    504:
                    505:        if (in6_ifattach_addaddr(ifp, ia) != 0) {
                    506:                /* ia will be freed on failure */
                    507:                return -1;
                    508:        }
                    509:
                    510:        return 0;
                    511: }
                    512:
                    513: static int
                    514: in6_ifattach_loopback(ifp)
                    515:        struct ifnet *ifp;      /* must be IFT_LOOP */
                    516: {
                    517:        struct in6_ifaddr *ia;
                    518:
                    519:        /*
                    520:         * configure link-local address
                    521:         */
                    522:        ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
                    523:        bzero((caddr_t)ia, sizeof(*ia));
                    524:        ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
                    525:        ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
                    526:        ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
                    527:        ia->ia_ifp = ifp;
                    528:
                    529:        bzero(&ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
                    530:        ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
                    531:        ia->ia_prefixmask.sin6_family = AF_INET6;
                    532:        ia->ia_prefixmask.sin6_addr = in6mask128;
                    533:
                    534:        /*
                    535:         * Always initialize ia_dstaddr (= broadcast address) to loopback
                    536:         * address, to make getifaddr happier.
                    537:         *
                    538:         * For BSDI, it is mandatory.  The BSDI version of
                    539:         * ifa_ifwithroute() rejects to add a route to the loopback
                    540:         * interface.  Even for other systems, loopback looks somewhat
                    541:         * special.
                    542:         */
                    543:        bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
                    544:        ia->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
                    545:        ia->ia_dstaddr.sin6_family = AF_INET6;
                    546:        ia->ia_dstaddr.sin6_addr = in6addr_loopback;
                    547:
                    548:        bzero(&ia->ia_addr, sizeof(ia->ia_addr));
                    549:        ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
                    550:        ia->ia_addr.sin6_family = AF_INET6;
                    551:        ia->ia_addr.sin6_addr = in6addr_loopback;
                    552:
                    553:        ia->ia_ifa.ifa_metric = ifp->if_metric;
                    554:
                    555:        if (in6_ifattach_addaddr(ifp, ia) != 0) {
                    556:                /* ia will be freed on failure */
                    557:                return -1;
1.2       itojun    558:        }
1.25      itojun    559:
                    560:        return 0;
1.2       itojun    561: }
                    562:
1.17      itojun    563: /*
                    564:  * XXX multiple loopback interface needs more care.  for instance,
                    565:  * nodelocal address needs to be configured onto only one of them.
1.25      itojun    566:  * XXX multiple link-local address case
1.17      itojun    567:  */
1.2       itojun    568: void
1.25      itojun    569: in6_ifattach(ifp, altifp)
1.2       itojun    570:        struct ifnet *ifp;
1.25      itojun    571:        struct ifnet *altifp;   /* secondary EUI64 source */
1.2       itojun    572: {
                    573:        static size_t if_indexlim = 8;
                    574:        struct sockaddr_in6 mltaddr;
                    575:        struct sockaddr_in6 mltmask;
                    576:        struct sockaddr_in6 gate;
                    577:        struct sockaddr_in6 mask;
1.25      itojun    578:        struct in6_ifaddr *ia;
                    579:        struct in6_addr in6;
1.13      itojun    580:
1.38      itojun    581:        /* some of the interfaces are inherently not IPv6 capable */
                    582:        switch (ifp->if_type) {
1.42      itojun    583:        case IFT_BRIDGE:
                    584:                return;
1.38      itojun    585:        case IFT_PROPVIRTUAL:
                    586:                if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
                    587:                    '0' <= ifp->if_xname[sizeof("bridge")] &&
                    588:                    ifp->if_xname[sizeof("bridge")] <= '9')
                    589:                        return;
                    590:                break;
                    591:        }
                    592:
1.2       itojun    593:        /*
                    594:         * We have some arrays that should be indexed by if_index.
                    595:         * since if_index will grow dynamically, they should grow too.
1.13      itojun    596:         *      struct in6_ifstat **in6_ifstat
                    597:         *      struct icmp6_ifstat **icmp6_ifstat
1.2       itojun    598:         */
1.25      itojun    599:        if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
                    600:            if_index >= if_indexlim) {
1.2       itojun    601:                size_t n;
                    602:                caddr_t q;
1.7       itojun    603:                size_t olim;
1.2       itojun    604:
1.7       itojun    605:                olim = if_indexlim;
                    606:                while (if_index >= if_indexlim)
1.2       itojun    607:                        if_indexlim <<= 1;
                    608:
1.13      itojun    609:                /* grow in6_ifstat */
                    610:                n = if_indexlim * sizeof(struct in6_ifstat *);
                    611:                q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
                    612:                bzero(q, n);
                    613:                if (in6_ifstat) {
                    614:                        bcopy((caddr_t)in6_ifstat, q,
                    615:                                olim * sizeof(struct in6_ifstat *));
                    616:                        free((caddr_t)in6_ifstat, M_IFADDR);
                    617:                }
                    618:                in6_ifstat = (struct in6_ifstat **)q;
                    619:                in6_ifstatmax = if_indexlim;
                    620:
                    621:                /* grow icmp6_ifstat */
                    622:                n = if_indexlim * sizeof(struct icmp6_ifstat *);
1.2       itojun    623:                q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
                    624:                bzero(q, n);
1.13      itojun    625:                if (icmp6_ifstat) {
                    626:                        bcopy((caddr_t)icmp6_ifstat, q,
                    627:                                olim * sizeof(struct icmp6_ifstat *));
                    628:                        free((caddr_t)icmp6_ifstat, M_IFADDR);
1.2       itojun    629:                }
1.13      itojun    630:                icmp6_ifstat = (struct icmp6_ifstat **)q;
                    631:                icmp6_ifstatmax = if_indexlim;
1.2       itojun    632:        }
1.37      itojun    633:
                    634:        /* create a multicast kludge storage (if we have not had one) */
                    635:        in6_createmkludge(ifp);
1.2       itojun    636:
                    637:        /*
1.25      itojun    638:         * quirks based on interface type
1.2       itojun    639:         */
1.25      itojun    640:        switch (ifp->if_type) {
                    641: #ifdef IFT_STF
                    642:        case IFT_STF:
                    643:                /*
1.38      itojun    644:                 * 6to4 interface is a very special kind of beast.
                    645:                 * no multicast, no linklocal.  RFC2529 specifies how to make
                    646:                 * linklocals for 6to4 interface, but there's no use and
                    647:                 * it is rather harmful to have one.
1.25      itojun    648:                 */
                    649:                goto statinit;
                    650: #endif
                    651:        default:
                    652:                break;
1.7       itojun    653:        }
1.2       itojun    654:
                    655:        /*
1.25      itojun    656:         * usually, we require multicast capability to the interface
1.2       itojun    657:         */
1.25      itojun    658:        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
1.38      itojun    659:                log(LOG_INFO, "in6_ifattach: "
                    660:                    "%s is not multicast capable, IPv6 not enabled\n",
1.25      itojun    661:                    if_name(ifp));
                    662:                return;
                    663:        }
1.15      thorpej   664:
1.2       itojun    665:        /*
1.25      itojun    666:         * assign link-local address, if there's none
1.2       itojun    667:         */
1.25      itojun    668:        ia = in6ifa_ifpforlinklocal(ifp, 0);
                    669:        if (ia == NULL) {
                    670:                if (in6_ifattach_linklocal(ifp, altifp) != 0)
                    671:                        return;
                    672:                ia = in6ifa_ifpforlinklocal(ifp, 0);
1.2       itojun    673:
1.25      itojun    674:                if (ia == NULL) {
1.31      itojun    675:                        printf("%s: failed to add link-local address\n",
1.25      itojun    676:                            if_name(ifp));
1.2       itojun    677:
1.25      itojun    678:                        /* we can't initialize multicasts without link-local */
                    679:                        goto statinit;
1.2       itojun    680:                }
                    681:        }
                    682:
1.25      itojun    683:        if (ifp->if_flags & IFF_POINTOPOINT) {
1.2       itojun    684:                /*
                    685:                 * route local address to loopback
                    686:                 */
                    687:                bzero(&gate, sizeof(gate));
                    688:                gate.sin6_len = sizeof(struct sockaddr_in6);
                    689:                gate.sin6_family = AF_INET6;
                    690:                gate.sin6_addr = in6addr_loopback;
                    691:                bzero(&mask, sizeof(mask));
                    692:                mask.sin6_len = sizeof(struct sockaddr_in6);
                    693:                mask.sin6_family = AF_INET6;
                    694:                mask.sin6_addr = in6mask64;
                    695:                rtrequest(RTM_ADD,
                    696:                          (struct sockaddr *)&ia->ia_addr,
                    697:                          (struct sockaddr *)&gate,
                    698:                          (struct sockaddr *)&mask,
                    699:                          RTF_UP|RTF_HOST,
                    700:                          (struct rtentry **)0);
                    701:        }
                    702:
                    703:        /*
1.25      itojun    704:         * assign loopback address for loopback interface
                    705:         * XXX multiple loopback interface case
1.2       itojun    706:         */
1.25      itojun    707:        in6 = in6addr_loopback;
                    708:        if (ifp->if_flags & IFF_LOOPBACK) {
                    709:                if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
                    710:                        if (in6_ifattach_loopback(ifp) != 0)
                    711:                                return;
                    712:                }
                    713:        }
1.2       itojun    714:
1.25      itojun    715: #ifdef DIAGNOSTIC
                    716:        if (!ia) {
                    717:                panic("ia == NULL in in6_ifattach");
                    718:                /*NOTREACHED*/
1.2       itojun    719:        }
1.25      itojun    720: #endif
1.2       itojun    721:
                    722:        /*
                    723:         * join multicast
                    724:         */
                    725:        if (ifp->if_flags & IFF_MULTICAST) {
                    726:                int error;      /* not used */
1.25      itojun    727:                struct in6_multi *in6m;
1.2       itojun    728:
1.25      itojun    729:                /* Restore saved multicast addresses (if any). */
1.2       itojun    730:                in6_restoremkludge(ia, ifp);
                    731:
                    732:                bzero(&mltmask, sizeof(mltmask));
                    733:                mltmask.sin6_len = sizeof(struct sockaddr_in6);
                    734:                mltmask.sin6_family = AF_INET6;
                    735:                mltmask.sin6_addr = in6mask32;
                    736:
                    737:                /*
                    738:                 * join link-local all-nodes address
                    739:                 */
                    740:                bzero(&mltaddr, sizeof(mltaddr));
                    741:                mltaddr.sin6_len = sizeof(struct sockaddr_in6);
                    742:                mltaddr.sin6_family = AF_INET6;
                    743:                mltaddr.sin6_addr = in6addr_linklocal_allnodes;
                    744:                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
                    745:
1.25      itojun    746:                IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
                    747:                if (in6m == NULL) {
1.2       itojun    748:                        rtrequest(RTM_ADD,
                    749:                                  (struct sockaddr *)&mltaddr,
1.25      itojun    750:                                  (struct sockaddr *)&ia->ia_addr,
1.2       itojun    751:                                  (struct sockaddr *)&mltmask,
1.25      itojun    752:                                  RTF_UP|RTF_CLONING,  /* xxx */
1.2       itojun    753:                                  (struct rtentry **)0);
1.36      itojun    754:                        if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error)) {
                    755:                                nd6log((LOG_ERR, "%s: failed to join %s "
                    756:                                    "(errno=%d)\n", if_name(ifp),
                    757:                                    ip6_sprintf(&mltaddr.sin6_addr),
                    758:                                    error));
                    759:                        }
1.25      itojun    760:                }
                    761:
                    762:                if (ifp->if_flags & IFF_LOOPBACK) {
                    763:                        in6 = in6addr_loopback;
                    764:                        ia = in6ifa_ifpwithaddr(ifp, &in6);
1.2       itojun    765:                        /*
1.25      itojun    766:                         * join node-local all-nodes address, on loopback
1.2       itojun    767:                         */
1.25      itojun    768:                        mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
                    769:
                    770:                        IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
                    771:                        if (in6m == NULL && ia != NULL) {
                    772:                                rtrequest(RTM_ADD,
                    773:                                          (struct sockaddr *)&mltaddr,
                    774:                                          (struct sockaddr *)&ia->ia_addr,
                    775:                                          (struct sockaddr *)&mltmask,
                    776:                                          RTF_UP,
                    777:                                          (struct rtentry **)0);
1.36      itojun    778:                                if (!in6_addmulti(&mltaddr.sin6_addr, ifp,
                    779:                                    &error)) {
                    780:                                        nd6log((LOG_ERR, "%s: failed to join "
                    781:                                            "%s (errno=%d)\n", if_name(ifp),
                    782:                                            ip6_sprintf(&mltaddr.sin6_addr),
                    783:                                            error));
                    784:                                }
1.25      itojun    785:                        }
1.2       itojun    786:                }
                    787:        }
                    788:
1.25      itojun    789: statinit:;
                    790:
1.2       itojun    791:        /* update dynamically. */
                    792:        if (in6_maxmtu < ifp->if_mtu)
                    793:                in6_maxmtu = ifp->if_mtu;
                    794:
1.13      itojun    795:        if (in6_ifstat[ifp->if_index] == NULL) {
                    796:                in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
                    797:                        malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
                    798:                bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
                    799:        }
                    800:        if (icmp6_ifstat[ifp->if_index] == NULL) {
                    801:                icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
                    802:                        malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
                    803:                bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
                    804:        }
                    805:
1.2       itojun    806:        /* initialize NDP variables */
                    807:        nd6_ifattach(ifp);
                    808: }
                    809:
1.17      itojun    810: /*
                    811:  * NOTE: in6_ifdetach() does not support loopback if at this moment.
1.41      itojun    812:  * We don't need this function in bsdi, because interfaces are never removed
                    813:  * from the ifnet list in bsdi.
1.17      itojun    814:  */
1.2       itojun    815: void
                    816: in6_ifdetach(ifp)
                    817:        struct ifnet *ifp;
                    818: {
                    819:        struct in6_ifaddr *ia, *oia;
1.30      itojun    820:        struct ifaddr *ifa, *next;
1.2       itojun    821:        struct rtentry *rt;
                    822:        short rtflags;
1.16      itojun    823:        struct sockaddr_in6 sin6;
1.2       itojun    824:
1.18      itojun    825:        /* nuke prefix list.  this may try to remove some of ifaddrs as well */
                    826:        in6_purgeprefix(ifp);
                    827:
                    828:        /* remove neighbor management table */
                    829:        nd6_purge(ifp);
                    830:
1.30      itojun    831:        /* nuke any of IPv6 addresses we have */
                    832:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
                    833:        {
                    834:                next = ifa->ifa_list.tqe_next;
                    835:                if (ifa->ifa_addr->sa_family != AF_INET6)
                    836:                        continue;
                    837:                in6_purgeaddr(ifa, ifp);
                    838:        }
                    839:
                    840:        /* undo everything done by in6_ifattach(), just in case */
                    841:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
1.13      itojun    842:        {
1.30      itojun    843:                next = ifa->ifa_list.tqe_next;
                    844:
                    845:
1.2       itojun    846:                if (ifa->ifa_addr->sa_family != AF_INET6
                    847:                 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
                    848:                        continue;
                    849:                }
                    850:
                    851:                ia = (struct in6_ifaddr *)ifa;
                    852:
                    853:                /* remove from the routing table */
                    854:                if ((ia->ia_flags & IFA_ROUTE)
1.14      itojun    855:                 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
1.2       itojun    856:                        rtflags = rt->rt_flags;
                    857:                        rtfree(rt);
                    858:                        rtrequest(RTM_DELETE,
                    859:                                (struct sockaddr *)&ia->ia_addr,
1.24      itojun    860:                                (struct sockaddr *)&ia->ia_addr,
1.2       itojun    861:                                (struct sockaddr *)&ia->ia_prefixmask,
                    862:                                rtflags, (struct rtentry **)0);
                    863:                }
                    864:
                    865:                /* remove from the linked list */
                    866:                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1.30      itojun    867:                IFAFREE(&ia->ia_ifa);
1.2       itojun    868:
                    869:                /* also remove from the IPv6 address chain(itojun&jinmei) */
                    870:                oia = ia;
                    871:                if (oia == (ia = in6_ifaddr))
                    872:                        in6_ifaddr = ia->ia_next;
                    873:                else {
                    874:                        while (ia->ia_next && (ia->ia_next != oia))
                    875:                                ia = ia->ia_next;
                    876:                        if (ia->ia_next)
                    877:                                ia->ia_next = oia->ia_next;
1.34      itojun    878:                        else {
                    879:                                nd6log((LOG_ERR,
                    880:                                    "%s: didn't unlink in6ifaddr from "
                    881:                                    "list\n", if_name(ifp)));
                    882:                        }
1.2       itojun    883:                }
                    884:
1.30      itojun    885:                IFAFREE(&oia->ia_ifa);
1.16      itojun    886:        }
                    887:
1.17      itojun    888:        /* cleanup multicast address kludge table, if there is any */
                    889:        in6_purgemkludge(ifp);
1.30      itojun    890:
1.41      itojun    891:        /*
                    892:         * remove neighbor management table.  we call it twice just to make
                    893:         * sure we nuke everything.  maybe we need just one call.
                    894:         * XXX: since the first call did not release addresses, some prefixes
                    895:         * might remain.  We should call nd6_purge() again to release the
                    896:         * prefixes after removing all addresses above.
                    897:         * (Or can we just delay calling nd6_purge until at this point?)
                    898:         */
1.30      itojun    899:        nd6_purge(ifp);
1.18      itojun    900:
1.16      itojun    901:        /* remove route to link-local allnodes multicast (ff02::1) */
                    902:        bzero(&sin6, sizeof(sin6));
                    903:        sin6.sin6_len = sizeof(struct sockaddr_in6);
                    904:        sin6.sin6_family = AF_INET6;
                    905:        sin6.sin6_addr = in6addr_linklocal_allnodes;
                    906:        sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1.33      itojun    907:        rt = rtalloc1((struct sockaddr *)&sin6, 0);
                    908:        if (rt && rt->rt_ifp == ifp) {
1.16      itojun    909:                rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
                    910:                        rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
                    911:                rtfree(rt);
1.2       itojun    912:        }
                    913: }

CVSweb <webmaster@jp.NetBSD.org>