[BACK]Return to in6.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/in6.c, Revision 1.32.4.1

1.32.4.1! itojun      1: /*     $NetBSD: in6.c,v 1.32 2000/04/27 16:44:19 itojun Exp $  */
        !             2: /*     $KAME: in6.c,v 1.99 2000/07/11 17:00:58 jinmei Exp $    */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.18      itojun      7:  *
1.2       itojun      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the project nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
1.18      itojun     19:  *
1.2       itojun     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     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. All advertising materials mentioning features or use of this software
                     46:  *    must display the following acknowledgement:
                     47:  *     This product includes software developed by the University of
                     48:  *     California, Berkeley and its contributors.
                     49:  * 4. Neither the name of the University nor the names of its contributors
                     50:  *    may be used to endorse or promote products derived from this software
                     51:  *    without specific prior written permission.
                     52:  *
                     53:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     54:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     55:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     56:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     57:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     58:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     59:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     60:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     61:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     62:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     63:  * SUCH DAMAGE.
                     64:  *
                     65:  *     @(#)in.c        8.2 (Berkeley) 11/15/93
                     66:  */
                     67:
                     68: #include "opt_inet.h"
                     69:
                     70: #include <sys/param.h>
                     71: #include <sys/ioctl.h>
                     72: #include <sys/errno.h>
                     73: #include <sys/malloc.h>
                     74: #include <sys/socket.h>
                     75: #include <sys/socketvar.h>
                     76: #include <sys/sockio.h>
                     77: #include <sys/systm.h>
                     78: #include <sys/proc.h>
                     79: #include <sys/time.h>
                     80: #include <sys/kernel.h>
1.8       itojun     81: #include <sys/syslog.h>
1.2       itojun     82:
                     83: #include <net/if.h>
                     84: #include <net/if_types.h>
                     85: #include <net/route.h>
                     86: #include "gif.h"
                     87: #if NGIF > 0
                     88: #include <net/if_gif.h>
                     89: #endif
                     90: #include <net/if_dl.h>
                     91:
                     92: #include <netinet/in.h>
                     93: #include <netinet/in_var.h>
                     94: #include <net/if_ether.h>
                     95:
                     96: #include <netinet6/nd6.h>
1.16      itojun     97: #include <netinet/ip6.h>
1.8       itojun     98: #include <netinet6/ip6_var.h>
1.2       itojun     99: #include <netinet6/mld6_var.h>
                    100: #include <netinet6/ip6_mroute.h>
                    101: #include <netinet6/in6_ifattach.h>
                    102:
1.8       itojun    103: #include <net/net_osdep.h>
                    104:
1.20      itojun    105: /* enable backward compatibility code for obsoleted ioctls */
                    106: #define COMPAT_IN6IFIOCTL
                    107:
1.2       itojun    108: /*
                    109:  * Definitions of some costant IP6 addresses.
                    110:  */
                    111: const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
                    112: const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
                    113: const struct in6_addr in6addr_nodelocal_allnodes =
                    114:        IN6ADDR_NODELOCAL_ALLNODES_INIT;
                    115: const struct in6_addr in6addr_linklocal_allnodes =
                    116:        IN6ADDR_LINKLOCAL_ALLNODES_INIT;
                    117: const struct in6_addr in6addr_linklocal_allrouters =
                    118:        IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
                    119:
                    120: const struct in6_addr in6mask0 = IN6MASK0;
                    121: const struct in6_addr in6mask32 = IN6MASK32;
                    122: const struct in6_addr in6mask64 = IN6MASK64;
                    123: const struct in6_addr in6mask96 = IN6MASK96;
                    124: const struct in6_addr in6mask128 = IN6MASK128;
                    125:
                    126: static int in6_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
                    127:        struct ifnet *, struct proc *));
                    128:
                    129: /*
                    130:  * This structure is used to keep track of in6_multi chains which belong to
                    131:  * deleted interface addresses.
                    132:  */
                    133: static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */
                    134:
                    135: struct multi6_kludge {
                    136:        LIST_ENTRY(multi6_kludge) mk_entry;
                    137:        struct ifnet *mk_ifp;
                    138:        struct in6_multihead mk_head;
                    139: };
                    140:
                    141: /*
                    142:  * Check if the loopback entry will be automatically generated.
                    143:  *   if 0 returned, will not be automatically generated.
                    144:  *   if 1 returned, will be automatically generated.
                    145:  */
                    146: static int
                    147: in6_is_ifloop_auto(struct ifaddr *ifa)
                    148: {
                    149: #define SIN6(s) ((struct sockaddr_in6 *)s)
                    150:        /*
                    151:         * If RTF_CLONING is unset, or (IFF_LOOPBACK | IFF_POINTOPOINT),
                    152:         * or netmask is all0 or all1, then cloning will not happen,
                    153:         * then we can't rely on its loopback entry generation.
                    154:         */
                    155:        if ((ifa->ifa_flags & RTF_CLONING) == 0 ||
                    156:            (ifa->ifa_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) ||
                    157:            (SIN6(ifa->ifa_netmask)->sin6_len == sizeof(struct sockaddr_in6)
                    158:             &&
                    159:             IN6_ARE_ADDR_EQUAL(&SIN6(ifa->ifa_netmask)->sin6_addr,
                    160:                                &in6mask128)) ||
                    161:            ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_len == 0)
                    162:                return 0;
                    163:        else
                    164:                return 1;
                    165: #undef SIN6
                    166: }
                    167:
                    168: /*
                    169:  * Subroutine for in6_ifaddloop() and in6_ifremloop().
                    170:  * This routine does actual work.
                    171:  */
                    172: static void
                    173: in6_ifloop_request(int cmd, struct ifaddr *ifa)
                    174: {
                    175:        struct sockaddr_in6 lo_sa;
                    176:        struct sockaddr_in6 all1_sa;
1.32.4.1! itojun    177:        struct rtentry *nrt = NULL, **nrtp = NULL;
1.2       itojun    178:
                    179:        bzero(&lo_sa, sizeof(lo_sa));
                    180:        bzero(&all1_sa, sizeof(all1_sa));
                    181:        lo_sa.sin6_family = AF_INET6;
                    182:        lo_sa.sin6_len = sizeof(struct sockaddr_in6);
                    183:        all1_sa = lo_sa;
                    184:        lo_sa.sin6_addr = in6addr_loopback;
                    185:        all1_sa.sin6_addr = in6mask128;
                    186:
1.32.4.1! itojun    187:        /*
        !           188:         * So we add or remove static loopback entry, here.
        !           189:         * This request for deletion could fail, e.g. when we remove
        !           190:         * an address right after adding it.
        !           191:         */
        !           192:        if (cmd == RTM_ADD)
        !           193:                nrtp = &nrt;
1.2       itojun    194:        rtrequest(cmd, ifa->ifa_addr,
                    195:                  (struct sockaddr *)&lo_sa,
                    196:                  (struct sockaddr *)&all1_sa,
1.32.4.1! itojun    197:                  RTF_UP|RTF_HOST, nrtp);
1.2       itojun    198:
                    199:        /*
                    200:         * Make sure rt_ifa be equal to IFA, the second argument of the
                    201:         * function.
                    202:         * We need this because when we refer rt_ifa->ia6_flags in ip6_input,
                    203:         * we assume that the rt_ifa points to the address instead of the
                    204:         * loopback address.
                    205:         */
                    206:        if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
1.10      thorpej   207:                IFAFREE(nrt->rt_ifa);
                    208:                IFAREF(ifa);
1.2       itojun    209:                nrt->rt_ifa = ifa;
                    210:        }
                    211:        if (nrt)
                    212:                nrt->rt_refcnt--;
                    213: }
                    214:
                    215: /*
                    216:  * Add ownaddr as loopback rtentry, if necessary(ex. on p2p link).
                    217:  * Because, KAME needs loopback rtentry for ownaddr check in
                    218:  * ip6_input().
                    219:  */
                    220: static void
                    221: in6_ifaddloop(struct ifaddr *ifa)
                    222: {
                    223:        if (!in6_is_ifloop_auto(ifa)) {
                    224:                struct rtentry *rt;
                    225:
                    226:                /* If there is no loopback entry, allocate one. */
1.9       itojun    227:                rt = rtalloc1(ifa->ifa_addr, 0);
1.2       itojun    228:                if (rt == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
                    229:                        in6_ifloop_request(RTM_ADD, ifa);
                    230:                if (rt)
                    231:                        rt->rt_refcnt--;
                    232:        }
                    233: }
                    234:
                    235: /*
                    236:  * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
                    237:  * if it exists.
                    238:  */
                    239: static void
                    240: in6_ifremloop(struct ifaddr *ifa)
                    241: {
                    242:        if (!in6_is_ifloop_auto(ifa)) {
                    243:                struct in6_ifaddr *ia;
                    244:                int ia_count = 0;
                    245:
                    246:                /* If only one ifa for the loopback entry, delete it. */
                    247:                for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
1.8       itojun    248:                        if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa),
1.2       itojun    249:                                               &ia->ia_addr.sin6_addr)) {
                    250:                                ia_count++;
                    251:                                if (ia_count > 1)
                    252:                                        break;
                    253:                        }
                    254:                }
                    255:                if (ia_count == 1)
                    256:                        in6_ifloop_request(RTM_DELETE, ifa);
                    257:        }
                    258: }
                    259:
                    260: int
1.8       itojun    261: in6_ifindex2scopeid(idx)
                    262:        int idx;
                    263: {
                    264:        struct ifnet *ifp;
                    265:        struct ifaddr *ifa;
                    266:        struct sockaddr_in6 *sin6;
                    267:
                    268:        if (idx < 0 || if_index < idx)
                    269:                return -1;
                    270:        ifp = ifindex2ifnet[idx];
                    271:
                    272:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
                    273:        {
                    274:                if (ifa->ifa_addr->sa_family != AF_INET6)
                    275:                        continue;
                    276:                sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
                    277:                if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
                    278:                        return sin6->sin6_scope_id & 0xffff;
                    279:        }
                    280:
                    281:        return -1;
                    282: }
                    283:
                    284: int
1.2       itojun    285: in6_mask2len(mask)
                    286:        struct in6_addr *mask;
                    287: {
                    288:        int x, y;
                    289:
                    290:        for (x = 0; x < sizeof(*mask); x++) {
                    291:                if (mask->s6_addr8[x] != 0xff)
                    292:                        break;
                    293:        }
                    294:        y = 0;
                    295:        if (x < sizeof(*mask)) {
                    296:                for (y = 0; y < 8; y++) {
                    297:                        if ((mask->s6_addr8[x] & (0x80 >> y)) == 0)
                    298:                                break;
                    299:                }
                    300:        }
                    301:        return x * 8 + y;
                    302: }
                    303:
                    304: void
                    305: in6_len2mask(mask, len)
                    306:        struct in6_addr *mask;
                    307:        int len;
                    308: {
                    309:        int i;
                    310:
                    311:        bzero(mask, sizeof(*mask));
                    312:        for (i = 0; i < len / 8; i++)
                    313:                mask->s6_addr8[i] = 0xff;
                    314:        if (len % 8)
                    315:                mask->s6_addr8[i] = (0xff00 >> (len % 8)) & 0xff;
                    316: }
                    317:
                    318: #define ifa2ia6(ifa)   ((struct in6_ifaddr *)(ifa))
1.19      itojun    319: #define ia62ifa(ia6)   (&((ia6)->ia_ifa))
1.2       itojun    320:
                    321: int
                    322: in6_control(so, cmd, data, ifp, p)
                    323:        struct  socket *so;
                    324:        u_long cmd;
                    325:        caddr_t data;
                    326:        struct ifnet *ifp;
                    327:        struct proc *p;
                    328: {
                    329:        struct  in6_ifreq *ifr = (struct in6_ifreq *)data;
                    330:        struct  in6_ifaddr *ia, *oia;
                    331:        struct  in6_aliasreq *ifra = (struct in6_aliasreq *)data;
1.20      itojun    332:        struct  sockaddr_in6 oldaddr;
                    333: #ifdef COMPAT_IN6IFIOCTL
1.30      itojun    334:        struct  sockaddr_in6 net;
1.20      itojun    335: #endif
1.24      itojun    336:        int error = 0, hostIsNew, prefixIsNew;
                    337:        int newifaddr;
1.8       itojun    338:        time_t time_second = (time_t)time.tv_sec;
                    339:        int privileged;
                    340:
                    341:        privileged = 0;
                    342:        if (p && !suser(p->p_ucred, &p->p_acflag))
                    343:                privileged++;
1.2       itojun    344:
                    345:        /*
                    346:         * xxx should prevent processes for link-local addresses?
                    347:         */
                    348: #if NGIF > 0
                    349:        if (ifp && ifp->if_type == IFT_GIF) {
                    350:                switch (cmd) {
                    351:                case SIOCSIFPHYADDR_IN6:
1.8       itojun    352:                        if (!privileged)
1.2       itojun    353:                                return(EPERM);
                    354:                        /*fall through*/
                    355:                case SIOCGIFPSRCADDR_IN6:
                    356:                case SIOCGIFPDSTADDR_IN6:
                    357:                        return gif_ioctl(ifp, cmd, data);
                    358:                }
                    359:        }
                    360: #endif
                    361:        switch (cmd) {
                    362:        case SIOCGETSGCNT_IN6:
                    363:        case SIOCGETMIFCNT_IN6:
                    364:                return (mrt6_ioctl(cmd, data));
                    365:        }
                    366:
1.20      itojun    367:        if (ifp == NULL)
1.2       itojun    368:                return(EOPNOTSUPP);
                    369:
                    370:        switch (cmd) {
                    371:        case SIOCSNDFLUSH_IN6:
                    372:        case SIOCSPFXFLUSH_IN6:
                    373:        case SIOCSRTRFLUSH_IN6:
1.8       itojun    374:        case SIOCSDEFIFACE_IN6:
1.31      itojun    375:        case SIOCSIFINFO_FLAGS:
1.8       itojun    376:                if (!privileged)
1.2       itojun    377:                        return(EPERM);
                    378:                /*fall through*/
                    379:        case SIOCGIFINFO_IN6:
                    380:        case SIOCGDRLST_IN6:
                    381:        case SIOCGPRLST_IN6:
                    382:        case SIOCGNBRINFO_IN6:
1.8       itojun    383:        case SIOCGDEFIFACE_IN6:
1.2       itojun    384:                return(nd6_ioctl(cmd, data, ifp));
                    385:        }
                    386:
                    387:        switch (cmd) {
                    388:        case SIOCSIFPREFIX_IN6:
                    389:        case SIOCDIFPREFIX_IN6:
                    390:        case SIOCAIFPREFIX_IN6:
                    391:        case SIOCCIFPREFIX_IN6:
                    392:        case SIOCSGIFPREFIX_IN6:
1.8       itojun    393:                if (!privileged)
1.2       itojun    394:                        return(EPERM);
                    395:                /*fall through*/
                    396:        case SIOCGIFPREFIX_IN6:
1.8       itojun    397:                return(in6_prefix_ioctl(so, cmd, data, ifp));
1.2       itojun    398:        }
                    399:
                    400:        switch (cmd) {
                    401:        case SIOCALIFADDR:
                    402:        case SIOCDLIFADDR:
1.8       itojun    403:                if (!privileged)
1.2       itojun    404:                        return(EPERM);
                    405:                /*fall through*/
                    406:        case SIOCGLIFADDR:
                    407:                return in6_lifaddr_ioctl(so, cmd, data, ifp, p);
                    408:        }
                    409:
                    410:        /*
                    411:         * Find address for this interface, if it exists.
                    412:         */
1.20      itojun    413:        if (ifra->ifra_addr.sin6_family == AF_INET6) { /* XXX */
1.8       itojun    414:                struct sockaddr_in6 *sa6 =
                    415:                        (struct sockaddr_in6 *)&ifra->ifra_addr;
                    416:
                    417:                if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
                    418:                        if (sa6->sin6_addr.s6_addr16[1] == 0) {
1.2       itojun    419:                                /* interface ID is not embedded by the user */
1.8       itojun    420:                                sa6->sin6_addr.s6_addr16[1] =
                    421:                                        htons(ifp->if_index);
1.30      itojun    422:                        } else if (sa6->sin6_addr.s6_addr16[1] !=
1.20      itojun    423:                                    htons(ifp->if_index)) {
                    424:                                return(EINVAL); /* ifid is contradict */
                    425:                        }
1.8       itojun    426:                        if (sa6->sin6_scope_id) {
                    427:                                if (sa6->sin6_scope_id !=
                    428:                                    (u_int32_t)ifp->if_index)
                    429:                                        return(EINVAL);
                    430:                                sa6->sin6_scope_id = 0; /* XXX: good way? */
                    431:                        }
1.2       itojun    432:                }
1.20      itojun    433:                ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
1.2       itojun    434:        }
                    435:
                    436:        switch (cmd) {
                    437:
                    438:        case SIOCDIFADDR_IN6:
1.20      itojun    439:                /*
                    440:                 * for IPv4, we look for existing in6_ifaddr here to allow
                    441:                 * "ifconfig if0 delete" to remove first IPv4 address on the
                    442:                 * interface.  For IPv6, as the spec allow multiple interface
                    443:                 * address from the day one, we consider "remove the first one"
                    444:                 * semantics to be not preferrable.
                    445:                 */
                    446:                if (ia == NULL)
1.2       itojun    447:                        return(EADDRNOTAVAIL);
                    448:                /* FALLTHROUGH */
                    449:        case SIOCAIFADDR_IN6:
                    450:        case SIOCSIFADDR_IN6:
1.20      itojun    451: #ifdef COMPAT_IN6IFIOCTL
                    452:        case SIOCSIFDSTADDR_IN6:
1.2       itojun    453:        case SIOCSIFNETMASK_IN6:
1.20      itojun    454:                /*
                    455:                 * Since IPv6 allows a node to assign multiple addresses
                    456:                 * on a single interface, SIOCSIFxxx ioctls are not suitable
                    457:                 * and should be unused.
                    458:                 */
1.30      itojun    459: #endif
1.20      itojun    460:                if (ifra->ifra_addr.sin6_family != AF_INET6)
                    461:                        return(EAFNOSUPPORT);
1.8       itojun    462:                if (!privileged)
1.2       itojun    463:                        return(EPERM);
1.20      itojun    464:                if (ia == NULL) {
1.2       itojun    465:                        ia = (struct in6_ifaddr *)
                    466:                                malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
                    467:                        if (ia == NULL)
                    468:                                return (ENOBUFS);
                    469:                        bzero((caddr_t)ia, sizeof(*ia));
1.20      itojun    470:                        /* Initialize the address and masks */
1.2       itojun    471:                        ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
1.20      itojun    472:                        ia->ia_addr.sin6_family = AF_INET6;
                    473:                        ia->ia_addr.sin6_len = sizeof(ia->ia_addr);
                    474:                        if (ifp->if_flags & IFF_POINTOPOINT) {
1.23      itojun    475:                                ia->ia_ifa.ifa_dstaddr
                    476:                                        = (struct sockaddr *)&ia->ia_dstaddr;
1.20      itojun    477:                                ia->ia_dstaddr.sin6_family = AF_INET6;
                    478:                                ia->ia_dstaddr.sin6_len = sizeof(ia->ia_dstaddr);
1.23      itojun    479:                        } else {
                    480:                                ia->ia_ifa.ifa_dstaddr = NULL;
                    481:                                bzero(&ia->ia_dstaddr, sizeof(ia->ia_dstaddr));
1.20      itojun    482:                        }
1.2       itojun    483:                        ia->ia_ifa.ifa_netmask
                    484:                                = (struct sockaddr *)&ia->ia_prefixmask;
                    485:
                    486:                        ia->ia_ifp = ifp;
                    487:                        if ((oia = in6_ifaddr) != NULL) {
                    488:                                for ( ; oia->ia_next; oia = oia->ia_next)
                    489:                                        continue;
                    490:                                oia->ia_next = ia;
                    491:                        } else
                    492:                                in6_ifaddr = ia;
1.10      thorpej   493:                        IFAREF(&ia->ia_ifa);
                    494:
1.15      itojun    495:                        TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,
                    496:                            ifa_list);
1.10      thorpej   497:                        IFAREF(&ia->ia_ifa);
1.24      itojun    498:
                    499:                        newifaddr = 1;
                    500:                } else
                    501:                        newifaddr = 0;
1.2       itojun    502:
                    503:                if (cmd == SIOCAIFADDR_IN6) {
                    504:                        /* sanity for overflow - beware unsigned */
                    505:                        struct in6_addrlifetime *lt;
                    506:                        lt = &ifra->ifra_lifetime;
                    507:                        if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
                    508:                         && lt->ia6t_vltime + time_second < time_second) {
                    509:                                return EINVAL;
                    510:                        }
                    511:                        if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
                    512:                         && lt->ia6t_pltime + time_second < time_second) {
                    513:                                return EINVAL;
                    514:                        }
                    515:                }
                    516:                break;
                    517:
                    518:        case SIOCGIFADDR_IN6:
                    519:                /* This interface is basically deprecated. use SIOCGIFCONF. */
                    520:                /* fall through */
                    521:        case SIOCGIFAFLAG_IN6:
                    522:        case SIOCGIFNETMASK_IN6:
                    523:        case SIOCGIFDSTADDR_IN6:
1.8       itojun    524:        case SIOCGIFALIFETIME_IN6:
1.2       itojun    525:                /* must think again about its semantics */
1.20      itojun    526:                if (ia == NULL)
1.2       itojun    527:                        return(EADDRNOTAVAIL);
                    528:                break;
                    529:        case SIOCSIFALIFETIME_IN6:
                    530:            {
                    531:                struct in6_addrlifetime *lt;
                    532:
1.8       itojun    533:                if (!privileged)
1.2       itojun    534:                        return(EPERM);
1.20      itojun    535:                if (ia == NULL)
1.2       itojun    536:                        return(EADDRNOTAVAIL);
                    537:                /* sanity for overflow - beware unsigned */
                    538:                lt = &ifr->ifr_ifru.ifru_lifetime;
                    539:                if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME
                    540:                 && lt->ia6t_vltime + time_second < time_second) {
                    541:                        return EINVAL;
                    542:                }
                    543:                if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME
                    544:                 && lt->ia6t_pltime + time_second < time_second) {
                    545:                        return EINVAL;
                    546:                }
                    547:                break;
                    548:            }
                    549:        }
                    550:
                    551:        switch (cmd) {
                    552:
                    553:        case SIOCGIFADDR_IN6:
                    554:                ifr->ifr_addr = ia->ia_addr;
                    555:                break;
                    556:
                    557:        case SIOCGIFDSTADDR_IN6:
                    558:                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                    559:                        return(EINVAL);
                    560:                ifr->ifr_dstaddr = ia->ia_dstaddr;
                    561:                break;
                    562:
                    563:        case SIOCGIFNETMASK_IN6:
                    564:                ifr->ifr_addr = ia->ia_prefixmask;
                    565:                break;
                    566:
                    567:        case SIOCGIFAFLAG_IN6:
                    568:                ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;
                    569:                break;
1.18      itojun    570:
1.8       itojun    571:        case SIOCGIFSTAT_IN6:
                    572:                if (ifp == NULL)
                    573:                        return EINVAL;
                    574:                if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax
                    575:                 || in6_ifstat[ifp->if_index] == NULL) {
                    576:                        /* return EAFNOSUPPORT? */
                    577:                        bzero(&ifr->ifr_ifru.ifru_stat,
                    578:                                sizeof(ifr->ifr_ifru.ifru_stat));
                    579:                } else
                    580:                        ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index];
                    581:                break;
                    582:
                    583:        case SIOCGIFSTAT_ICMP6:
                    584:                if (ifp == NULL)
                    585:                        return EINVAL;
                    586:                if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax ||
                    587:                    icmp6_ifstat[ifp->if_index] == NULL) {
                    588:                        /* return EAFNOSUPPORT? */
                    589:                        bzero(&ifr->ifr_ifru.ifru_stat,
                    590:                                sizeof(ifr->ifr_ifru.ifru_icmp6stat));
                    591:                } else
                    592:                        ifr->ifr_ifru.ifru_icmp6stat =
                    593:                                *icmp6_ifstat[ifp->if_index];
                    594:                break;
                    595:
1.20      itojun    596: #ifdef COMPAT_IN6IFIOCTL               /* should be unused */
1.2       itojun    597:        case SIOCSIFDSTADDR_IN6:
                    598:                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                    599:                        return(EINVAL);
                    600:                oldaddr = ia->ia_dstaddr;
                    601:                ia->ia_dstaddr = ifr->ifr_dstaddr;
                    602:
                    603:                /* link-local index check */
                    604:                if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
                    605:                        if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
                    606:                                /* interface ID is not embedded by the user */
                    607:                                ia->ia_dstaddr.sin6_addr.s6_addr16[1]
                    608:                                        = htons(ifp->if_index);
1.30      itojun    609:                        } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
1.2       itojun    610:                                    htons(ifp->if_index)) {
1.20      itojun    611:                                ia->ia_dstaddr = oldaddr;
                    612:                                return(EINVAL); /* ifid is contradict */
                    613:                        }
1.2       itojun    614:                }
                    615:
                    616:                if (ifp->if_ioctl && (error = (ifp->if_ioctl)
                    617:                                      (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
                    618:                        ia->ia_dstaddr = oldaddr;
                    619:                        return(error);
                    620:                }
                    621:                if (ia->ia_flags & IFA_ROUTE) {
                    622:                        ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
                    623:                        rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
                    624:                        ia->ia_ifa.ifa_dstaddr =
                    625:                                (struct sockaddr *)&ia->ia_dstaddr;
                    626:                        rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
                    627:                }
                    628:                break;
                    629:
1.30      itojun    630: #endif
1.2       itojun    631:        case SIOCGIFALIFETIME_IN6:
                    632:                ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;
                    633:                break;
                    634:
                    635:        case SIOCSIFALIFETIME_IN6:
                    636:                ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;
                    637:                /* for sanity */
                    638:                if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
                    639:                        ia->ia6_lifetime.ia6t_expire =
                    640:                                time_second + ia->ia6_lifetime.ia6t_vltime;
                    641:                } else
                    642:                        ia->ia6_lifetime.ia6t_expire = 0;
                    643:                if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
                    644:                        ia->ia6_lifetime.ia6t_preferred =
                    645:                                time_second + ia->ia6_lifetime.ia6t_pltime;
                    646:                } else
                    647:                        ia->ia6_lifetime.ia6t_preferred = 0;
                    648:                break;
                    649:
                    650:        case SIOCSIFADDR_IN6:
1.24      itojun    651:                error = in6_ifinit(ifp, ia, &ifr->ifr_addr, 1);
1.25      itojun    652: #if 0
1.26      itojun    653:                /*
                    654:                 * the code chokes if we are to assign multiple addresses with
                    655:                 * the same address prefix (rtinit() will return EEXIST, which
                    656:                 * is not fatal actually).  we will get memory leak if we
                    657:                 * don't do it.
                    658:                 * -> we may want to hide EEXIST from rtinit().
                    659:                 */
1.24      itojun    660:   undo:
                    661:                if (error && newifaddr) {
                    662:                        TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
                    663:                        IFAFREE(&ia->ia_ifa);
                    664:
                    665:                        oia = ia;
                    666:                        if (oia == (ia = in6_ifaddr))
                    667:                                in6_ifaddr = ia->ia_next;
                    668:                        else {
                    669:                                while (ia->ia_next && (ia->ia_next != oia))
                    670:                                        ia = ia->ia_next;
                    671:                                if (ia->ia_next)
                    672:                                        ia->ia_next = oia->ia_next;
                    673:                                else {
                    674:                                        printf("Didn't unlink in6_ifaddr "
                    675:                                            "from list\n");
                    676:                                }
                    677:                        }
1.32      itojun    678:                        IFAFREE(&oia->ia_ifa);
1.24      itojun    679:                }
1.25      itojun    680: #endif
1.24      itojun    681:                return error;
1.2       itojun    682:
1.20      itojun    683: #ifdef COMPAT_IN6IFIOCTL               /* XXX should be unused */
1.2       itojun    684:        case SIOCSIFNETMASK_IN6:
                    685:                ia->ia_prefixmask = ifr->ifr_addr;
                    686:                bzero(&net, sizeof(net));
                    687:                net.sin6_len = sizeof(struct sockaddr_in6);
                    688:                net.sin6_family = AF_INET6;
                    689:                net.sin6_port = htons(0);
                    690:                net.sin6_flowinfo = htonl(0);
                    691:                net.sin6_addr.s6_addr32[0]
                    692:                        = ia->ia_addr.sin6_addr.s6_addr32[0] &
                    693:                                ia->ia_prefixmask.sin6_addr.s6_addr32[0];
                    694:                net.sin6_addr.s6_addr32[1]
                    695:                        = ia->ia_addr.sin6_addr.s6_addr32[1] &
                    696:                                ia->ia_prefixmask.sin6_addr.s6_addr32[1];
                    697:                net.sin6_addr.s6_addr32[2]
                    698:                        = ia->ia_addr.sin6_addr.s6_addr32[2] &
                    699:                                ia->ia_prefixmask.sin6_addr.s6_addr32[2];
                    700:                net.sin6_addr.s6_addr32[3]
                    701:                        = ia->ia_addr.sin6_addr.s6_addr32[3] &
                    702:                                ia->ia_prefixmask.sin6_addr.s6_addr32[3];
                    703:                ia->ia_net = net;
                    704:                break;
1.30      itojun    705: #endif
1.2       itojun    706:
                    707:        case SIOCAIFADDR_IN6:
                    708:                prefixIsNew = 0;
                    709:                hostIsNew = 1;
                    710:
                    711:                if (ifra->ifra_addr.sin6_len == 0) {
                    712:                        ifra->ifra_addr = ia->ia_addr;
                    713:                        hostIsNew = 0;
                    714:                } else if (IN6_ARE_ADDR_EQUAL(&ifra->ifra_addr.sin6_addr,
                    715:                                              &ia->ia_addr.sin6_addr))
                    716:                        hostIsNew = 0;
                    717:
1.20      itojun    718:                /* Validate address families: */
                    719:                /*
                    720:                 * The destination address for a p2p link must have a family
                    721:                 * of AF_UNSPEC or AF_INET6.
                    722:                 */
                    723:                if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
                    724:                    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&
                    725:                    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)
                    726:                        return(EAFNOSUPPORT);
                    727:                /*
                    728:                 * The prefixmask must have a family of AF_UNSPEC or AF_INET6.
                    729:                 */
                    730:                if (ifra->ifra_prefixmask.sin6_family != AF_INET6 &&
                    731:                    ifra->ifra_prefixmask.sin6_family != AF_UNSPEC)
                    732:                        return(EAFNOSUPPORT);
                    733:
1.2       itojun    734:                if (ifra->ifra_prefixmask.sin6_len) {
                    735:                        in6_ifscrub(ifp, ia);
                    736:                        ia->ia_prefixmask = ifra->ifra_prefixmask;
                    737:                        prefixIsNew = 1;
                    738:                }
                    739:                if ((ifp->if_flags & IFF_POINTOPOINT) &&
                    740:                    (ifra->ifra_dstaddr.sin6_family == AF_INET6)) {
                    741:                        in6_ifscrub(ifp, ia);
1.17      itojun    742:                        oldaddr = ia->ia_dstaddr;
1.2       itojun    743:                        ia->ia_dstaddr = ifra->ifra_dstaddr;
                    744:                        /* link-local index check: should be a separate function? */
                    745:                        if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_dstaddr.sin6_addr)) {
                    746:                                if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] == 0) {
                    747:                                        /*
                    748:                                         * interface ID is not embedded by
                    749:                                         * the user
                    750:                                         */
                    751:                                        ia->ia_dstaddr.sin6_addr.s6_addr16[1]
                    752:                                                = htons(ifp->if_index);
1.20      itojun    753:                                } else if (ia->ia_dstaddr.sin6_addr.s6_addr16[1] !=
                    754:                                            htons(ifp->if_index)) {
                    755:                                        ia->ia_dstaddr = oldaddr;
                    756:                                        return(EINVAL); /* ifid is contradict */
1.2       itojun    757:                                }
                    758:                        }
                    759:                        prefixIsNew = 1; /* We lie; but effect's the same */
                    760:                }
1.24      itojun    761:                if (hostIsNew || prefixIsNew) {
1.2       itojun    762:                        error = in6_ifinit(ifp, ia, &ifra->ifra_addr, 0);
1.25      itojun    763: #if 0
1.24      itojun    764:                        if (error)
                    765:                                goto undo;
1.25      itojun    766: #endif
1.24      itojun    767:                }
1.20      itojun    768:                if (hostIsNew && (ifp->if_flags & IFF_MULTICAST)) {
1.2       itojun    769:                        int error_local = 0;
                    770:
                    771:                        /*
                    772:                         * join solicited multicast addr for new host id
                    773:                         */
                    774:                        struct in6_addr llsol;
                    775:                        bzero(&llsol, sizeof(struct in6_addr));
                    776:                        llsol.s6_addr16[0] = htons(0xff02);
                    777:                        llsol.s6_addr16[1] = htons(ifp->if_index);
                    778:                        llsol.s6_addr32[1] = 0;
                    779:                        llsol.s6_addr32[2] = htonl(1);
                    780:                        llsol.s6_addr32[3] =
                    781:                                ifra->ifra_addr.sin6_addr.s6_addr32[3];
                    782:                        llsol.s6_addr8[12] = 0xff;
                    783:                        (void)in6_addmulti(&llsol, ifp, &error_local);
                    784:                        if (error == 0)
                    785:                                error = error_local;
                    786:                }
                    787:
                    788:                ia->ia6_flags = ifra->ifra_flags;
                    789:                ia->ia6_flags &= ~IN6_IFF_DUPLICATED;   /*safety*/
                    790:
                    791:                ia->ia6_lifetime = ifra->ifra_lifetime;
                    792:                /* for sanity */
                    793:                if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
                    794:                        ia->ia6_lifetime.ia6t_expire =
                    795:                                time_second + ia->ia6_lifetime.ia6t_vltime;
                    796:                } else
                    797:                        ia->ia6_lifetime.ia6t_expire = 0;
                    798:                if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
                    799:                        ia->ia6_lifetime.ia6t_preferred =
                    800:                                time_second + ia->ia6_lifetime.ia6t_pltime;
                    801:                } else
                    802:                        ia->ia6_lifetime.ia6t_preferred = 0;
                    803:
                    804:                /*
1.18      itojun    805:                 * Perform DAD, if needed.
1.2       itojun    806:                 * XXX It may be of use, if we can administratively
                    807:                 * disable DAD.
                    808:                 */
                    809:                switch (ifp->if_type) {
1.6       is        810:                case IFT_ARCNET:
1.2       itojun    811:                case IFT_ETHER:
                    812:                case IFT_FDDI:
                    813: #if 0
                    814:                case IFT_ATM:
                    815:                case IFT_SLIP:
                    816:                case IFT_PPP:
                    817: #endif
                    818:                        ia->ia6_flags |= IN6_IFF_TENTATIVE;
1.15      itojun    819:                        nd6_dad_start(&ia->ia_ifa, NULL);
1.2       itojun    820:                        break;
1.8       itojun    821:                case IFT_FAITH:
1.2       itojun    822:                case IFT_GIF:
                    823:                case IFT_LOOP:
                    824:                default:
                    825:                        break;
                    826:                }
                    827:
1.8       itojun    828:                if (hostIsNew) {
                    829:                        int iilen;
                    830:                        int error_local = 0;
                    831:
                    832:                        iilen = (sizeof(ia->ia_prefixmask.sin6_addr) << 3) -
                    833:                                in6_mask2len(&ia->ia_prefixmask.sin6_addr);
                    834:                        error_local = in6_prefix_add_ifid(iilen, ia);
                    835:                        if (error == 0)
                    836:                                error = error_local;
                    837:                }
                    838:
1.2       itojun    839:                return(error);
                    840:
                    841:        case SIOCDIFADDR_IN6:
1.10      thorpej   842:                in6_purgeaddr(&ia->ia_ifa, ifp);
1.2       itojun    843:                break;
                    844:
                    845:        default:
1.20      itojun    846:                if (ifp == NULL || ifp->if_ioctl == 0)
1.2       itojun    847:                        return(EOPNOTSUPP);
                    848:                return((*ifp->if_ioctl)(ifp, cmd, data));
                    849:        }
                    850:        return(0);
                    851: }
                    852:
1.10      thorpej   853: void
                    854: in6_purgeaddr(ifa, ifp)
                    855:        struct ifaddr *ifa;
                    856:        struct ifnet *ifp;
                    857: {
                    858:        struct in6_ifaddr *oia, *ia = (void *) ifa;
                    859:
                    860:        in6_ifscrub(ifp, ia);
                    861:
                    862:        if (ifp->if_flags & IFF_MULTICAST) {
                    863:                /*
                    864:                 * delete solicited multicast addr for deleting host id
                    865:                 */
                    866:                struct in6_multi *in6m;
                    867:                struct in6_addr llsol;
                    868:                bzero(&llsol, sizeof(struct in6_addr));
                    869:                llsol.s6_addr16[0] = htons(0xff02);
                    870:                llsol.s6_addr16[1] = htons(ifp->if_index);
                    871:                llsol.s6_addr32[1] = 0;
                    872:                llsol.s6_addr32[2] = htonl(1);
                    873:                llsol.s6_addr32[3] =
                    874:                        ia->ia_addr.sin6_addr.s6_addr32[3];
                    875:                llsol.s6_addr8[12] = 0xff;
                    876:
                    877:                IN6_LOOKUP_MULTI(llsol, ifp, in6m);
                    878:                if (in6m)
                    879:                        in6_delmulti(in6m);
                    880:        }
                    881:
                    882:        TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list);
                    883:        IFAFREE(&ia->ia_ifa);
                    884:
                    885:        oia = ia;
                    886:        if (oia == (ia = in6_ifaddr))
                    887:                in6_ifaddr = ia->ia_next;
                    888:        else {
                    889:                while (ia->ia_next && (ia->ia_next != oia))
                    890:                        ia = ia->ia_next;
                    891:                if (ia->ia_next)
                    892:                        ia->ia_next = oia->ia_next;
                    893:                else
                    894:                        printf("Didn't unlink in6_ifaddr from list\n");
                    895:        }
                    896:        {
                    897:                int iilen;
                    898:
                    899:                iilen = (sizeof(oia->ia_prefixmask.sin6_addr) << 3) -
                    900:                        in6_mask2len(&oia->ia_prefixmask.sin6_addr);
                    901:                in6_prefix_remove_ifid(iilen, oia);
                    902:        }
                    903:        if (oia->ia6_multiaddrs.lh_first != NULL) {
                    904:                /*
                    905:                 * XXX thorpej@netbsd.org -- if the interface is going
                    906:                 * XXX away, don't save the multicast entries, delete them!
                    907:                 */
                    908:                if (oia->ia_ifa.ifa_ifp->if_output == if_nulloutput) {
                    909:                        struct in6_multi *in6m;
                    910:
                    911:                        while ((in6m =
                    912:                            LIST_FIRST(&oia->ia6_multiaddrs)) != NULL)
                    913:                                in6_delmulti(in6m);
                    914:                } else
                    915:                        in6_savemkludge(oia);
                    916:        }
                    917:
                    918:        IFAFREE(&oia->ia_ifa);
1.14      thorpej   919: }
1.11      itojun    920:
1.14      thorpej   921: void
                    922: in6_purgeif(ifp)
                    923:        struct ifnet *ifp;
                    924: {
                    925:        struct ifaddr *ifa, *nifa;
1.11      itojun    926:
1.14      thorpej   927:        for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL; ifa = nifa) {
                    928:                nifa = TAILQ_NEXT(ifa, ifa_list);
                    929:                if (ifa->ifa_addr->sa_family != AF_INET6)
                    930:                        continue;
                    931:                in6_purgeaddr(ifa, ifp);
1.11      itojun    932:        }
1.14      thorpej   933:
                    934:        in6_ifdetach(ifp);
1.10      thorpej   935: }
                    936:
1.2       itojun    937: /*
                    938:  * SIOC[GAD]LIFADDR.
                    939:  *     SIOCGLIFADDR: get first address. (???)
                    940:  *     SIOCGLIFADDR with IFLR_PREFIX:
                    941:  *             get first address that matches the specified prefix.
                    942:  *     SIOCALIFADDR: add the specified address.
                    943:  *     SIOCALIFADDR with IFLR_PREFIX:
                    944:  *             add the specified prefix, filling hostid part from
                    945:  *             the first link-local address.  prefixlen must be <= 64.
                    946:  *     SIOCDLIFADDR: delete the specified address.
                    947:  *     SIOCDLIFADDR with IFLR_PREFIX:
                    948:  *             delete the first address that matches the specified prefix.
                    949:  * return values:
                    950:  *     EINVAL on invalid parameters
                    951:  *     EADDRNOTAVAIL on prefix match failed/specified address not found
                    952:  *     other values may be returned from in6_ioctl()
                    953:  *
                    954:  * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64.
                    955:  * this is to accomodate address naming scheme other than RFC2374,
                    956:  * in the future.
                    957:  * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374
                    958:  * address encoding scheme. (see figure on page 8)
                    959:  */
                    960: static int
                    961: in6_lifaddr_ioctl(so, cmd, data, ifp, p)
                    962:        struct socket *so;
                    963:        u_long cmd;
                    964:        caddr_t data;
                    965:        struct ifnet *ifp;
                    966:        struct proc *p;
                    967: {
                    968:        struct if_laddrreq *iflr = (struct if_laddrreq *)data;
                    969:        struct ifaddr *ifa;
1.8       itojun    970:        struct sockaddr *sa;
1.2       itojun    971:
                    972:        /* sanity checks */
                    973:        if (!data || !ifp) {
                    974:                panic("invalid argument to in6_lifaddr_ioctl");
                    975:                /*NOTRECHED*/
                    976:        }
                    977:
                    978:        switch (cmd) {
                    979:        case SIOCGLIFADDR:
                    980:                /* address must be specified on GET with IFLR_PREFIX */
                    981:                if ((iflr->flags & IFLR_PREFIX) == 0)
                    982:                        break;
                    983:                /*FALLTHROUGH*/
                    984:        case SIOCALIFADDR:
                    985:        case SIOCDLIFADDR:
                    986:                /* address must be specified on ADD and DELETE */
1.8       itojun    987:                sa = (struct sockaddr *)&iflr->addr;
                    988:                if (sa->sa_family != AF_INET6)
1.2       itojun    989:                        return EINVAL;
1.8       itojun    990:                if (sa->sa_len != sizeof(struct sockaddr_in6))
1.2       itojun    991:                        return EINVAL;
                    992:                /* XXX need improvement */
1.8       itojun    993:                sa = (struct sockaddr *)&iflr->dstaddr;
                    994:                if (sa->sa_family && sa->sa_family != AF_INET6)
1.2       itojun    995:                        return EINVAL;
1.8       itojun    996:                if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6))
1.2       itojun    997:                        return EINVAL;
                    998:                break;
                    999:        default: /*shouldn't happen*/
                   1000: #if 0
                   1001:                panic("invalid cmd to in6_lifaddr_ioctl");
                   1002:                /*NOTREACHED*/
                   1003: #else
                   1004:                return EOPNOTSUPP;
                   1005: #endif
                   1006:        }
                   1007:        if (sizeof(struct in6_addr) * 8 < iflr->prefixlen)
                   1008:                return EINVAL;
                   1009:
                   1010:        switch (cmd) {
                   1011:        case SIOCALIFADDR:
                   1012:            {
                   1013:                struct in6_aliasreq ifra;
                   1014:                struct in6_addr *hostid = NULL;
                   1015:                int prefixlen;
                   1016:
                   1017:                if ((iflr->flags & IFLR_PREFIX) != 0) {
                   1018:                        struct sockaddr_in6 *sin6;
                   1019:
                   1020:                        /*
                   1021:                         * hostid is to fill in the hostid part of the
                   1022:                         * address.  hostid points to the first link-local
                   1023:                         * address attached to the interface.
                   1024:                         */
1.21      itojun   1025:                        ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);
1.2       itojun   1026:                        if (!ifa)
                   1027:                                return EADDRNOTAVAIL;
1.8       itojun   1028:                        hostid = IFA_IN6(ifa);
1.2       itojun   1029:
                   1030:                        /* prefixlen must be <= 64. */
                   1031:                        if (64 < iflr->prefixlen)
                   1032:                                return EINVAL;
                   1033:                        prefixlen = iflr->prefixlen;
                   1034:
                   1035:                        /* hostid part must be zero. */
                   1036:                        sin6 = (struct sockaddr_in6 *)&iflr->addr;
                   1037:                        if (sin6->sin6_addr.s6_addr32[2] != 0
                   1038:                         || sin6->sin6_addr.s6_addr32[3] != 0) {
                   1039:                                return EINVAL;
                   1040:                        }
                   1041:                } else
                   1042:                        prefixlen = iflr->prefixlen;
                   1043:
                   1044:                /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
                   1045:                bzero(&ifra, sizeof(ifra));
                   1046:                bcopy(iflr->iflr_name, ifra.ifra_name,
                   1047:                        sizeof(ifra.ifra_name));
                   1048:
1.8       itojun   1049:                bcopy(&iflr->addr, &ifra.ifra_addr,
                   1050:                        ((struct sockaddr *)&iflr->addr)->sa_len);
1.2       itojun   1051:                if (hostid) {
                   1052:                        /* fill in hostid part */
                   1053:                        ifra.ifra_addr.sin6_addr.s6_addr32[2] =
                   1054:                                hostid->s6_addr32[2];
                   1055:                        ifra.ifra_addr.sin6_addr.s6_addr32[3] =
                   1056:                                hostid->s6_addr32[3];
                   1057:                }
                   1058:
1.8       itojun   1059:                if (((struct sockaddr *)&iflr->dstaddr)->sa_family) {   /*XXX*/
1.2       itojun   1060:                        bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
1.8       itojun   1061:                                ((struct sockaddr *)&iflr->dstaddr)->sa_len);
1.2       itojun   1062:                        if (hostid) {
                   1063:                                ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] =
                   1064:                                        hostid->s6_addr32[2];
                   1065:                                ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] =
                   1066:                                        hostid->s6_addr32[3];
                   1067:                        }
                   1068:                }
                   1069:
                   1070:                ifra.ifra_prefixmask.sin6_family = AF_INET6;
                   1071:                ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
                   1072:                in6_len2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
                   1073:
                   1074:                ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX;
                   1075:                return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, p);
                   1076:            }
                   1077:        case SIOCGLIFADDR:
                   1078:        case SIOCDLIFADDR:
                   1079:            {
                   1080:                struct in6_ifaddr *ia;
                   1081:                struct in6_addr mask, candidate, match;
                   1082:                struct sockaddr_in6 *sin6;
                   1083:                int cmp;
                   1084:
                   1085:                bzero(&mask, sizeof(mask));
                   1086:                if (iflr->flags & IFLR_PREFIX) {
                   1087:                        /* lookup a prefix rather than address. */
                   1088:                        in6_len2mask(&mask, iflr->prefixlen);
                   1089:
                   1090:                        sin6 = (struct sockaddr_in6 *)&iflr->addr;
                   1091:                        bcopy(&sin6->sin6_addr, &match, sizeof(match));
                   1092:                        match.s6_addr32[0] &= mask.s6_addr32[0];
                   1093:                        match.s6_addr32[1] &= mask.s6_addr32[1];
                   1094:                        match.s6_addr32[2] &= mask.s6_addr32[2];
                   1095:                        match.s6_addr32[3] &= mask.s6_addr32[3];
                   1096:
                   1097:                        /* if you set extra bits, that's wrong */
                   1098:                        if (bcmp(&match, &sin6->sin6_addr, sizeof(match)))
                   1099:                                return EINVAL;
                   1100:
                   1101:                        cmp = 1;
                   1102:                } else {
                   1103:                        if (cmd == SIOCGLIFADDR) {
                   1104:                                /* on getting an address, take the 1st match */
                   1105:                                cmp = 0;        /*XXX*/
                   1106:                        } else {
                   1107:                                /* on deleting an address, do exact match */
                   1108:                                in6_len2mask(&mask, 128);
                   1109:                                sin6 = (struct sockaddr_in6 *)&iflr->addr;
                   1110:                                bcopy(&sin6->sin6_addr, &match, sizeof(match));
                   1111:
                   1112:                                cmp = 1;
                   1113:                        }
                   1114:                }
                   1115:
                   1116:                for (ifa = ifp->if_addrlist.tqh_first;
                   1117:                     ifa;
1.8       itojun   1118:                     ifa = ifa->ifa_list.tqe_next)
                   1119:                {
1.2       itojun   1120:                        if (ifa->ifa_addr->sa_family != AF_INET6)
                   1121:                                continue;
                   1122:                        if (!cmp)
                   1123:                                break;
1.8       itojun   1124:                        bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate));
1.2       itojun   1125:                        candidate.s6_addr32[0] &= mask.s6_addr32[0];
                   1126:                        candidate.s6_addr32[1] &= mask.s6_addr32[1];
                   1127:                        candidate.s6_addr32[2] &= mask.s6_addr32[2];
                   1128:                        candidate.s6_addr32[3] &= mask.s6_addr32[3];
                   1129:                        if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
                   1130:                                break;
                   1131:                }
                   1132:                if (!ifa)
                   1133:                        return EADDRNOTAVAIL;
                   1134:                ia = ifa2ia6(ifa);
                   1135:
                   1136:                if (cmd == SIOCGLIFADDR) {
                   1137:                        /* fill in the if_laddrreq structure */
                   1138:                        bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
                   1139:
                   1140:                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
                   1141:                                bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
                   1142:                                        ia->ia_dstaddr.sin6_len);
                   1143:                        } else
                   1144:                                bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
                   1145:
                   1146:                        iflr->prefixlen =
                   1147:                                in6_mask2len(&ia->ia_prefixmask.sin6_addr);
                   1148:
                   1149:                        iflr->flags = ia->ia6_flags;    /*XXX*/
                   1150:
                   1151:                        return 0;
                   1152:                } else {
                   1153:                        struct in6_aliasreq ifra;
                   1154:
                   1155:                        /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
                   1156:                        bzero(&ifra, sizeof(ifra));
                   1157:                        bcopy(iflr->iflr_name, ifra.ifra_name,
                   1158:                                sizeof(ifra.ifra_name));
                   1159:
                   1160:                        bcopy(&ia->ia_addr, &ifra.ifra_addr,
                   1161:                                ia->ia_addr.sin6_len);
                   1162:                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
                   1163:                                bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
                   1164:                                        ia->ia_dstaddr.sin6_len);
1.23      itojun   1165:                        } else {
                   1166:                                bzero(&ifra.ifra_dstaddr,
                   1167:                                    sizeof(ifra.ifra_dstaddr));
1.2       itojun   1168:                        }
                   1169:                        bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr,
                   1170:                                ia->ia_prefixmask.sin6_len);
                   1171:
                   1172:                        ifra.ifra_flags = ia->ia6_flags;
                   1173:                        return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
                   1174:                                ifp, p);
                   1175:                }
                   1176:            }
                   1177:        }
                   1178:
                   1179:        return EOPNOTSUPP;      /*just for safety*/
                   1180: }
                   1181:
                   1182: /*
                   1183:  * Delete any existing route for an interface.
                   1184:  */
                   1185: void
                   1186: in6_ifscrub(ifp, ia)
                   1187:        register struct ifnet *ifp;
                   1188:        register struct in6_ifaddr *ia;
                   1189: {
                   1190:        if ((ia->ia_flags & IFA_ROUTE) == 0)
                   1191:                return;
                   1192:        if (ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
                   1193:                rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
                   1194:        else
                   1195:                rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
                   1196:        ia->ia_flags &= ~IFA_ROUTE;
                   1197:
                   1198:        /* Remove ownaddr's loopback rtentry, if it exists. */
                   1199:        in6_ifremloop(&(ia->ia_ifa));
                   1200: }
                   1201:
                   1202: /*
                   1203:  * Initialize an interface's intetnet6 address
                   1204:  * and routing table entry.
                   1205:  */
                   1206: int
                   1207: in6_ifinit(ifp, ia, sin6, scrub)
                   1208:        struct ifnet *ifp;
                   1209:        struct in6_ifaddr *ia;
                   1210:        struct sockaddr_in6 *sin6;
                   1211:        int scrub;
                   1212: {
                   1213:        struct  sockaddr_in6 oldaddr;
                   1214:        int     error, flags = RTF_UP;
                   1215:        int     s = splimp();
                   1216:
                   1217:        oldaddr = ia->ia_addr;
                   1218:        ia->ia_addr = *sin6;
                   1219:        /*
                   1220:         * Give the interface a chance to initialize
                   1221:         * if this is its first address,
                   1222:         * and to validate the address if necessary.
                   1223:         */
                   1224:        if (ifp->if_ioctl &&
                   1225:           (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
                   1226:                splx(s);
                   1227:                ia->ia_addr = oldaddr;
                   1228:                return(error);
                   1229:        }
                   1230:
                   1231:        switch (ifp->if_type) {
1.7       is       1232:        case IFT_ARCNET:
1.2       itojun   1233:        case IFT_ETHER:
                   1234:        case IFT_FDDI:
                   1235:                ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
                   1236:                ia->ia_ifa.ifa_flags |= RTF_CLONING;
                   1237:                break;
                   1238:        case IFT_PPP:
                   1239:                ia->ia_ifa.ifa_rtrequest = nd6_p2p_rtrequest;
                   1240:                ia->ia_ifa.ifa_flags |= RTF_CLONING;
                   1241:                break;
                   1242:        }
                   1243:
                   1244:        splx(s);
                   1245:        if (scrub) {
                   1246:                ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
                   1247:                in6_ifscrub(ifp, ia);
                   1248:                ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
                   1249:        }
1.18      itojun   1250:        /* xxx
1.2       itojun   1251:         * in_socktrim
                   1252:         */
                   1253:        /*
                   1254:         * Add route for the network.
                   1255:         */
                   1256:        ia->ia_ifa.ifa_metric = ifp->if_metric;
                   1257:        if (ifp->if_flags & IFF_LOOPBACK) {
                   1258:                ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
                   1259:                flags |= RTF_HOST;
                   1260:        } else if (ifp->if_flags & IFF_POINTOPOINT) {
                   1261:                if (ia->ia_dstaddr.sin6_family != AF_INET6)
                   1262:                        return(0);
                   1263:                flags |= RTF_HOST;
                   1264:        }
                   1265:        if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
                   1266:                ia->ia_flags |= IFA_ROUTE;
                   1267:
                   1268:        /* Add ownaddr as loopback rtentry, if necessary(ex. on p2p link). */
                   1269:        in6_ifaddloop(&(ia->ia_ifa));
                   1270:
                   1271:        if (ifp->if_flags & IFF_MULTICAST)
                   1272:                in6_restoremkludge(ia, ifp);
                   1273:
                   1274:        return(error);
                   1275: }
                   1276:
                   1277: /*
                   1278:  * Multicast address kludge:
                   1279:  * If there were any multicast addresses attached to this interface address,
                   1280:  * either move them to another address on this interface, or save them until
                   1281:  * such time as this interface is reconfigured for IPv6.
                   1282:  */
                   1283: void
                   1284: in6_savemkludge(oia)
                   1285:        struct in6_ifaddr *oia;
                   1286: {
                   1287:        struct in6_ifaddr *ia;
                   1288:        struct in6_multi *in6m, *next;
                   1289:
                   1290:        IFP_TO_IA6(oia->ia_ifp, ia);
                   1291:        if (ia) {       /* there is another address */
                   1292:                for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){
                   1293:                        next = in6m->in6m_entry.le_next;
                   1294:                        IFAFREE(&in6m->in6m_ia->ia_ifa);
1.10      thorpej  1295:                        IFAREF(&ia->ia_ifa);
1.2       itojun   1296:                        in6m->in6m_ia = ia;
                   1297:                        LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
                   1298:                }
                   1299:        } else {        /* last address on this if deleted, save */
                   1300:                struct multi6_kludge *mk;
                   1301:
                   1302:                mk = malloc(sizeof(*mk), M_IPMADDR, M_WAITOK);
                   1303:
                   1304:                LIST_INIT(&mk->mk_head);
                   1305:                mk->mk_ifp = oia->ia_ifp;
                   1306:
                   1307:                for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){
                   1308:                        next = in6m->in6m_entry.le_next;
1.12      itojun   1309:                        IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
                   1310:                        in6m->in6m_ia = NULL;
1.2       itojun   1311:                        LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry);
                   1312:                }
                   1313:
                   1314:                if (mk->mk_head.lh_first != NULL) {
                   1315:                        LIST_INSERT_HEAD(&in6_mk, mk, mk_entry);
1.30      itojun   1316:                } else {
1.2       itojun   1317:                        FREE(mk, M_IPMADDR);
                   1318:                }
                   1319:        }
                   1320: }
                   1321:
                   1322: /*
                   1323:  * Continuation of multicast address hack:
                   1324:  * If there was a multicast group list previously saved for this interface,
                   1325:  * then we re-attach it to the first address configured on the i/f.
                   1326:  */
                   1327: void
                   1328: in6_restoremkludge(ia, ifp)
                   1329:        struct in6_ifaddr *ia;
                   1330:        struct ifnet *ifp;
                   1331: {
                   1332:        struct multi6_kludge *mk;
                   1333:
                   1334:        for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) {
                   1335:                if (mk->mk_ifp == ifp) {
                   1336:                        struct in6_multi *in6m, *next;
                   1337:
                   1338:                        for (in6m = mk->mk_head.lh_first; in6m; in6m = next){
                   1339:                                next = in6m->in6m_entry.le_next;
1.12      itojun   1340:                                in6m->in6m_ia = ia;
1.30      itojun   1341:                                IFAREF(&ia->ia_ifa);
1.2       itojun   1342:                                LIST_INSERT_HEAD(&ia->ia6_multiaddrs,
                   1343:                                                 in6m, in6m_entry);
                   1344:                        }
                   1345:                        LIST_REMOVE(mk, mk_entry);
                   1346:                        free(mk, M_IPMADDR);
                   1347:                        break;
                   1348:                }
                   1349:        }
                   1350: }
                   1351:
1.12      itojun   1352: void
                   1353: in6_purgemkludge(ifp)
                   1354:        struct ifnet *ifp;
                   1355: {
                   1356:        struct multi6_kludge *mk;
1.13      itojun   1357:        struct in6_multi *in6m;
1.12      itojun   1358:
                   1359:        for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) {
                   1360:                if (mk->mk_ifp != ifp)
                   1361:                        continue;
                   1362:
1.13      itojun   1363:                /* leave from all multicast groups joined */
                   1364:                while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL)
1.12      itojun   1365:                        in6_delmulti(in6m);
                   1366:                LIST_REMOVE(mk, mk_entry);
                   1367:                free(mk, M_IPMADDR);
                   1368:                break;
                   1369:        }
                   1370: }
                   1371:
1.2       itojun   1372: /*
1.18      itojun   1373:  * Add an address to the list of IP6 multicast addresses for a
1.2       itojun   1374:  * given interface.
                   1375:  */
                   1376: struct in6_multi *
                   1377: in6_addmulti(maddr6, ifp, errorp)
                   1378:        register struct in6_addr *maddr6;
                   1379:        register struct ifnet *ifp;
                   1380:        int *errorp;
                   1381: {
                   1382:        struct  in6_ifaddr *ia;
                   1383:        struct  in6_ifreq ifr;
                   1384:        struct  in6_multi *in6m;
1.4       itojun   1385:        int     s = splsoftnet();
1.2       itojun   1386:
                   1387:        *errorp = 0;
                   1388:        /*
                   1389:         * See if address already in list.
                   1390:         */
                   1391:        IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
                   1392:        if (in6m != NULL) {
                   1393:                /*
                   1394:                 * Found it; just increment the refrence count.
                   1395:                 */
                   1396:                in6m->in6m_refcount++;
                   1397:        } else {
                   1398:                /*
                   1399:                 * New address; allocate a new multicast record
                   1400:                 * and link it into the interface's multicast list.
                   1401:                 */
                   1402:                in6m = (struct in6_multi *)
                   1403:                        malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT);
                   1404:                if (in6m == NULL) {
                   1405:                        splx(s);
                   1406:                        *errorp = ENOBUFS;
                   1407:                        return(NULL);
                   1408:                }
                   1409:                in6m->in6m_addr = *maddr6;
                   1410:                in6m->in6m_ifp = ifp;
                   1411:                in6m->in6m_refcount = 1;
                   1412:                IFP_TO_IA6(ifp, ia);
                   1413:                if (ia == NULL) {
                   1414:                        free(in6m, M_IPMADDR);
                   1415:                        splx(s);
                   1416:                        *errorp = EADDRNOTAVAIL; /* appropriate? */
                   1417:                        return(NULL);
                   1418:                }
                   1419:                in6m->in6m_ia = ia;
1.10      thorpej  1420:                IFAREF(&ia->ia_ifa);    /* gain a reference */
1.2       itojun   1421:                LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
                   1422:
                   1423:                /*
                   1424:                 * Ask the network driver to update its multicast reception
                   1425:                 * filter appropriately for the new address.
                   1426:                 */
                   1427:                bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
                   1428:                ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
                   1429:                ifr.ifr_addr.sin6_family = AF_INET6;
                   1430:                ifr.ifr_addr.sin6_addr = *maddr6;
                   1431:                if (ifp->if_ioctl == NULL)
                   1432:                        *errorp = ENXIO; /* XXX: appropriate? */
                   1433:                else
                   1434:                        *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI,
                   1435:                                                    (caddr_t)&ifr);
                   1436:                if (*errorp) {
                   1437:                        LIST_REMOVE(in6m, in6m_entry);
                   1438:                        free(in6m, M_IPMADDR);
                   1439:                        splx(s);
                   1440:                        return(NULL);
                   1441:                }
                   1442:                /*
                   1443:                 * Let MLD6 know that we have joined a new IP6 multicast
                   1444:                 * group.
                   1445:                 */
                   1446:                mld6_start_listening(in6m);
                   1447:        }
                   1448:        splx(s);
                   1449:        return(in6m);
                   1450: }
                   1451:
                   1452: /*
                   1453:  * Delete a multicast address record.
                   1454:  */
                   1455: void
                   1456: in6_delmulti(in6m)
                   1457:        struct in6_multi *in6m;
                   1458: {
                   1459:        struct  in6_ifreq ifr;
1.4       itojun   1460:        int     s = splsoftnet();
1.2       itojun   1461:
                   1462:        if (--in6m->in6m_refcount == 0) {
                   1463:                /*
                   1464:                 * No remaining claims to this record; let MLD6 know
                   1465:                 * that we are leaving the multicast group.
                   1466:                 */
                   1467:                mld6_stop_listening(in6m);
                   1468:
                   1469:                /*
                   1470:                 * Unlink from list.
                   1471:                 */
                   1472:                LIST_REMOVE(in6m, in6m_entry);
1.12      itojun   1473:                if (in6m->in6m_ia)
                   1474:                        IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */
1.2       itojun   1475:
                   1476:                /*
1.18      itojun   1477:                 * Notify the network driver to update its multicast
1.2       itojun   1478:                 * reception filter.
                   1479:                 */
                   1480:                bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6));
                   1481:                ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
                   1482:                ifr.ifr_addr.sin6_family = AF_INET6;
                   1483:                ifr.ifr_addr.sin6_addr = in6m->in6m_addr;
                   1484:                (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp,
                   1485:                                            SIOCDELMULTI, (caddr_t)&ifr);
                   1486:                free(in6m, M_IPMADDR);
                   1487:        }
                   1488:        splx(s);
                   1489: }
                   1490:
                   1491: /*
                   1492:  * Find an IPv6 interface link-local address specific to an interface.
                   1493:  */
                   1494: struct in6_ifaddr *
1.21      itojun   1495: in6ifa_ifpforlinklocal(ifp, ignoreflags)
1.2       itojun   1496:        struct ifnet *ifp;
1.21      itojun   1497:        int ignoreflags;
1.2       itojun   1498: {
                   1499:        register struct ifaddr *ifa;
                   1500:
1.8       itojun   1501:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
                   1502:        {
1.2       itojun   1503:                if (ifa->ifa_addr == NULL)
                   1504:                        continue;       /* just for safety */
                   1505:                if (ifa->ifa_addr->sa_family != AF_INET6)
                   1506:                        continue;
1.21      itojun   1507:                if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) {
                   1508:                        if ((((struct in6_ifaddr *)ifa)->ia6_flags &
                   1509:                             ignoreflags) != 0)
                   1510:                                continue;
1.2       itojun   1511:                        break;
1.21      itojun   1512:                }
1.2       itojun   1513:        }
                   1514:
                   1515:        return((struct in6_ifaddr *)ifa);
                   1516: }
                   1517:
                   1518:
                   1519: /*
                   1520:  * find the internet address corresponding to a given interface and address.
                   1521:  */
                   1522: struct in6_ifaddr *
                   1523: in6ifa_ifpwithaddr(ifp, addr)
                   1524:        struct ifnet *ifp;
                   1525:        struct in6_addr *addr;
                   1526: {
                   1527:        register struct ifaddr *ifa;
                   1528:
1.8       itojun   1529:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
                   1530:        {
1.2       itojun   1531:                if (ifa->ifa_addr == NULL)
                   1532:                        continue;       /* just for safety */
                   1533:                if (ifa->ifa_addr->sa_family != AF_INET6)
                   1534:                        continue;
1.8       itojun   1535:                if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
1.2       itojun   1536:                        break;
                   1537:        }
                   1538:
                   1539:        return((struct in6_ifaddr *)ifa);
                   1540: }
                   1541:
                   1542: /*
                   1543:  * Convert IP6 address to printable (loggable) representation.
                   1544:  */
                   1545: static char digits[] = "0123456789abcdef";
                   1546: static int ip6round = 0;
                   1547: char *
                   1548: ip6_sprintf(addr)
                   1549: register struct in6_addr *addr;
                   1550: {
                   1551:        static char ip6buf[8][48];
                   1552:        register int i;
                   1553:        register char *cp;
                   1554:        register u_short *a = (u_short *)addr;
                   1555:        register u_char *d;
                   1556:        int dcolon = 0;
                   1557:
                   1558:        ip6round = (ip6round + 1) & 7;
                   1559:        cp = ip6buf[ip6round];
                   1560:
                   1561:        for (i = 0; i < 8; i++) {
                   1562:                if (dcolon == 1) {
                   1563:                        if (*a == 0) {
                   1564:                                if (i == 7)
                   1565:                                        *cp++ = ':';
                   1566:                                a++;
                   1567:                                continue;
                   1568:                        } else
                   1569:                                dcolon = 2;
                   1570:                }
                   1571:                if (*a == 0) {
                   1572:                        if (dcolon == 0 && *(a + 1) == 0) {
                   1573:                                if (i == 0)
                   1574:                                        *cp++ = ':';
                   1575:                                *cp++ = ':';
                   1576:                                dcolon = 1;
                   1577:                        } else {
                   1578:                                *cp++ = '0';
                   1579:                                *cp++ = ':';
                   1580:                        }
                   1581:                        a++;
                   1582:                        continue;
                   1583:                }
                   1584:                d = (u_char *)a;
                   1585:                *cp++ = digits[*d >> 4];
                   1586:                *cp++ = digits[*d++ & 0xf];
                   1587:                *cp++ = digits[*d >> 4];
                   1588:                *cp++ = digits[*d & 0xf];
                   1589:                *cp++ = ':';
                   1590:                a++;
                   1591:        }
                   1592:        *--cp = 0;
                   1593:        return(ip6buf[ip6round]);
                   1594: }
                   1595:
                   1596: int
                   1597: in6_localaddr(in6)
                   1598:        struct in6_addr *in6;
                   1599: {
                   1600:        struct in6_ifaddr *ia;
                   1601:
                   1602:        if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6))
                   1603:                return 1;
                   1604:
                   1605:        for (ia = in6_ifaddr; ia; ia = ia->ia_next)
                   1606:                if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr,
                   1607:                                              &ia->ia_prefixmask.sin6_addr))
                   1608:                        return 1;
                   1609:
                   1610:        return (0);
                   1611: }
                   1612:
                   1613: /*
                   1614:  * Get a scope of the address. Node-local, link-local, site-local or global.
                   1615:  */
                   1616: int
                   1617: in6_addrscope (addr)
                   1618: struct in6_addr *addr;
                   1619: {
                   1620:        int scope;
                   1621:
                   1622:        if (addr->s6_addr8[0] == 0xfe) {
                   1623:                scope = addr->s6_addr8[1] & 0xc0;
                   1624:
                   1625:                switch (scope) {
                   1626:                case 0x80:
                   1627:                        return IPV6_ADDR_SCOPE_LINKLOCAL;
                   1628:                        break;
                   1629:                case 0xc0:
                   1630:                        return IPV6_ADDR_SCOPE_SITELOCAL;
                   1631:                        break;
                   1632:                default:
                   1633:                        return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
                   1634:                        break;
                   1635:                }
                   1636:        }
                   1637:
                   1638:
                   1639:        if (addr->s6_addr8[0] == 0xff) {
                   1640:                scope = addr->s6_addr8[1] & 0x0f;
                   1641:
1.18      itojun   1642:                /*
1.2       itojun   1643:                 * due to other scope such as reserved,
                   1644:                 * return scope doesn't work.
                   1645:                 */
                   1646:                switch (scope) {
                   1647:                case IPV6_ADDR_SCOPE_NODELOCAL:
                   1648:                        return IPV6_ADDR_SCOPE_NODELOCAL;
                   1649:                        break;
                   1650:                case IPV6_ADDR_SCOPE_LINKLOCAL:
                   1651:                        return IPV6_ADDR_SCOPE_LINKLOCAL;
                   1652:                        break;
                   1653:                case IPV6_ADDR_SCOPE_SITELOCAL:
                   1654:                        return IPV6_ADDR_SCOPE_SITELOCAL;
                   1655:                        break;
                   1656:                default:
                   1657:                        return IPV6_ADDR_SCOPE_GLOBAL;
                   1658:                        break;
                   1659:                }
                   1660:        }
                   1661:
                   1662:        if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
                   1663:                if (addr->s6_addr8[15] == 1) /* loopback */
                   1664:                        return IPV6_ADDR_SCOPE_NODELOCAL;
                   1665:                if (addr->s6_addr8[15] == 0) /* unspecified */
                   1666:                        return IPV6_ADDR_SCOPE_LINKLOCAL;
                   1667:        }
                   1668:
                   1669:        return IPV6_ADDR_SCOPE_GLOBAL;
                   1670: }
                   1671:
1.21      itojun   1672: int
                   1673: in6_addr2scopeid(ifp, addr)
                   1674:        struct ifnet *ifp;      /* must not be NULL */
                   1675:        struct in6_addr *addr;  /* must not be NULL */
                   1676: {
                   1677:        int scope = in6_addrscope(addr);
                   1678:
                   1679:        switch(scope) {
                   1680:        case IPV6_ADDR_SCOPE_NODELOCAL:
                   1681:                return(-1);     /* XXX: is this an appropriate value? */
                   1682:
                   1683:        case IPV6_ADDR_SCOPE_LINKLOCAL:
                   1684:                /* XXX: we do not distinguish between a link and an I/F. */
                   1685:                return(ifp->if_index);
                   1686:
                   1687:        case IPV6_ADDR_SCOPE_SITELOCAL:
                   1688:                return(0);      /* XXX: invalid. */
                   1689:
                   1690:        default:
                   1691:                return(0);      /* XXX: treat as global. */
                   1692:        }
                   1693: }
                   1694:
1.2       itojun   1695: /*
                   1696:  * return length of part which dst and src are equal
                   1697:  * hard coding...
                   1698:  */
                   1699:
                   1700: int
                   1701: in6_matchlen(src, dst)
                   1702: struct in6_addr *src, *dst;
                   1703: {
                   1704:        int match = 0;
                   1705:        u_char *s = (u_char *)src, *d = (u_char *)dst;
                   1706:        u_char *lim = s + 16, r;
                   1707:
                   1708:        while (s < lim)
                   1709:                if ((r = (*d++ ^ *s++)) != 0) {
                   1710:                        while (r < 128) {
                   1711:                                match++;
                   1712:                                r <<= 1;
                   1713:                        }
                   1714:                        break;
                   1715:                } else
                   1716:                        match += 8;
                   1717:        return match;
                   1718: }
                   1719:
1.8       itojun   1720: int
                   1721: in6_are_prefix_equal(p1, p2, len)
                   1722:        struct in6_addr *p1, *p2;
                   1723:        int len;
                   1724: {
                   1725:        int bytelen, bitlen;
                   1726:
                   1727:        /* sanity check */
                   1728:        if (0 > len || len > 128) {
                   1729:                log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n",
                   1730:                    len);
                   1731:                return(0);
                   1732:        }
                   1733:
                   1734:        bytelen = len / 8;
                   1735:        bitlen = len % 8;
                   1736:
                   1737:        if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen))
                   1738:                return(0);
                   1739:        if (p1->s6_addr[bytelen] >> (8 - bitlen) !=
                   1740:            p2->s6_addr[bytelen] >> (8 - bitlen))
                   1741:                return(0);
                   1742:
                   1743:        return(1);
                   1744: }
                   1745:
                   1746: void
                   1747: in6_prefixlen2mask(maskp, len)
                   1748:        struct in6_addr *maskp;
                   1749:        int len;
                   1750: {
                   1751:        u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
                   1752:        int bytelen, bitlen, i;
                   1753:
                   1754:        /* sanity check */
                   1755:        if (0 > len || len > 128) {
                   1756:                log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n",
                   1757:                    len);
                   1758:                return;
                   1759:        }
                   1760:
                   1761:        bzero(maskp, sizeof(*maskp));
                   1762:        bytelen = len / 8;
                   1763:        bitlen = len % 8;
                   1764:        for (i = 0; i < bytelen; i++)
                   1765:                maskp->s6_addr[i] = 0xff;
                   1766:        if (bitlen)
                   1767:                maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
                   1768: }
                   1769:
1.2       itojun   1770: /*
                   1771:  * return the best address out of the same scope
                   1772:  */
                   1773: struct in6_ifaddr *
1.21      itojun   1774: in6_ifawithscope(oifp, dst)
                   1775:        register struct ifnet *oifp;
1.2       itojun   1776:        register struct in6_addr *dst;
                   1777: {
1.30      itojun   1778:        int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
1.21      itojun   1779:        int blen = -1;
1.2       itojun   1780:        struct ifaddr *ifa;
1.21      itojun   1781:        struct ifnet *ifp;
                   1782:        struct in6_ifaddr *ifa_best = NULL;
                   1783:
                   1784:        if (oifp == NULL) {
                   1785:                printf("in6_ifawithscope: output interface is not specified\n");
                   1786:                return(NULL);
                   1787:        }
1.2       itojun   1788:
                   1789:        /*
1.21      itojun   1790:         * We search for all addresses on all interfaces from the beginning.
                   1791:         * Comparing an interface with the outgoing interface will be done
                   1792:         * only at the final stage of tiebreaking.
1.2       itojun   1793:         */
1.21      itojun   1794:        for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
1.8       itojun   1795:        {
1.21      itojun   1796:                /*
                   1797:                 * We can never take an address that breaks the scope zone
                   1798:                 * of the destination.
                   1799:                 */
                   1800:                if (in6_addr2scopeid(ifp, dst) != in6_addr2scopeid(oifp, dst))
1.2       itojun   1801:                        continue;
                   1802:
1.21      itojun   1803:                for (ifa = ifp->if_addrlist.tqh_first; ifa;
                   1804:                     ifa = ifa->ifa_list.tqe_next)
                   1805:                {
                   1806:                        int tlen = -1, dscopecmp, bscopecmp, matchcmp;
                   1807:
                   1808:                        if (ifa->ifa_addr->sa_family != AF_INET6)
                   1809:                                continue;
                   1810:
                   1811:                        src_scope = in6_addrscope(IFA_IN6(ifa));
                   1812:
                   1813: #ifdef ADDRSELECT_DEBUG                /* should be removed after stabilization */
                   1814:                        dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
                   1815:                        printf("in6_ifawithscope: dst=%s bestaddr=%s, "
                   1816:                               "newaddr=%s, scope=%x, dcmp=%d, bcmp=%d, "
                   1817:                               "matchlen=%d, flgs=%x\n",
                   1818:                               ip6_sprintf(dst),
                   1819:                               ifa_best ? ip6_sprintf(&ifa_best->ia_addr.sin6_addr) : "none",
                   1820:                               ip6_sprintf(IFA_IN6(ifa)), src_scope,
                   1821:                               dscopecmp,
                   1822:                               ifa_best ? IN6_ARE_SCOPE_CMP(src_scope, best_scope) : -1,
                   1823:                               in6_matchlen(IFA_IN6(ifa), dst),
                   1824:                               ((struct in6_ifaddr *)ifa)->ia6_flags);
                   1825: #endif
                   1826:
                   1827:                        /*
                   1828:                         * Don't use an address before completing DAD
                   1829:                         * nor a duplicated address.
                   1830:                         */
                   1831:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
                   1832:                            IN6_IFF_NOTREADY)
                   1833:                                continue;
                   1834:
                   1835:                        /* XXX: is there any case to allow anycasts? */
                   1836:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
                   1837:                            IN6_IFF_ANYCAST)
                   1838:                                continue;
                   1839:
                   1840:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
                   1841:                            IN6_IFF_DETACHED)
                   1842:                                continue;
                   1843:
                   1844:                        /*
                   1845:                         * If this is the first address we find,
                   1846:                         * keep it anyway.
                   1847:                         */
                   1848:                        if (ifa_best == NULL)
                   1849:                                goto replace;
                   1850:
                   1851:                        /*
                   1852:                         * ifa_best is never NULL beyond this line except
                   1853:                         * within the block labeled "replace".
                   1854:                         */
                   1855:
                   1856:                        /*
                   1857:                         * If ifa_best has a smaller scope than dst and
                   1858:                         * the current address has a larger one than
                   1859:                         * (or equal to) dst, always replace ifa_best.
                   1860:                         * Also, if the current address has a smaller scope
                   1861:                         * than dst, ignore it unless ifa_best also has a
                   1862:                         * smaller scope.
                   1863:                         */
                   1864:                        if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
                   1865:                            IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
                   1866:                                goto replace;
                   1867:                        if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
                   1868:                            IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
                   1869:                                continue;
                   1870:
                   1871:                        /*
                   1872:                         * A deprecated address SHOULD NOT be used in new
                   1873:                         * communications if an alternate (non-deprecated)
                   1874:                         * address is available and has sufficient scope.
                   1875:                         * RFC 2462, Section 5.5.4.
                   1876:                         */
                   1877:                        if (((struct in6_ifaddr *)ifa)->ia6_flags &
                   1878:                            IN6_IFF_DEPRECATED) {
                   1879:                                /*
                   1880:                                 * Ignore any deprecated addresses if
                   1881:                                 * specified by configuration.
                   1882:                                 */
                   1883:                                if (!ip6_use_deprecated)
                   1884:                                        continue;
                   1885:
                   1886:                                /*
                   1887:                                 * If we have already found a non-deprecated
                   1888:                                 * candidate, just ignore deprecated addresses.
                   1889:                                 */
                   1890:                                if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED)
                   1891:                                    == 0)
                   1892:                                        continue;
                   1893:                        }
                   1894:
                   1895:                        /*
                   1896:                         * A non-deprecated address is always preferred
                   1897:                         * to a deprecated one regardless of scopes and
                   1898:                         * address matching.
                   1899:                         */
                   1900:                        if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
                   1901:                            (((struct in6_ifaddr *)ifa)->ia6_flags &
                   1902:                             IN6_IFF_DEPRECATED) == 0)
                   1903:                                goto replace;
                   1904:
                   1905:                        /*
                   1906:                         * At this point, we have two cases:
                   1907:                         * 1. we are looking at a non-deprecated address,
                   1908:                         *    and ifa_best is also non-deprecated.
                   1909:                         * 2. we are looking at a deprecated address,
                   1910:                         *    and ifa_best is also deprecated.
                   1911:                         * Also, we do not have to consider a case where
                   1912:                         * the scope of if_best is larger(smaller) than dst and
                   1913:                         * the scope of the current address is smaller(larger)
                   1914:                         * than dst. Such a case has already been covered.
                   1915:                         * Tiebreaking is done according to the following
                   1916:                         * items:
                   1917:                         * - the scope comparison between the address and
                   1918:                         *   dst (dscopecmp)
                   1919:                         * - the scope comparison between the address and
                   1920:                         *   ifa_best (bscopecmp)
                   1921:                         * - if the address match dst longer than ifa_best
                   1922:                         *   (matchcmp)
                   1923:                         * - if the address is on the outgoing I/F (outI/F)
                   1924:                         *
                   1925:                         * Roughly speaking, the selection policy is
                   1926:                         * - the most important item is scope. The same scope
                   1927:                         *   is best. Then search for a larger scope.
                   1928:                         *   Smaller scopes are the last resort.
                   1929:                         * - A deprecated address is chosen only when we have
                   1930:                         *   no address that has an enough scope, but is
                   1931:                         *   prefered to any addresses of smaller scopes.
                   1932:                         * - Longest address match against dst is considered
                   1933:                         *   only for addresses that has the same scope of dst.
                   1934:                         * - If there is no other reasons to choose one,
                   1935:                         *   addresses on the outgoing I/F are preferred.
                   1936:                         *
                   1937:                         * The precise decision table is as follows:
                   1938:                         * dscopecmp bscopecmp matchcmp outI/F | replace?
                   1939:                         *    !equal     equal      N/A    Yes |      Yes (1)
                   1940:                         *    !equal     equal      N/A     No |       No (2)
                   1941:                         *    larger    larger      N/A    N/A |       No (3)
                   1942:                         *    larger   smaller      N/A    N/A |      Yes (4)
                   1943:                         *   smaller    larger      N/A    N/A |      Yes (5)
                   1944:                         *   smaller   smaller      N/A    N/A |       No (6)
                   1945:                         *     equal   smaller      N/A    N/A |      Yes (7)
                   1946:                         *     equal    larger       (already done)
                   1947:                         *     equal     equal   larger    N/A |      Yes (8)
                   1948:                         *     equal     equal  smaller    N/A |       No (9)
                   1949:                         *     equal     equal    equal    Yes |      Yes (a)
                   1950:                         *     eaual     eqaul    equal     No |       No (b)
                   1951:                         */
                   1952:                        dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
                   1953:                        bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope);
                   1954:
                   1955:                        if (dscopecmp && bscopecmp == 0) {
                   1956:                                if (oifp == ifp) /* (1) */
                   1957:                                        goto replace;
                   1958:                                continue; /* (2) */
                   1959:                        }
                   1960:                        if (dscopecmp > 0) {
                   1961:                                if (bscopecmp > 0) /* (3) */
                   1962:                                        continue;
                   1963:                                goto replace; /* (4) */
                   1964:                        }
                   1965:                        if (dscopecmp < 0) {
                   1966:                                if (bscopecmp > 0) /* (5) */
                   1967:                                        goto replace;
                   1968:                                continue; /* (6) */
                   1969:                        }
                   1970:
                   1971:                        /* now dscopecmp must be 0 */
                   1972:                        if (bscopecmp < 0)
                   1973:                                goto replace; /* (7) */
                   1974:
1.2       itojun   1975:                        /*
1.21      itojun   1976:                         * At last both dscopecmp and bscopecmp must be 0.
                   1977:                         * We need address matching against dst for
                   1978:                         * tiebreaking.
1.2       itojun   1979:                         */
1.21      itojun   1980:                        tlen = in6_matchlen(IFA_IN6(ifa), dst);
                   1981:                        matchcmp = tlen - blen;
                   1982:                        if (matchcmp > 0) /* (8) */
                   1983:                                goto replace;
                   1984:                        if (matchcmp < 0) /* (9) */
                   1985:                                continue;
                   1986:                        if (oifp == ifp) /* (a) */
                   1987:                                goto replace;
                   1988:                        continue; /* (b) */
                   1989:
                   1990:                  replace:
                   1991:                        ifa_best = (struct in6_ifaddr *)ifa;
                   1992:                        blen = tlen >= 0 ? tlen :
                   1993:                                in6_matchlen(IFA_IN6(ifa), dst);
                   1994:                        best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr);
1.2       itojun   1995:                }
                   1996:        }
                   1997:
1.21      itojun   1998:        /* count statistics for future improvements */
                   1999:        if (ifa_best == NULL)
                   2000:                ip6stat.ip6s_sources_none++;
                   2001:        else {
                   2002:                if (oifp == ifa_best->ia_ifp)
                   2003:                        ip6stat.ip6s_sources_sameif[best_scope]++;
                   2004:                else
                   2005:                        ip6stat.ip6s_sources_otherif[best_scope]++;
                   2006:
                   2007:                if (best_scope == dst_scope)
                   2008:                        ip6stat.ip6s_sources_samescope[best_scope]++;
                   2009:                else
                   2010:                        ip6stat.ip6s_sources_otherscope[best_scope]++;
                   2011:
                   2012:                if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
                   2013:                        ip6stat.ip6s_sources_deprecated[best_scope]++;
1.2       itojun   2014:        }
                   2015:
1.21      itojun   2016:        return(ifa_best);
1.2       itojun   2017: }
                   2018:
                   2019: /*
                   2020:  * return the best address out of the same scope. if no address was
                   2021:  * found, return the first valid address from designated IF.
                   2022:  */
                   2023:
                   2024: struct in6_ifaddr *
                   2025: in6_ifawithifp(ifp, dst)
                   2026:        register struct ifnet *ifp;
                   2027:        register struct in6_addr *dst;
                   2028: {
                   2029:        int dst_scope = in6_addrscope(dst), blen = -1, tlen;
                   2030:        struct ifaddr *ifa;
                   2031:        struct in6_ifaddr *besta = 0;
1.8       itojun   2032:        struct in6_ifaddr *dep[2];      /*last-resort: deprecated*/
                   2033:
                   2034:        dep[0] = dep[1] = NULL;
1.2       itojun   2035:
                   2036:        /*
1.18      itojun   2037:         * We first look for addresses in the same scope.
1.2       itojun   2038:         * If there is one, return it.
                   2039:         * If two or more, return one which matches the dst longest.
                   2040:         * If none, return one of global addresses assigned other ifs.
                   2041:         */
1.8       itojun   2042:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
                   2043:        {
1.2       itojun   2044:                if (ifa->ifa_addr->sa_family != AF_INET6)
                   2045:                        continue;
                   2046:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
                   2047:                        continue; /* XXX: is there any case to allow anycast? */
                   2048:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
                   2049:                        continue; /* don't use this interface */
                   2050:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
                   2051:                        continue;
1.8       itojun   2052:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
                   2053:                        if (ip6_use_deprecated)
                   2054:                                dep[0] = (struct in6_ifaddr *)ifa;
1.2       itojun   2055:                        continue;
1.8       itojun   2056:                }
1.2       itojun   2057:
1.8       itojun   2058:                if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
1.2       itojun   2059:                        /*
                   2060:                         * call in6_matchlen() as few as possible
                   2061:                         */
                   2062:                        if (besta) {
                   2063:                                if (blen == -1)
                   2064:                                        blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
1.8       itojun   2065:                                tlen = in6_matchlen(IFA_IN6(ifa), dst);
1.2       itojun   2066:                                if (tlen > blen) {
                   2067:                                        blen = tlen;
                   2068:                                        besta = (struct in6_ifaddr *)ifa;
                   2069:                                }
1.18      itojun   2070:                        } else
1.2       itojun   2071:                                besta = (struct in6_ifaddr *)ifa;
                   2072:                }
                   2073:        }
                   2074:        if (besta)
                   2075:                return(besta);
                   2076:
1.8       itojun   2077:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
                   2078:        {
1.2       itojun   2079:                if (ifa->ifa_addr->sa_family != AF_INET6)
                   2080:                        continue;
                   2081:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
                   2082:                        continue; /* XXX: is there any case to allow anycast? */
                   2083:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
                   2084:                        continue; /* don't use this interface */
                   2085:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
                   2086:                        continue;
1.8       itojun   2087:                if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
                   2088:                        if (ip6_use_deprecated)
                   2089:                                dep[1] = (struct in6_ifaddr *)ifa;
1.2       itojun   2090:                        continue;
1.8       itojun   2091:                }
1.2       itojun   2092:
                   2093:                return (struct in6_ifaddr *)ifa;
                   2094:        }
                   2095:
1.8       itojun   2096:        /* use the last-resort values, that are, deprecated addresses */
                   2097:        if (dep[0])
                   2098:                return dep[0];
                   2099:        if (dep[1])
                   2100:                return dep[1];
                   2101:
1.2       itojun   2102:        return NULL;
                   2103: }
                   2104:
                   2105: /*
                   2106:  * perform DAD when interface becomes IFF_UP.
                   2107:  */
                   2108: void
                   2109: in6_if_up(ifp)
                   2110:        struct ifnet *ifp;
                   2111: {
                   2112:        struct ifaddr *ifa;
                   2113:        struct in6_ifaddr *ia;
                   2114:        int dad_delay;          /* delay ticks before DAD output */
                   2115:
1.29      itojun   2116:        /*
                   2117:         * special cases, like 6to4, are handled in in6_ifattach
                   2118:         */
                   2119:        in6_ifattach(ifp, NULL);
1.2       itojun   2120:
                   2121:        dad_delay = 0;
1.8       itojun   2122:        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
                   2123:        {
1.2       itojun   2124:                if (ifa->ifa_addr->sa_family != AF_INET6)
                   2125:                        continue;
                   2126:                ia = (struct in6_ifaddr *)ifa;
                   2127:                if (ia->ia6_flags & IN6_IFF_TENTATIVE)
                   2128:                        nd6_dad_start(ifa, &dad_delay);
                   2129:        }
                   2130: }
                   2131:
                   2132: /*
                   2133:  * Calculate max IPv6 MTU through all the interfaces and store it
                   2134:  * to in6_maxmtu.
                   2135:  */
                   2136: void
                   2137: in6_setmaxmtu()
                   2138: {
                   2139:        unsigned long maxmtu = 0;
                   2140:        struct ifnet *ifp;
                   2141:
1.8       itojun   2142:        for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
                   2143:        {
1.2       itojun   2144:                if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
                   2145:                    nd_ifinfo[ifp->if_index].linkmtu > maxmtu)
                   2146:                        maxmtu =  nd_ifinfo[ifp->if_index].linkmtu;
                   2147:        }
                   2148:        if (maxmtu)     /* update only when maxmtu is positive */
                   2149:                in6_maxmtu = maxmtu;
                   2150: }

CVSweb <webmaster@jp.NetBSD.org>