[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.2.2

1.1.2.2 ! itojun      1: /*     $NetBSD: in6_src.c,v 1.1.2.1 2000/08/27 01:11:27 itojun Exp $   */
        !             2: /*     $KAME: in6_src.c,v 1.34 2000/08/26 10:00:45 itojun Exp $        */
1.1       itojun      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) {
1.1.2.1   itojun    345: #ifndef IPNOPRIVPORTS
1.1       itojun    346:                if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0))
                    347:                        return (EACCES);
1.1.2.1   itojun    348: #endif
1.1.2.2 ! itojun    349:                min = ip6_lowportmin;
        !           350:                max = ip6_lowportmax;
1.1       itojun    351:        } else {
1.1.2.2 ! itojun    352:                min = ip6_anonportmin;
        !           353:                max = ip6_anonportmax;
1.1       itojun    354:        }
                    355:
                    356:        /* value out of range */
                    357:        if (head->in6p_lport < min)
                    358:                head->in6p_lport = min;
                    359:        else if (head->in6p_lport > max)
                    360:                head->in6p_lport = min;
                    361:        last_port = head->in6p_lport;
                    362:        goto startover; /*to randomize*/
                    363:        for (;;) {
                    364:                lport = htons(head->in6p_lport);
                    365:                if (IN6_IS_ADDR_V4MAPPED(laddr)) {
                    366: #if 0
                    367:                        t = in_pcblookup_bind(&tcbtable,
                    368:                                              (struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
                    369:                                              lport);
                    370: #else
                    371:                        t = NULL;
                    372: #endif
                    373:                } else {
                    374:                        t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
                    375:                                          lport, wild);
                    376:                }
                    377:                if (t == 0)
                    378:                        break;
                    379:          startover:
                    380:                if (head->in6p_lport >= max)
                    381:                        head->in6p_lport = min;
                    382:                else
                    383:                        head->in6p_lport++;
                    384:                if (head->in6p_lport == last_port)
                    385:                        return (EADDRINUSE);
                    386:        }
                    387:
                    388:        in6p->in6p_lport = lport;
                    389:        return(0);              /* success */
                    390: }

CVSweb <webmaster@jp.NetBSD.org>