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

Annotation of src/sys/netinet6/in6_src.c, Revision 1.1

1.1     ! itojun      1: /*     $NetBSD$        */
        !             2: /*     $KAME: in6_src.c,v 1.15 2000/05/30 10:16:24 jinmei Exp $        */
        !             3:
        !             4: /*
        !             5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the project nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  */
        !            32:
        !            33: /*
        !            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_pcb.c    8.2 (Berkeley) 1/4/94
        !            66:  */
        !            67:
        !            68: #include "opt_inet.h"
        !            69:
        !            70: #include <sys/param.h>
        !            71: #include <sys/systm.h>
        !            72: #include <sys/malloc.h>
        !            73: #include <sys/mbuf.h>
        !            74: #include <sys/protosw.h>
        !            75: #include <sys/socket.h>
        !            76: #include <sys/socketvar.h>
        !            77: #include <sys/ioctl.h>
        !            78: #include <sys/errno.h>
        !            79: #include <sys/time.h>
        !            80: #include <sys/proc.h>
        !            81:
        !            82: #include <net/if.h>
        !            83: #include <net/route.h>
        !            84:
        !            85: #include <netinet/in.h>
        !            86: #include <netinet/in_var.h>
        !            87: #include <netinet/in_systm.h>
        !            88: #include <netinet/ip.h>
        !            89: #include <netinet/in_pcb.h>
        !            90: #include <netinet6/in6_var.h>
        !            91: #include <netinet/ip6.h>
        !            92: #include <netinet6/in6_pcb.h>
        !            93: #include <netinet6/ip6_var.h>
        !            94: #include <netinet6/nd6.h>
        !            95:
        !            96: #include <net/net_osdep.h>
        !            97:
        !            98: #include "loop.h"
        !            99: extern struct ifnet loif[NLOOP];
        !           100:
        !           101: /*
        !           102:  * Return an IPv6 address, which is the most appropriate for given
        !           103:  * destination and user specified options.
        !           104:  * If necessary, this function lookups the routing table and return
        !           105:  * an entry to the caller for later use.
        !           106:  */
        !           107: struct in6_addr *
        !           108: in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
        !           109:        struct sockaddr_in6 *dstsock;
        !           110:        struct ip6_pktopts *opts;
        !           111:        struct ip6_moptions *mopts;
        !           112:        struct route_in6 *ro;
        !           113:        struct in6_addr *laddr;
        !           114:        int *errorp;
        !           115: {
        !           116:        struct in6_addr *dst;
        !           117:        struct in6_ifaddr *ia6 = 0;
        !           118:        struct in6_pktinfo *pi = NULL;
        !           119:
        !           120:        dst = &dstsock->sin6_addr;
        !           121:        *errorp = 0;
        !           122:
        !           123:        /*
        !           124:         * If the source address is explicitly specified by the caller,
        !           125:         * use it.
        !           126:         */
        !           127:        if (opts && (pi = opts->ip6po_pktinfo) &&
        !           128:            !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
        !           129:                return(&pi->ipi6_addr);
        !           130:
        !           131:        /*
        !           132:         * If the source address is not specified but the socket(if any)
        !           133:         * is already bound, use the bound address.
        !           134:         */
        !           135:        if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
        !           136:                return(laddr);
        !           137:
        !           138:        /*
        !           139:         * If the caller doesn't specify the source address but
        !           140:         * the outgoing interface, use an address associated with
        !           141:         * the interface.
        !           142:         */
        !           143:        if (pi && pi->ipi6_ifindex) {
        !           144:                /* XXX boundary check is assumed to be already done. */
        !           145:                ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
        !           146:                                       dst);
        !           147:                if (ia6 == 0) {
        !           148:                        *errorp = EADDRNOTAVAIL;
        !           149:                        return(0);
        !           150:                }
        !           151:                return(&satosin6(&ia6->ia_addr)->sin6_addr);
        !           152:        }
        !           153:
        !           154:        /*
        !           155:         * If the destination address is a link-local unicast address or
        !           156:         * a multicast address, and if the outgoing interface is specified
        !           157:         * by the sin6_scope_id filed, use an address associated with the
        !           158:         * interface.
        !           159:         * XXX: We're now trying to define more specific semantics of
        !           160:         *      sin6_scope_id field, so this part will be rewritten in
        !           161:         *      the near future.
        !           162:         */
        !           163:        if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
        !           164:            dstsock->sin6_scope_id) {
        !           165:                /*
        !           166:                 * I'm not sure if boundary check for scope_id is done
        !           167:                 * somewhere...
        !           168:                 */
        !           169:                if (dstsock->sin6_scope_id < 0 ||
        !           170:                    if_index < dstsock->sin6_scope_id) {
        !           171:                        *errorp = ENXIO; /* XXX: better error? */
        !           172:                        return(0);
        !           173:                }
        !           174:                ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
        !           175:                                       dst);
        !           176:                if (ia6 == 0) {
        !           177:                        *errorp = EADDRNOTAVAIL;
        !           178:                        return(0);
        !           179:                }
        !           180:                return(&satosin6(&ia6->ia_addr)->sin6_addr);
        !           181:        }
        !           182:
        !           183:        /*
        !           184:         * If the destination address is a multicast address and
        !           185:         * the outgoing interface for the address is specified
        !           186:         * by the caller, use an address associated with the interface.
        !           187:         * There is a sanity check here; if the destination has node-local
        !           188:         * scope, the outgoing interfacde should be a loopback address.
        !           189:         * Even if the outgoing interface is not specified, we also
        !           190:         * choose a loopback interface as the outgoing interface.
        !           191:         */
        !           192:        if (IN6_IS_ADDR_MULTICAST(dst)) {
        !           193:                struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
        !           194:
        !           195:                if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
        !           196:                        ifp = &loif[0];
        !           197:                }
        !           198:
        !           199:                if (ifp) {
        !           200:                        ia6 = in6_ifawithscope(ifp, dst);
        !           201:                        if (ia6 == 0) {
        !           202:                                *errorp = EADDRNOTAVAIL;
        !           203:                                return(0);
        !           204:                        }
        !           205:                        return(&satosin6(&ia6->ia_addr)->sin6_addr);
        !           206:                }
        !           207:        }
        !           208:
        !           209:        /*
        !           210:         * If the next hop address for the packet is specified
        !           211:         * by caller, use an address associated with the route
        !           212:         * to the next hop.
        !           213:         */
        !           214:        {
        !           215:                struct sockaddr_in6 *sin6_next;
        !           216:                struct rtentry *rt;
        !           217:
        !           218:                if (opts && opts->ip6po_nexthop) {
        !           219:                        sin6_next = satosin6(opts->ip6po_nexthop);
        !           220:                        rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
        !           221:                        if (rt) {
        !           222:                                ia6 = in6_ifawithscope(rt->rt_ifp, dst);
        !           223:                                if (ia6 == 0)
        !           224:                                        ia6 = ifatoia6(rt->rt_ifa);
        !           225:                        }
        !           226:                        if (ia6 == 0) {
        !           227:                                *errorp = EADDRNOTAVAIL;
        !           228:                                return(0);
        !           229:                        }
        !           230:                        return(&satosin6(&ia6->ia_addr)->sin6_addr);
        !           231:                }
        !           232:        }
        !           233:
        !           234:        /*
        !           235:         * If route is known or can be allocated now,
        !           236:         * our src addr is taken from the i/f, else punt.
        !           237:         */
        !           238:        if (ro) {
        !           239:                if (ro->ro_rt &&
        !           240:                    !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
        !           241:                        RTFREE(ro->ro_rt);
        !           242:                        ro->ro_rt = (struct rtentry *)0;
        !           243:                }
        !           244:                if (ro->ro_rt == (struct rtentry *)0 ||
        !           245:                    ro->ro_rt->rt_ifp == (struct ifnet *)0) {
        !           246:                        /* No route yet, so try to acquire one */
        !           247:                        bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
        !           248:                        ro->ro_dst.sin6_family = AF_INET6;
        !           249:                        ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
        !           250:                        ro->ro_dst.sin6_addr = *dst;
        !           251:                        ro->ro_dst.sin6_scope_id = dstsock->sin6_scope_id;
        !           252:                        if (IN6_IS_ADDR_MULTICAST(dst)) {
        !           253:                                ro->ro_rt = rtalloc1(&((struct route *)ro)
        !           254:                                                     ->ro_dst, 0);
        !           255:                        } else {
        !           256:                                rtalloc((struct route *)ro);
        !           257:                        }
        !           258:                }
        !           259:
        !           260:                /*
        !           261:                 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
        !           262:                 * the address. But we don't know why it does so.
        !           263:                 * It is necessary to ensure the scope even for lo0
        !           264:                 * so doesn't check out IFF_LOOPBACK.
        !           265:                 */
        !           266:
        !           267:                if (ro->ro_rt) {
        !           268:                        ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
        !           269:                        if (ia6 == 0) /* xxx scope error ?*/
        !           270:                                ia6 = ifatoia6(ro->ro_rt->rt_ifa);
        !           271:                }
        !           272: #if 0
        !           273:                /*
        !           274:                 * xxx The followings are necessary? (kazu)
        !           275:                 * I don't think so.
        !           276:                 * It's for SO_DONTROUTE option in IPv4.(jinmei)
        !           277:                 */
        !           278:                if (ia6 == 0) {
        !           279:                        struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
        !           280:
        !           281:                        sin6->sin6_addr = *dst;
        !           282:
        !           283:                        ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
        !           284:                        if (ia6 == 0)
        !           285:                                ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
        !           286:                        if (ia6 == 0)
        !           287:                                return(0);
        !           288:                        return(&satosin6(&ia6->ia_addr)->sin6_addr);
        !           289:                }
        !           290: #endif /* 0 */
        !           291:                if (ia6 == 0) {
        !           292:                        *errorp = EHOSTUNREACH; /* no route */
        !           293:                        return(0);
        !           294:                }
        !           295:                return(&satosin6(&ia6->ia_addr)->sin6_addr);
        !           296:        }
        !           297:
        !           298:        *errorp = EADDRNOTAVAIL;
        !           299:        return(0);
        !           300: }
        !           301:
        !           302: /*
        !           303:  * Default hop limit selection. The precedence is as follows:
        !           304:  * 1. Hoplimit value specified via ioctl.
        !           305:  * 2. (If the outgoing interface is detected) the current
        !           306:  *     hop limit of the interface specified by router advertisement.
        !           307:  * 3. The system default hoplimit.
        !           308: */
        !           309: int
        !           310: in6_selecthlim(in6p, ifp)
        !           311:        struct in6pcb *in6p;
        !           312:        struct ifnet *ifp;
        !           313: {
        !           314:        if (in6p && in6p->in6p_hops >= 0)
        !           315:                return(in6p->in6p_hops);
        !           316:        else if (ifp)
        !           317:                return(nd_ifinfo[ifp->if_index].chlim);
        !           318:        else
        !           319:                return(ip6_defhlim);
        !           320: }
        !           321:
        !           322: /*
        !           323:  * Find an empty port and set it to the specified PCB.
        !           324:  */
        !           325: int
        !           326: in6_pcbsetport(laddr, in6p)
        !           327:        struct in6_addr *laddr;
        !           328:        struct in6pcb *in6p;
        !           329: {
        !           330:        struct socket *so = in6p->in6p_socket;
        !           331:        struct in6pcb *head = in6p->in6p_head;
        !           332:        u_int16_t last_port, lport = 0;
        !           333:        int wild = 0;
        !           334:        void *t;
        !           335:        u_int16_t min, max;
        !           336:        struct proc *p = curproc;               /* XXX */
        !           337:
        !           338:        /* XXX: this is redundant when called from in6_pcbbind */
        !           339:        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
        !           340:           ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
        !           341:            (so->so_options & SO_ACCEPTCONN) == 0))
        !           342:                wild = IN6PLOOKUP_WILDCARD;
        !           343:
        !           344:        if (in6p->in6p_flags & IN6P_LOWPORT) {
        !           345:                if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0))
        !           346:                        return (EACCES);
        !           347:                min = IPV6PORT_RESERVEDMIN;
        !           348:                max = IPV6PORT_RESERVEDMAX;
        !           349:        } else {
        !           350:                min = IPV6PORT_ANONMIN;
        !           351:                max = IPV6PORT_ANONMAX;
        !           352:        }
        !           353:
        !           354:        /* value out of range */
        !           355:        if (head->in6p_lport < min)
        !           356:                head->in6p_lport = min;
        !           357:        else if (head->in6p_lport > max)
        !           358:                head->in6p_lport = min;
        !           359:        last_port = head->in6p_lport;
        !           360:        goto startover; /*to randomize*/
        !           361:        for (;;) {
        !           362:                lport = htons(head->in6p_lport);
        !           363:                if (IN6_IS_ADDR_V4MAPPED(laddr)) {
        !           364: #if 0
        !           365:                        t = in_pcblookup_bind(&tcbtable,
        !           366:                                              (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
        !           367:                                              lport);
        !           368: #else
        !           369:                        t = NULL;
        !           370: #endif
        !           371:                } else {
        !           372:                        t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
        !           373:                                          lport, wild);
        !           374:                }
        !           375:                if (t == 0)
        !           376:                        break;
        !           377:          startover:
        !           378:                if (head->in6p_lport >= max)
        !           379:                        head->in6p_lport = min;
        !           380:                else
        !           381:                        head->in6p_lport++;
        !           382:                if (head->in6p_lport == last_port)
        !           383:                        return (EADDRINUSE);
        !           384:        }
        !           385:
        !           386:        in6p->in6p_lport = lport;
        !           387:        return(0);              /* success */
        !           388: }

CVSweb <webmaster@jp.NetBSD.org>