[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     ! 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