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

1.48    ! itojun      1: /*     $NetBSD: in6_ifattach.c,v 1.47 2002/06/07 04:30:40 itojun Exp $ */
1.37      itojun      2: /*     $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $  */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.24      itojun      7:  *
1.2       itojun      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the project nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
1.24      itojun     19:  *
1.2       itojun     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
1.39      lukem      32:
                     33: #include <sys/cdefs.h>
1.48    ! itojun     34: __KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.47 2002/06/07 04:30:40 itojun Exp $");
1.2       itojun     35:
                     36: #include <sys/param.h>
                     37: #include <sys/systm.h>
                     38: #include <sys/malloc.h>
                     39: #include <sys/socket.h>
                     40: #include <sys/sockio.h>
1.13      itojun     41: #include <sys/kernel.h>
1.34      itojun     42: #include <sys/syslog.h>
1.13      itojun     43: #include <sys/md5.h>
1.2       itojun     44:
                     45: #include <net/if.h>
                     46: #include <net/if_dl.h>
                     47: #include <net/if_types.h>
                     48: #include <net/route.h>
                     49:
                     50: #include <netinet/in.h>
                     51: #include <netinet/in_var.h>
                     52:
1.19      itojun     53: #include <netinet/ip6.h>
1.2       itojun     54: #include <netinet6/ip6_var.h>
                     55: #include <netinet6/in6_ifattach.h>
                     56: #include <netinet6/ip6_var.h>
                     57: #include <netinet6/nd6.h>
                     58:
1.13      itojun     59: #include <net/net_osdep.h>
                     60:
1.2       itojun     61: unsigned long in6_maxmtu = 0;
                     62:
1.48    ! itojun     63: int ip6_auto_linklocal = 1;    /* enable by default */
        !            64:
1.25      itojun     65: static int get_rand_ifid __P((struct ifnet *, struct in6_addr *));
                     66: static int get_hw_ifid __P((struct ifnet *, struct in6_addr *));
                     67: static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *));
                     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;
1.40      itojun     92:        struct in6_addr *in6;   /* upper 64bits are preserved */
1.25      itojun     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;
1.40      itojun    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:
1.48    ! itojun    160:        switch (ifp->if_type) {
        !           161:        case IFT_IEEE1394:
        !           162:        case IFT_IEEE80211:
        !           163:                /* IEEE1394 uses 16byte length address starting with EUI64 */
        !           164:                if (addrlen > 8)
        !           165:                        addrlen = 8;
        !           166:                break;
        !           167:        default:
        !           168:                break;
        !           169:        }
        !           170:
1.25      itojun    171:        /* get EUI64 */
                    172:        switch (ifp->if_type) {
1.48    ! itojun    173:        /* IEEE802/EUI64 cases - what others? */
1.25      itojun    174:        case IFT_ETHER:
                    175:        case IFT_FDDI:
                    176:        case IFT_ATM:
1.32      onoe      177:        case IFT_IEEE1394:
1.48    ! itojun    178:        case IFT_IEEE80211:
1.25      itojun    179:                /* look at IEEE802/EUI64 only */
                    180:                if (addrlen != 8 && addrlen != 6)
                    181:                        return -1;
1.13      itojun    182:
1.25      itojun    183:                /*
                    184:                 * check for invalid MAC address - on bsdi, we see it a lot
                    185:                 * since wildboar configures all-zero MAC on pccard before
                    186:                 * card insertion.
                    187:                 */
                    188:                if (bcmp(addr, allzero, addrlen) == 0)
                    189:                        return -1;
                    190:                if (bcmp(addr, allone, addrlen) == 0)
                    191:                        return -1;
                    192:
                    193:                /* make EUI64 address */
                    194:                if (addrlen == 8)
                    195:                        bcopy(addr, &in6->s6_addr[8], 8);
                    196:                else if (addrlen == 6) {
                    197:                        in6->s6_addr[8] = addr[0];
                    198:                        in6->s6_addr[9] = addr[1];
                    199:                        in6->s6_addr[10] = addr[2];
                    200:                        in6->s6_addr[11] = 0xff;
1.26      itojun    201:                        in6->s6_addr[12] = 0xfe;
1.25      itojun    202:                        in6->s6_addr[13] = addr[3];
                    203:                        in6->s6_addr[14] = addr[4];
                    204:                        in6->s6_addr[15] = addr[5];
                    205:                }
1.7       itojun    206:                break;
1.25      itojun    207:
                    208:        case IFT_ARCNET:
                    209:                if (addrlen != 1)
                    210:                        return -1;
                    211:                if (!addr[0])
                    212:                        return -1;
                    213:
                    214:                bzero(&in6->s6_addr[8], 8);
                    215:                in6->s6_addr[15] = addr[0];
                    216:
1.27      itojun    217:                /*
                    218:                 * due to insufficient bitwidth, we mark it local.
                    219:                 */
1.25      itojun    220:                in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
                    221:                in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
1.7       itojun    222:                break;
1.25      itojun    223:
                    224:        case IFT_GIF:
                    225: #ifdef IFT_STF
                    226:        case IFT_STF:
                    227: #endif
                    228:                /*
1.34      itojun    229:                 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
1.27      itojun    230:                 * however, IPv4 address is not very suitable as unique
                    231:                 * identifier source (can be renumbered).
                    232:                 * we don't do this.
1.25      itojun    233:                 */
                    234:                return -1;
                    235:
1.7       itojun    236:        default:
1.25      itojun    237:                return -1;
                    238:        }
                    239:
                    240:        /* sanity check: g bit must not indicate "group" */
                    241:        if (EUI64_GROUP(in6))
                    242:                return -1;
                    243:
                    244:        /* convert EUI64 into IPv6 interface identifier */
                    245:        EUI64_TO_IFID(in6);
                    246:
                    247:        /*
                    248:         * sanity check: ifid must not be all zero, avoid conflict with
                    249:         * subnet router anycast
                    250:         */
                    251:        if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
                    252:            bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
                    253:                return -1;
1.7       itojun    254:        }
                    255:
                    256:        return 0;
1.2       itojun    257: }
                    258:
                    259: /*
1.25      itojun    260:  * Get interface identifier for the specified interface.  If it is not
                    261:  * available on ifp0, borrow interface identifier from other information
                    262:  * sources.
1.13      itojun    263:  */
                    264: static int
1.25      itojun    265: get_ifid(ifp0, altifp, in6)
                    266:        struct ifnet *ifp0;
                    267:        struct ifnet *altifp;   /*secondary EUI64 source*/
                    268:        struct in6_addr *in6;
1.13      itojun    269: {
1.25      itojun    270:        struct ifnet *ifp;
                    271:
                    272:        /* first, try to get it from the interface itself */
                    273:        if (get_hw_ifid(ifp0, in6) == 0) {
1.34      itojun    274:                nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
                    275:                    if_name(ifp0)));
1.25      itojun    276:                goto success;
                    277:        }
                    278:
                    279:        /* try secondary EUI64 source. this basically is for ATM PVC */
                    280:        if (altifp && get_hw_ifid(altifp, in6) == 0) {
1.34      itojun    281:                nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
                    282:                    if_name(ifp0), if_name(altifp)));
1.25      itojun    283:                goto success;
                    284:        }
                    285:
                    286:        /* next, try to get it from some other hardware interface */
                    287:        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
                    288:        {
                    289:                if (ifp == ifp0)
                    290:                        continue;
                    291:                if (get_hw_ifid(ifp, in6) != 0)
                    292:                        continue;
1.27      itojun    293:
1.25      itojun    294:                /*
                    295:                 * to borrow ifid from other interface, ifid needs to be
                    296:                 * globally unique
                    297:                 */
                    298:                if (IFID_UNIVERSAL(in6)) {
1.34      itojun    299:                        nd6log((LOG_DEBUG,
                    300:                            "%s: borrow interface identifier from %s\n",
                    301:                            if_name(ifp0), if_name(ifp)));
1.25      itojun    302:                        goto success;
                    303:                }
                    304:        }
1.13      itojun    305:
1.25      itojun    306:        /* last resort: get from random number source */
                    307:        if (get_rand_ifid(ifp, in6) == 0) {
1.34      itojun    308:                nd6log((LOG_DEBUG,
                    309:                    "%s: interface identifier generated by random number\n",
                    310:                    if_name(ifp0)));
1.25      itojun    311:                goto success;
                    312:        }
1.13      itojun    313:
1.31      itojun    314:        printf("%s: failed to get interface identifier\n", if_name(ifp0));
1.25      itojun    315:        return -1;
1.13      itojun    316:
1.25      itojun    317: success:
1.47      itojun    318:        nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
                    319:            if_name(ifp0), in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
                    320:            in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
                    321:            in6->s6_addr[14], in6->s6_addr[15]));
1.13      itojun    322:        return 0;
                    323: }
                    324:
1.25      itojun    325: static int
1.48    ! itojun    326: in6_ifattach_linklocal(ifp, altifp)
1.25      itojun    327:        struct ifnet *ifp;
1.48    ! itojun    328:        struct ifnet *altifp;   /*secondary EUI64 source*/
        !           329: {
1.25      itojun    330:        struct in6_ifaddr *ia;
1.48    ! itojun    331:        struct in6_aliasreq ifra;
        !           332:        struct nd_prefix pr0;
        !           333:        int i, error;
1.25      itojun    334:
                    335:        /*
1.48    ! itojun    336:         * configure link-local address.
1.25      itojun    337:         */
1.48    ! itojun    338:        bzero(&ifra, sizeof(ifra));
1.2       itojun    339:
1.25      itojun    340:        /*
1.48    ! itojun    341:         * in6_update_ifa() does not use ifra_name, but we accurately set it
        !           342:         * for safety.
1.25      itojun    343:         */
1.48    ! itojun    344:        strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
1.2       itojun    345:
1.48    ! itojun    346:        ifra.ifra_addr.sin6_family = AF_INET6;
        !           347:        ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
        !           348:        ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
        !           349:        ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !           350:        ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
        !           351:        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
        !           352:                ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
        !           353:                ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
        !           354:        } else {
        !           355:                if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
        !           356:                        nd6log((LOG_ERR,
        !           357:                            "%s: no ifid available\n", if_name(ifp)));
        !           358:                        return(-1);
1.25      itojun    359:                }
                    360:        }
                    361:
1.48    ! itojun    362:        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
        !           363:        ifra.ifra_prefixmask.sin6_family = AF_INET6;
        !           364:        ifra.ifra_prefixmask.sin6_addr = in6mask64;
        !           365: #ifdef SCOPEDROUTING
        !           366:        /* take into account the sin6_scope_id field for routing */
        !           367:        ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff;
1.25      itojun    368: #endif
1.48    ! itojun    369:        /* link-local addresses should NEVER expire. */
        !           370:        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
        !           371:        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
1.25      itojun    372:
1.48    ! itojun    373:        /*
        !           374:         * Do not let in6_update_ifa() do DAD, since we need a random delay
        !           375:         * before sending an NS at the first time the interface becomes up.
        !           376:         * Instead, in6_if_up() will start DAD with a proper random delay.
        !           377:         */
        !           378:        ifra.ifra_flags |= IN6_IFF_NODAD;
1.25      itojun    379:
1.48    ! itojun    380:        /*
        !           381:         * Now call in6_update_ifa() to do a bunch of procedures to configure
        !           382:         * a link-local address. We can set NULL to the 3rd argument, because
        !           383:         * we know there's no other link-local address on the interface
        !           384:         * and therefore we are adding one (instead of updating one).
        !           385:         */
        !           386:        if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
1.25      itojun    387:                /*
1.48    ! itojun    388:                 * XXX: When the interface does not support IPv6, this call
        !           389:                 * would fail in the SIOCSIFADDR ioctl.  I believe the
        !           390:                 * notification is rather confusing in this case, so just
        !           391:                 * suppress it.  (jinmei@kame.net 20010130)
1.25      itojun    392:                 */
1.48    ! itojun    393:                if (error != EAFNOSUPPORT)
        !           394:                        log(LOG_NOTICE, "in6_ifattach_linklocal: failed to "
        !           395:                            "configure a link-local address on %s "
        !           396:                            "(errno=%d)\n",
        !           397:                            if_name(ifp), error);
        !           398:                return(-1);
1.25      itojun    399:        }
                    400:
                    401:        /*
1.48    ! itojun    402:         * Adjust ia6_flags so that in6_if_up will perform DAD.
        !           403:         * XXX: Some P2P interfaces seem not to send packets just after
        !           404:         * becoming up, so we skip p2p interfaces for safety.
1.25      itojun    405:         */
1.48    ! itojun    406:        ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
        !           407: #ifdef DIAGNOSTIC
        !           408:        if (!ia) {
        !           409:                panic("ia == NULL in in6_ifattach_linklocal");
        !           410:                /* NOTREACHED */
        !           411:        }
        !           412: #endif
        !           413:        if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) {
        !           414:                ia->ia6_flags &= ~IN6_IFF_NODAD;
        !           415:                ia->ia6_flags |= IN6_IFF_TENTATIVE;
1.25      itojun    416:        }
                    417:
1.48    ! itojun    418:        /*
        !           419:         * Make the link-local prefix (fe80::/64%link) as on-link.
        !           420:         * Since we'd like to manage prefixes separately from addresses,
        !           421:         * we make an ND6 prefix structure for the link-local prefix,
        !           422:         * and add it to the prefix list as a never-expire prefix.
        !           423:         * XXX: this change might affect some existing code base...
        !           424:         */
        !           425:        bzero(&pr0, sizeof(pr0));
        !           426:        pr0.ndpr_ifp = ifp;
        !           427:        /* this should be 64 at this moment. */
        !           428:        pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
        !           429:        pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
        !           430:        pr0.ndpr_prefix = ifra.ifra_addr;
        !           431:        /* apply the mask for safety. (nd6_prelist_add will apply it again) */
        !           432:        for (i = 0; i < 4; i++) {
        !           433:                pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
        !           434:                    in6mask64.s6_addr32[i];
        !           435:        }
        !           436:        /*
        !           437:         * Initialize parameters.  The link-local prefix must always be
        !           438:         * on-link, and its lifetimes never expire.
        !           439:         */
        !           440:        pr0.ndpr_raf_onlink = 1;
        !           441:        pr0.ndpr_raf_auto = 1;  /* probably meaningless */
        !           442:        pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
        !           443:        pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
        !           444:        /*
        !           445:         * Since there is no other link-local addresses, nd6_prefix_lookup()
        !           446:         * probably returns NULL.  However, we cannot always expect the result.
        !           447:         * For example, if we first remove the (only) existing link-local
        !           448:         * address, and then reconfigure another one, the prefix is still
        !           449:         * valid with referring to the old link-local address.
        !           450:         */
        !           451:        if (nd6_prefix_lookup(&pr0) == NULL) {
        !           452:                if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
        !           453:                        return(error);
1.25      itojun    454:        }
                    455:
                    456:        return 0;
                    457: }
                    458:
                    459: static int
                    460: in6_ifattach_loopback(ifp)
                    461:        struct ifnet *ifp;      /* must be IFT_LOOP */
                    462: {
1.48    ! itojun    463:        struct in6_aliasreq ifra;
        !           464:        int error;
        !           465:
        !           466:        bzero(&ifra, sizeof(ifra));
1.25      itojun    467:
                    468:        /*
1.48    ! itojun    469:         * in6_update_ifa() does not use ifra_name, but we accurately set it
        !           470:         * for safety.
1.25      itojun    471:         */
1.48    ! itojun    472:        strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
        !           473:
        !           474:        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
        !           475:        ifra.ifra_prefixmask.sin6_family = AF_INET6;
        !           476:        ifra.ifra_prefixmask.sin6_addr = in6mask128;
1.25      itojun    477:
                    478:        /*
                    479:         * Always initialize ia_dstaddr (= broadcast address) to loopback
1.48    ! itojun    480:         * address.  Follows IPv4 practice - see in_ifinit().
        !           481:         */
        !           482:        ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
        !           483:        ifra.ifra_dstaddr.sin6_family = AF_INET6;
        !           484:        ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
        !           485:
        !           486:        ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
        !           487:        ifra.ifra_addr.sin6_family = AF_INET6;
        !           488:        ifra.ifra_addr.sin6_addr = in6addr_loopback;
        !           489:
        !           490:        /* the loopback  address should NEVER expire. */
        !           491:        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
        !           492:        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
        !           493:
        !           494:        /* we don't need to perform DAD on loopback interfaces. */
        !           495:        ifra.ifra_flags |= IN6_IFF_NODAD;
        !           496:
        !           497:        /*
        !           498:         * We are sure that this is a newly assigned address, so we can set
        !           499:         * NULL to the 3rd arg.
        !           500:         */
        !           501:        if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
        !           502:                log(LOG_ERR, "in6_ifattach_loopback: failed to configure "
        !           503:                    "the loopback address on %s (errno=%d)\n",
        !           504:                    if_name(ifp), error);
        !           505:                return(-1);
        !           506:        }
1.25      itojun    507:
1.48    ! itojun    508:        return 0;
        !           509: }
        !           510:
        !           511: /*
        !           512:  * compute NI group address, based on the current hostname setting.
        !           513:  * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
        !           514:  *
        !           515:  * when ifp == NULL, the caller is responsible for filling scopeid.
        !           516:  */
        !           517: int
        !           518: in6_nigroup(ifp, name, namelen, sa6)
        !           519:        struct ifnet *ifp;
        !           520:        const char *name;
        !           521:        int namelen;
        !           522:        struct sockaddr_in6 *sa6;
        !           523: {
        !           524:        const char *p;
        !           525:        u_char *q;
        !           526:        MD5_CTX ctxt;
        !           527:        u_int8_t digest[16];
        !           528:        char l;
        !           529:        char n[64];     /* a single label must not exceed 63 chars */
1.25      itojun    530:
1.48    ! itojun    531:        if (!namelen || !name)
1.25      itojun    532:                return -1;
1.48    ! itojun    533:
        !           534:        p = name;
        !           535:        while (p && *p && *p != '.' && p - name < namelen)
        !           536:                p++;
        !           537:        if (p - name > sizeof(n) - 1)
        !           538:                return -1;      /* label too long */
        !           539:        l = p - name;
        !           540:        strncpy(n, name, l);
        !           541:        n[(int)l] = '\0';
        !           542:        for (q = n; *q; q++) {
        !           543:                if ('A' <= *q && *q <= 'Z')
        !           544:                        *q = *q - 'A' + 'a';
1.2       itojun    545:        }
1.25      itojun    546:
1.48    ! itojun    547:        /* generate 8 bytes of pseudo-random value. */
        !           548:        bzero(&ctxt, sizeof(ctxt));
        !           549:        MD5Init(&ctxt);
        !           550:        MD5Update(&ctxt, &l, sizeof(l));
        !           551:        MD5Update(&ctxt, n, l);
        !           552:        MD5Final(digest, &ctxt);
        !           553:
        !           554:        bzero(sa6, sizeof(*sa6));
        !           555:        sa6->sin6_family = AF_INET6;
        !           556:        sa6->sin6_len = sizeof(*sa6);
        !           557:        sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
        !           558:        sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !           559:        sa6->sin6_addr.s6_addr8[11] = 2;
        !           560:        bcopy(digest, &sa6->sin6_addr.s6_addr32[3],
        !           561:            sizeof(sa6->sin6_addr.s6_addr32[3]));
        !           562:
1.25      itojun    563:        return 0;
1.2       itojun    564: }
                    565:
1.17      itojun    566: /*
                    567:  * XXX multiple loopback interface needs more care.  for instance,
                    568:  * nodelocal address needs to be configured onto only one of them.
1.25      itojun    569:  * XXX multiple link-local address case
1.17      itojun    570:  */
1.2       itojun    571: void
1.25      itojun    572: in6_ifattach(ifp, altifp)
1.2       itojun    573:        struct ifnet *ifp;
1.25      itojun    574:        struct ifnet *altifp;   /* secondary EUI64 source */
1.2       itojun    575: {
1.25      itojun    576:        struct in6_ifaddr *ia;
                    577:        struct in6_addr in6;
1.13      itojun    578:
1.38      itojun    579:        /* some of the interfaces are inherently not IPv6 capable */
                    580:        switch (ifp->if_type) {
1.42      itojun    581:        case IFT_BRIDGE:
                    582:                return;
1.38      itojun    583:        }
                    584:
1.46      itojun    585:        /*
                    586:         * if link mtu is too small, don't try to configure IPv6.
                    587:         * remember there could be some link-layer that has special
                    588:         * fragmentation logic.
                    589:         */
                    590:        if (ifp->if_mtu < IPV6_MMTU)
                    591:                return;
                    592:
1.37      itojun    593:        /* create a multicast kludge storage (if we have not had one) */
                    594:        in6_createmkludge(ifp);
1.2       itojun    595:
                    596:        /*
1.25      itojun    597:         * quirks based on interface type
1.2       itojun    598:         */
1.25      itojun    599:        switch (ifp->if_type) {
                    600: #ifdef IFT_STF
                    601:        case IFT_STF:
                    602:                /*
1.38      itojun    603:                 * 6to4 interface is a very special kind of beast.
                    604:                 * no multicast, no linklocal.  RFC2529 specifies how to make
                    605:                 * linklocals for 6to4 interface, but there's no use and
                    606:                 * it is rather harmful to have one.
1.25      itojun    607:                 */
1.46      itojun    608:                return;
1.25      itojun    609: #endif
                    610:        default:
                    611:                break;
1.7       itojun    612:        }
1.2       itojun    613:
                    614:        /*
1.25      itojun    615:         * usually, we require multicast capability to the interface
1.2       itojun    616:         */
1.25      itojun    617:        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
1.38      itojun    618:                log(LOG_INFO, "in6_ifattach: "
                    619:                    "%s is not multicast capable, IPv6 not enabled\n",
1.25      itojun    620:                    if_name(ifp));
                    621:                return;
                    622:        }
1.15      thorpej   623:
1.2       itojun    624:        /*
1.48    ! itojun    625:         * assign loopback address for loopback interface.
        !           626:         * XXX multiple loopback interface case.
1.2       itojun    627:         */
1.48    ! itojun    628:        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
        !           629:                in6 = in6addr_loopback;
1.25      itojun    630:                if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
                    631:                        if (in6_ifattach_loopback(ifp) != 0)
                    632:                                return;
                    633:                }
                    634:        }
1.2       itojun    635:
                    636:        /*
1.48    ! itojun    637:         * assign a link-local address, if there's none.
1.2       itojun    638:         */
1.48    ! itojun    639:        if (ip6_auto_linklocal) {
        !           640:                ia = in6ifa_ifpforlinklocal(ifp, 0);
        !           641:                if (ia == NULL) {
        !           642:                        if (in6_ifattach_linklocal(ifp, altifp) == 0) {
        !           643:                                /* linklocal address assigned */
        !           644:                        } else {
        !           645:                                /* failed to assign linklocal address. bark? */
1.25      itojun    646:                        }
1.2       itojun    647:                }
                    648:        }
                    649: }
                    650:
1.17      itojun    651: /*
                    652:  * NOTE: in6_ifdetach() does not support loopback if at this moment.
1.41      itojun    653:  * We don't need this function in bsdi, because interfaces are never removed
                    654:  * from the ifnet list in bsdi.
1.17      itojun    655:  */
1.2       itojun    656: void
                    657: in6_ifdetach(ifp)
                    658:        struct ifnet *ifp;
                    659: {
                    660:        struct in6_ifaddr *ia, *oia;
1.30      itojun    661:        struct ifaddr *ifa, *next;
1.2       itojun    662:        struct rtentry *rt;
                    663:        short rtflags;
1.16      itojun    664:        struct sockaddr_in6 sin6;
1.48    ! itojun    665:        struct in6_multi_mship *imm;
1.18      itojun    666:
                    667:        /* remove neighbor management table */
                    668:        nd6_purge(ifp);
                    669:
1.30      itojun    670:        /* nuke any of IPv6 addresses we have */
                    671:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
                    672:        {
                    673:                next = ifa->ifa_list.tqe_next;
                    674:                if (ifa->ifa_addr->sa_family != AF_INET6)
                    675:                        continue;
1.48    ! itojun    676:                in6_purgeaddr(ifa);
1.30      itojun    677:        }
                    678:
                    679:        /* undo everything done by in6_ifattach(), just in case */
                    680:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
1.13      itojun    681:        {
1.30      itojun    682:                next = ifa->ifa_list.tqe_next;
                    683:
                    684:
1.2       itojun    685:                if (ifa->ifa_addr->sa_family != AF_INET6
                    686:                 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
                    687:                        continue;
                    688:                }
                    689:
                    690:                ia = (struct in6_ifaddr *)ifa;
                    691:
1.48    ! itojun    692:                /*
        !           693:                 * leave from multicast groups we have joined for the interface
        !           694:                 */
        !           695:                while ((imm = ia->ia6_memberships.lh_first) != NULL) {
        !           696:                        LIST_REMOVE(imm, i6mm_chain);
        !           697:                        in6_leavegroup(imm);
        !           698:                }
        !           699:
1.2       itojun    700:                /* remove from the routing table */
1.48    ! itojun    701:                if ((ia->ia_flags & IFA_ROUTE) &&
        !           702:                    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
1.2       itojun    703:                        rtflags = rt->rt_flags;
                    704:                        rtfree(rt);
1.47      itojun    705:                        rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
                    706:                            (struct sockaddr *)&ia->ia_addr,
                    707:                            (struct sockaddr *)&ia->ia_prefixmask,
                    708:                            rtflags, (struct rtentry **)0);
1.2       itojun    709:                }
                    710:
                    711:                /* remove from the linked list */
                    712:                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1.30      itojun    713:                IFAFREE(&ia->ia_ifa);
1.2       itojun    714:
                    715:                /* also remove from the IPv6 address chain(itojun&jinmei) */
                    716:                oia = ia;
                    717:                if (oia == (ia = in6_ifaddr))
                    718:                        in6_ifaddr = ia->ia_next;
                    719:                else {
                    720:                        while (ia->ia_next && (ia->ia_next != oia))
                    721:                                ia = ia->ia_next;
                    722:                        if (ia->ia_next)
                    723:                                ia->ia_next = oia->ia_next;
1.34      itojun    724:                        else {
1.48    ! itojun    725:                                nd6log((LOG_ERR,
1.47      itojun    726:                                    "%s: didn't unlink in6ifaddr from list\n",
                    727:                                    if_name(ifp)));
1.34      itojun    728:                        }
1.2       itojun    729:                }
                    730:
1.30      itojun    731:                IFAFREE(&oia->ia_ifa);
1.16      itojun    732:        }
                    733:
1.17      itojun    734:        /* cleanup multicast address kludge table, if there is any */
                    735:        in6_purgemkludge(ifp);
1.30      itojun    736:
1.41      itojun    737:        /*
                    738:         * remove neighbor management table.  we call it twice just to make
                    739:         * sure we nuke everything.  maybe we need just one call.
                    740:         * XXX: since the first call did not release addresses, some prefixes
                    741:         * might remain.  We should call nd6_purge() again to release the
                    742:         * prefixes after removing all addresses above.
                    743:         * (Or can we just delay calling nd6_purge until at this point?)
                    744:         */
1.30      itojun    745:        nd6_purge(ifp);
1.18      itojun    746:
1.16      itojun    747:        /* remove route to link-local allnodes multicast (ff02::1) */
                    748:        bzero(&sin6, sizeof(sin6));
                    749:        sin6.sin6_len = sizeof(struct sockaddr_in6);
                    750:        sin6.sin6_family = AF_INET6;
                    751:        sin6.sin6_addr = in6addr_linklocal_allnodes;
                    752:        sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1.33      itojun    753:        rt = rtalloc1((struct sockaddr *)&sin6, 0);
                    754:        if (rt && rt->rt_ifp == ifp) {
1.16      itojun    755:                rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
1.48    ! itojun    756:                    rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1.16      itojun    757:                rtfree(rt);
1.2       itojun    758:        }
                    759: }

CVSweb <webmaster@jp.NetBSD.org>