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

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

1.1     ! nbrk        1: /*     $OpenBSD: in6.c,v 1.72 2006/11/17 01:11:23 itojun Exp $ */
        !             2: /*     $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun 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: /*
        !            34:  * Copyright (c) 1982, 1986, 1991, 1993
        !            35:  *     The Regents of the University of California.  All rights reserved.
        !            36:  *
        !            37:  * Redistribution and use in source and binary forms, with or without
        !            38:  * modification, are permitted provided that the following conditions
        !            39:  * are met:
        !            40:  * 1. Redistributions of source code must retain the above copyright
        !            41:  *    notice, this list of conditions and the following disclaimer.
        !            42:  * 2. Redistributions in binary form must reproduce the above copyright
        !            43:  *    notice, this list of conditions and the following disclaimer in the
        !            44:  *    documentation and/or other materials provided with the distribution.
        !            45:  * 3. Neither the name of the University nor the names of its contributors
        !            46:  *    may be used to endorse or promote products derived from this software
        !            47:  *    without specific prior written permission.
        !            48:  *
        !            49:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            50:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            51:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            52:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            53:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            54:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            55:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            56:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            57:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            58:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            59:  * SUCH DAMAGE.
        !            60:  *
        !            61:  *     @(#)in.c        8.2 (Berkeley) 11/15/93
        !            62:  */
        !            63:
        !            64: #include <sys/param.h>
        !            65: #include <sys/ioctl.h>
        !            66: #include <sys/errno.h>
        !            67: #include <sys/malloc.h>
        !            68: #include <sys/socket.h>
        !            69: #include <sys/socketvar.h>
        !            70: #include <sys/sockio.h>
        !            71: #include <sys/systm.h>
        !            72: #include <sys/proc.h>
        !            73: #include <sys/time.h>
        !            74: #include <sys/kernel.h>
        !            75: #include <sys/syslog.h>
        !            76:
        !            77: #include <net/if.h>
        !            78: #include <net/if_types.h>
        !            79: #include <net/route.h>
        !            80: #include <net/if_dl.h>
        !            81:
        !            82: #include <netinet/in.h>
        !            83: #include <netinet/in_var.h>
        !            84: #include <netinet/if_ether.h>
        !            85:
        !            86: #include <netinet/ip6.h>
        !            87: #include <netinet6/ip6_var.h>
        !            88: #include <netinet6/nd6.h>
        !            89: #include <netinet6/mld6_var.h>
        !            90: #ifdef MROUTING
        !            91: #include <netinet6/ip6_mroute.h>
        !            92: #endif
        !            93: #include <netinet6/in6_ifattach.h>
        !            94:
        !            95: /* backward compatibility for a while... */
        !            96: #define COMPAT_IN6IFIOCTL
        !            97:
        !            98: /*
        !            99:  * Definitions of some constant IP6 addresses.
        !           100:  */
        !           101: const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
        !           102: const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
        !           103: const struct in6_addr in6addr_intfacelocal_allnodes =
        !           104:        IN6ADDR_INTFACELOCAL_ALLNODES_INIT;
        !           105: const struct in6_addr in6addr_linklocal_allnodes =
        !           106:        IN6ADDR_LINKLOCAL_ALLNODES_INIT;
        !           107: const struct in6_addr in6addr_linklocal_allrouters =
        !           108:        IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
        !           109:
        !           110: const struct in6_addr in6mask0 = IN6MASK0;
        !           111: const struct in6_addr in6mask32 = IN6MASK32;
        !           112: const struct in6_addr in6mask64 = IN6MASK64;
        !           113: const struct in6_addr in6mask96 = IN6MASK96;
        !           114: const struct in6_addr in6mask128 = IN6MASK128;
        !           115:
        !           116: static int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t,
        !           117:        struct ifnet *, struct proc *);
        !           118: static int in6_ifinit(struct ifnet *, struct in6_ifaddr *,
        !           119:        struct sockaddr_in6 *, int);
        !           120: static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
        !           121:
        !           122: const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6,
        !           123:                                     0, 0, IN6ADDR_ANY_INIT, 0};
        !           124:
        !           125: /*
        !           126:  * This structure is used to keep track of in6_multi chains which belong to
        !           127:  * deleted interface addresses.
        !           128:  */
        !           129: static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */
        !           130:
        !           131: struct multi6_kludge {
        !           132:        LIST_ENTRY(multi6_kludge) mk_entry;
        !           133:        struct ifnet *mk_ifp;
        !           134:        struct in6_multihead mk_head;
        !           135: };
        !           136:
        !           137: /*
        !           138:  * Subroutine for in6_ifaddloop() and in6_ifremloop().
        !           139:  * This routine does actual work.
        !           140:  */
        !           141: static void
        !           142: in6_ifloop_request(int cmd, struct ifaddr *ifa)
        !           143: {
        !           144:        struct sockaddr_in6 lo_sa;
        !           145:        struct sockaddr_in6 all1_sa;
        !           146:        struct rtentry *nrt = NULL;
        !           147:        int e;
        !           148:
        !           149:        bzero(&lo_sa, sizeof(lo_sa));
        !           150:        bzero(&all1_sa, sizeof(all1_sa));
        !           151:        lo_sa.sin6_family = all1_sa.sin6_family = AF_INET6;
        !           152:        lo_sa.sin6_len = all1_sa.sin6_len = sizeof(struct sockaddr_in6);
        !           153:        lo_sa.sin6_addr = in6addr_loopback;
        !           154:        all1_sa.sin6_addr = in6mask128;
        !           155:
        !           156:        /*
        !           157:         * We specify the address itself as the gateway, and set the
        !           158:         * RTF_LLINFO flag, so that the corresponding host route would have
        !           159:         * the flag, and thus applications that assume traditional behavior
        !           160:         * would be happy.  Note that we assume the caller of the function
        !           161:         * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
        !           162:         * which changes the outgoing interface to the loopback interface.
        !           163:         * XXX only table 0 for now
        !           164:         */
        !           165:        e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr,
        !           166:            (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt, 0);
        !           167:        if (e != 0) {
        !           168:                log(LOG_ERR, "in6_ifloop_request: "
        !           169:                    "%s operation failed for %s (errno=%d)\n",
        !           170:                    cmd == RTM_ADD ? "ADD" : "DELETE",
        !           171:                    ip6_sprintf(&((struct in6_ifaddr *)ifa)->ia_addr.sin6_addr),
        !           172:                    e);
        !           173:        }
        !           174:
        !           175:        /*
        !           176:         * Make sure rt_ifa be equal to IFA, the second argument of the
        !           177:         * function.
        !           178:         * We need this because when we refer to rt_ifa->ia6_flags in
        !           179:         * ip6_input, we assume that the rt_ifa points to the address instead
        !           180:         * of the loopback address.
        !           181:         */
        !           182:        if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
        !           183:                IFAFREE(nrt->rt_ifa);
        !           184:                ifa->ifa_refcnt++;
        !           185:                nrt->rt_ifa = ifa;
        !           186:        }
        !           187:
        !           188:        /*
        !           189:         * Report the addition/removal of the address to the routing socket.
        !           190:         * XXX: since we called rtinit for a p2p interface with a destination,
        !           191:         *      we end up reporting twice in such a case.  Should we rather
        !           192:         *      omit the second report?
        !           193:         */
        !           194:        if (nrt) {
        !           195:                rt_newaddrmsg(cmd, ifa, e, nrt);
        !           196:                if (cmd == RTM_DELETE) {
        !           197:                        if (nrt->rt_refcnt <= 0) {
        !           198:                                /* XXX: we should free the entry ourselves. */
        !           199:                                nrt->rt_refcnt++;
        !           200:                                rtfree(nrt);
        !           201:                        }
        !           202:                } else {
        !           203:                        /* the cmd must be RTM_ADD here */
        !           204:                        nrt->rt_refcnt--;
        !           205:                }
        !           206:        }
        !           207: }
        !           208:
        !           209: /*
        !           210:  * Add ownaddr as loopback rtentry.  We previously add the route only if
        !           211:  * necessary (ex. on a p2p link).  However, since we now manage addresses
        !           212:  * separately from prefixes, we should always add the route.  We can't
        !           213:  * rely on the cloning mechanism from the corresponding interface route
        !           214:  * any more.
        !           215:  */
        !           216: void
        !           217: in6_ifaddloop(struct ifaddr *ifa)
        !           218: {
        !           219:        struct rtentry *rt;
        !           220:
        !           221:        /* If there is no loopback entry, allocate one. */
        !           222:        rt = rtalloc1(ifa->ifa_addr, 0, 0);
        !           223:        if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
        !           224:            (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
        !           225:                in6_ifloop_request(RTM_ADD, ifa);
        !           226:        if (rt)
        !           227:                rt->rt_refcnt--;
        !           228: }
        !           229:
        !           230: /*
        !           231:  * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
        !           232:  * if it exists.
        !           233:  */
        !           234: void
        !           235: in6_ifremloop(struct ifaddr *ifa)
        !           236: {
        !           237:        struct in6_ifaddr *ia;
        !           238:        struct rtentry *rt;
        !           239:        int ia_count = 0;
        !           240:
        !           241:        /*
        !           242:         * Some of BSD variants do not remove cloned routes
        !           243:         * from an interface direct route, when removing the direct route
        !           244:         * (see comments in net/net_osdep.h).  Even for variants that do remove
        !           245:         * cloned routes, they could fail to remove the cloned routes when
        !           246:         * we handle multple addresses that share a common prefix.
        !           247:         * So, we should remove the route corresponding to the deleted address.
        !           248:         */
        !           249:
        !           250:        /*
        !           251:         * Delete the entry only if exact one ifa exists.  More than one ifa
        !           252:         * can exist if we assign a same single address to multiple
        !           253:         * (probably p2p) interfaces.
        !           254:         * XXX: we should avoid such a configuration in IPv6...
        !           255:         */
        !           256:        for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
        !           257:                if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr)) {
        !           258:                        ia_count++;
        !           259:                        if (ia_count > 1)
        !           260:                                break;
        !           261:                }
        !           262:        }
        !           263:
        !           264:        if (ia_count == 1) {
        !           265:                /*
        !           266:                 * Before deleting, check if a corresponding loopbacked host
        !           267:                 * route surely exists.  With this check, we can avoid to
        !           268:                 * delete an interface direct route whose destination is same
        !           269:                 * as the address being removed.  This can happen when removing
        !           270:                 * a subnet-router anycast address on an interface attahced
        !           271:                 * to a shared medium.
        !           272:                 */
        !           273:                rt = rtalloc1(ifa->ifa_addr, 0, 0);
        !           274:                if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
        !           275:                    (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
        !           276:                        rt->rt_refcnt--;
        !           277:                        in6_ifloop_request(RTM_DELETE, ifa);
        !           278:                }
        !           279:        }
        !           280: }
        !           281:
        !           282: int
        !           283: in6_mask2len(mask, lim0)
        !           284:        struct in6_addr *mask;
        !           285:        u_char *lim0;
        !           286: {
        !           287:        int x = 0, y;
        !           288:        u_char *lim = lim0, *p;
        !           289:
        !           290:        /* ignore the scope_id part */
        !           291:        if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
        !           292:                lim = (u_char *)mask + sizeof(*mask);
        !           293:        for (p = (u_char *)mask; p < lim; x++, p++) {
        !           294:                if (*p != 0xff)
        !           295:                        break;
        !           296:        }
        !           297:        y = 0;
        !           298:        if (p < lim) {
        !           299:                for (y = 0; y < 8; y++) {
        !           300:                        if ((*p & (0x80 >> y)) == 0)
        !           301:                                break;
        !           302:                }
        !           303:        }
        !           304:
        !           305:        /*
        !           306:         * when the limit pointer is given, do a stricter check on the
        !           307:         * remaining bits.
        !           308:         */
        !           309:        if (p < lim) {
        !           310:                if (y != 0 && (*p & (0x00ff >> y)) != 0)
        !           311:                        return (-1);
        !           312:                for (p = p + 1; p < lim; p++)
        !           313:                        if (*p != 0)
        !           314:                                return (-1);
        !           315:        }
        !           316:
        !           317:        return x * 8 + y;
        !           318: }
        !           319:
        !           320: #define ifa2ia6(ifa)   ((struct in6_ifaddr *)(ifa))
        !           321: #define ia62ifa(ia6)   (&((ia6)->ia_ifa))
        !           322:
        !           323: int
        !           324: in6_control(so, cmd, data, ifp, p)
        !           325:        struct  socket *so;
        !           326:        u_long cmd;
        !           327:        caddr_t data;
        !           328:        struct ifnet *ifp;
        !           329:        struct proc *p;
        !           330: {
        !           331:        struct  in6_ifreq *ifr = (struct in6_ifreq *)data;
        !           332:        struct  in6_ifaddr *ia = NULL;
        !           333:        struct  in6_aliasreq *ifra = (struct in6_aliasreq *)data;
        !           334:        struct sockaddr_in6 *sa6;
        !           335:        int privileged;
        !           336:
        !           337:        privileged = 0;
        !           338:        if ((so->so_state & SS_PRIV) != 0)
        !           339:                privileged++;
        !           340:
        !           341: #ifdef MROUTING
        !           342:        switch (cmd) {
        !           343:        case SIOCGETSGCNT_IN6:
        !           344:        case SIOCGETMIFCNT_IN6:
        !           345:                return (mrt6_ioctl(cmd, data));
        !           346:        }
        !           347: #endif
        !           348:
        !           349:        if (ifp == NULL)
        !           350:                return (EOPNOTSUPP);
        !           351:
        !           352:        switch (cmd) {
        !           353:        case SIOCSNDFLUSH_IN6:
        !           354:        case SIOCSPFXFLUSH_IN6:
        !           355:        case SIOCSRTRFLUSH_IN6:
        !           356:        case SIOCSDEFIFACE_IN6:
        !           357:        case SIOCSIFINFO_FLAGS:
        !           358:                if (!privileged)
        !           359:                        return (EPERM);
        !           360:                /* FALLTHROUGH */
        !           361:        case OSIOCGIFINFO_IN6:
        !           362:        case SIOCGIFINFO_IN6:
        !           363:        case SIOCGDRLST_IN6:
        !           364:        case SIOCGPRLST_IN6:
        !           365:        case SIOCGNBRINFO_IN6:
        !           366:        case SIOCGDEFIFACE_IN6:
        !           367:                return (nd6_ioctl(cmd, data, ifp));
        !           368:        }
        !           369:
        !           370:        switch (cmd) {
        !           371:        case SIOCSIFPREFIX_IN6:
        !           372:        case SIOCDIFPREFIX_IN6:
        !           373:        case SIOCAIFPREFIX_IN6:
        !           374:        case SIOCCIFPREFIX_IN6:
        !           375:        case SIOCSGIFPREFIX_IN6:
        !           376:        case SIOCGIFPREFIX_IN6:
        !           377:                log(LOG_NOTICE,
        !           378:                    "prefix ioctls are now invalidated. "
        !           379:                    "please use ifconfig.\n");
        !           380:                return (EOPNOTSUPP);
        !           381:        }
        !           382:
        !           383:        switch (cmd) {
        !           384:        case SIOCALIFADDR:
        !           385:        case SIOCDLIFADDR:
        !           386:                if (!privileged)
        !           387:                        return (EPERM);
        !           388:                /* FALLTHROUGH */
        !           389:        case SIOCGLIFADDR:
        !           390:                return in6_lifaddr_ioctl(so, cmd, data, ifp, p);
        !           391:        }
        !           392:
        !           393:        /*
        !           394:         * Find address for this interface, if it exists.
        !           395:         *
        !           396:         * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation
        !           397:         * only, and used the first interface address as the target of other
        !           398:         * operations (without checking ifra_addr).  This was because netinet
        !           399:         * code/API assumed at most 1 interface address per interface.
        !           400:         * Since IPv6 allows a node to assign multiple addresses
        !           401:         * on a single interface, we almost always look and check the
        !           402:         * presence of ifra_addr, and reject invalid ones here.
        !           403:         * It also decreases duplicated code among SIOC*_IN6 operations.
        !           404:         */
        !           405:        switch (cmd) {
        !           406:        case SIOCAIFADDR_IN6:
        !           407:        case SIOCSIFPHYADDR_IN6:
        !           408:                sa6 = &ifra->ifra_addr;
        !           409:                break;
        !           410:        case SIOCSIFADDR_IN6:
        !           411:        case SIOCGIFADDR_IN6:
        !           412:        case SIOCSIFDSTADDR_IN6:
        !           413:        case SIOCSIFNETMASK_IN6:
        !           414:        case SIOCGIFDSTADDR_IN6:
        !           415:        case SIOCGIFNETMASK_IN6:
        !           416:        case SIOCDIFADDR_IN6:
        !           417:        case SIOCGIFPSRCADDR_IN6:
        !           418:        case SIOCGIFPDSTADDR_IN6:
        !           419:        case SIOCGIFAFLAG_IN6:
        !           420:        case SIOCSNDFLUSH_IN6:
        !           421:        case SIOCSPFXFLUSH_IN6:
        !           422:        case SIOCSRTRFLUSH_IN6:
        !           423:        case SIOCGIFALIFETIME_IN6:
        !           424:        case SIOCSIFALIFETIME_IN6:
        !           425:        case SIOCGIFSTAT_IN6:
        !           426:        case SIOCGIFSTAT_ICMP6:
        !           427:                sa6 = &ifr->ifr_addr;
        !           428:                break;
        !           429:        default:
        !           430:                sa6 = NULL;
        !           431:                break;
        !           432:        }
        !           433:        if (sa6 && sa6->sin6_family == AF_INET6) {
        !           434:                if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
        !           435:                        if (sa6->sin6_addr.s6_addr16[1] == 0) {
        !           436:                                /* link ID is not embedded by the user */
        !           437:                                sa6->sin6_addr.s6_addr16[1] =
        !           438:                                    htons(ifp->if_index);
        !           439:                        } else if (sa6->sin6_addr.s6_addr16[1] !=
        !           440:                            htons(ifp->if_index)) {
        !           441:                                return (EINVAL);        /* link ID contradicts */
        !           442:                        }
        !           443:                        if (sa6->sin6_scope_id) {
        !           444:                                if (sa6->sin6_scope_id !=
        !           445:                                    (u_int32_t)ifp->if_index)
        !           446:                                        return (EINVAL);
        !           447:                                sa6->sin6_scope_id = 0; /* XXX: good way? */
        !           448:                        }
        !           449:                }
        !           450:                ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
        !           451:        } else
        !           452:                ia = NULL;
        !           453:
        !           454:        switch (cmd) {
        !           455:        case SIOCSIFADDR_IN6:
        !           456:        case SIOCSIFDSTADDR_IN6:
        !           457:        case SIOCSIFNETMASK_IN6:
        !           458:                /*
        !           459:                 * Since IPv6 allows a node to assign multiple addresses
        !           460:                 * on a single interface, SIOCSIFxxx ioctls are deprecated.
        !           461:                 */
        !           462:                return (EINVAL);
        !           463:
        !           464:        case SIOCDIFADDR_IN6:
        !           465:                /*
        !           466:                 * for IPv4, we look for existing in_ifaddr here to allow
        !           467:                 * "ifconfig if0 delete" to remove the first IPv4 address on
        !           468:                 * the interface.  For IPv6, as the spec allows multiple
        !           469:                 * interface address from the day one, we consider "remove the
        !           470:                 * first one" semantics to be not preferable.
        !           471:                 */
        !           472:                if (ia == NULL)
        !           473:                        return (EADDRNOTAVAIL);
        !           474:                /* FALLTHROUGH */
        !           475:        case SIOCAIFADDR_IN6:
        !           476:                /*
        !           477:                 * We always require users to specify a valid IPv6 address for
        !           478:                 * the corresponding operation.
        !           479:                 */
        !           480:                if (ifra->ifra_addr.sin6_family != AF_INET6 ||
        !           481:                    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
        !           482:                        return (EAFNOSUPPORT);
        !           483:                if (!privileged)
        !           484:                        return (EPERM);
        !           485:
        !           486:                break;
        !           487:
        !           488:        case SIOCGIFADDR_IN6:
        !           489:                /* This interface is basically deprecated. use SIOCGIFCONF. */
        !           490:                /* FALLTHROUGH */
        !           491:        case SIOCGIFAFLAG_IN6:
        !           492:        case SIOCGIFNETMASK_IN6:
        !           493:        case SIOCGIFDSTADDR_IN6:
        !           494:        case SIOCGIFALIFETIME_IN6:
        !           495:                /* must think again about its semantics */
        !           496:                if (ia == NULL)
        !           497:                        return (EADDRNOTAVAIL);
        !           498:                break;
        !           499:        case SIOCSIFALIFETIME_IN6:
        !           500:            {
        !           501:                struct in6_addrlifetime *lt;
        !           502:
        !           503:                if (!privileged)
        !           504:                        return (EPERM);
        !           505:                if (ia == NULL)
        !           506:                        return (EADDRNOTAVAIL);
        !           507:                /* sanity for overflow - beware unsigned */
        !           508:                lt = &ifr->ifr_ifru.ifru_lifetime;
        !           509:                if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
        !           510:                 && lt->ia6t_vltime + time_second < time_second) {
        !           511:                        return EINVAL;
        !           512:                }
        !           513:                if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
        !           514:                 && lt->ia6t_pltime + time_second < time_second) {
        !           515:                        return EINVAL;
        !           516:                }
        !           517:                break;
        !           518:            }
        !           519:        }
        !           520:
        !           521:        switch (cmd) {
        !           522:
        !           523:        case SIOCGIFADDR_IN6:
        !           524:                ifr->ifr_addr = ia->ia_addr;
        !           525:                break;
        !           526:
        !           527:        case SIOCGIFDSTADDR_IN6:
        !           528:                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
        !           529:                        return (EINVAL);
        !           530:                /*
        !           531:                 * XXX: should we check if ifa_dstaddr is NULL and return
        !           532:                 * an error?
        !           533:                 */
        !           534:                ifr->ifr_dstaddr = ia->ia_dstaddr;
        !           535:                break;
        !           536:
        !           537:        case SIOCGIFNETMASK_IN6:
        !           538:                ifr->ifr_addr = ia->ia_prefixmask;
        !           539:                break;
        !           540:
        !           541:        case SIOCGIFAFLAG_IN6:
        !           542:                ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
        !           543:                break;
        !           544:
        !           545:        case SIOCGIFSTAT_IN6:
        !           546:                if (ifp == NULL)
        !           547:                        return EINVAL;
        !           548:                bzero(&ifr->ifr_ifru.ifru_stat,
        !           549:                    sizeof(ifr->ifr_ifru.ifru_stat));
        !           550:                ifr->ifr_ifru.ifru_stat =
        !           551:                    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat;
        !           552:                break;
        !           553:
        !           554:        case SIOCGIFSTAT_ICMP6:
        !           555:                if (ifp == NULL)
        !           556:                        return EINVAL;
        !           557:                bzero(&ifr->ifr_ifru.ifru_icmp6stat,
        !           558:                    sizeof(ifr->ifr_ifru.ifru_icmp6stat));
        !           559:                ifr->ifr_ifru.ifru_icmp6stat =
        !           560:                    *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat;
        !           561:                break;
        !           562:
        !           563:        case SIOCGIFALIFETIME_IN6:
        !           564:                ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
        !           565:                if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
        !           566:                        time_t maxexpire;
        !           567:                        struct in6_addrlifetime *retlt =
        !           568:                            &ifr->ifr_ifru.ifru_lifetime;
        !           569:
        !           570:                        /*
        !           571:                         * XXX: adjust expiration time assuming time_t is
        !           572:                         * signed.
        !           573:                         */
        !           574:                        maxexpire = (-1) &
        !           575:                            ~(1 << ((sizeof(maxexpire) * 8) - 1));
        !           576:                        if (ia->ia6_lifetime.ia6t_vltime <
        !           577:                            maxexpire - ia->ia6_updatetime) {
        !           578:                                retlt->ia6t_expire = ia->ia6_updatetime +
        !           579:                                    ia->ia6_lifetime.ia6t_vltime;
        !           580:                        } else
        !           581:                                retlt->ia6t_expire = maxexpire;
        !           582:                }
        !           583:                if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
        !           584:                        time_t maxexpire;
        !           585:                        struct in6_addrlifetime *retlt =
        !           586:                            &ifr->ifr_ifru.ifru_lifetime;
        !           587:
        !           588:                        /*
        !           589:                         * XXX: adjust expiration time assuming time_t is
        !           590:                         * signed.
        !           591:                         */
        !           592:                        maxexpire = (-1) &
        !           593:                            ~(1 << ((sizeof(maxexpire) * 8) - 1));
        !           594:                        if (ia->ia6_lifetime.ia6t_pltime <
        !           595:                            maxexpire - ia->ia6_updatetime) {
        !           596:                                retlt->ia6t_preferred = ia->ia6_updatetime +
        !           597:                                    ia->ia6_lifetime.ia6t_pltime;
        !           598:                        } else
        !           599:                                retlt->ia6t_preferred = maxexpire;
        !           600:                }
        !           601:                break;
        !           602:
        !           603:        case SIOCSIFALIFETIME_IN6:
        !           604:                ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
        !           605:                /* for sanity */
        !           606:                if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
        !           607:                        ia->ia6_lifetime.ia6t_expire =
        !           608:                                time_second + ia->ia6_lifetime.ia6t_vltime;
        !           609:                } else
        !           610:                        ia->ia6_lifetime.ia6t_expire = 0;
        !           611:                if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
        !           612:                        ia->ia6_lifetime.ia6t_preferred =
        !           613:                                time_second + ia->ia6_lifetime.ia6t_pltime;
        !           614:                } else
        !           615:                        ia->ia6_lifetime.ia6t_preferred = 0;
        !           616:                break;
        !           617:
        !           618:        case SIOCAIFADDR_IN6:
        !           619:        {
        !           620:                int i, error = 0;
        !           621:                struct nd_prefix pr0, *pr;
        !           622:
        !           623:                /* reject read-only flags */
        !           624:                if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
        !           625:                    (ifra->ifra_flags & IN6_IFF_DETACHED) != 0 ||
        !           626:                    (ifra->ifra_flags & IN6_IFF_NODAD) != 0 ||
        !           627:                    (ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0) {
        !           628:                        return (EINVAL);
        !           629:                }
        !           630:                /*
        !           631:                 * first, make or update the interface address structure,
        !           632:                 * and link it to the list.
        !           633:                 */
        !           634:                if ((error = in6_update_ifa(ifp, ifra, ia)) != 0)
        !           635:                        return (error);
        !           636:                if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
        !           637:                    == NULL) {
        !           638:                        /*
        !           639:                         * this can happen when the user specify the 0 valid
        !           640:                         * lifetime.
        !           641:                         */
        !           642:                        break;
        !           643:                }
        !           644:
        !           645:                /*
        !           646:                 * then, make the prefix on-link on the interface.
        !           647:                 * XXX: we'd rather create the prefix before the address, but
        !           648:                 * we need at least one address to install the corresponding
        !           649:                 * interface route, so we configure the address first.
        !           650:                 */
        !           651:
        !           652:                /*
        !           653:                 * convert mask to prefix length (prefixmask has already
        !           654:                 * been validated in in6_update_ifa().
        !           655:                 */
        !           656:                bzero(&pr0, sizeof(pr0));
        !           657:                pr0.ndpr_ifp = ifp;
        !           658:                pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
        !           659:                    NULL);
        !           660:                if (pr0.ndpr_plen == 128) {
        !           661:                        break;  /* we don't need to install a host route. */
        !           662:                }
        !           663:                pr0.ndpr_prefix = ifra->ifra_addr;
        !           664:                pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr;
        !           665:                /* apply the mask for safety. */
        !           666:                for (i = 0; i < 4; i++) {
        !           667:                        pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
        !           668:                            ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];
        !           669:                }
        !           670:                /*
        !           671:                 * XXX: since we don't have an API to set prefix (not address)
        !           672:                 * lifetimes, we just use the same lifetimes as addresses.
        !           673:                 * The (temporarily) installed lifetimes can be overridden by
        !           674:                 * later advertised RAs (when accept_rtadv is non 0), which is
        !           675:                 * an intended behavior.
        !           676:                 */
        !           677:                pr0.ndpr_raf_onlink = 1; /* should be configurable? */
        !           678:                pr0.ndpr_raf_auto =
        !           679:                    ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
        !           680:                pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
        !           681:                pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
        !           682:
        !           683:                /* add the prefix if not yet. */
        !           684:                if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
        !           685:                        /*
        !           686:                         * nd6_prelist_add will install the corresponding
        !           687:                         * interface route.
        !           688:                         */
        !           689:                        if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
        !           690:                                return (error);
        !           691:                        if (pr == NULL) {
        !           692:                                log(LOG_ERR, "nd6_prelist_add succeeded but "
        !           693:                                    "no prefix\n");
        !           694:                                return (EINVAL); /* XXX panic here? */
        !           695:                        }
        !           696:                }
        !           697:
        !           698:                /* relate the address to the prefix */
        !           699:                if (ia->ia6_ndpr == NULL) {
        !           700:                        ia->ia6_ndpr = pr;
        !           701:                        pr->ndpr_refcnt++;
        !           702:                }
        !           703:
        !           704:                /*
        !           705:                 * this might affect the status of autoconfigured addresses,
        !           706:                 * that is, this address might make other addresses detached.
        !           707:                 */
        !           708:                pfxlist_onlink_check();
        !           709:
        !           710:                dohooks(ifp->if_addrhooks, 0);
        !           711:                break;
        !           712:        }
        !           713:
        !           714:        case SIOCDIFADDR_IN6:
        !           715:        {
        !           716:                int i = 0, purgeprefix = 0;
        !           717:                struct nd_prefix pr0, *pr = NULL;
        !           718:
        !           719:                /*
        !           720:                 * If the address being deleted is the only one that owns
        !           721:                 * the corresponding prefix, expire the prefix as well.
        !           722:                 * XXX: theoretically, we don't have to worry about such
        !           723:                 * relationship, since we separate the address management
        !           724:                 * and the prefix management.  We do this, however, to provide
        !           725:                 * as much backward compatibility as possible in terms of
        !           726:                 * the ioctl operation.
        !           727:                 */
        !           728:                bzero(&pr0, sizeof(pr0));
        !           729:                pr0.ndpr_ifp = ifp;
        !           730:                pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr,
        !           731:                    NULL);
        !           732:                if (pr0.ndpr_plen == 128)
        !           733:                        goto purgeaddr;
        !           734:                pr0.ndpr_prefix = ia->ia_addr;
        !           735:                pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr;
        !           736:                for (i = 0; i < 4; i++) {
        !           737:                        pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
        !           738:                            ia->ia_prefixmask.sin6_addr.s6_addr32[i];
        !           739:                }
        !           740:                if ((pr = nd6_prefix_lookup(&pr0)) != NULL &&
        !           741:                    pr == ia->ia6_ndpr) {
        !           742:                        pr->ndpr_refcnt--;
        !           743:                        if (pr->ndpr_refcnt == 0)
        !           744:                                purgeprefix = 1;
        !           745:                }
        !           746:
        !           747:          purgeaddr:
        !           748:                in6_purgeaddr(&ia->ia_ifa);
        !           749:                if (pr && purgeprefix)
        !           750:                        prelist_remove(pr);
        !           751:                dohooks(ifp->if_addrhooks, 0);
        !           752:                break;
        !           753:        }
        !           754:
        !           755:        default:
        !           756:                if (ifp == NULL || ifp->if_ioctl == 0)
        !           757:                        return (EOPNOTSUPP);
        !           758:                return ((*ifp->if_ioctl)(ifp, cmd, data));
        !           759:        }
        !           760:
        !           761:        return (0);
        !           762: }
        !           763:
        !           764: /*
        !           765:  * Update parameters of an IPv6 interface address.
        !           766:  * If necessary, a new entry is created and linked into address chains.
        !           767:  * This function is separated from in6_control().
        !           768:  * XXX: should this be performed under splnet()?
        !           769:  */
        !           770: int
        !           771: in6_update_ifa(ifp, ifra, ia)
        !           772:        struct ifnet *ifp;
        !           773:        struct in6_aliasreq *ifra;
        !           774:        struct in6_ifaddr *ia;
        !           775: {
        !           776:        int error = 0, hostIsNew = 0, plen = -1;
        !           777:        struct in6_ifaddr *oia;
        !           778:        struct sockaddr_in6 dst6;
        !           779:        struct in6_addrlifetime *lt;
        !           780:        struct in6_multi_mship *imm;
        !           781:        struct rtentry *rt;
        !           782:
        !           783:        /* Validate parameters */
        !           784:        if (ifp == NULL || ifra == NULL) /* this maybe redundant */
        !           785:                return (EINVAL);
        !           786:
        !           787:        /*
        !           788:         * The destination address for a p2p link must have a family
        !           789:         * of AF_UNSPEC or AF_INET6.
        !           790:         */
        !           791:        if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
        !           792:            ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
        !           793:            ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
        !           794:                return (EAFNOSUPPORT);
        !           795:        /*
        !           796:         * validate ifra_prefixmask.  don't check sin6_family, netmask
        !           797:         * does not carry fields other than sin6_len.
        !           798:         */
        !           799:        if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))
        !           800:                return (EINVAL);
        !           801:        /*
        !           802:         * Because the IPv6 address architecture is classless, we require
        !           803:         * users to specify a (non 0) prefix length (mask) for a new address.
        !           804:         * We also require the prefix (when specified) mask is valid, and thus
        !           805:         * reject a non-consecutive mask.
        !           806:         */
        !           807:        if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)
        !           808:                return (EINVAL);
        !           809:        if (ifra->ifra_prefixmask.sin6_len != 0) {
        !           810:                plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
        !           811:                    (u_char *)&ifra->ifra_prefixmask +
        !           812:                    ifra->ifra_prefixmask.sin6_len);
        !           813:                if (plen <= 0)
        !           814:                        return (EINVAL);
        !           815:        } else {
        !           816:                /*
        !           817:                 * In this case, ia must not be NULL.  We just use its prefix
        !           818:                 * length.
        !           819:                 */
        !           820:                plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
        !           821:        }
        !           822:        /*
        !           823:         * If the destination address on a p2p interface is specified,
        !           824:         * and the address is a scoped one, validate/set the scope
        !           825:         * zone identifier.
        !           826:         */
        !           827:        dst6 = ifra->ifra_dstaddr;
        !           828:        if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 &&
        !           829:            (dst6.sin6_family == AF_INET6)) {
        !           830:                /* link-local index check: should be a separate function? */
        !           831:                if (IN6_IS_ADDR_LINKLOCAL(&dst6.sin6_addr)) {
        !           832:                        if (dst6.sin6_addr.s6_addr16[1] == 0) {
        !           833:                                /*
        !           834:                                 * interface ID is not embedded by
        !           835:                                 * the user
        !           836:                                 */
        !           837:                                dst6.sin6_addr.s6_addr16[1] =
        !           838:                                    htons(ifp->if_index);
        !           839:                        } else if (dst6.sin6_addr.s6_addr16[1] !=
        !           840:                            htons(ifp->if_index)) {
        !           841:                                return (EINVAL);        /* ifid contradicts */
        !           842:                        }
        !           843:                }
        !           844:        }
        !           845:        /*
        !           846:         * The destination address can be specified only for a p2p or a
        !           847:         * loopback interface.  If specified, the corresponding prefix length
        !           848:         * must be 128.
        !           849:         */
        !           850:        if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {
        !           851: #ifdef FORCE_P2PPLEN
        !           852:                int i;
        !           853: #endif
        !           854:
        !           855:                if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {
        !           856:                        /* XXX: noisy message */
        !           857:                        nd6log((LOG_INFO, "in6_update_ifa: a destination can "
        !           858:                            "be specified for a p2p or a loopback IF only\n"));
        !           859:                        return (EINVAL);
        !           860:                }
        !           861:                if (plen != 128) {
        !           862:                        nd6log((LOG_INFO, "in6_update_ifa: prefixlen should "
        !           863:                            "be 128 when dstaddr is specified\n"));
        !           864: #ifdef FORCE_P2PPLEN
        !           865:                        /*
        !           866:                         * To be compatible with old configurations,
        !           867:                         * such as ifconfig gif0 inet6 2001::1 2001::2
        !           868:                         * prefixlen 126, we override the specified
        !           869:                         * prefixmask as if the prefix length was 128.
        !           870:                         */
        !           871:                        ifra->ifra_prefixmask.sin6_len =
        !           872:                            sizeof(struct sockaddr_in6);
        !           873:                        for (i = 0; i < 4; i++)
        !           874:                                ifra->ifra_prefixmask.sin6_addr.s6_addr32[i] =
        !           875:                                    0xffffffff;
        !           876:                        plen = 128;
        !           877: #else
        !           878:                        return (EINVAL);
        !           879: #endif
        !           880:                }
        !           881:        }
        !           882:        /* lifetime consistency check */
        !           883:        lt = &ifra->ifra_lifetime;
        !           884:        if (lt->ia6t_pltime > lt->ia6t_vltime)
        !           885:                return (EINVAL);
        !           886:        if (lt->ia6t_vltime == 0) {
        !           887:                /*
        !           888:                 * the following log might be noisy, but this is a typical
        !           889:                 * configuration mistake or a tool's bug.
        !           890:                 */
        !           891:                nd6log((LOG_INFO,
        !           892:                    "in6_update_ifa: valid lifetime is 0 for %s\n",
        !           893:                    ip6_sprintf(&ifra->ifra_addr.sin6_addr)));
        !           894:
        !           895:                if (ia == NULL)
        !           896:                        return (0); /* there's nothing to do */
        !           897:        }
        !           898:
        !           899:        /*
        !           900:         * If this is a new address, allocate a new ifaddr and link it
        !           901:         * into chains.
        !           902:         */
        !           903:        if (ia == NULL) {
        !           904:                hostIsNew = 1;
        !           905:                /*
        !           906:                 * When in6_update_ifa() is called in a process of a received
        !           907:                 * RA, it is called under an interrupt context.  So, we should
        !           908:                 * call malloc with M_NOWAIT.
        !           909:                 */
        !           910:                ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR,
        !           911:                    M_NOWAIT);
        !           912:                if (ia == NULL)
        !           913:                        return (ENOBUFS);
        !           914:                bzero((caddr_t)ia, sizeof(*ia));
        !           915:                LIST_INIT(&ia->ia6_memberships);
        !           916:                /* Initialize the address and masks, and put time stamp */
        !           917:                ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
        !           918:                ia->ia_addr.sin6_family = AF_INET6;
        !           919:                ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
        !           920:                ia->ia6_createtime = ia->ia6_updatetime = time_second;
        !           921:                if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {
        !           922:                        /*
        !           923:                         * XXX: some functions expect that ifa_dstaddr is not
        !           924:                         * NULL for p2p interfaces.
        !           925:                         */
        !           926:                        ia->ia_ifa.ifa_dstaddr =
        !           927:                            (struct sockaddr *)&ia->ia_dstaddr;
        !           928:                } else {
        !           929:                        ia->ia_ifa.ifa_dstaddr = NULL;
        !           930:                }
        !           931:                ia->ia_ifa.ifa_netmask =
        !           932:                    (struct sockaddr *)&ia->ia_prefixmask;
        !           933:
        !           934:                ia->ia_ifp = ifp;
        !           935:                if ((oia = in6_ifaddr) != NULL) {
        !           936:                        for ( ; oia->ia_next; oia = oia->ia_next)
        !           937:                                continue;
        !           938:                        oia->ia_next = ia;
        !           939:                } else
        !           940:                        in6_ifaddr = ia;
        !           941:                TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
        !           942:                                  ifa_list);
        !           943:        }
        !           944:
        !           945:        /* set prefix mask */
        !           946:        if (ifra->ifra_prefixmask.sin6_len) {
        !           947:                /*
        !           948:                 * We prohibit changing the prefix length of an existing
        !           949:                 * address, because
        !           950:                 * + such an operation should be rare in IPv6, and
        !           951:                 * + the operation would confuse prefix management.
        !           952:                 */
        !           953:                if (ia->ia_prefixmask.sin6_len &&
        !           954:                    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {
        !           955:                        nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an"
        !           956:                            " existing (%s) address should not be changed\n",
        !           957:                            ip6_sprintf(&ia->ia_addr.sin6_addr)));
        !           958:                        error = EINVAL;
        !           959:                        goto unlink;
        !           960:                }
        !           961:                ia->ia_prefixmask = ifra->ifra_prefixmask;
        !           962:        }
        !           963:
        !           964:        /*
        !           965:         * If a new destination address is specified, scrub the old one and
        !           966:         * install the new destination.  Note that the interface must be
        !           967:         * p2p or loopback (see the check above.)
        !           968:         */
        !           969:        if (dst6.sin6_family == AF_INET6 &&
        !           970:            !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
        !           971:                int e;
        !           972:
        !           973:                if ((ia->ia_flags & IFA_ROUTE) != 0 &&
        !           974:                    (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) {
        !           975:                        nd6log((LOG_ERR, "in6_update_ifa: failed to remove "
        !           976:                            "a route to the old destination: %s\n",
        !           977:                            ip6_sprintf(&ia->ia_addr.sin6_addr)));
        !           978:                        /* proceed anyway... */
        !           979:                } else
        !           980:                        ia->ia_flags &= ~IFA_ROUTE;
        !           981:                ia->ia_dstaddr = dst6;
        !           982:        }
        !           983:
        !           984:        /*
        !           985:         * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred
        !           986:         * to see if the address is deprecated or invalidated, but initialize
        !           987:         * these members for applications.
        !           988:         */
        !           989:        ia->ia6_lifetime = ifra->ifra_lifetime;
        !           990:        if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
        !           991:                ia->ia6_lifetime.ia6t_expire =
        !           992:                    time_second + ia->ia6_lifetime.ia6t_vltime;
        !           993:        } else
        !           994:                ia->ia6_lifetime.ia6t_expire = 0;
        !           995:        if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
        !           996:                ia->ia6_lifetime.ia6t_preferred =
        !           997:                    time_second + ia->ia6_lifetime.ia6t_pltime;
        !           998:        } else
        !           999:                ia->ia6_lifetime.ia6t_preferred = 0;
        !          1000:
        !          1001:        /* reset the interface and routing table appropriately. */
        !          1002:        if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
        !          1003:                goto unlink;
        !          1004:
        !          1005:        /*
        !          1006:         * configure address flags.
        !          1007:         */
        !          1008:        ia->ia6_flags = ifra->ifra_flags;
        !          1009:        /*
        !          1010:         * backward compatibility - if IN6_IFF_DEPRECATED is set from the
        !          1011:         * userland, make it deprecated.
        !          1012:         */
        !          1013:        if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
        !          1014:                ia->ia6_lifetime.ia6t_pltime = 0;
        !          1015:                ia->ia6_lifetime.ia6t_preferred = time_second;
        !          1016:        }
        !          1017:        /*
        !          1018:         * Make the address tentative before joining multicast addresses,
        !          1019:         * so that corresponding MLD responses would not have a tentative
        !          1020:         * source address.
        !          1021:         */
        !          1022:        ia->ia6_flags &= ~IN6_IFF_DUPLICATED;   /* safety */
        !          1023:        if (hostIsNew && in6if_do_dad(ifp))
        !          1024:                ia->ia6_flags |= IN6_IFF_TENTATIVE;
        !          1025:
        !          1026:        /*
        !          1027:         * We are done if we have simply modified an existing address.
        !          1028:         */
        !          1029:        if (!hostIsNew)
        !          1030:                return (error);
        !          1031:
        !          1032:        /*
        !          1033:         * Beyond this point, we should call in6_purgeaddr upon an error,
        !          1034:         * not just go to unlink.
        !          1035:         */
        !          1036:
        !          1037:        /* join necessary multiast groups */
        !          1038:        if ((ifp->if_flags & IFF_MULTICAST) != 0) {
        !          1039:                struct sockaddr_in6 mltaddr, mltmask;
        !          1040:
        !          1041:                /* join solicited multicast addr for new host id */
        !          1042:                struct sockaddr_in6 llsol;
        !          1043:
        !          1044:                bzero(&llsol, sizeof(llsol));
        !          1045:                llsol.sin6_family = AF_INET6;
        !          1046:                llsol.sin6_len = sizeof(llsol);
        !          1047:                llsol.sin6_addr.s6_addr16[0] = htons(0xff02);
        !          1048:                llsol.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !          1049:                llsol.sin6_addr.s6_addr32[1] = 0;
        !          1050:                llsol.sin6_addr.s6_addr32[2] = htonl(1);
        !          1051:                llsol.sin6_addr.s6_addr32[3] =
        !          1052:                    ifra->ifra_addr.sin6_addr.s6_addr32[3];
        !          1053:                llsol.sin6_addr.s6_addr8[12] = 0xff;
        !          1054:                imm = in6_joingroup(ifp, &llsol.sin6_addr, &error);
        !          1055:                if (!imm) {
        !          1056:                        nd6log((LOG_ERR, "in6_update_ifa: "
        !          1057:                            "addmulti failed for %s on %s (errno=%d)\n",
        !          1058:                            ip6_sprintf(&llsol.sin6_addr),
        !          1059:                            ifp->if_xname, error));
        !          1060:                        goto cleanup;
        !          1061:                }
        !          1062:                LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
        !          1063:
        !          1064:                bzero(&mltmask, sizeof(mltmask));
        !          1065:                mltmask.sin6_len = sizeof(struct sockaddr_in6);
        !          1066:                mltmask.sin6_family = AF_INET6;
        !          1067:                mltmask.sin6_addr = in6mask32;
        !          1068:
        !          1069:                /*
        !          1070:                 * join link-local all-nodes address
        !          1071:                 */
        !          1072:                bzero(&mltaddr, sizeof(mltaddr));
        !          1073:                mltaddr.sin6_len = sizeof(struct sockaddr_in6);
        !          1074:                mltaddr.sin6_family = AF_INET6;
        !          1075:                mltaddr.sin6_addr = in6addr_linklocal_allnodes;
        !          1076:                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !          1077:                mltaddr.sin6_scope_id = 0;
        !          1078:
        !          1079:                /*
        !          1080:                 * XXX: do we really need this automatic routes?
        !          1081:                 * We should probably reconsider this stuff.  Most applications
        !          1082:                 * actually do not need the routes, since they usually specify
        !          1083:                 * the outgoing interface.
        !          1084:                 */
        !          1085:                rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0);
        !          1086:                if (rt) {
        !          1087:                        /*
        !          1088:                         * 32bit came from "mltmask"
        !          1089:                         */
        !          1090:                        if (memcmp(&mltaddr.sin6_addr,
        !          1091:                            &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
        !          1092:                            32 / 8)) {
        !          1093:                                RTFREE(rt);
        !          1094:                                rt = NULL;
        !          1095:                        }
        !          1096:                }
        !          1097:                if (!rt) {
        !          1098:                        struct rt_addrinfo info;
        !          1099:
        !          1100:                        bzero(&info, sizeof(info));
        !          1101:                        info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;
        !          1102:                        info.rti_info[RTAX_GATEWAY] =
        !          1103:                            (struct sockaddr *)&ia->ia_addr;
        !          1104:                        info.rti_info[RTAX_NETMASK] =
        !          1105:                            (struct sockaddr *)&mltmask;
        !          1106:                        info.rti_info[RTAX_IFA] =
        !          1107:                            (struct sockaddr *)&ia->ia_addr;
        !          1108:                        /* XXX: we need RTF_CLONING to fake nd6_rtrequest */
        !          1109:                        info.rti_flags = RTF_UP | RTF_CLONING;
        !          1110:                        error = rtrequest1(RTM_ADD, &info, NULL, 0);
        !          1111:                        if (error)
        !          1112:                                goto cleanup;
        !          1113:                } else {
        !          1114:                        RTFREE(rt);
        !          1115:                }
        !          1116:                imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
        !          1117:                if (!imm) {
        !          1118:                        nd6log((LOG_WARNING,
        !          1119:                            "in6_update_ifa: addmulti failed for "
        !          1120:                            "%s on %s (errno=%d)\n",
        !          1121:                            ip6_sprintf(&mltaddr.sin6_addr),
        !          1122:                            ifp->if_xname, error));
        !          1123:                        goto cleanup;
        !          1124:                }
        !          1125:                LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
        !          1126:
        !          1127:                /*
        !          1128:                 * join node information group address
        !          1129:                 */
        !          1130:                if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr) == 0) {
        !          1131:                        imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
        !          1132:                        if (!imm) {
        !          1133:                                nd6log((LOG_WARNING, "in6_update_ifa: "
        !          1134:                                    "addmulti failed for %s on %s (errno=%d)\n",
        !          1135:                                    ip6_sprintf(&mltaddr.sin6_addr),
        !          1136:                                    ifp->if_xname, error));
        !          1137:                                /* XXX not very fatal, go on... */
        !          1138:                        } else {
        !          1139:                                LIST_INSERT_HEAD(&ia->ia6_memberships,
        !          1140:                                    imm, i6mm_chain);
        !          1141:                        }
        !          1142:                }
        !          1143:
        !          1144:                /*
        !          1145:                 * join interface-local all-nodes address.
        !          1146:                 * (ff01::1%ifN, and ff01::%ifN/32)
        !          1147:                 */
        !          1148:                bzero(&mltaddr.sin6_addr, sizeof(mltaddr.sin6_addr));
        !          1149:                mltaddr.sin6_len = sizeof(struct sockaddr_in6);
        !          1150:                mltaddr.sin6_family = AF_INET6;
        !          1151:                mltaddr.sin6_addr = in6addr_intfacelocal_allnodes;
        !          1152:                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
        !          1153:                mltaddr.sin6_scope_id = 0;
        !          1154:
        !          1155:                /* XXX: again, do we really need the route? */
        !          1156:                rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0);
        !          1157:                if (rt) {
        !          1158:                        /* 32bit came from "mltmask" */
        !          1159:                        if (memcmp(&mltaddr.sin6_addr,
        !          1160:                            &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
        !          1161:                            32 / 8)) {
        !          1162:                                RTFREE(rt);
        !          1163:                                rt = NULL;
        !          1164:                        }
        !          1165:                }
        !          1166:                if (!rt) {
        !          1167:                        struct rt_addrinfo info;
        !          1168:
        !          1169:                        bzero(&info, sizeof(info));
        !          1170:                        info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;
        !          1171:                        info.rti_info[RTAX_GATEWAY] =
        !          1172:                            (struct sockaddr *)&ia->ia_addr;
        !          1173:                        info.rti_info[RTAX_NETMASK] =
        !          1174:                            (struct sockaddr *)&mltmask;
        !          1175:                        info.rti_info[RTAX_IFA] =
        !          1176:                            (struct sockaddr *)&ia->ia_addr;
        !          1177:                        info.rti_flags = RTF_UP | RTF_CLONING;
        !          1178:                        error = rtrequest1(RTM_ADD, &info, NULL, 0);
        !          1179:                        if (error)
        !          1180:                                goto cleanup;
        !          1181:                } else {
        !          1182:                        RTFREE(rt);
        !          1183:                }
        !          1184:                imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);
        !          1185:                if (!imm) {
        !          1186:                        nd6log((LOG_WARNING, "in6_update_ifa: "
        !          1187:                            "addmulti failed for %s on %s (errno=%d)\n",
        !          1188:                            ip6_sprintf(&mltaddr.sin6_addr),
        !          1189:                            ifp->if_xname, error));
        !          1190:                        goto cleanup;
        !          1191:                }
        !          1192:                LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
        !          1193:        }
        !          1194:
        !          1195:        /*
        !          1196:         * Perform DAD, if needed.
        !          1197:         * XXX It may be of use, if we can administratively
        !          1198:         * disable DAD.
        !          1199:         */
        !          1200:        if (hostIsNew && in6if_do_dad(ifp) &&
        !          1201:            (ifra->ifra_flags & IN6_IFF_NODAD) == 0)
        !          1202:        {
        !          1203:                nd6_dad_start((struct ifaddr *)ia, NULL);
        !          1204:        }
        !          1205:
        !          1206:        return (error);
        !          1207:
        !          1208:   unlink:
        !          1209:        /*
        !          1210:         * XXX: if a change of an existing address failed, keep the entry
        !          1211:         * anyway.
        !          1212:         */
        !          1213:        if (hostIsNew)
        !          1214:                in6_unlink_ifa(ia, ifp);
        !          1215:        return (error);
        !          1216:
        !          1217:   cleanup:
        !          1218:        in6_purgeaddr(&ia->ia_ifa);
        !          1219:        return error;
        !          1220: }
        !          1221:
        !          1222: void
        !          1223: in6_purgeaddr(ifa)
        !          1224:        struct ifaddr *ifa;
        !          1225: {
        !          1226:        struct ifnet *ifp = ifa->ifa_ifp;
        !          1227:        struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
        !          1228:        struct in6_multi_mship *imm;
        !          1229:
        !          1230:        /* stop DAD processing */
        !          1231:        nd6_dad_stop(ifa);
        !          1232:
        !          1233:        /*
        !          1234:         * delete route to the destination of the address being purged.
        !          1235:         * The interface must be p2p or loopback in this case.
        !          1236:         */
        !          1237:        if ((ia->ia_flags & IFA_ROUTE) != 0 && ia->ia_dstaddr.sin6_len != 0) {
        !          1238:                int e;
        !          1239:
        !          1240:                if ((e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))
        !          1241:                    != 0) {
        !          1242:                        log(LOG_ERR, "in6_purgeaddr: failed to remove "
        !          1243:                            "a route to the p2p destination: %s on %s, "
        !          1244:                            "errno=%d\n",
        !          1245:                            ip6_sprintf(&ia->ia_addr.sin6_addr), ifp->if_xname,
        !          1246:                            e);
        !          1247:                        /* proceed anyway... */
        !          1248:                } else
        !          1249:                        ia->ia_flags &= ~IFA_ROUTE;
        !          1250:        }
        !          1251:
        !          1252:        /* Remove ownaddr's loopback rtentry, if it exists. */
        !          1253:        in6_ifremloop(&(ia->ia_ifa));
        !          1254:
        !          1255:        /*
        !          1256:         * leave from multicast groups we have joined for the interface
        !          1257:         */
        !          1258:        while (!LIST_EMPTY(&ia->ia6_memberships)) {
        !          1259:                imm = LIST_FIRST(&ia->ia6_memberships);
        !          1260:                LIST_REMOVE(imm, i6mm_chain);
        !          1261:                in6_leavegroup(imm);
        !          1262:        }
        !          1263:
        !          1264:        in6_unlink_ifa(ia, ifp);
        !          1265: }
        !          1266:
        !          1267: static void
        !          1268: in6_unlink_ifa(ia, ifp)
        !          1269:        struct in6_ifaddr *ia;
        !          1270:        struct ifnet *ifp;
        !          1271: {
        !          1272:        struct in6_ifaddr *oia;
        !          1273:        int     s = splnet();
        !          1274:
        !          1275:        TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
        !          1276:
        !          1277:        oia = ia;
        !          1278:        if (oia == (ia = in6_ifaddr))
        !          1279:                in6_ifaddr = ia->ia_next;
        !          1280:        else {
        !          1281:                while (ia->ia_next && (ia->ia_next != oia))
        !          1282:                        ia = ia->ia_next;
        !          1283:                if (ia->ia_next)
        !          1284:                        ia->ia_next = oia->ia_next;
        !          1285:                else {
        !          1286:                        /* search failed */
        !          1287:                        printf("Couldn't unlink in6_ifaddr from in6_ifaddr\n");
        !          1288:                }
        !          1289:        }
        !          1290:
        !          1291:        if (!LIST_EMPTY(&oia->ia6_multiaddrs)) {
        !          1292:                in6_savemkludge(oia);
        !          1293:        }
        !          1294:
        !          1295:        /*
        !          1296:         * When an autoconfigured address is being removed, release the
        !          1297:         * reference to the base prefix.  Also, since the release might
        !          1298:         * affect the status of other (detached) addresses, call
        !          1299:         * pfxlist_onlink_check().
        !          1300:         */
        !          1301:        if ((oia->ia6_flags & IN6_IFF_AUTOCONF) != 0) {
        !          1302:                if (oia->ia6_ndpr == NULL) {
        !          1303:                        log(LOG_NOTICE, "in6_unlink_ifa: autoconf'ed address "
        !          1304:                            "%p has no prefix\n", oia);
        !          1305:                } else {
        !          1306:                        oia->ia6_ndpr->ndpr_refcnt--;
        !          1307:                        oia->ia6_flags &= ~IN6_IFF_AUTOCONF;
        !          1308:                        oia->ia6_ndpr = NULL;
        !          1309:                }
        !          1310:
        !          1311:                pfxlist_onlink_check();
        !          1312:        }
        !          1313:
        !          1314:        /*
        !          1315:         * release another refcnt for the link from in6_ifaddr.
        !          1316:         * Note that we should decrement the refcnt at least once for all *BSD.
        !          1317:         */
        !          1318:        IFAFREE(&oia->ia_ifa);
        !          1319:
        !          1320:        splx(s);
        !          1321: }
        !          1322:
        !          1323: void
        !          1324: in6_purgeif(ifp)
        !          1325:        struct ifnet *ifp;
        !          1326: {
        !          1327:        struct ifaddr *ifa, *nifa;
        !          1328:
        !          1329:        for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa)
        !          1330:        {
        !          1331:                nifa = TAILQ_NEXT(ifa, ifa_list);
        !          1332:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !          1333:                        continue;
        !          1334:                in6_purgeaddr(ifa);
        !          1335:        }
        !          1336:
        !          1337:        in6_ifdetach(ifp);
        !          1338: }
        !          1339:
        !          1340: /*
        !          1341:  * SIOC[GAD]LIFADDR.
        !          1342:  *     SIOCGLIFADDR: get first address. (?)
        !          1343:  *     SIOCGLIFADDR with IFLR_PREFIX:
        !          1344:  *             get first address that matches the specified prefix.
        !          1345:  *     SIOCALIFADDR: add the specified address.
        !          1346:  *     SIOCALIFADDR with IFLR_PREFIX:
        !          1347:  *             add the specified prefix, filling hostid part from
        !          1348:  *             the first link-local address.  prefixlen must be <= 64.
        !          1349:  *     SIOCDLIFADDR: delete the specified address.
        !          1350:  *     SIOCDLIFADDR with IFLR_PREFIX:
        !          1351:  *             delete the first address that matches the specified prefix.
        !          1352:  * return values:
        !          1353:  *     EINVAL on invalid parameters
        !          1354:  *     EADDRNOTAVAIL on prefix match failed/specified address not found
        !          1355:  *     other values may be returned from in6_ioctl()
        !          1356:  *
        !          1357:  * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
        !          1358:  * this is to accommodate address naming scheme other than RFC2374,
        !          1359:  * in the future.
        !          1360:  * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
        !          1361:  * address encoding scheme. (see figure on page 8)
        !          1362:  */
        !          1363: static int
        !          1364: in6_lifaddr_ioctl(so, cmd, data, ifp, p)
        !          1365:        struct socket *so;
        !          1366:        u_long cmd;
        !          1367:        caddr_t data;
        !          1368:        struct ifnet *ifp;
        !          1369:        struct proc *p;
        !          1370: {
        !          1371:        struct if_laddrreq *iflr = (struct if_laddrreq *)data;
        !          1372:        struct ifaddr *ifa;
        !          1373:        struct sockaddr *sa;
        !          1374:
        !          1375:        /* sanity checks */
        !          1376:        if (!data || !ifp) {
        !          1377:                panic("invalid argument to in6_lifaddr_ioctl");
        !          1378:                /* NOTREACHED */
        !          1379:        }
        !          1380:
        !          1381:        switch (cmd) {
        !          1382:        case SIOCGLIFADDR:
        !          1383:                /* address must be specified on GET with IFLR_PREFIX */
        !          1384:                if ((iflr->flags & IFLR_PREFIX) == 0)
        !          1385:                        break;
        !          1386:                /* FALLTHROUGH */
        !          1387:        case SIOCALIFADDR:
        !          1388:        case SIOCDLIFADDR:
        !          1389:                /* address must be specified on ADD and DELETE */
        !          1390:                sa = (struct sockaddr *)&iflr->addr;
        !          1391:                if (sa->sa_family != AF_INET6)
        !          1392:                        return EINVAL;
        !          1393:                if (sa->sa_len != sizeof(struct sockaddr_in6))
        !          1394:                        return EINVAL;
        !          1395:                /* XXX need improvement */
        !          1396:                sa = (struct sockaddr *)&iflr->dstaddr;
        !          1397:                if (sa->sa_family && sa->sa_family != AF_INET6)
        !          1398:                        return EINVAL;
        !          1399:                if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
        !          1400:                        return EINVAL;
        !          1401:                break;
        !          1402:        default: /* shouldn't happen */
        !          1403: #if 0
        !          1404:                panic("invalid cmd to in6_lifaddr_ioctl");
        !          1405:                /* NOTREACHED */
        !          1406: #else
        !          1407:                return EOPNOTSUPP;
        !          1408: #endif
        !          1409:        }
        !          1410:        if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
        !          1411:                return EINVAL;
        !          1412:
        !          1413:        switch (cmd) {
        !          1414:        case SIOCALIFADDR:
        !          1415:            {
        !          1416:                struct in6_aliasreq ifra;
        !          1417:                struct in6_addr *hostid = NULL;
        !          1418:                int prefixlen;
        !          1419:
        !          1420:                if ((iflr->flags & IFLR_PREFIX) != 0) {
        !          1421:                        struct sockaddr_in6 *sin6;
        !          1422:
        !          1423:                        /*
        !          1424:                         * hostid is to fill in the hostid part of the
        !          1425:                         * address.  hostid points to the first link-local
        !          1426:                         * address attached to the interface.
        !          1427:                         */
        !          1428:                        ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
        !          1429:                        if (!ifa)
        !          1430:                                return EADDRNOTAVAIL;
        !          1431:                        hostid = IFA_IN6(ifa);
        !          1432:
        !          1433:                        /* prefixlen must be <= 64. */
        !          1434:                        if (64 < iflr->prefixlen)
        !          1435:                                return EINVAL;
        !          1436:                        prefixlen = iflr->prefixlen;
        !          1437:
        !          1438:                        /* hostid part must be zero. */
        !          1439:                        sin6 = (struct sockaddr_in6 *)&iflr->addr;
        !          1440:                        if (sin6->sin6_addr.s6_addr32[2] != 0
        !          1441:                         || sin6->sin6_addr.s6_addr32[3] != 0) {
        !          1442:                                return EINVAL;
        !          1443:                        }
        !          1444:                } else
        !          1445:                        prefixlen = iflr->prefixlen;
        !          1446:
        !          1447:                /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
        !          1448:                bzero(&ifra, sizeof(ifra));
        !          1449:                bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name));
        !          1450:
        !          1451:                bcopy(&iflr->addr, &ifra.ifra_addr,
        !          1452:                    ((struct sockaddr *)&iflr->addr)->sa_len);
        !          1453:                if (hostid) {
        !          1454:                        /* fill in hostid part */
        !          1455:                        ifra.ifra_addr.sin6_addr.s6_addr32[2] =
        !          1456:                            hostid->s6_addr32[2];
        !          1457:                        ifra.ifra_addr.sin6_addr.s6_addr32[3] =
        !          1458:                            hostid->s6_addr32[3];
        !          1459:                }
        !          1460:
        !          1461:                if (((struct sockaddr *)&iflr->dstaddr)->sa_family) {   /*XXX*/
        !          1462:                        bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
        !          1463:                            ((struct sockaddr *)&iflr->dstaddr)->sa_len);
        !          1464:                        if (hostid) {
        !          1465:                                ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
        !          1466:                                    hostid->s6_addr32[2];
        !          1467:                                ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
        !          1468:                                    hostid->s6_addr32[3];
        !          1469:                        }
        !          1470:                }
        !          1471:
        !          1472:                ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
        !          1473:                in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
        !          1474:
        !          1475:                ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
        !          1476:                return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p);
        !          1477:            }
        !          1478:        case SIOCGLIFADDR:
        !          1479:        case SIOCDLIFADDR:
        !          1480:            {
        !          1481:                struct in6_ifaddr *ia;
        !          1482:                struct in6_addr mask, candidate, match;
        !          1483:                struct sockaddr_in6 *sin6;
        !          1484:                int cmp;
        !          1485:
        !          1486:                bzero(&mask, sizeof(mask));
        !          1487:                if (iflr->flags & IFLR_PREFIX) {
        !          1488:                        /* lookup a prefix rather than address. */
        !          1489:                        in6_prefixlen2mask(&mask, iflr->prefixlen);
        !          1490:
        !          1491:                        sin6 = (struct sockaddr_in6 *)&iflr->addr;
        !          1492:                        bcopy(&sin6->sin6_addr, &match, sizeof(match));
        !          1493:                        match.s6_addr32[0] &= mask.s6_addr32[0];
        !          1494:                        match.s6_addr32[1] &= mask.s6_addr32[1];
        !          1495:                        match.s6_addr32[2] &= mask.s6_addr32[2];
        !          1496:                        match.s6_addr32[3] &= mask.s6_addr32[3];
        !          1497:
        !          1498:                        /* if you set extra bits, that's wrong */
        !          1499:                        if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
        !          1500:                                return EINVAL;
        !          1501:
        !          1502:                        cmp = 1;
        !          1503:                } else {
        !          1504:                        if (cmd == SIOCGLIFADDR) {
        !          1505:                                /* on getting an address, take the 1st match */
        !          1506:                                cmp = 0;        /* XXX */
        !          1507:                        } else {
        !          1508:                                /* on deleting an address, do exact match */
        !          1509:                                in6_prefixlen2mask(&mask, 128);
        !          1510:                                sin6 = (struct sockaddr_in6 *)&iflr->addr;
        !          1511:                                bcopy(&sin6->sin6_addr, &match, sizeof(match));
        !          1512:
        !          1513:                                cmp = 1;
        !          1514:                        }
        !          1515:                }
        !          1516:
        !          1517:                TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          1518:                        if (ifa->ifa_addr->sa_family != AF_INET6)
        !          1519:                                continue;
        !          1520:                        if (!cmp)
        !          1521:                                break;
        !          1522:
        !          1523:                        bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
        !          1524:                        candidate.s6_addr32[0] &= mask.s6_addr32[0];
        !          1525:                        candidate.s6_addr32[1] &= mask.s6_addr32[1];
        !          1526:                        candidate.s6_addr32[2] &= mask.s6_addr32[2];
        !          1527:                        candidate.s6_addr32[3] &= mask.s6_addr32[3];
        !          1528:                        if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
        !          1529:                                break;
        !          1530:                }
        !          1531:                if (!ifa)
        !          1532:                        return EADDRNOTAVAIL;
        !          1533:                ia = ifa2ia6(ifa);
        !          1534:
        !          1535:                if (cmd == SIOCGLIFADDR) {
        !          1536:                        /* fill in the if_laddrreq structure */
        !          1537:                        bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
        !          1538:                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
        !          1539:                                bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
        !          1540:                                    ia->ia_dstaddr.sin6_len);
        !          1541:                        } else
        !          1542:                                bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
        !          1543:
        !          1544:                        iflr->prefixlen =
        !          1545:                            in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
        !          1546:
        !          1547:                        iflr->flags = ia->ia6_flags;    /*XXX*/
        !          1548:
        !          1549:                        return 0;
        !          1550:                } else {
        !          1551:                        struct in6_aliasreq ifra;
        !          1552:
        !          1553:                        /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
        !          1554:                        bzero(&ifra, sizeof(ifra));
        !          1555:                        bcopy(iflr->iflr_name, ifra.ifra_name,
        !          1556:                            sizeof(ifra.ifra_name));
        !          1557:
        !          1558:                        bcopy(&ia->ia_addr, &ifra.ifra_addr,
        !          1559:                            ia->ia_addr.sin6_len);
        !          1560:                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
        !          1561:                                bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
        !          1562:                                    ia->ia_dstaddr.sin6_len);
        !          1563:                        } else {
        !          1564:                                bzero(&ifra.ifra_dstaddr,
        !          1565:                                    sizeof(ifra.ifra_dstaddr));
        !          1566:                        }
        !          1567:                        bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
        !          1568:                            ia->ia_prefixmask.sin6_len);
        !          1569:
        !          1570:                        ifra.ifra_flags = ia->ia6_flags;
        !          1571:                        return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
        !          1572:                            ifp, p);
        !          1573:                }
        !          1574:            }
        !          1575:        }
        !          1576:
        !          1577:        return EOPNOTSUPP;      /* just for safety */
        !          1578: }
        !          1579:
        !          1580: /*
        !          1581:  * Initialize an interface's intetnet6 address
        !          1582:  * and routing table entry.
        !          1583:  */
        !          1584: static int
        !          1585: in6_ifinit(ifp, ia, sin6, newhost)
        !          1586:        struct ifnet *ifp;
        !          1587:        struct in6_ifaddr *ia;
        !          1588:        struct sockaddr_in6 *sin6;
        !          1589:        int newhost;
        !          1590: {
        !          1591:        int     error = 0, plen, ifacount = 0;
        !          1592:        int     s = splnet();
        !          1593:        struct ifaddr *ifa;
        !          1594:
        !          1595:        /*
        !          1596:         * Give the interface a chance to initialize
        !          1597:         * if this is its first address (or it is a CARP interface)
        !          1598:         * and to validate the address if necessary.
        !          1599:         */
        !          1600:        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          1601:                if (ifa->ifa_addr == NULL)
        !          1602:                        continue;       /* just for safety */
        !          1603:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !          1604:                        continue;
        !          1605:                ifacount++;
        !          1606:        }
        !          1607:
        !          1608:        ia->ia_addr = *sin6;
        !          1609:
        !          1610:        if ((ifacount <= 1 || ifp->if_type == IFT_CARP) && ifp->if_ioctl &&
        !          1611:            (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
        !          1612:                splx(s);
        !          1613:                return (error);
        !          1614:        }
        !          1615:        splx(s);
        !          1616:
        !          1617:        ia->ia_ifa.ifa_metric = ifp->if_metric;
        !          1618:
        !          1619:        /* we could do in(6)_socktrim here, but just omit it at this moment. */
        !          1620:
        !          1621:        /*
        !          1622:         * Special case:
        !          1623:         * If the destination address is specified for a point-to-point
        !          1624:         * interface, install a route to the destination as an interface
        !          1625:         * direct route.
        !          1626:         */
        !          1627:        plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
        !          1628:        if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) {
        !          1629:                if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD,
        !          1630:                                    RTF_UP | RTF_HOST)) != 0)
        !          1631:                        return (error);
        !          1632:                ia->ia_flags |= IFA_ROUTE;
        !          1633:        }
        !          1634:
        !          1635:        /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
        !          1636:        if (newhost) {
        !          1637:                /* set the rtrequest function to create llinfo */
        !          1638:                ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
        !          1639:                in6_ifaddloop(&(ia->ia_ifa));
        !          1640:        }
        !          1641:
        !          1642:        if (ifp->if_flags & IFF_MULTICAST)
        !          1643:                in6_restoremkludge(ia, ifp);
        !          1644:
        !          1645:        return (error);
        !          1646: }
        !          1647:
        !          1648: /*
        !          1649:  * Multicast address kludge:
        !          1650:  * If there were any multicast addresses attached to this interface address,
        !          1651:  * either move them to another address on this interface, or save them until
        !          1652:  * such time as this interface is reconfigured for IPv6.
        !          1653:  */
        !          1654: void
        !          1655: in6_savemkludge(oia)
        !          1656:        struct in6_ifaddr *oia;
        !          1657: {
        !          1658:        struct in6_ifaddr *ia;
        !          1659:        struct in6_multi *in6m, *next;
        !          1660:
        !          1661:        IFP_TO_IA6(oia->ia_ifp, ia);
        !          1662:        if (ia) {       /* there is another address */
        !          1663:                for (in6m = LIST_FIRST(&oia->ia6_multiaddrs);
        !          1664:                    in6m != LIST_END(&oia->ia6_multiaddrs); in6m = next) {
        !          1665:                        next = LIST_NEXT(in6m, in6m_entry);
        !          1666:                        IFAFREE(&in6m->in6m_ia->ia_ifa);
        !          1667:                        ia->ia_ifa.ifa_refcnt++;
        !          1668:                        in6m->in6m_ia = ia;
        !          1669:                        LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
        !          1670:                }
        !          1671:        } else {        /* last address on this if deleted, save */
        !          1672:                struct multi6_kludge *mk;
        !          1673:
        !          1674:                LIST_FOREACH(mk, &in6_mk, mk_entry) {
        !          1675:                        if (mk->mk_ifp == oia->ia_ifp)
        !          1676:                                break;
        !          1677:                }
        !          1678:                if (mk == NULL) /* this should not happen! */
        !          1679:                        panic("in6_savemkludge: no kludge space");
        !          1680:
        !          1681:                for (in6m = LIST_FIRST(&oia->ia6_multiaddrs);
        !          1682:                    in6m != LIST_END(&oia->ia6_multiaddrs); in6m = next) {
        !          1683:                        next = LIST_NEXT(in6m, in6m_entry);
        !          1684:                        IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
        !          1685:                        in6m->in6m_ia = NULL;
        !          1686:                        LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry);
        !          1687:                }
        !          1688:        }
        !          1689: }
        !          1690:
        !          1691: /*
        !          1692:  * Continuation of multicast address hack:
        !          1693:  * If there was a multicast group list previously saved for this interface,
        !          1694:  * then we re-attach it to the first address configured on the i/f.
        !          1695:  */
        !          1696: void
        !          1697: in6_restoremkludge(ia, ifp)
        !          1698:        struct in6_ifaddr *ia;
        !          1699:        struct ifnet *ifp;
        !          1700: {
        !          1701:        struct multi6_kludge *mk;
        !          1702:
        !          1703:        LIST_FOREACH(mk, &in6_mk, mk_entry) {
        !          1704:                if (mk->mk_ifp == ifp) {
        !          1705:                        struct in6_multi *in6m, *next;
        !          1706:
        !          1707:                        for (in6m = LIST_FIRST(&mk->mk_head);
        !          1708:                            in6m != LIST_END(&mk->mk_head);
        !          1709:                            in6m = next) {
        !          1710:                                next = LIST_NEXT(in6m, in6m_entry);
        !          1711:                                in6m->in6m_ia = ia;
        !          1712:                                ia->ia_ifa.ifa_refcnt++;
        !          1713:                                LIST_INSERT_HEAD(&ia->ia6_multiaddrs,
        !          1714:                                                 in6m, in6m_entry);
        !          1715:                        }
        !          1716:                        LIST_INIT(&mk->mk_head);
        !          1717:                        break;
        !          1718:                }
        !          1719:        }
        !          1720: }
        !          1721:
        !          1722: /*
        !          1723:  * Allocate space for the kludge at interface initialization time.
        !          1724:  * Formerly, we dynamically allocated the space in in6_savemkludge() with
        !          1725:  * malloc(M_WAITOK).  However, it was wrong since the function could be called
        !          1726:  * under an interrupt context (software timer on address lifetime expiration).
        !          1727:  * Also, we cannot just give up allocating the strucutre, since the group
        !          1728:  * membership structure is very complex and we need to keep it anyway.
        !          1729:  * Of course, this function MUST NOT be called under an interrupt context.
        !          1730:  * Specifically, it is expected to be called only from in6_ifattach(), though
        !          1731:  * it is a global function.
        !          1732:  */
        !          1733: void
        !          1734: in6_createmkludge(ifp)
        !          1735:        struct ifnet *ifp;
        !          1736: {
        !          1737:        struct multi6_kludge *mk;
        !          1738:
        !          1739:        LIST_FOREACH(mk, &in6_mk, mk_entry) {
        !          1740:                /* If we've already had one, do not allocate. */
        !          1741:                if (mk->mk_ifp == ifp)
        !          1742:                        return;
        !          1743:        }
        !          1744:
        !          1745:        mk = malloc(sizeof(*mk), M_IPMADDR, M_WAITOK);
        !          1746:
        !          1747:        bzero(mk, sizeof(*mk));
        !          1748:        LIST_INIT(&mk->mk_head);
        !          1749:        mk->mk_ifp = ifp;
        !          1750:        LIST_INSERT_HEAD(&in6_mk, mk, mk_entry);
        !          1751: }
        !          1752:
        !          1753: void
        !          1754: in6_purgemkludge(ifp)
        !          1755:        struct ifnet *ifp;
        !          1756: {
        !          1757:        struct multi6_kludge *mk;
        !          1758:        struct in6_multi *in6m;
        !          1759:
        !          1760:        LIST_FOREACH(mk, &in6_mk, mk_entry) {
        !          1761:                if (mk->mk_ifp != ifp)
        !          1762:                        continue;
        !          1763:
        !          1764:                /* leave from all multicast groups joined */
        !          1765:                while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL)
        !          1766:                        in6_delmulti(in6m);
        !          1767:                LIST_REMOVE(mk, mk_entry);
        !          1768:                free(mk, M_IPMADDR);
        !          1769:                break;
        !          1770:        }
        !          1771: }
        !          1772:
        !          1773: /*
        !          1774:  * Add an address to the list of IP6 multicast addresses for a
        !          1775:  * given interface.
        !          1776:  */
        !          1777: struct in6_multi *
        !          1778: in6_addmulti(maddr6, ifp, errorp)
        !          1779:        struct in6_addr *maddr6;
        !          1780:        struct ifnet *ifp;
        !          1781:        int *errorp;
        !          1782: {
        !          1783:        struct  in6_ifaddr *ia;
        !          1784:        struct  in6_ifreq ifr;
        !          1785:        struct  in6_multi *in6m;
        !          1786:        int     s = splsoftnet();
        !          1787:
        !          1788:        *errorp = 0;
        !          1789:        /*
        !          1790:         * See if address already in list.
        !          1791:         */
        !          1792:        IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
        !          1793:        if (in6m != NULL) {
        !          1794:                /*
        !          1795:                 * Found it; just increment the refrence count.
        !          1796:                 */
        !          1797:                in6m->in6m_refcount++;
        !          1798:        } else {
        !          1799:                /*
        !          1800:                 * New address; allocate a new multicast record
        !          1801:                 * and link it into the interface's multicast list.
        !          1802:                 */
        !          1803:                in6m = (struct in6_multi *)
        !          1804:                        malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
        !          1805:                if (in6m == NULL) {
        !          1806:                        splx(s);
        !          1807:                        *errorp = ENOBUFS;
        !          1808:                        return (NULL);
        !          1809:                }
        !          1810:                in6m->in6m_addr = *maddr6;
        !          1811:                in6m->in6m_ifp = ifp;
        !          1812:                in6m->in6m_refcount = 1;
        !          1813:                IFP_TO_IA6(ifp, ia);
        !          1814:                if (ia == NULL) {
        !          1815:                        free(in6m, M_IPMADDR);
        !          1816:                        splx(s);
        !          1817:                        *errorp = EADDRNOTAVAIL; /* appropriate? */
        !          1818:                        return (NULL);
        !          1819:                }
        !          1820:                in6m->in6m_ia = ia;
        !          1821:                ia->ia_ifa.ifa_refcnt++; /* gain a reference */
        !          1822:                LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
        !          1823:
        !          1824:                /*
        !          1825:                 * Ask the network driver to update its multicast reception
        !          1826:                 * filter appropriately for the new address.
        !          1827:                 */
        !          1828:                bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
        !          1829:                ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
        !          1830:                ifr.ifr_addr.sin6_family = AF_INET6;
        !          1831:                ifr.ifr_addr.sin6_addr = *maddr6;
        !          1832:                if (ifp->if_ioctl == NULL)
        !          1833:                        *errorp = ENXIO; /* XXX: appropriate? */
        !          1834:                else
        !          1835:                        *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,
        !          1836:                            (caddr_t)&ifr);
        !          1837:                if (*errorp) {
        !          1838:                        LIST_REMOVE(in6m, in6m_entry);
        !          1839:                        free(in6m, M_IPMADDR);
        !          1840:                        IFAFREE(&ia->ia_ifa);
        !          1841:                        splx(s);
        !          1842:                        return (NULL);
        !          1843:                }
        !          1844:                /*
        !          1845:                 * Let MLD6 know that we have joined a new IP6 multicast
        !          1846:                 * group.
        !          1847:                 */
        !          1848:                mld6_start_listening(in6m);
        !          1849:        }
        !          1850:        splx(s);
        !          1851:        return (in6m);
        !          1852: }
        !          1853:
        !          1854: /*
        !          1855:  * Delete a multicast address record.
        !          1856:  */
        !          1857: void
        !          1858: in6_delmulti(in6m)
        !          1859:        struct in6_multi *in6m;
        !          1860: {
        !          1861:        struct  in6_ifreq ifr;
        !          1862:        int     s = splsoftnet();
        !          1863:
        !          1864:        if (--in6m->in6m_refcount == 0) {
        !          1865:                /*
        !          1866:                 * No remaining claims to this record; let MLD6 know
        !          1867:                 * that we are leaving the multicast group.
        !          1868:                 */
        !          1869:                mld6_stop_listening(in6m);
        !          1870:
        !          1871:                /*
        !          1872:                 * Unlink from list.
        !          1873:                 */
        !          1874:                LIST_REMOVE(in6m, in6m_entry);
        !          1875:                if (in6m->in6m_ia) {
        !          1876:                        IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
        !          1877:                }
        !          1878:
        !          1879:                /*
        !          1880:                 * Notify the network driver to update its multicast
        !          1881:                 * reception filter.
        !          1882:                 */
        !          1883:                bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
        !          1884:                ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
        !          1885:                ifr.ifr_addr.sin6_family = AF_INET6;
        !          1886:                ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
        !          1887:                (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp,
        !          1888:                                            SIOCDELMULTI, (caddr_t)&ifr);
        !          1889:                free(in6m, M_IPMADDR);
        !          1890:        }
        !          1891:        splx(s);
        !          1892: }
        !          1893:
        !          1894: struct in6_multi_mship *
        !          1895: in6_joingroup(ifp, addr, errorp)
        !          1896:        struct ifnet *ifp;
        !          1897:        struct in6_addr *addr;
        !          1898:        int *errorp;
        !          1899: {
        !          1900:        struct in6_multi_mship *imm;
        !          1901:
        !          1902:        imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT);
        !          1903:        if (!imm) {
        !          1904:                *errorp = ENOBUFS;
        !          1905:                return NULL;
        !          1906:        }
        !          1907:        imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp);
        !          1908:        if (!imm->i6mm_maddr) {
        !          1909:                /* *errorp is alrady set */
        !          1910:                free(imm, M_IPMADDR);
        !          1911:                return NULL;
        !          1912:        }
        !          1913:        return imm;
        !          1914: }
        !          1915:
        !          1916: int
        !          1917: in6_leavegroup(imm)
        !          1918:        struct in6_multi_mship *imm;
        !          1919: {
        !          1920:
        !          1921:        if (imm->i6mm_maddr)
        !          1922:                in6_delmulti(imm->i6mm_maddr);
        !          1923:        free(imm,  M_IPMADDR);
        !          1924:        return 0;
        !          1925: }
        !          1926:
        !          1927: /*
        !          1928:  * Find an IPv6 interface link-local address specific to an interface.
        !          1929:  */
        !          1930: struct in6_ifaddr *
        !          1931: in6ifa_ifpforlinklocal(ifp, ignoreflags)
        !          1932:        struct ifnet *ifp;
        !          1933:        int ignoreflags;
        !          1934: {
        !          1935:        struct ifaddr *ifa;
        !          1936:
        !          1937:        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          1938:                if (ifa->ifa_addr == NULL)
        !          1939:                        continue;       /* just for safety */
        !          1940:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !          1941:                        continue;
        !          1942:                if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
        !          1943:                        if ((((struct in6_ifaddr *)ifa)->ia6_flags &
        !          1944:                             ignoreflags) != 0)
        !          1945:                                continue;
        !          1946:                        break;
        !          1947:                }
        !          1948:        }
        !          1949:
        !          1950:        return ((struct in6_ifaddr *)ifa);
        !          1951: }
        !          1952:
        !          1953:
        !          1954: /*
        !          1955:  * find the internet address corresponding to a given interface and address.
        !          1956:  */
        !          1957: struct in6_ifaddr *
        !          1958: in6ifa_ifpwithaddr(ifp, addr)
        !          1959:        struct ifnet *ifp;
        !          1960:        struct in6_addr *addr;
        !          1961: {
        !          1962:        struct ifaddr *ifa;
        !          1963:
        !          1964:        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          1965:                if (ifa->ifa_addr == NULL)
        !          1966:                        continue;       /* just for safety */
        !          1967:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !          1968:                        continue;
        !          1969:                if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
        !          1970:                        break;
        !          1971:        }
        !          1972:
        !          1973:        return ((struct in6_ifaddr *)ifa);
        !          1974: }
        !          1975:
        !          1976: /*
        !          1977:  * Convert IP6 address to printable (loggable) representation.
        !          1978:  */
        !          1979: static char digits[] = "0123456789abcdef";
        !          1980: static int ip6round = 0;
        !          1981: char *
        !          1982: ip6_sprintf(addr)
        !          1983:        struct in6_addr *addr;
        !          1984: {
        !          1985:        static char ip6buf[8][48];
        !          1986:        int i;
        !          1987:        char *cp;
        !          1988:        u_short *a = (u_short *)addr;
        !          1989:        u_char *d;
        !          1990:        int dcolon = 0;
        !          1991:
        !          1992:        ip6round = (ip6round + 1) & 7;
        !          1993:        cp = ip6buf[ip6round];
        !          1994:
        !          1995:        for (i = 0; i < 8; i++) {
        !          1996:                if (dcolon == 1) {
        !          1997:                        if (*a == 0) {
        !          1998:                                if (i == 7)
        !          1999:                                        *cp++ = ':';
        !          2000:                                a++;
        !          2001:                                continue;
        !          2002:                        } else
        !          2003:                                dcolon = 2;
        !          2004:                }
        !          2005:                if (*a == 0) {
        !          2006:                        if (dcolon == 0 && *(a + 1) == 0) {
        !          2007:                                if (i == 0)
        !          2008:                                        *cp++ = ':';
        !          2009:                                *cp++ = ':';
        !          2010:                                dcolon = 1;
        !          2011:                        } else {
        !          2012:                                *cp++ = '0';
        !          2013:                                *cp++ = ':';
        !          2014:                        }
        !          2015:                        a++;
        !          2016:                        continue;
        !          2017:                }
        !          2018:                d = (u_char *)a;
        !          2019:                *cp++ = digits[*d >> 4];
        !          2020:                *cp++ = digits[*d++ & 0xf];
        !          2021:                *cp++ = digits[*d >> 4];
        !          2022:                *cp++ = digits[*d & 0xf];
        !          2023:                *cp++ = ':';
        !          2024:                a++;
        !          2025:        }
        !          2026:        *--cp = 0;
        !          2027:        return (ip6buf[ip6round]);
        !          2028: }
        !          2029:
        !          2030: /*
        !          2031:  * Get a scope of the address. Node-local, link-local, site-local or global.
        !          2032:  */
        !          2033: int
        !          2034: in6_addrscope (addr)
        !          2035: struct in6_addr *addr;
        !          2036: {
        !          2037:        int scope;
        !          2038:
        !          2039:        if (addr->s6_addr8[0] == 0xfe) {
        !          2040:                scope = addr->s6_addr8[1] & 0xc0;
        !          2041:
        !          2042:                switch (scope) {
        !          2043:                case 0x80:
        !          2044:                        return IPV6_ADDR_SCOPE_LINKLOCAL;
        !          2045:                        break;
        !          2046:                case 0xc0:
        !          2047:                        return IPV6_ADDR_SCOPE_SITELOCAL;
        !          2048:                        break;
        !          2049:                default:
        !          2050:                        return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
        !          2051:                        break;
        !          2052:                }
        !          2053:        }
        !          2054:
        !          2055:
        !          2056:        if (addr->s6_addr8[0] == 0xff) {
        !          2057:                scope = addr->s6_addr8[1] & 0x0f;
        !          2058:
        !          2059:                /*
        !          2060:                 * due to other scope such as reserved,
        !          2061:                 * return scope doesn't work.
        !          2062:                 */
        !          2063:                switch (scope) {
        !          2064:                case IPV6_ADDR_SCOPE_INTFACELOCAL:
        !          2065:                        return IPV6_ADDR_SCOPE_INTFACELOCAL;
        !          2066:                        break;
        !          2067:                case IPV6_ADDR_SCOPE_LINKLOCAL:
        !          2068:                        return IPV6_ADDR_SCOPE_LINKLOCAL;
        !          2069:                        break;
        !          2070:                case IPV6_ADDR_SCOPE_SITELOCAL:
        !          2071:                        return IPV6_ADDR_SCOPE_SITELOCAL;
        !          2072:                        break;
        !          2073:                default:
        !          2074:                        return IPV6_ADDR_SCOPE_GLOBAL;
        !          2075:                        break;
        !          2076:                }
        !          2077:        }
        !          2078:
        !          2079:        if (bcmp(&in6addr_loopback, addr, sizeof(*addr) - 1) == 0) {
        !          2080:                if (addr->s6_addr8[15] == 1) /* loopback */
        !          2081:                        return IPV6_ADDR_SCOPE_INTFACELOCAL;
        !          2082:                if (addr->s6_addr8[15] == 0) /* unspecified */
        !          2083:                        return IPV6_ADDR_SCOPE_LINKLOCAL;
        !          2084:        }
        !          2085:
        !          2086:        return IPV6_ADDR_SCOPE_GLOBAL;
        !          2087: }
        !          2088:
        !          2089: int
        !          2090: in6_addr2scopeid(ifp, addr)
        !          2091:        struct ifnet *ifp;      /* must not be NULL */
        !          2092:        struct in6_addr *addr;  /* must not be NULL */
        !          2093: {
        !          2094:        int scope = in6_addrscope(addr);
        !          2095:
        !          2096:        switch(scope) {
        !          2097:        case IPV6_ADDR_SCOPE_INTFACELOCAL:
        !          2098:        case IPV6_ADDR_SCOPE_LINKLOCAL:
        !          2099:                /* XXX: we do not distinguish between a link and an I/F. */
        !          2100:                return (ifp->if_index);
        !          2101:
        !          2102:        case IPV6_ADDR_SCOPE_SITELOCAL:
        !          2103:                return (0);     /* XXX: invalid. */
        !          2104:
        !          2105:        default:
        !          2106:                return (0);     /* XXX: treat as global. */
        !          2107:        }
        !          2108: }
        !          2109:
        !          2110: int
        !          2111: in6_is_addr_deprecated(sa6)
        !          2112:        struct sockaddr_in6 *sa6;
        !          2113: {
        !          2114:        struct in6_ifaddr *ia;
        !          2115:
        !          2116:        for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
        !          2117:                if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
        !          2118:                    &sa6->sin6_addr) &&
        !          2119:                    (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0)
        !          2120:                        return (1); /* true */
        !          2121:
        !          2122:                /* XXX: do we still have to go thru the rest of the list? */
        !          2123:        }
        !          2124:
        !          2125:        return (0);             /* false */
        !          2126: }
        !          2127:
        !          2128: /*
        !          2129:  * return length of part which dst and src are equal
        !          2130:  * hard coding...
        !          2131:  */
        !          2132: int
        !          2133: in6_matchlen(src, dst)
        !          2134: struct in6_addr *src, *dst;
        !          2135: {
        !          2136:        int match = 0;
        !          2137:        u_char *s = (u_char *)src, *d = (u_char *)dst;
        !          2138:        u_char *lim = s + 16, r;
        !          2139:
        !          2140:        while (s < lim)
        !          2141:                if ((r = (*d++ ^ *s++)) != 0) {
        !          2142:                        while (r < 128) {
        !          2143:                                match++;
        !          2144:                                r <<= 1;
        !          2145:                        }
        !          2146:                        break;
        !          2147:                } else
        !          2148:                        match += 8;
        !          2149:        return match;
        !          2150: }
        !          2151:
        !          2152: int
        !          2153: in6_are_prefix_equal(p1, p2, len)
        !          2154:        struct in6_addr *p1, *p2;
        !          2155:        int len;
        !          2156: {
        !          2157:        int bytelen, bitlen;
        !          2158:
        !          2159:        /* sanity check */
        !          2160:        if (0 > len || len > 128) {
        !          2161:                log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
        !          2162:                    len);
        !          2163:                return (0);
        !          2164:        }
        !          2165:
        !          2166:        bytelen = len / 8;
        !          2167:        bitlen = len % 8;
        !          2168:
        !          2169:        if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
        !          2170:                return (0);
        !          2171:        /* len == 128 is ok because bitlen == 0 then */
        !          2172:        if (bitlen != 0 &&
        !          2173:            p1->s6_addr[bytelen] >> (8 - bitlen) !=
        !          2174:            p2->s6_addr[bytelen] >> (8 - bitlen))
        !          2175:                return (0);
        !          2176:
        !          2177:        return (1);
        !          2178: }
        !          2179:
        !          2180: void
        !          2181: in6_prefixlen2mask(maskp, len)
        !          2182:        struct in6_addr *maskp;
        !          2183:        int len;
        !          2184: {
        !          2185:        u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
        !          2186:        int bytelen, bitlen, i;
        !          2187:
        !          2188:        /* sanity check */
        !          2189:        if (0 > len || len > 128) {
        !          2190:                log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
        !          2191:                    len);
        !          2192:                return;
        !          2193:        }
        !          2194:
        !          2195:        bzero(maskp, sizeof(*maskp));
        !          2196:        bytelen = len / 8;
        !          2197:        bitlen = len % 8;
        !          2198:        for (i = 0; i < bytelen; i++)
        !          2199:                maskp->s6_addr[i] = 0xff;
        !          2200:        /* len == 128 is ok because bitlen == 0 then */
        !          2201:        if (bitlen)
        !          2202:                maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
        !          2203: }
        !          2204:
        !          2205: /*
        !          2206:  * return the best address out of the same scope
        !          2207:  */
        !          2208: struct in6_ifaddr *
        !          2209: in6_ifawithscope(oifp, dst)
        !          2210:        struct ifnet *oifp;
        !          2211:        struct in6_addr *dst;
        !          2212: {
        !          2213:        int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
        !          2214:        int blen = -1;
        !          2215:        struct ifaddr *ifa;
        !          2216:        struct ifnet *ifp;
        !          2217:        struct in6_ifaddr *ifa_best = NULL;
        !          2218:
        !          2219:        if (oifp == NULL) {
        !          2220:                printf("in6_ifawithscope: output interface is not specified\n");
        !          2221:                return (NULL);
        !          2222:        }
        !          2223:
        !          2224:        /*
        !          2225:         * We search for all addresses on all interfaces from the beginning.
        !          2226:         * Comparing an interface with the outgoing interface will be done
        !          2227:         * only at the final stage of tiebreaking.
        !          2228:         */
        !          2229:        for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
        !          2230:        {
        !          2231:                /*
        !          2232:                 * We can never take an address that breaks the scope zone
        !          2233:                 * of the destination.
        !          2234:                 */
        !          2235:                if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst))
        !          2236:                        continue;
        !          2237:
        !          2238:                TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          2239:                        int tlen = -1, dscopecmp, bscopecmp, matchcmp;
        !          2240:
        !          2241:                        if (ifa->ifa_addr->sa_family != AF_INET6)
        !          2242:                                continue;
        !          2243:
        !          2244:                        src_scope = in6_addrscope(IFA_IN6(ifa));
        !          2245:
        !          2246: #ifdef ADDRSELECT_DEBUG                /* should be removed after stabilization */
        !          2247:                        dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
        !          2248:                        printf("in6_ifawithscope: dst=%s bestaddr=%s, "
        !          2249:                               "newaddr=%s, scope=%x, dcmp=%d, bcmp=%d, "
        !          2250:                               "matchlen=%d, flgs=%x\n",
        !          2251:                               ip6_sprintf(dst),
        !          2252:                               ifa_best ? ip6_sprintf(&ifa_best->ia_addr.sin6_addr) : "none",
        !          2253:                               ip6_sprintf(IFA_IN6(ifa)), src_scope,
        !          2254:                               dscopecmp,
        !          2255:                               ifa_best ? IN6_ARE_SCOPE_CMP(src_scope, best_scope) : -1,
        !          2256:                               in6_matchlen(IFA_IN6(ifa), dst),
        !          2257:                               ((struct in6_ifaddr *)ifa)->ia6_flags);
        !          2258: #endif
        !          2259:
        !          2260:                        /*
        !          2261:                         * Don't use an address before completing DAD
        !          2262:                         * nor a duplicated address.
        !          2263:                         */
        !          2264:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
        !          2265:                            IN6_IFF_NOTREADY)
        !          2266:                                continue;
        !          2267:
        !          2268:                        /* XXX: is there any case to allow anycasts? */
        !          2269:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
        !          2270:                            IN6_IFF_ANYCAST)
        !          2271:                                continue;
        !          2272:
        !          2273:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
        !          2274:                            IN6_IFF_DETACHED)
        !          2275:                                continue;
        !          2276:
        !          2277:                        /*
        !          2278:                         * If this is the first address we find,
        !          2279:                         * keep it anyway.
        !          2280:                         */
        !          2281:                        if (ifa_best == NULL)
        !          2282:                                goto replace;
        !          2283:
        !          2284:                        /*
        !          2285:                         * ifa_best is never NULL beyond this line except
        !          2286:                         * within the block labeled "replace".
        !          2287:                         */
        !          2288:
        !          2289:                        /*
        !          2290:                         * If ifa_best has a smaller scope than dst and
        !          2291:                         * the current address has a larger one than
        !          2292:                         * (or equal to) dst, always replace ifa_best.
        !          2293:                         * Also, if the current address has a smaller scope
        !          2294:                         * than dst, ignore it unless ifa_best also has a
        !          2295:                         * smaller scope.
        !          2296:                         */
        !          2297:                        if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
        !          2298:                            IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
        !          2299:                                goto replace;
        !          2300:                        if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
        !          2301:                            IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
        !          2302:                                continue;
        !          2303:
        !          2304:                        /*
        !          2305:                         * A deprecated address SHOULD NOT be used in new
        !          2306:                         * communications if an alternate (non-deprecated)
        !          2307:                         * address is available and has sufficient scope.
        !          2308:                         * RFC 2462, Section 5.5.4.
        !          2309:                         */
        !          2310:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
        !          2311:                            IN6_IFF_DEPRECATED) {
        !          2312:                                /*
        !          2313:                                 * Ignore any deprecated addresses if
        !          2314:                                 * specified by configuration.
        !          2315:                                 */
        !          2316:                                if (!ip6_use_deprecated)
        !          2317:                                        continue;
        !          2318:
        !          2319:                                /*
        !          2320:                                 * If we have already found a non-deprecated
        !          2321:                                 * candidate, just ignore deprecated addresses.
        !          2322:                                 */
        !          2323:                                if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED)
        !          2324:                                    == 0)
        !          2325:                                        continue;
        !          2326:                        }
        !          2327:
        !          2328:                        /*
        !          2329:                         * A non-deprecated address is always preferred
        !          2330:                         * to a deprecated one regardless of scopes and
        !          2331:                         * address matching.
        !          2332:                         */
        !          2333:                        if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
        !          2334:                            (((struct in6_ifaddr *)ifa)->ia6_flags &
        !          2335:                             IN6_IFF_DEPRECATED) == 0)
        !          2336:                                goto replace;
        !          2337:
        !          2338:                        /*
        !          2339:                         * At this point, we have two cases:
        !          2340:                         * 1. we are looking at a non-deprecated address,
        !          2341:                         *    and ifa_best is also non-deprecated.
        !          2342:                         * 2. we are looking at a deprecated address,
        !          2343:                         *    and ifa_best is also deprecated.
        !          2344:                         * Also, we do not have to consider a case where
        !          2345:                         * the scope of if_best is larger(smaller) than dst and
        !          2346:                         * the scope of the current address is smaller(larger)
        !          2347:                         * than dst. Such a case has already been covered.
        !          2348:                         * Tiebreaking is done according to the following
        !          2349:                         * items:
        !          2350:                         * - the scope comparison between the address and
        !          2351:                         *   dst (dscopecmp)
        !          2352:                         * - the scope comparison between the address and
        !          2353:                         *   ifa_best (bscopecmp)
        !          2354:                         * - if the address match dst longer than ifa_best
        !          2355:                         *   (matchcmp)
        !          2356:                         * - if the address is on the outgoing I/F (outI/F)
        !          2357:                         *
        !          2358:                         * Roughly speaking, the selection policy is
        !          2359:                         * - the most important item is scope. The same scope
        !          2360:                         *   is best. Then search for a larger scope.
        !          2361:                         *   Smaller scopes are the last resort.
        !          2362:                         * - A deprecated address is chosen only when we have
        !          2363:                         *   no address that has an enough scope, but is
        !          2364:                         *   prefered to any addresses of smaller scopes.
        !          2365:                         * - Longest address match against dst is considered
        !          2366:                         *   only for addresses that has the same scope of dst.
        !          2367:                         * - If there is no other reasons to choose one,
        !          2368:                         *   addresses on the outgoing I/F are preferred.
        !          2369:                         *
        !          2370:                         * The precise decision table is as follows:
        !          2371:                         * dscopecmp bscopecmp matchcmp outI/F | replace?
        !          2372:                         *    !equal     equal      N/A    Yes |      Yes (1)
        !          2373:                         *    !equal     equal      N/A     No |       No (2)
        !          2374:                         *    larger    larger      N/A    N/A |       No (3)
        !          2375:                         *    larger   smaller      N/A    N/A |      Yes (4)
        !          2376:                         *   smaller    larger      N/A    N/A |      Yes (5)
        !          2377:                         *   smaller   smaller      N/A    N/A |       No (6)
        !          2378:                         *     equal   smaller      N/A    N/A |      Yes (7)
        !          2379:                         *     equal    larger       (already done)
        !          2380:                         *     equal     equal   larger    N/A |      Yes (8)
        !          2381:                         *     equal     equal  smaller    N/A |       No (9)
        !          2382:                         *     equal     equal    equal    Yes |      Yes (a)
        !          2383:                         *     eaual     eqaul    equal     No |       No (b)
        !          2384:                         */
        !          2385:                        dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
        !          2386:                        bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope);
        !          2387:
        !          2388:                        if (dscopecmp && bscopecmp == 0) {
        !          2389:                                if (oifp == ifp) /* (1) */
        !          2390:                                        goto replace;
        !          2391:                                continue; /* (2) */
        !          2392:                        }
        !          2393:                        if (dscopecmp > 0) {
        !          2394:                                if (bscopecmp > 0) /* (3) */
        !          2395:                                        continue;
        !          2396:                                goto replace; /* (4) */
        !          2397:                        }
        !          2398:                        if (dscopecmp < 0) {
        !          2399:                                if (bscopecmp > 0) /* (5) */
        !          2400:                                        goto replace;
        !          2401:                                continue; /* (6) */
        !          2402:                        }
        !          2403:
        !          2404:                        /* now dscopecmp must be 0 */
        !          2405:                        if (bscopecmp < 0)
        !          2406:                                goto replace; /* (7) */
        !          2407:
        !          2408:                        /*
        !          2409:                         * At last both dscopecmp and bscopecmp must be 0.
        !          2410:                         * We need address matching against dst for
        !          2411:                         * tiebreaking.
        !          2412:                         */
        !          2413:                        tlen = in6_matchlen(IFA_IN6(ifa), dst);
        !          2414:                        matchcmp = tlen - blen;
        !          2415:                        if (matchcmp > 0) /* (8) */
        !          2416:                                goto replace;
        !          2417:                        if (matchcmp < 0) /* (9) */
        !          2418:                                continue;
        !          2419:                        if (oifp == ifp) /* (a) */
        !          2420:                                goto replace;
        !          2421:                        continue; /* (b) */
        !          2422:
        !          2423:                  replace:
        !          2424:                        ifa_best = (struct in6_ifaddr *)ifa;
        !          2425:                        blen = tlen >= 0 ? tlen :
        !          2426:                                in6_matchlen(IFA_IN6(ifa), dst);
        !          2427:                        best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr);
        !          2428:                }
        !          2429:        }
        !          2430:
        !          2431:        /* count statistics for future improvements */
        !          2432:        if (ifa_best == NULL)
        !          2433:                ip6stat.ip6s_sources_none++;
        !          2434:        else {
        !          2435:                if (oifp == ifa_best->ia_ifp)
        !          2436:                        ip6stat.ip6s_sources_sameif[best_scope]++;
        !          2437:                else
        !          2438:                        ip6stat.ip6s_sources_otherif[best_scope]++;
        !          2439:
        !          2440:                if (best_scope == dst_scope)
        !          2441:                        ip6stat.ip6s_sources_samescope[best_scope]++;
        !          2442:                else
        !          2443:                        ip6stat.ip6s_sources_otherscope[best_scope]++;
        !          2444:
        !          2445:                if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
        !          2446:                        ip6stat.ip6s_sources_deprecated[best_scope]++;
        !          2447:        }
        !          2448:
        !          2449:        return (ifa_best);
        !          2450: }
        !          2451:
        !          2452: /*
        !          2453:  * return the best address out of the same scope. if no address was
        !          2454:  * found, return the first valid address from designated IF.
        !          2455:  */
        !          2456: struct in6_ifaddr *
        !          2457: in6_ifawithifp(ifp, dst)
        !          2458:        struct ifnet *ifp;
        !          2459:        struct in6_addr *dst;
        !          2460: {
        !          2461:        int dst_scope = in6_addrscope(dst), blen = -1, tlen;
        !          2462:        struct ifaddr *ifa;
        !          2463:        struct in6_ifaddr *besta = 0;
        !          2464:        struct in6_ifaddr *dep[2];      /*last-resort: deprecated*/
        !          2465:
        !          2466:        dep[0] = dep[1] = NULL;
        !          2467:
        !          2468:        /*
        !          2469:         * We first look for addresses in the same scope.
        !          2470:         * If there is one, return it.
        !          2471:         * If two or more, return one which matches the dst longest.
        !          2472:         * If none, return one of global addresses assigned other ifs.
        !          2473:         */
        !          2474:        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          2475:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !          2476:                        continue;
        !          2477:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
        !          2478:                        continue; /* XXX: is there any case to allow anycast? */
        !          2479:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
        !          2480:                        continue; /* don't use this interface */
        !          2481:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
        !          2482:                        continue;
        !          2483:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
        !          2484:                        if (ip6_use_deprecated)
        !          2485:                                dep[0] = (struct in6_ifaddr *)ifa;
        !          2486:                        continue;
        !          2487:                }
        !          2488:
        !          2489:                if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
        !          2490:                        /*
        !          2491:                         * call in6_matchlen() as few as possible
        !          2492:                         */
        !          2493:                        if (besta) {
        !          2494:                                if (blen == -1)
        !          2495:                                        blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
        !          2496:                                tlen = in6_matchlen(IFA_IN6(ifa), dst);
        !          2497:                                if (tlen > blen) {
        !          2498:                                        blen = tlen;
        !          2499:                                        besta = (struct in6_ifaddr *)ifa;
        !          2500:                                }
        !          2501:                        } else
        !          2502:                                besta = (struct in6_ifaddr *)ifa;
        !          2503:                }
        !          2504:        }
        !          2505:        if (besta)
        !          2506:                return (besta);
        !          2507:
        !          2508:        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          2509:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !          2510:                        continue;
        !          2511:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
        !          2512:                        continue; /* XXX: is there any case to allow anycast? */
        !          2513:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
        !          2514:                        continue; /* don't use this interface */
        !          2515:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
        !          2516:                        continue;
        !          2517:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
        !          2518:                        if (ip6_use_deprecated)
        !          2519:                                dep[1] = (struct in6_ifaddr *)ifa;
        !          2520:                        continue;
        !          2521:                }
        !          2522:
        !          2523:                return (struct in6_ifaddr *)ifa;
        !          2524:        }
        !          2525:
        !          2526:        /* use the last-resort values, that are, deprecated addresses */
        !          2527:        if (dep[0])
        !          2528:                return dep[0];
        !          2529:        if (dep[1])
        !          2530:                return dep[1];
        !          2531:
        !          2532:        return NULL;
        !          2533: }
        !          2534:
        !          2535: /*
        !          2536:  * perform DAD when interface becomes IFF_UP.
        !          2537:  */
        !          2538: void
        !          2539: in6_if_up(ifp)
        !          2540:        struct ifnet *ifp;
        !          2541: {
        !          2542:        struct ifaddr *ifa;
        !          2543:        struct in6_ifaddr *ia;
        !          2544:        int dad_delay;          /* delay ticks before DAD output */
        !          2545:
        !          2546:        /*
        !          2547:         * special cases, like 6to4, are handled in in6_ifattach
        !          2548:         */
        !          2549:        in6_ifattach(ifp, NULL);
        !          2550:
        !          2551:        dad_delay = 0;
        !          2552:        TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          2553:                if (ifa->ifa_addr->sa_family != AF_INET6)
        !          2554:                        continue;
        !          2555:                ia = (struct in6_ifaddr *)ifa;
        !          2556:                if (ia->ia6_flags & IN6_IFF_TENTATIVE)
        !          2557:                        nd6_dad_start(ifa, &dad_delay);
        !          2558:        }
        !          2559: }
        !          2560:
        !          2561: int
        !          2562: in6if_do_dad(ifp)
        !          2563:        struct ifnet *ifp;
        !          2564: {
        !          2565:        if ((ifp->if_flags & IFF_LOOPBACK) != 0)
        !          2566:                return (0);
        !          2567:
        !          2568:        switch (ifp->if_type) {
        !          2569:        case IFT_FAITH:
        !          2570:                /*
        !          2571:                 * These interfaces do not have the IFF_LOOPBACK flag,
        !          2572:                 * but loop packets back.  We do not have to do DAD on such
        !          2573:                 * interfaces.  We should even omit it, because loop-backed
        !          2574:                 * NS would confuse the DAD procedure.
        !          2575:                 */
        !          2576:                return (0);
        !          2577:        default:
        !          2578:                /*
        !          2579:                 * Our DAD routine requires the interface up and running.
        !          2580:                 * However, some interfaces can be up before the RUNNING
        !          2581:                 * status.  Additionaly, users may try to assign addresses
        !          2582:                 * before the interface becomes up (or running).
        !          2583:                 * We simply skip DAD in such a case as a work around.
        !          2584:                 * XXX: we should rather mark "tentative" on such addresses,
        !          2585:                 * and do DAD after the interface becomes ready.
        !          2586:                 */
        !          2587:                if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) !=
        !          2588:                    (IFF_UP|IFF_RUNNING))
        !          2589:                        return (0);
        !          2590:
        !          2591:                return (1);
        !          2592:        }
        !          2593: }
        !          2594:
        !          2595: /*
        !          2596:  * Calculate max IPv6 MTU through all the interfaces and store it
        !          2597:  * to in6_maxmtu.
        !          2598:  */
        !          2599: void
        !          2600: in6_setmaxmtu()
        !          2601: {
        !          2602:        unsigned long maxmtu = 0;
        !          2603:        struct ifnet *ifp;
        !          2604:
        !          2605:        for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
        !          2606:        {
        !          2607:                /* this function can be called during ifnet initialization */
        !          2608:                if (!ifp->if_afdata[AF_INET6])
        !          2609:                        continue;
        !          2610:                if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
        !          2611:                    IN6_LINKMTU(ifp) > maxmtu)
        !          2612:                        maxmtu = IN6_LINKMTU(ifp);
        !          2613:        }
        !          2614:        if (maxmtu)          /* update only when maxmtu is positive */
        !          2615:                in6_maxmtu = maxmtu;
        !          2616: }
        !          2617:
        !          2618: void *
        !          2619: in6_domifattach(ifp)
        !          2620:        struct ifnet *ifp;
        !          2621: {
        !          2622:        struct in6_ifextra *ext;
        !          2623:
        !          2624:        ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK);
        !          2625:        bzero(ext, sizeof(*ext));
        !          2626:
        !          2627:        ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat),
        !          2628:            M_IFADDR, M_WAITOK);
        !          2629:        bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat));
        !          2630:
        !          2631:        ext->icmp6_ifstat =
        !          2632:            (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat),
        !          2633:            M_IFADDR, M_WAITOK);
        !          2634:        bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat));
        !          2635:
        !          2636:        ext->nd_ifinfo = nd6_ifattach(ifp);
        !          2637:        return ext;
        !          2638: }
        !          2639:
        !          2640: void
        !          2641: in6_domifdetach(ifp, aux)
        !          2642:        struct ifnet *ifp;
        !          2643:        void *aux;
        !          2644: {
        !          2645:        struct in6_ifextra *ext = (struct in6_ifextra *)aux;
        !          2646:
        !          2647:        nd6_ifdetach(ext->nd_ifinfo);
        !          2648:        free(ext->in6_ifstat, M_IFADDR);
        !          2649:        free(ext->icmp6_ifstat, M_IFADDR);
        !          2650:        free(ext, M_IFADDR);
        !          2651: }

CVSweb