[BACK]Return to in6_ifattach.c CVS log [TXT][DIR] Up to [local] / sys / netinet6

Annotation of sys/netinet6/in6_ifattach.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: in6_ifattach.c,v 1.45 2007/06/08 09:31:38 henning Exp $       */
        !             2: /*     $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
        !             6:  * All rights reserved.
        !             7:  *
        !             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.
        !            19:  *
        !            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>
        !            38: #include <sys/kernel.h>
        !            39: #include <sys/syslog.h>
        !            40:
        !            41: #include <crypto/md5.h>
        !            42:
        !            43: #include <net/if.h>
        !            44: #include <net/if_dl.h>
        !            45: #include <net/if_types.h>
        !            46: #include <net/route.h>
        !            47:
        !            48: #include <netinet/in.h>
        !            49: #include <netinet/in_var.h>
        !            50: #include <netinet/if_ether.h>
        !            51:
        !            52: #include <netinet/ip6.h>
        !            53: #include <netinet6/ip6_var.h>
        !            54: #include <netinet6/in6_ifattach.h>
        !            55: #include <netinet6/ip6_var.h>
        !            56: #include <netinet6/nd6.h>
        !            57: #ifdef MROUTING
        !            58: #include <netinet6/ip6_mroute.h>
        !            59: #endif
        !            60:
        !            61: unsigned long in6_maxmtu = 0;
        !            62:
        !            63: int ip6_auto_linklocal = 1;    /* enable by default */
        !            64:
        !            65: static int get_rand_ifid(struct ifnet *, struct in6_addr *);
        !            66: static int get_hw_ifid(struct ifnet *, struct in6_addr *);
        !            67: static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
        !            68: static int in6_ifattach_loopback(struct ifnet *);
        !            69:
        !            70: #define EUI64_GBIT     0x01
        !            71: #define EUI64_UBIT     0x02
        !            72: #define EUI64_TO_IFID(in6)     do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
        !            73: #define EUI64_GROUP(in6)       ((in6)->s6_addr[8] & EUI64_GBIT)
        !            74: #define EUI64_INDIVIDUAL(in6)  (!EUI64_GROUP(in6))
        !            75: #define EUI64_LOCAL(in6)       ((in6)->s6_addr[8] & EUI64_UBIT)
        !            76: #define EUI64_UNIVERSAL(in6)   (!EUI64_LOCAL(in6))
        !            77:
        !            78: #define IFID_LOCAL(in6)                (!EUI64_LOCAL(in6))
        !            79: #define IFID_UNIVERSAL(in6)    (!EUI64_UNIVERSAL(in6))
        !            80:
        !            81: /*
        !            82:  * Generate a last-resort interface identifier, when the machine has no
        !            83:  * IEEE802/EUI64 address sources.
        !            84:  * The goal here is to get an interface identifier that is
        !            85:  * (1) random enough and (2) does not change across reboot.
        !            86:  * We currently use MD5(hostname) for it.
        !            87:  */
        !            88: static int
        !            89: get_rand_ifid(ifp, in6)
        !            90:        struct ifnet *ifp;
        !            91:        struct in6_addr *in6;   /* upper 64bits are preserved */
        !            92: {
        !            93:        MD5_CTX ctxt;
        !            94:        u_int8_t digest[16];
        !            95:
        !            96: #if 0
        !            97:        /* we need at least several letters as seed for ifid */
        !            98:        if (hostnamelen < 3)
        !            99:                return -1;
        !           100: #endif
        !           101:
        !           102:        /* generate 8 bytes of pseudo-random value. */
        !           103:        bzero(&ctxt, sizeof(ctxt));
        !           104:        MD5Init(&ctxt);
        !           105:        MD5Update(&ctxt, hostname, hostnamelen);
        !           106:        MD5Final(digest, &ctxt);
        !           107:
        !           108:        /* assumes sizeof(digest) > sizeof(ifid) */
        !           109:        bcopy(digest, &in6->s6_addr[8], 8);
        !           110:
        !           111:        /* make sure to set "u" bit to local, and "g" bit to individual. */
        !           112:        in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
        !           113:        in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
        !           114:
        !           115:        /* convert EUI64 into IPv6 interface identifier */
        !           116:        EUI64_TO_IFID(in6);
        !           117:
        !           118:        return 0;
        !           119: }
        !           120:
        !           121: /*
        !           122:  * Get interface identifier for the specified interface.
        !           123:  * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
        !           124:  */
        !           125: static int
        !           126: get_hw_ifid(ifp, in6)
        !           127:        struct ifnet *ifp;
        !           128:        struct in6_addr *in6;   /* upper 64bits are preserved */
        !           129: {
        !           130:        struct ifaddr *ifa;
        !           131:        struct sockaddr_dl *sdl;
        !           132:        char *addr;
        !           133:        size_t addrlen;
        !           134:        static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
        !           135:        static u_int8_t allone[8] =
        !           136:                { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        !           137:
        !           138:        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !           139:                if (ifa->ifa_addr->sa_family != AF_LINK)
        !           140:                        continue;
        !           141:                sdl = (struct sockaddr_dl *)ifa->ifa_addr;
        !           142:                if (sdl == NULL)
        !           143:                        continue;
        !           144:                if (sdl->sdl_alen == 0)
        !           145:                        continue;
        !           146:
        !           147:                goto found;
        !           148:        }
        !           149:
        !           150:        return -1;
        !           151:
        !           152: found:
        !           153:        addr = LLADDR(sdl);
        !           154:        addrlen = sdl->sdl_alen;
        !           155:
        !           156:        switch (ifp->if_type) {
        !           157:        case IFT_IEEE1394:
        !           158:        case IFT_IEEE80211:
        !           159:                /* IEEE1394 uses 16byte length address starting with EUI64 */
        !           160:                if (addrlen > 8)
        !           161:                        addrlen = 8;
        !           162:                break;
        !           163:        default:
        !           164:                break;
        !           165:        }
        !           166:
        !           167:        /* get EUI64 */
        !           168:        switch (ifp->if_type) {
        !           169:        /* IEEE802/EUI64 cases - what others? */
        !           170:        case IFT_ETHER:
        !           171:        case IFT_CARP:
        !           172:        case IFT_FDDI:
        !           173:        case IFT_ATM:
        !           174:        case IFT_IEEE1394:
        !           175:        case IFT_IEEE80211:
        !           176:                /* look at IEEE802/EUI64 only */
        !           177:                if (addrlen != 8 && addrlen != 6)
        !           178:                        return -1;
        !           179:
        !           180:                /*
        !           181:                 * check for invalid MAC address - on bsdi, we see it a lot
        !           182:                 * since wildboar configures all-zero MAC on pccard before
        !           183:                 * card insertion.
        !           184:                 */
        !           185:                if (bcmp(addr, allzero, addrlen) == 0)
        !           186:                        return -1;
        !           187:                if (bcmp(addr, allone, addrlen) == 0)
        !           188:                        return -1;
        !           189:
        !           190:                /* make EUI64 address */
        !           191:                if (addrlen == 8)
        !           192:                        bcopy(addr, &in6->s6_addr[8], 8);
        !           193:                else if (addrlen == 6) {
        !           194:                        in6->s6_addr[8] = addr[0];
        !           195:                        in6->s6_addr[9] = addr[1];
        !           196:                        in6->s6_addr[10] = addr[2];
        !           197:                        in6->s6_addr[11] = 0xff;
        !           198:                        in6->s6_addr[12] = 0xfe;
        !           199:                        in6->s6_addr[13] = addr[3];
        !           200:                        in6->s6_addr[14] = addr[4];
        !           201:                        in6->s6_addr[15] = addr[5];
        !           202:                }
        !           203:                break;
        !           204:
        !           205:        case IFT_GIF:
        !           206:                /*
        !           207:                 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
        !           208:                 * however, IPv4 address is not very suitable as unique
        !           209:                 * identifier source (can be renumbered).
        !           210:                 * we don't do this.
        !           211:                 */
        !           212:                return -1;
        !           213:
        !           214:        default:
        !           215:                return -1;
        !           216:        }
        !           217:
        !           218:        /* sanity check: g bit must not indicate "group" */
        !           219:        if (EUI64_GROUP(in6))
        !           220:                return -1;
        !           221:
        !           222:        /* convert EUI64 into IPv6 interface identifier */
        !           223:        EUI64_TO_IFID(in6);
        !           224:
        !           225:        /*
        !           226:         * sanity check: ifid must not be all zero, avoid conflict with
        !           227:         * subnet router anycast
        !           228:         */
        !           229:        if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
        !           230:            bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
        !           231:                return -1;
        !           232:        }
        !           233:
        !           234:        return 0;
        !           235: }
        !           236:
        !           237: /*
        !           238:  * Get interface identifier for the specified interface.  If it is not
        !           239:  * available on ifp0, borrow interface identifier from other information
        !           240:  * sources.
        !           241:  */
        !           242: static int
        !           243: get_ifid(ifp0, altifp, in6)
        !           244:        struct ifnet *ifp0;
        !           245:        struct ifnet *altifp;   /* secondary EUI64 source */
        !           246:        struct in6_addr *in6;
        !           247: {
        !           248:        struct ifnet *ifp;
        !           249:
        !           250:        /* first, try to get it from the interface itself */
        !           251:        if (get_hw_ifid(ifp0, in6) == 0) {
        !           252:                nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
        !           253:                    ifp0->if_xname));
        !           254:                goto success;
        !           255:        }
        !           256:
        !           257:        /* try secondary EUI64 source. this basically is for ATM PVC */
        !           258:        if (altifp && get_hw_ifid(altifp, in6) == 0) {
        !           259:                nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
        !           260:                    ifp0->if_xname, altifp->if_xname));
        !           261:                goto success;
        !           262:        }
        !           263:
        !           264:        /* next, try to get it from some other hardware interface */
        !           265:        TAILQ_FOREACH(ifp, &ifnet, if_list) {
        !           266:                if (ifp == ifp0)
        !           267:                        continue;
        !           268:                if (get_hw_ifid(ifp, in6) != 0)
        !           269:                        continue;
        !           270:
        !           271:                /*
        !           272:                 * to borrow ifid from other interface, ifid needs to be
        !           273:                 * globally unique
        !           274:                 */
        !           275:                if (IFID_UNIVERSAL(in6)) {
        !           276:                        nd6log((LOG_DEBUG,
        !           277:                            "%s: borrow interface identifier from %s\n",
        !           278:                            ifp0->if_xname, ifp->if_xname));
        !           279:                        goto success;
        !           280:                }
        !           281:        }
        !           282:
        !           283:        /* last resort: get from random number source */
        !           284:        if (get_rand_ifid(ifp, in6) == 0) {
        !           285:                nd6log((LOG_DEBUG,
        !           286:                    "%s: interface identifier generated by random number\n",
        !           287:                    ifp0->if_xname));
        !           288:                goto success;
        !           289:        }
        !           290:
        !           291:        printf("%s: failed to get interface identifier\n", ifp0->if_xname);
        !           292:        return -1;
        !           293:
        !           294: success:
        !           295:        nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
        !           296:            ifp0->if_xname, in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
        !           297:            in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
        !           298:            in6->s6_addr[14], in6->s6_addr[15]));
        !           299:        return 0;
        !           300: }
        !           301:
        !           302: int
        !           303: in6_ifattach_linklocal(ifp, altifp)
        !           304:        struct ifnet *ifp;
        !           305:        struct ifnet *altifp;   /*secondary EUI64 source*/
        !           306: {
        !           307:        struct in6_ifaddr *ia;
        !           308:        struct in6_aliasreq ifra;
        !           309:        struct nd_prefix pr0;
        !           310:        int i, error;
        !           311:
        !           312:        /*
        !           313:         * configure link-local address.
        !           314:         */
        !           315:        bzero(&ifra, sizeof(ifra));
        !           316:
        !           317:        /*
        !           318:         * in6_update_ifa() does not use ifra_name, but we accurately set it
        !           319:         * for safety.
        !           320:         */
        !           321:        strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
        !           322:
        !           323:        ifra.ifra_addr.sin6_family = AF_INET6;
        !           324:        ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
        !           325:        ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
        !           326:        ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !           327:        ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
        !           328:        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
        !           329:                ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
        !           330:                ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
        !           331:        } else {
        !           332:                if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
        !           333:                        nd6log((LOG_ERR,
        !           334:                            "%s: no ifid available\n", ifp->if_xname));
        !           335:                        return (-1);
        !           336:                }
        !           337:        }
        !           338:
        !           339:        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
        !           340:        ifra.ifra_prefixmask.sin6_family = AF_INET6;
        !           341:        ifra.ifra_prefixmask.sin6_addr = in6mask64;
        !           342:        /* link-local addresses should NEVER expire. */
        !           343:        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
        !           344:        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
        !           345:
        !           346:        /*
        !           347:         * Do not let in6_update_ifa() do DAD, since we need a random delay
        !           348:         * before sending an NS at the first time the interface becomes up.
        !           349:         * Instead, in6_if_up() will start DAD with a proper random delay.
        !           350:         */
        !           351:        ifra.ifra_flags |= IN6_IFF_NODAD;
        !           352:
        !           353:        /*
        !           354:         * Now call in6_update_ifa() to do a bunch of procedures to configure
        !           355:         * a link-local address. In the case of CARP, we may be called after
        !           356:         * one has already been configured, so check if it's already there
        !           357:         * with in6ifa_ifpforlinklocal() and clobber it if it exists.
        !           358:         */
        !           359:        if ((error = in6_update_ifa(ifp, &ifra,
        !           360:             in6ifa_ifpforlinklocal(ifp, 0))) != 0) {
        !           361:                /*
        !           362:                 * XXX: When the interface does not support IPv6, this call
        !           363:                 * would fail in the SIOCSIFADDR ioctl.  I believe the
        !           364:                 * notification is rather confusing in this case, so just
        !           365:                 * suppress it.  (jinmei@kame.net 20010130)
        !           366:                 */
        !           367:                if (error != EAFNOSUPPORT)
        !           368:                        nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
        !           369:                            "configure a link-local address on %s "
        !           370:                            "(errno=%d)\n",
        !           371:                            ifp->if_xname, error));
        !           372:                return (-1);
        !           373:        }
        !           374:
        !           375:        /*
        !           376:         * Adjust ia6_flags so that in6_if_up will perform DAD.
        !           377:         * XXX: Some P2P interfaces seem not to send packets just after
        !           378:         * becoming up, so we skip p2p interfaces for safety.
        !           379:         */
        !           380:        ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
        !           381: #ifdef DIAGNOSTIC
        !           382:        if (!ia) {
        !           383:                panic("ia == NULL in in6_ifattach_linklocal");
        !           384:                /* NOTREACHED */
        !           385:        }
        !           386: #endif
        !           387:        if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) ||
        !           388:            (ifp->if_type == IFT_CARP)) == 0) {
        !           389:                ia->ia6_flags &= ~IN6_IFF_NODAD;
        !           390:                ia->ia6_flags |= IN6_IFF_TENTATIVE;
        !           391:        }
        !           392:
        !           393:        /*
        !           394:         * Make the link-local prefix (fe80::/64%link) as on-link.
        !           395:         * Since we'd like to manage prefixes separately from addresses,
        !           396:         * we make an ND6 prefix structure for the link-local prefix,
        !           397:         * and add it to the prefix list as a never-expire prefix.
        !           398:         * XXX: this change might affect some existing code base...
        !           399:         */
        !           400:        bzero(&pr0, sizeof(pr0));
        !           401:        pr0.ndpr_ifp = ifp;
        !           402:        /* this should be 64 at this moment. */
        !           403:        pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
        !           404:        pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
        !           405:        pr0.ndpr_prefix = ifra.ifra_addr;
        !           406:        /* apply the mask for safety. (nd6_prelist_add will apply it again) */
        !           407:        for (i = 0; i < 4; i++) {
        !           408:                pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
        !           409:                    in6mask64.s6_addr32[i];
        !           410:        }
        !           411:        /*
        !           412:         * Initialize parameters.  The link-local prefix must always be
        !           413:         * on-link, and its lifetimes never expire.
        !           414:         */
        !           415:        pr0.ndpr_raf_onlink = 1;
        !           416:        pr0.ndpr_raf_auto = 1;  /* probably meaningless */
        !           417:        pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
        !           418:        pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
        !           419:        /*
        !           420:         * Since there is no other link-local addresses, nd6_prefix_lookup()
        !           421:         * probably returns NULL.  However, we cannot always expect the result.
        !           422:         * For example, if we first remove the (only) existing link-local
        !           423:         * address, and then reconfigure another one, the prefix is still
        !           424:         * valid with referring to the old link-local address.
        !           425:         */
        !           426:        if (nd6_prefix_lookup(&pr0) == NULL) {
        !           427:                if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
        !           428:                        return (error);
        !           429:        }
        !           430:
        !           431:        return 0;
        !           432: }
        !           433:
        !           434: static int
        !           435: in6_ifattach_loopback(ifp)
        !           436:        struct ifnet *ifp;      /* must be IFT_LOOP */
        !           437: {
        !           438:        struct in6_aliasreq ifra;
        !           439:        int error;
        !           440:
        !           441:        bzero(&ifra, sizeof(ifra));
        !           442:
        !           443:        /*
        !           444:         * in6_update_ifa() does not use ifra_name, but we accurately set it
        !           445:         * for safety.
        !           446:         */
        !           447:        strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
        !           448:
        !           449:        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
        !           450:        ifra.ifra_prefixmask.sin6_family = AF_INET6;
        !           451:        ifra.ifra_prefixmask.sin6_addr = in6mask128;
        !           452:
        !           453:        /*
        !           454:         * Always initialize ia_dstaddr (= broadcast address) to loopback
        !           455:         * address.  Follows IPv4 practice - see in_ifinit().
        !           456:         */
        !           457:        ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
        !           458:        ifra.ifra_dstaddr.sin6_family = AF_INET6;
        !           459:        ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
        !           460:
        !           461:        ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
        !           462:        ifra.ifra_addr.sin6_family = AF_INET6;
        !           463:        ifra.ifra_addr.sin6_addr = in6addr_loopback;
        !           464:
        !           465:        /* the loopback  address should NEVER expire. */
        !           466:        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
        !           467:        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
        !           468:
        !           469:        /* we don't need to perform DAD on loopback interfaces. */
        !           470:        ifra.ifra_flags |= IN6_IFF_NODAD;
        !           471:
        !           472:        /*
        !           473:         * We are sure that this is a newly assigned address, so we can set
        !           474:         * NULL to the 3rd arg.
        !           475:         */
        !           476:        if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
        !           477:                nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure "
        !           478:                    "the loopback address on %s (errno=%d)\n",
        !           479:                    ifp->if_xname, error));
        !           480:                return (-1);
        !           481:        }
        !           482:
        !           483:        return 0;
        !           484: }
        !           485:
        !           486: /*
        !           487:  * compute NI group address, based on the current hostname setting.
        !           488:  * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
        !           489:  *
        !           490:  * when ifp == NULL, the caller is responsible for filling scopeid.
        !           491:  */
        !           492: int
        !           493: in6_nigroup(ifp, name, namelen, sa6)
        !           494:        struct ifnet *ifp;
        !           495:        const char *name;
        !           496:        int namelen;
        !           497:        struct sockaddr_in6 *sa6;
        !           498: {
        !           499:        const char *p;
        !           500:        u_int8_t *q;
        !           501:        MD5_CTX ctxt;
        !           502:        u_int8_t digest[16];
        !           503:        u_int8_t l;
        !           504:        u_int8_t n[64]; /* a single label must not exceed 63 chars */
        !           505:
        !           506:        if (!namelen || !name)
        !           507:                return -1;
        !           508:
        !           509:        p = name;
        !           510:        while (p && *p && *p != '.' && p - name < namelen)
        !           511:                p++;
        !           512:        if (p - name > sizeof(n) - 1)
        !           513:                return -1;      /* label too long */
        !           514:        l = p - name;
        !           515:        strncpy((char *)n, name, l);
        !           516:        n[(int)l] = '\0';
        !           517:        for (q = n; *q; q++) {
        !           518:                if ('A' <= *q && *q <= 'Z')
        !           519:                        *q = *q - 'A' + 'a';
        !           520:        }
        !           521:
        !           522:        /* generate 8 bytes of pseudo-random value. */
        !           523:        bzero(&ctxt, sizeof(ctxt));
        !           524:        MD5Init(&ctxt);
        !           525:        MD5Update(&ctxt, &l, sizeof(l));
        !           526:        MD5Update(&ctxt, n, l);
        !           527:        MD5Final(digest, &ctxt);
        !           528:
        !           529:        bzero(sa6, sizeof(*sa6));
        !           530:        sa6->sin6_family = AF_INET6;
        !           531:        sa6->sin6_len = sizeof(*sa6);
        !           532:        sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
        !           533:        sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !           534:        sa6->sin6_addr.s6_addr8[11] = 2;
        !           535:        bcopy(digest, &sa6->sin6_addr.s6_addr32[3],
        !           536:            sizeof(sa6->sin6_addr.s6_addr32[3]));
        !           537:
        !           538:        return 0;
        !           539: }
        !           540:
        !           541: /*
        !           542:  * XXX multiple loopback interface needs more care.  for instance,
        !           543:  * nodelocal address needs to be configured onto only one of them.
        !           544:  * XXX multiple link-local address case
        !           545:  */
        !           546: void
        !           547: in6_ifattach(ifp, altifp)
        !           548:        struct ifnet *ifp;
        !           549:        struct ifnet *altifp;   /* secondary EUI64 source */
        !           550: {
        !           551:        struct in6_ifaddr *ia;
        !           552:        struct in6_addr in6;
        !           553:
        !           554:        /* some of the interfaces are inherently not IPv6 capable */
        !           555:        switch (ifp->if_type) {
        !           556:        case IFT_BRIDGE:
        !           557:        case IFT_ENC:
        !           558:        case IFT_PFLOG:
        !           559:        case IFT_PFSYNC:
        !           560:                return;
        !           561:        }
        !           562:
        !           563:        /*
        !           564:         * if link mtu is too small, don't try to configure IPv6.
        !           565:         * remember there could be some link-layer that has special
        !           566:         * fragmentation logic.
        !           567:         */
        !           568:        if (ifp->if_mtu < IPV6_MMTU) {
        !           569:                nd6log((LOG_INFO, "in6_ifattach: "
        !           570:                    "%s has too small MTU, IPv6 not enabled\n",
        !           571:                    ifp->if_xname));
        !           572:                return;
        !           573:        }
        !           574:
        !           575:        /* create a multicast kludge storage (if we have not had one) */
        !           576:        in6_createmkludge(ifp);
        !           577:
        !           578:        /*
        !           579:         * quirks based on interface type
        !           580:         */
        !           581:        switch (ifp->if_type) {
        !           582:        /* we attach a link-local address when a vhid is assigned */
        !           583:        case IFT_CARP:
        !           584:                return;
        !           585:        default:
        !           586:                break;
        !           587:        }
        !           588:
        !           589:        /*
        !           590:         * usually, we require multicast capability to the interface
        !           591:         */
        !           592:        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
        !           593:                nd6log((LOG_INFO, "in6_ifattach: "
        !           594:                    "%s is not multicast capable, IPv6 not enabled\n",
        !           595:                    ifp->if_xname));
        !           596:                return;
        !           597:        }
        !           598:
        !           599:        /*
        !           600:         * assign loopback address for loopback interface.
        !           601:         * XXX multiple loopback interface case.
        !           602:         */
        !           603:        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
        !           604:                in6 = in6addr_loopback;
        !           605:                if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
        !           606:                        if (in6_ifattach_loopback(ifp) != 0)
        !           607:                                return;
        !           608:                }
        !           609:        }
        !           610:
        !           611:        /*
        !           612:         * assign a link-local address, if there's none.
        !           613:         */
        !           614:        if (ip6_auto_linklocal) {
        !           615:                ia = in6ifa_ifpforlinklocal(ifp, 0);
        !           616:                if (ia == NULL) {
        !           617:                        if (in6_ifattach_linklocal(ifp, altifp) == 0) {
        !           618:                                /* linklocal address assigned */
        !           619:                        } else {
        !           620:                                /* failed to assign linklocal address. bark? */
        !           621:                        }
        !           622:                }
        !           623:        }
        !           624: }
        !           625:
        !           626: /*
        !           627:  * NOTE: in6_ifdetach() does not support loopback if at this moment.
        !           628:  */
        !           629: void
        !           630: in6_ifdetach(ifp)
        !           631:        struct ifnet *ifp;
        !           632: {
        !           633:        struct in6_ifaddr *ia, *oia;
        !           634:        struct ifaddr *ifa, *next;
        !           635:        struct rtentry *rt;
        !           636:        short rtflags;
        !           637:        struct sockaddr_in6 sin6;
        !           638:        struct in6_multi_mship *imm;
        !           639:
        !           640: #ifdef MROUTING
        !           641:        /* remove ip6_mrouter stuff */
        !           642:        ip6_mrouter_detach(ifp);
        !           643: #endif
        !           644:
        !           645:        /* remove neighbor management table */
        !           646:        nd6_purge(ifp);
        !           647:
        !           648:        /* nuke any of IPv6 addresses we have */
        !           649:        for (ifa = TAILQ_FIRST(&ifp->if_addrlist);
        !           650:            ifa != TAILQ_END(&ifp->if_addrlist); ifa = next) {
        !           651:                next = TAILQ_NEXT(ifa, ifa_list);
        !           652:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !           653:                        continue;
        !           654:                in6_purgeaddr(ifa);
        !           655:        }
        !           656:
        !           657:        /* undo everything done by in6_ifattach(), just in case */
        !           658:        for (ifa = TAILQ_FIRST(&ifp->if_addrlist);
        !           659:            ifa != TAILQ_END(&ifp->if_addrlist); ifa = next) {
        !           660:                next = TAILQ_NEXT(ifa, ifa_list);
        !           661:
        !           662:                if (ifa->ifa_addr->sa_family != AF_INET6
        !           663:                 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
        !           664:                        continue;
        !           665:                }
        !           666:
        !           667:                ia = (struct in6_ifaddr *)ifa;
        !           668:
        !           669:                /*
        !           670:                 * leave from multicast groups we have joined for the interface
        !           671:                 */
        !           672:                while (!LIST_EMPTY(&ia->ia6_memberships)) {
        !           673:                        imm = LIST_FIRST(&ia->ia6_memberships);
        !           674:                        LIST_REMOVE(imm, i6mm_chain);
        !           675:                        in6_leavegroup(imm);
        !           676:                }
        !           677:
        !           678:                /* remove from the routing table */
        !           679:                if ((ia->ia_flags & IFA_ROUTE) &&
        !           680:                    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0))) {
        !           681:                        rtflags = rt->rt_flags;
        !           682:                        rtfree(rt);
        !           683:                        rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
        !           684:                            (struct sockaddr *)&ia->ia_addr,
        !           685:                            (struct sockaddr *)&ia->ia_prefixmask,
        !           686:                            rtflags, (struct rtentry **)0, 0);
        !           687:                }
        !           688:
        !           689:                /* remove from the linked list */
        !           690:                TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
        !           691:                IFAFREE(&ia->ia_ifa);
        !           692:
        !           693:                /* also remove from the IPv6 address chain(itojun&jinmei) */
        !           694:                oia = ia;
        !           695:                if (oia == (ia = in6_ifaddr))
        !           696:                        in6_ifaddr = ia->ia_next;
        !           697:                else {
        !           698:                        while (ia->ia_next && (ia->ia_next != oia))
        !           699:                                ia = ia->ia_next;
        !           700:                        if (ia->ia_next)
        !           701:                                ia->ia_next = oia->ia_next;
        !           702:                        else {
        !           703:                                nd6log((LOG_ERR,
        !           704:                                    "%s: didn't unlink in6ifaddr from list\n",
        !           705:                                    ifp->if_xname));
        !           706:                        }
        !           707:                }
        !           708:
        !           709:                IFAFREE(&oia->ia_ifa);
        !           710:        }
        !           711:
        !           712:        /* cleanup multicast address kludge table, if there is any */
        !           713:        in6_purgemkludge(ifp);
        !           714:
        !           715:        /*
        !           716:         * remove neighbor management table.  we call it twice just to make
        !           717:         * sure we nuke everything.  maybe we need just one call.
        !           718:         * XXX: since the first call did not release addresses, some prefixes
        !           719:         * might remain.  We should call nd6_purge() again to release the
        !           720:         * prefixes after removing all addresses above.
        !           721:         * (Or can we just delay calling nd6_purge until at this point?)
        !           722:         */
        !           723:        nd6_purge(ifp);
        !           724:
        !           725:        /* remove route to link-local allnodes multicast (ff02::1) */
        !           726:        bzero(&sin6, sizeof(sin6));
        !           727:        sin6.sin6_len = sizeof(struct sockaddr_in6);
        !           728:        sin6.sin6_family = AF_INET6;
        !           729:        sin6.sin6_addr = in6addr_linklocal_allnodes;
        !           730:        sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !           731:        rt = rtalloc1((struct sockaddr *)&sin6, 0, 0);
        !           732:        if (rt && rt->rt_ifp == ifp) {
        !           733:                rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
        !           734:                    rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
        !           735:                rtfree(rt);
        !           736:        }
        !           737: }

CVSweb