[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.30

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

CVSweb <webmaster@jp.NetBSD.org>