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

Annotation of sys/netinet6/in6_src.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: in6_src.c,v 1.22 2006/12/11 11:26:05 itojun Exp $     */
                      2: /*     $KAME: in6_src.c,v 1.36 2001/02/06 04:08:17 itojun Exp $        */
                      3:
                      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the project nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Copyright (c) 1982, 1986, 1991, 1993
                     35:  *     The Regents of the University of California.  All rights reserved.
                     36:  *
                     37:  * Redistribution and use in source and binary forms, with or without
                     38:  * modification, are permitted provided that the following conditions
                     39:  * are met:
                     40:  * 1. Redistributions of source code must retain the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer.
                     42:  * 2. Redistributions in binary form must reproduce the above copyright
                     43:  *    notice, this list of conditions and the following disclaimer in the
                     44:  *    documentation and/or other materials provided with the distribution.
                     45:  * 3. Neither the name of the University nor the names of its contributors
                     46:  *    may be used to endorse or promote products derived from this software
                     47:  *    without specific prior written permission.
                     48:  *
                     49:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     50:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     51:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     52:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     53:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     54:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     55:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     56:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     57:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     58:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     59:  * SUCH DAMAGE.
                     60:  *
                     61:  *     @(#)in_pcb.c    8.2 (Berkeley) 1/4/94
                     62:  */
                     63:
                     64: #include <sys/param.h>
                     65: #include <sys/systm.h>
                     66: #include <sys/malloc.h>
                     67: #include <sys/mbuf.h>
                     68: #include <sys/protosw.h>
                     69: #include <sys/socket.h>
                     70: #include <sys/socketvar.h>
                     71: #include <sys/ioctl.h>
                     72: #include <sys/errno.h>
                     73: #include <sys/time.h>
                     74: #include <sys/proc.h>
                     75:
                     76: #include <net/if.h>
                     77: #include <net/route.h>
                     78:
                     79: #include <netinet/in.h>
                     80: #include <netinet/in_var.h>
                     81: #include <netinet/in_systm.h>
                     82: #include <netinet/ip.h>
                     83: #include <netinet/in_pcb.h>
                     84: #include <netinet6/in6_var.h>
                     85: #include <netinet/ip6.h>
                     86: #include <netinet6/ip6_var.h>
                     87: #include <netinet6/nd6.h>
                     88:
                     89: static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
                     90:        struct ip6_moptions *, struct route_in6 *, struct ifnet **,
                     91:        struct rtentry **, int);
                     92:
                     93: /*
                     94:  * Return an IPv6 address, which is the most appropriate for a given
                     95:  * destination and user specified options.
                     96:  * If necessary, this function lookups the routing table and returns
                     97:  * an entry to the caller for later use.
                     98:  */
                     99: struct in6_addr *
                    100: in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
                    101:        struct sockaddr_in6 *dstsock;
                    102:        struct ip6_pktopts *opts;
                    103:        struct ip6_moptions *mopts;
                    104:        struct route_in6 *ro;
                    105:        struct in6_addr *laddr;
                    106:        int *errorp;
                    107: {
                    108:        struct in6_addr *dst;
                    109:        struct in6_ifaddr *ia6 = 0;
                    110:        struct in6_pktinfo *pi = NULL;
                    111:
                    112:        dst = &dstsock->sin6_addr;
                    113:        *errorp = 0;
                    114:
                    115:        /*
                    116:         * If the source address is explicitly specified by the caller,
                    117:         * use it.
                    118:         */
                    119:        if (opts && (pi = opts->ip6po_pktinfo) &&
                    120:            !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
                    121:                return (&pi->ipi6_addr);
                    122:
                    123:        /*
                    124:         * If the source address is not specified but the socket(if any)
                    125:         * is already bound, use the bound address.
                    126:         */
                    127:        if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
                    128:                return (laddr);
                    129:
                    130:        /*
                    131:         * If the caller doesn't specify the source address but
                    132:         * the outgoing interface, use an address associated with
                    133:         * the interface.
                    134:         */
                    135:        if (pi && pi->ipi6_ifindex) {
                    136:                /* XXX boundary check is assumed to be already done. */
                    137:                ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
                    138:                                       dst);
                    139:                if (ia6 == 0) {
                    140:                        *errorp = EADDRNOTAVAIL;
                    141:                        return (0);
                    142:                }
                    143:                return (&satosin6(&ia6->ia_addr)->sin6_addr);
                    144:        }
                    145:
                    146:        /*
                    147:         * If the destination address is a link-local unicast address or
                    148:         * a link/interface-local multicast address, and if the outgoing
                    149:         * interface is specified by the sin6_scope_id filed, use an address
                    150:         * associated with the interface.
                    151:         * XXX: We're now trying to define more specific semantics of
                    152:         *      sin6_scope_id field, so this part will be rewritten in
                    153:         *      the near future.
                    154:         */
                    155:        if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
                    156:             IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
                    157:                /*
                    158:                 * I'm not sure if boundary check for scope_id is done
                    159:                 * somewhere...
                    160:                 */
                    161:                if (dstsock->sin6_scope_id < 0 ||
                    162:                    if_indexlim <= dstsock->sin6_scope_id ||
                    163:                    !ifindex2ifnet[dstsock->sin6_scope_id]) {
                    164:                        *errorp = ENXIO; /* XXX: better error? */
                    165:                        return (0);
                    166:                }
                    167:                ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
                    168:                                       dst);
                    169:                if (ia6 == 0) {
                    170:                        *errorp = EADDRNOTAVAIL;
                    171:                        return (0);
                    172:                }
                    173:                return (&satosin6(&ia6->ia_addr)->sin6_addr);
                    174:        }
                    175:
                    176:        /*
                    177:         * If the destination address is a multicast address and
                    178:         * the outgoing interface for the address is specified
                    179:         * by the caller, use an address associated with the interface.
                    180:         * Even if the outgoing interface is not specified, we also
                    181:         * choose a loopback interface as the outgoing interface.
                    182:         */
                    183:        if (IN6_IS_ADDR_MULTICAST(dst)) {
                    184:                struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
                    185:
                    186:                if (!ifp && dstsock->sin6_scope_id)
                    187:                        ifp = ifindex2ifnet[htons(dstsock->sin6_scope_id)];
                    188:
                    189:                if (ifp) {
                    190:                        ia6 = in6_ifawithscope(ifp, dst);
                    191:                        if (ia6 == 0) {
                    192:                                *errorp = EADDRNOTAVAIL;
                    193:                                return (0);
                    194:                        }
                    195:                        return (&satosin6(&ia6->ia_addr)->sin6_addr);
                    196:                }
                    197:        }
                    198:
                    199:        /*
                    200:         * If the next hop address for the packet is specified
                    201:         * by caller, use an address associated with the route
                    202:         * to the next hop.
                    203:         */
                    204:        {
                    205:                struct sockaddr_in6 *sin6_next;
                    206:                struct rtentry *rt;
                    207:
                    208:                if (opts && opts->ip6po_nexthop) {
                    209:                        sin6_next = satosin6(opts->ip6po_nexthop);
                    210:                        rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
                    211:                        if (rt) {
                    212:                                ia6 = in6_ifawithscope(rt->rt_ifp, dst);
                    213:                                if (ia6 == 0)
                    214:                                        ia6 = ifatoia6(rt->rt_ifa);
                    215:                        }
                    216:                        if (ia6 == 0) {
                    217:                                *errorp = EADDRNOTAVAIL;
                    218:                                return (0);
                    219:                        }
                    220:                        return (&satosin6(&ia6->ia_addr)->sin6_addr);
                    221:                }
                    222:        }
                    223:
                    224:        /*
                    225:         * If route is known or can be allocated now,
                    226:         * our src addr is taken from the i/f, else punt.
                    227:         */
                    228:        if (ro) {
                    229:                if (ro->ro_rt &&
                    230:                    !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
                    231:                        RTFREE(ro->ro_rt);
                    232:                        ro->ro_rt = (struct rtentry *)0;
                    233:                }
                    234:                if (ro->ro_rt == (struct rtentry *)0 ||
                    235:                    ro->ro_rt->rt_ifp == (struct ifnet *)0) {
                    236:                        struct sockaddr_in6 *sa6;
                    237:
                    238:                        /* No route yet, so try to acquire one */
                    239:                        bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
                    240:                        sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
                    241:                        sa6->sin6_family = AF_INET6;
                    242:                        sa6->sin6_len = sizeof(struct sockaddr_in6);
                    243:                        sa6->sin6_addr = *dst;
                    244:                        sa6->sin6_scope_id = dstsock->sin6_scope_id;
                    245:                        if (IN6_IS_ADDR_MULTICAST(dst)) {
                    246:                                ro->ro_rt = rtalloc1(&((struct route *)ro)
                    247:                                                     ->ro_dst, 0, 0);
                    248:                        } else {
                    249:                                rtalloc_mpath((struct route *)ro, NULL, 0);
                    250:                        }
                    251:                }
                    252:
                    253:                /*
                    254:                 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
                    255:                 * the address. But we don't know why it does so.
                    256:                 * It is necessary to ensure the scope even for lo0
                    257:                 * so doesn't check out IFF_LOOPBACK.
                    258:                 */
                    259:
                    260:                if (ro->ro_rt) {
                    261:                        ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
                    262:                        if (ia6 == 0) /* xxx scope error ?*/
                    263:                                ia6 = ifatoia6(ro->ro_rt->rt_ifa);
                    264:                }
                    265: #if 0
                    266:                /*
                    267:                 * xxx The followings are necessary? (kazu)
                    268:                 * I don't think so.
                    269:                 * It's for SO_DONTROUTE option in IPv4.(jinmei)
                    270:                 */
                    271:                if (ia6 == 0) {
                    272:                        struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
                    273:
                    274:                        sin6->sin6_addr = *dst;
                    275:
                    276:                        ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
                    277:                        if (ia6 == 0)
                    278:                                ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
                    279:                        if (ia6 == 0)
                    280:                                return (0);
                    281:                        return (&satosin6(&ia6->ia_addr)->sin6_addr);
                    282:                }
                    283: #endif /* 0 */
                    284:                if (ia6 == 0) {
                    285:                        *errorp = EHOSTUNREACH; /* no route */
                    286:                        return (0);
                    287:                }
                    288:                return (&satosin6(&ia6->ia_addr)->sin6_addr);
                    289:        }
                    290:
                    291:        *errorp = EADDRNOTAVAIL;
                    292:        return (0);
                    293: }
                    294:
                    295: static int
                    296: selectroute(dstsock, opts, mopts, ro, retifp, retrt, norouteok)
                    297:        struct sockaddr_in6 *dstsock;
                    298:        struct ip6_pktopts *opts;
                    299:        struct ip6_moptions *mopts;
                    300:        struct route_in6 *ro;
                    301:        struct ifnet **retifp;
                    302:        struct rtentry **retrt;
                    303:        int norouteok;
                    304: {
                    305:        int error = 0;
                    306:        struct ifnet *ifp = NULL;
                    307:        struct rtentry *rt = NULL;
                    308:        struct sockaddr_in6 *sin6_next;
                    309:        struct in6_pktinfo *pi = NULL;
                    310:        struct in6_addr *dst;
                    311:
                    312:        dst = &dstsock->sin6_addr;
                    313:
                    314: #if 0
                    315:        if (dstsock->sin6_addr.s6_addr32[0] == 0 &&
                    316:            dstsock->sin6_addr.s6_addr32[1] == 0 &&
                    317:            !IN6_IS_ADDR_LOOPBACK(&dstsock->sin6_addr)) {
                    318:                printf("in6_selectroute: strange destination %s\n",
                    319:                       ip6_sprintf(&dstsock->sin6_addr));
                    320:        } else {
                    321:                printf("in6_selectroute: destination = %s%%%d\n",
                    322:                       ip6_sprintf(&dstsock->sin6_addr),
                    323:                       dstsock->sin6_scope_id); /* for debug */
                    324:        }
                    325: #endif
                    326:
                    327:        /* If the caller specify the outgoing interface explicitly, use it. */
                    328:        if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
                    329:                /* XXX boundary check is assumed to be already done. */
                    330:                ifp = ifindex2ifnet[pi->ipi6_ifindex];
                    331:                if (ifp != NULL &&
                    332:                    (norouteok || retrt == NULL ||
                    333:                     IN6_IS_ADDR_MULTICAST(dst))) {
                    334:                        /*
                    335:                         * we do not have to check or get the route for
                    336:                         * multicast.
                    337:                         */
                    338:                        goto done;
                    339:                } else
                    340:                        goto getroute;
                    341:        }
                    342:
                    343:        /*
                    344:         * If the destination address is a multicast address and the outgoing
                    345:         * interface for the address is specified by the caller, use it.
                    346:         */
                    347:        if (IN6_IS_ADDR_MULTICAST(dst) &&
                    348:            mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {
                    349:                goto done; /* we do not need a route for multicast. */
                    350:        }
                    351:
                    352:   getroute:
                    353:        /*
                    354:         * If the next hop address for the packet is specified by the caller,
                    355:         * use it as the gateway.
                    356:         */
                    357:        if (opts && opts->ip6po_nexthop) {
                    358:                struct route_in6 *ron;
                    359:
                    360:                sin6_next = satosin6(opts->ip6po_nexthop);
                    361:
                    362:                /* at this moment, we only support AF_INET6 next hops */
                    363:                if (sin6_next->sin6_family != AF_INET6) {
                    364:                        error = EAFNOSUPPORT; /* or should we proceed? */
                    365:                        goto done;
                    366:                }
                    367:
                    368:                /*
                    369:                 * If the next hop is an IPv6 address, then the node identified
                    370:                 * by that address must be a neighbor of the sending host.
                    371:                 */
                    372:                ron = &opts->ip6po_nextroute;
                    373:                if ((ron->ro_rt &&
                    374:                    (ron->ro_rt->rt_flags & (RTF_UP | RTF_GATEWAY)) !=
                    375:                    RTF_UP) ||
                    376:                    !IN6_ARE_ADDR_EQUAL(&satosin6(&ron->ro_dst)->sin6_addr,
                    377:                    &sin6_next->sin6_addr)) {
                    378:                        if (ron->ro_rt) {
                    379:                                RTFREE(ron->ro_rt);
                    380:                                ron->ro_rt = NULL;
                    381:                        }
                    382:                        *satosin6(&ron->ro_dst) = *sin6_next;
                    383:                }
                    384:                if (ron->ro_rt == NULL) {
                    385:                        rtalloc((struct route *)ron); /* multi path case? */
                    386:                        if (ron->ro_rt == NULL ||
                    387:                            (ron->ro_rt->rt_flags & RTF_GATEWAY)) {
                    388:                                if (ron->ro_rt) {
                    389:                                        RTFREE(ron->ro_rt);
                    390:                                        ron->ro_rt = NULL;
                    391:                                }
                    392:                                error = EHOSTUNREACH;
                    393:                                goto done;
                    394:                        }
                    395:                }
                    396:                if (!nd6_is_addr_neighbor(sin6_next, ron->ro_rt->rt_ifp)) {
                    397:                        RTFREE(ron->ro_rt);
                    398:                        ron->ro_rt = NULL;
                    399:                        error = EHOSTUNREACH;
                    400:                        goto done;
                    401:                }
                    402:                rt = ron->ro_rt;
                    403:                ifp = rt->rt_ifp;
                    404:
                    405:                /*
                    406:                 * When cloning is required, try to allocate a route to the
                    407:                 * destination so that the caller can store path MTU
                    408:                 * information.
                    409:                 */
                    410:                goto done;
                    411:        }
                    412:
                    413:        /*
                    414:         * Use a cached route if it exists and is valid, else try to allocate
                    415:         * a new one.  Note that we should check the address family of the
                    416:         * cached destination, in case of sharing the cache with IPv4.
                    417:         */
                    418:        if (ro) {
                    419:                if (ro->ro_rt &&
                    420:                    (!(ro->ro_rt->rt_flags & RTF_UP) ||
                    421:                     ((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 ||
                    422:                     !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
                    423:                     dst))) {
                    424:                        RTFREE(ro->ro_rt);
                    425:                        ro->ro_rt = (struct rtentry *)NULL;
                    426:                }
                    427:                if (ro->ro_rt == (struct rtentry *)NULL) {
                    428:                        struct sockaddr_in6 *sa6;
                    429:
                    430:                        /* No route yet, so try to acquire one */
                    431:                        bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
                    432:                        sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
                    433:                        *sa6 = *dstsock;
                    434:                        sa6->sin6_scope_id = 0;
                    435:                        rtalloc_mpath((struct route *)ro, NULL, 0);
                    436:                }
                    437:
                    438:                /*
                    439:                 * do not care about the result if we have the nexthop
                    440:                 * explicitly specified.
                    441:                 */
                    442:                if (opts && opts->ip6po_nexthop)
                    443:                        goto done;
                    444:
                    445:                if (ro->ro_rt) {
                    446:                        ifp = ro->ro_rt->rt_ifp;
                    447:
                    448:                        if (ifp == NULL) { /* can this really happen? */
                    449:                                RTFREE(ro->ro_rt);
                    450:                                ro->ro_rt = NULL;
                    451:                        }
                    452:                }
                    453:                if (ro->ro_rt == NULL)
                    454:                        error = EHOSTUNREACH;
                    455:                rt = ro->ro_rt;
                    456:
                    457:                /*
                    458:                 * Check if the outgoing interface conflicts with
                    459:                 * the interface specified by ipi6_ifindex (if specified).
                    460:                 * Note that loopback interface is always okay.
                    461:                 * (this may happen when we are sending a packet to one of
                    462:                 *  our own addresses.)
                    463:                 */
                    464:                if (opts && opts->ip6po_pktinfo &&
                    465:                    opts->ip6po_pktinfo->ipi6_ifindex) {
                    466:                        if (!(ifp->if_flags & IFF_LOOPBACK) &&
                    467:                            ifp->if_index !=
                    468:                            opts->ip6po_pktinfo->ipi6_ifindex) {
                    469:                                error = EHOSTUNREACH;
                    470:                                goto done;
                    471:                        }
                    472:                }
                    473:        }
                    474:
                    475:   done:
                    476:        if (ifp == NULL && rt == NULL) {
                    477:                /*
                    478:                 * This can happen if the caller did not pass a cached route
                    479:                 * nor any other hints.  We treat this case an error.
                    480:                 */
                    481:                error = EHOSTUNREACH;
                    482:        }
                    483:        if (error == EHOSTUNREACH)
                    484:                ip6stat.ip6s_noroute++;
                    485:
                    486:        if (retifp != NULL)
                    487:                *retifp = ifp;
                    488:        if (retrt != NULL)
                    489:                *retrt = rt;    /* rt may be NULL */
                    490:
                    491:        return (error);
                    492: }
                    493:
                    494: int
                    495: in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt)
                    496:        struct sockaddr_in6 *dstsock;
                    497:        struct ip6_pktopts *opts;
                    498:        struct ip6_moptions *mopts;
                    499:        struct route_in6 *ro;
                    500:        struct ifnet **retifp;
                    501:        struct rtentry **retrt;
                    502: {
                    503:
                    504:        return (selectroute(dstsock, opts, mopts, ro, retifp, retrt, 0));
                    505: }
                    506:
                    507: /*
                    508:  * Default hop limit selection. The precedence is as follows:
                    509:  * 1. Hoplimit value specified via ioctl.
                    510:  * 2. (If the outgoing interface is detected) the current
                    511:  *     hop limit of the interface specified by router advertisement.
                    512:  * 3. The system default hoplimit.
                    513: */
                    514: #define in6pcb         inpcb
                    515: #define in6p_hops      inp_hops
                    516: int
                    517: in6_selecthlim(in6p, ifp)
                    518:        struct in6pcb *in6p;
                    519:        struct ifnet *ifp;
                    520: {
                    521:        if (in6p && in6p->in6p_hops >= 0)
                    522:                return (in6p->in6p_hops);
                    523:        else if (ifp)
                    524:                return (ND_IFINFO(ifp)->chlim);
                    525:        else
                    526:                return (ip6_defhlim);
                    527: }
                    528: #undef in6pcb
                    529: #undef in6p_hops
                    530:
                    531: /*
                    532:  * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
                    533:  * If the address scope of is link-local, embed the interface index in the
                    534:  * address.  The routine determines our precedence
                    535:  * between advanced API scope/interface specification and basic API
                    536:  * specification.
                    537:  *
                    538:  * this function should be nuked in the future, when we get rid of
                    539:  * embedded scopeid thing.
                    540:  *
                    541:  * XXX actually, it is over-specification to return ifp against sin6_scope_id.
                    542:  * there can be multiple interfaces that belong to a particular scope zone
                    543:  * (in specification, we have 1:N mapping between a scope zone and interfaces).
                    544:  * we may want to change the function to return something other than ifp.
                    545:  */
                    546: int
                    547: in6_embedscope(in6, sin6, in6p, ifpp)
                    548:        struct in6_addr *in6;
                    549:        const struct sockaddr_in6 *sin6;
                    550:        struct inpcb *in6p;
                    551: #define in6p_outputopts        inp_outputopts6
                    552: #define in6p_moptions  inp_moptions6
                    553:        struct ifnet **ifpp;
                    554: {
                    555:        struct ifnet *ifp = NULL;
                    556:        u_int32_t scopeid;
                    557:
                    558:        *in6 = sin6->sin6_addr;
                    559:        scopeid = sin6->sin6_scope_id;
                    560:        if (ifpp)
                    561:                *ifpp = NULL;
                    562:
                    563:        /*
                    564:         * don't try to read sin6->sin6_addr beyond here, since the caller may
                    565:         * ask us to overwrite existing sockaddr_in6
                    566:         */
                    567:
                    568:        if (IN6_IS_SCOPE_EMBED(in6)) {
                    569:                struct in6_pktinfo *pi;
                    570:
                    571:                /*
                    572:                 * KAME assumption: link id == interface id
                    573:                 */
                    574:
                    575:                if (in6p && in6p->in6p_outputopts &&
                    576:                    (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
                    577:                    pi->ipi6_ifindex) {
                    578:                        ifp = ifindex2ifnet[pi->ipi6_ifindex];
                    579:                        in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
                    580:                } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
                    581:                           in6p->in6p_moptions &&
                    582:                           in6p->in6p_moptions->im6o_multicast_ifp) {
                    583:                        ifp = in6p->in6p_moptions->im6o_multicast_ifp;
                    584:                        in6->s6_addr16[1] = htons(ifp->if_index);
                    585:                } else if (scopeid) {
                    586:                        /* boundary check */
                    587:                        if (scopeid < 0 || if_indexlim <= scopeid ||
                    588:                            !ifindex2ifnet[scopeid])
                    589:                                return ENXIO;  /* XXX EINVAL? */
                    590:                        ifp = ifindex2ifnet[scopeid];
                    591:                        /*XXX assignment to 16bit from 32bit variable */
                    592:                        in6->s6_addr16[1] = htons(scopeid & 0xffff);
                    593:                }
                    594:
                    595:                if (ifpp)
                    596:                        *ifpp = ifp;
                    597:        }
                    598:
                    599:        return 0;
                    600: }
                    601: #undef in6p_outputopts
                    602: #undef in6p_moptions
                    603:
                    604: /*
                    605:  * generate standard sockaddr_in6 from embedded form.
                    606:  * touches sin6_addr and sin6_scope_id only.
                    607:  *
                    608:  * this function should be nuked in the future, when we get rid of
                    609:  * embedded scopeid thing.
                    610:  */
                    611: int
                    612: in6_recoverscope(sin6, in6, ifp)
                    613:        struct sockaddr_in6 *sin6;
                    614:        const struct in6_addr *in6;
                    615:        struct ifnet *ifp;
                    616: {
                    617:        u_int32_t scopeid;
                    618:
                    619:        sin6->sin6_addr = *in6;
                    620:
                    621:        /*
                    622:         * don't try to read *in6 beyond here, since the caller may
                    623:         * ask us to overwrite existing sockaddr_in6
                    624:         */
                    625:
                    626:        sin6->sin6_scope_id = 0;
                    627:        if (IN6_IS_SCOPE_EMBED(in6)) {
                    628:                /*
                    629:                 * KAME assumption: link id == interface id
                    630:                 */
                    631:                scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
                    632:                if (scopeid) {
                    633:                        /* sanity check */
                    634:                        if (scopeid < 0 || if_indexlim <= scopeid ||
                    635:                            !ifindex2ifnet[scopeid])
                    636:                                return ENXIO;
                    637:                        if (ifp && ifp->if_index != scopeid)
                    638:                                return ENXIO;
                    639:                        sin6->sin6_addr.s6_addr16[1] = 0;
                    640:                        sin6->sin6_scope_id = scopeid;
                    641:                }
                    642:        }
                    643:
                    644:        return 0;
                    645: }
                    646:
                    647: /*
                    648:  * just clear the embedded scope identifer.
                    649:  */
                    650: void
                    651: in6_clearscope(addr)
                    652:        struct in6_addr *addr;
                    653: {
                    654:        if (IN6_IS_SCOPE_EMBED(addr))
                    655:                addr->s6_addr16[1] = 0;
                    656: }

CVSweb