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

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

CVSweb <webmaster@jp.NetBSD.org>