Annotation of XNU/bsd/netinet/in_pcb.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Copyright (c) 1982, 1986, 1991, 1993, 1995
                     24:  *     The Regents of the University of California.  All rights reserved.
                     25:  *
                     26:  * Redistribution and use in source and binary forms, with or without
                     27:  * modification, are permitted provided that the following conditions
                     28:  * are met:
                     29:  * 1. Redistributions of source code must retain the above copyright
                     30:  *    notice, this list of conditions and the following disclaimer.
                     31:  * 2. Redistributions in binary form must reproduce the above copyright
                     32:  *    notice, this list of conditions and the following disclaimer in the
                     33:  *    documentation and/or other materials provided with the distribution.
                     34:  * 3. All advertising materials mentioning features or use of this software
                     35:  *    must display the following acknowledgement:
                     36:  *     This product includes software developed by the University of
                     37:  *     California, Berkeley and its contributors.
                     38:  * 4. Neither the name of the University nor the names of its contributors
                     39:  *    may be used to endorse or promote products derived from this software
                     40:  *    without specific prior written permission.
                     41:  *
                     42:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     43:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     44:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     45:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     46:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     47:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     48:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     49:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     50:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     51:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     52:  * SUCH DAMAGE.
                     53:  *
                     54:  *     @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
                     55:  */
                     56: 
                     57: #include <sys/param.h>
                     58: #include <sys/systm.h>
                     59: #include <sys/malloc.h>
                     60: #include <sys/mbuf.h>
                     61: #include <sys/protosw.h>
                     62: #include <sys/socket.h>
                     63: #include <sys/socketvar.h>
                     64: #include <sys/proc.h>
                     65: #include <sys/kernel.h>
                     66: #include <sys/sysctl.h>
                     67: 
                     68: #include <machine/limits.h>
                     69: 
                     70: #if ISFB31
                     71: #include <vm/vm_zone.h>
                     72: #else
                     73: #include <kern/zalloc.h>
                     74: #endif
                     75: 
                     76: #include <net/if.h>
                     77: #include <net/route.h>
                     78: 
                     79: #include <netinet/in.h>
                     80: #include <netinet/in_pcb.h>
                     81: #include <netinet/in_var.h>
                     82: #include <netinet/ip_var.h>
                     83: 
                     84: struct in_addr zeroin_addr;
                     85: 
                     86: static void    in_pcbremlists __P((struct inpcb *));
                     87: static void    in_rtchange __P((struct inpcb *, int));
                     88: 
                     89: 
                     90: /*
                     91:  * These configure the range of local port addresses assigned to
                     92:  * "unspecified" outgoing connections/packets/whatever.
                     93:  */
                     94: static int ipport_lowfirstauto  = IPPORT_RESERVED - 1; /* 1023 */
                     95: static int ipport_lowlastauto = IPPORT_RESERVEDSTART;  /* 600 */
                     96: static int ipport_firstauto = IPPORT_RESERVED;         /* 1024 */
                     97: static int ipport_lastauto  = IPPORT_USERRESERVED;     /* 5000 */
                     98: static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;    /* 49152 */
                     99: static int ipport_hilastauto  = IPPORT_HILASTAUTO;     /* 65535 */
                    100: 
                    101: #define RANGECHK(var, min, max) \
                    102:        if ((var) < (min)) { (var) = (min); } \
                    103:        else if ((var) > (max)) { (var) = (max); }
                    104: 
                    105: 
                    106: static int
                    107: sysctl_net_ipport_check SYSCTL_HANDLER_ARGS
                    108: {
                    109:        int error = sysctl_handle_int(oidp,
                    110:                oidp->oid_arg1, oidp->oid_arg2, req);
                    111:        if (!error) {
                    112:                RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
                    113:                RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
                    114:                RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
                    115:                RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
                    116:                RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
                    117:                RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
                    118:        }
                    119:        return error;
                    120: }
                    121: 
                    122: #undef RANGECHK
                    123: 
                    124: SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
                    125: 
                    126: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
                    127:           &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
                    128: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
                    129:           &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
                    130: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
                    131:           &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
                    132: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
                    133:           &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
                    134: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
                    135:           &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
                    136: SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
                    137:           &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
                    138: 
                    139: /*
                    140:  * in_pcb.c: manage the Protocol Control Blocks.
                    141:  *
                    142:  * NOTE: It is assumed that most of these functions will be called at
                    143:  * splnet(). XXX - There are, unfortunately, a few exceptions to this
                    144:  * rule that should be fixed.
                    145:  */
                    146: 
                    147: /*
                    148:  * Allocate a PCB and associate it with the socket.
                    149:  */
                    150: int
                    151: in_pcballoc(so, pcbinfo, p)
                    152:        struct socket *so;
                    153:        struct inpcbinfo *pcbinfo;
                    154:        struct proc *p;
                    155: {
                    156:        register struct inpcb *inp;
                    157: 
                    158:        inp = (struct inpcb *) zalloc(pcbinfo->ipi_zone);
                    159:        if (inp == NULL)
                    160:                return (ENOBUFS);
                    161:        bzero((caddr_t)inp, sizeof(*inp));
                    162:        inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
                    163:        inp->inp_pcbinfo = pcbinfo;
                    164:        inp->inp_socket = so;
                    165:        LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
                    166:        pcbinfo->ipi_count++;
                    167:        so->so_pcb = (caddr_t)inp;
                    168:        return (0);
                    169: }
                    170: 
                    171: int
                    172: in_pcbbind(inp, nam, p)
                    173:        register struct inpcb *inp;
                    174:        struct sockaddr *nam;
                    175:        struct proc *p;
                    176: {
                    177:        register struct socket *so = inp->inp_socket;
                    178:        u_short *lastport;
                    179:        struct sockaddr_in *sin;
                    180:        struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
                    181:        u_short lport = 0;
                    182:        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
                    183:        int error;
                    184: 
                    185:        if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
                    186:                return (EADDRNOTAVAIL);
                    187:        if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
                    188:                return (EINVAL);
                    189:        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
                    190:                wild = 1;
                    191:        if (nam) {
                    192:                sin = (struct sockaddr_in *)nam;
                    193:                if (nam->sa_len != sizeof (*sin))
                    194:                        return (EINVAL);
                    195: #ifdef notdef
                    196:                /*
                    197:                 * We should check the family, but old programs
                    198:                 * incorrectly fail to initialize it.
                    199:                 */
                    200:                if (sin->sin_family != AF_INET)
                    201:                        return (EAFNOSUPPORT);
                    202: #endif
                    203:                lport = sin->sin_port;
                    204:                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
                    205:                        /*
                    206:                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
                    207:                         * allow complete duplication of binding if
                    208:                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
                    209:                         * and a multicast address is bound on both
                    210:                         * new and duplicated sockets.
                    211:                         */
                    212:                        if (so->so_options & SO_REUSEADDR)
                    213:                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
                    214:                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
                    215:                        sin->sin_port = 0;              /* yech... */
                    216:                        if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
                    217:                                return (EADDRNOTAVAIL);
                    218:                }
                    219:                if (lport) {
                    220:                        struct inpcb *t;
                    221: 
                    222:                        /* GROSS */
                    223:                        if (ntohs(lport) < IPPORT_RESERVED && p &&
                    224:                            suser(p->p_ucred, &p->p_acflag))
                    225:                                return (EACCES);
                    226:                        if (so->so_uid &&
                    227:                            !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
                    228:                                t = in_pcblookup_local(inp->inp_pcbinfo,
                    229:                                    sin->sin_addr, lport, INPLOOKUP_WILDCARD);
                    230:                                if (t &&
                    231:                                    (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
                    232:                                     ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
                    233:                                     (t->inp_socket->so_options &
                    234:                                         SO_REUSEPORT) == 0) &&
                    235:                                    (so->so_uid != t->inp_socket->so_uid))
                    236:                                        return (EADDRINUSE);
                    237:                        }
                    238:                        t = in_pcblookup_local(pcbinfo, sin->sin_addr,
                    239:                            lport, wild);
                    240:                        if (t && (reuseport & t->inp_socket->so_options) == 0)
                    241:                                return (EADDRINUSE);
                    242:                }
                    243:                inp->inp_laddr = sin->sin_addr;
                    244:        }
                    245:        if (lport == 0) {
                    246:                u_short first, last;
                    247:                int count;
                    248: 
                    249:                inp->inp_flags |= INP_ANONPORT;
                    250: 
                    251:                if (inp->inp_flags & INP_HIGHPORT) {
                    252:                        first = ipport_hifirstauto;     /* sysctl */
                    253:                        last  = ipport_hilastauto;
                    254:                        lastport = &pcbinfo->lasthi;
                    255:                } else if (inp->inp_flags & INP_LOWPORT) {
                    256:                        if (p && (error = suser(p->p_ucred, &p->p_acflag)))
                    257:                                return error;
                    258:                        first = ipport_lowfirstauto;    /* 1023 */
                    259:                        last  = ipport_lowlastauto;     /* 600 */
                    260:                        lastport = &pcbinfo->lastlow;
                    261:                } else {
                    262:                        first = ipport_firstauto;       /* sysctl */
                    263:                        last  = ipport_lastauto;
                    264:                        lastport = &pcbinfo->lastport;
                    265:                }
                    266:                /*
                    267:                 * Simple check to ensure all ports are not used up causing
                    268:                 * a deadlock here.
                    269:                 *
                    270:                 * We split the two cases (up and down) so that the direction
                    271:                 * is not being tested on each round of the loop.
                    272:                 */
                    273:                if (first > last) {
                    274:                        /*
                    275:                         * counting down
                    276:                         */
                    277:                        count = first - last;
                    278: 
                    279:                        do {
                    280:                                if (count-- < 0) {      /* completely used? */
                    281:                                        /*
                    282:                                         * Undo any address bind that may have
                    283:                                         * occurred above.
                    284:                                         */
                    285:                                        inp->inp_laddr.s_addr = INADDR_ANY;
                    286:                                        return (EAGAIN);
                    287:                                }
                    288:                                --*lastport;
                    289:                                if (*lastport > first || *lastport < last)
                    290:                                        *lastport = first;
                    291:                                lport = htons(*lastport);
                    292:                        } while (in_pcblookup_local(pcbinfo,
                    293:                                 inp->inp_laddr, lport, wild));
                    294:                } else {
                    295:                        /*
                    296:                         * counting up
                    297:                         */
                    298:                        count = last - first;
                    299: 
                    300:                        do {
                    301:                                if (count-- < 0) {      /* completely used? */
                    302:                                        /*
                    303:                                         * Undo any address bind that may have
                    304:                                         * occurred above.
                    305:                                         */
                    306:                                        inp->inp_laddr.s_addr = INADDR_ANY;
                    307:                                        return (EAGAIN);
                    308:                                }
                    309:                                ++*lastport;
                    310:                                if (*lastport < first || *lastport > last)
                    311:                                        *lastport = first;
                    312:                                lport = htons(*lastport);
                    313:                        } while (in_pcblookup_local(pcbinfo,
                    314:                                 inp->inp_laddr, lport, wild));
                    315:                }
                    316:        }
                    317:        inp->inp_lport = lport;
                    318:        if (in_pcbinshash(inp) != 0) {
                    319:                inp->inp_laddr.s_addr = INADDR_ANY;
                    320:                inp->inp_lport = 0;
                    321:                return (EAGAIN);
                    322:        }
                    323:        return (0);
                    324: }
                    325: 
                    326: /*
                    327:  *   Transform old in_pcbconnect() into an inner subroutine for new
                    328:  *   in_pcbconnect(): Do some validity-checking on the remote
                    329:  *   address (in mbuf 'nam') and then determine local host address
                    330:  *   (i.e., which interface) to use to access that remote host.
                    331:  *
                    332:  *   This preserves definition of in_pcbconnect(), while supporting a
                    333:  *   slightly different version for T/TCP.  (This is more than
                    334:  *   a bit of a kludge, but cleaning up the internal interfaces would
                    335:  *   have forced minor changes in every protocol).
                    336:  */
                    337: 
                    338: int
                    339: in_pcbladdr(inp, nam, plocal_sin)
                    340:        register struct inpcb *inp;
                    341:        struct sockaddr *nam;
                    342:        struct sockaddr_in **plocal_sin;
                    343: {
                    344:        struct in_ifaddr *ia;
                    345:        register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
                    346: 
                    347:        if (nam->sa_len != sizeof (*sin))
                    348:                return (EINVAL);
                    349:        if (sin->sin_family != AF_INET)
                    350:                return (EAFNOSUPPORT);
                    351:        if (sin->sin_port == 0)
                    352:                return (EADDRNOTAVAIL);
                    353:        if (!TAILQ_EMPTY(&in_ifaddrhead)) {
                    354:                /*
                    355:                 * If the destination address is INADDR_ANY,
                    356:                 * use the primary local address.
                    357:                 * If the supplied address is INADDR_BROADCAST,
                    358:                 * and the primary interface supports broadcast,
                    359:                 * choose the broadcast address for that interface.
                    360:                 */
                    361: #define        satosin(sa)     ((struct sockaddr_in *)(sa))
                    362: #define sintosa(sin)   ((struct sockaddr *)(sin))
                    363: #define ifatoia(ifa)   ((struct in_ifaddr *)(ifa))
                    364:                if (sin->sin_addr.s_addr == INADDR_ANY)
                    365:                    sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr;
                    366:                else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
                    367:                  (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST))
                    368:                    sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr;
                    369:        }
                    370:        if (inp->inp_laddr.s_addr == INADDR_ANY) {
                    371:                register struct route *ro;
                    372: 
                    373:                ia = (struct in_ifaddr *)0;
                    374:                /*
                    375:                 * If route is known or can be allocated now,
                    376:                 * our src addr is taken from the i/f, else punt.
                    377:                 */
                    378:                ro = &inp->inp_route;
                    379:                if (ro->ro_rt &&
                    380:                    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
                    381:                        sin->sin_addr.s_addr ||
                    382:                    inp->inp_socket->so_options & SO_DONTROUTE)) {
                    383:                        RTFREE(ro->ro_rt);
                    384:                        ro->ro_rt = (struct rtentry *)0;
                    385:                }
                    386:                if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
                    387:                    (ro->ro_rt == (struct rtentry *)0 ||
                    388:                    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
                    389:                        /* No route yet, so try to acquire one */
                    390:                        ro->ro_dst.sa_family = AF_INET;
                    391:                        ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
                    392:                        ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
                    393:                                sin->sin_addr;
                    394:                        rtalloc(ro);
                    395:                }
                    396:                /*
                    397:                 * If we found a route, use the address
                    398:                 * corresponding to the outgoing interface
                    399:                 * unless it is the loopback (in case a route
                    400:                 * to our address on another net goes to loopback).
                    401:                 */
                    402:                if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
                    403:                        ia = ifatoia(ro->ro_rt->rt_ifa);
                    404:                if (ia == 0) {
                    405:                        u_short fport = sin->sin_port;
                    406: 
                    407:                        sin->sin_port = 0;
                    408:                        ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
                    409:                        if (ia == 0)
                    410:                                ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
                    411:                        sin->sin_port = fport;
                    412:                        if (ia == 0)
                    413:                                ia = in_ifaddrhead.tqh_first;
                    414:                        if (ia == 0)
                    415:                                return (EADDRNOTAVAIL);
                    416:                }
                    417:                /*
                    418:                 * If the destination address is multicast and an outgoing
                    419:                 * interface has been set as a multicast option, use the
                    420:                 * address of that interface as our source address.
                    421:                 */
                    422:                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
                    423:                    inp->inp_moptions != NULL) {
                    424:                        struct ip_moptions *imo;
                    425:                        struct ifnet *ifp;
                    426: 
                    427:                        imo = inp->inp_moptions;
                    428:                        if (imo->imo_multicast_ifp != NULL) {
                    429:                                ifp = imo->imo_multicast_ifp;
                    430:                                for (ia = in_ifaddrhead.tqh_first; ia; 
                    431:                                     ia = ia->ia_link.tqe_next)
                    432:                                        if (ia->ia_ifp == ifp)
                    433:                                                break;
                    434:                                if (ia == 0)
                    435:                                        return (EADDRNOTAVAIL);
                    436:                        }
                    437:                }
                    438:        /*
                    439:         * Don't do pcblookup call here; return interface in plocal_sin
                    440:         * and exit to caller, that will do the lookup.
                    441:         */
                    442:                *plocal_sin = &ia->ia_addr;
                    443: 
                    444:        }
                    445:        return(0);
                    446: }
                    447: 
                    448: /*
                    449:  * Outer subroutine:
                    450:  * Connect from a socket to a specified address.
                    451:  * Both address and port must be specified in argument sin.
                    452:  * If don't have a local address for this socket yet,
                    453:  * then pick one.
                    454:  */
                    455: int
                    456: in_pcbconnect(inp, nam, p)
                    457:        register struct inpcb *inp;
                    458:        struct sockaddr *nam;
                    459:        struct proc *p;
                    460: {
                    461:        struct sockaddr_in *ifaddr;
                    462:        register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
                    463:        int error;
                    464: 
                    465:        /*
                    466:         *   Call inner routine, to assign local interface address.
                    467:         */
                    468:        if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0)
                    469:                return(error);
                    470: 
                    471:        if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
                    472:            inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
                    473:            inp->inp_lport, 0) != NULL) {
                    474:                return (EADDRINUSE);
                    475:        }
                    476:        if (inp->inp_laddr.s_addr == INADDR_ANY) {
                    477:                if (inp->inp_lport == 0)
                    478:                        (void)in_pcbbind(inp, (struct sockaddr *)0, p);
                    479:                inp->inp_laddr = ifaddr->sin_addr;
                    480:        }
                    481:        inp->inp_faddr = sin->sin_addr;
                    482:        inp->inp_fport = sin->sin_port;
                    483:        in_pcbrehash(inp);
                    484:        return (0);
                    485: }
                    486: 
                    487: void
                    488: in_pcbdisconnect(inp)
                    489:        struct inpcb *inp;
                    490: {
                    491: 
                    492:        inp->inp_faddr.s_addr = INADDR_ANY;
                    493:        inp->inp_fport = 0;
                    494:        in_pcbrehash(inp);
                    495:        if (inp->inp_socket->so_state & SS_NOFDREF)
                    496:                in_pcbdetach(inp);
                    497: }
                    498: 
                    499: void
                    500: in_pcbdetach(inp)
                    501:        struct inpcb *inp;
                    502: {
                    503:        struct socket *so = inp->inp_socket;
                    504:        struct inpcbinfo *ipi = inp->inp_pcbinfo;
                    505: 
                    506:        inp->inp_gencnt = ++ipi->ipi_gencnt;
                    507:        in_pcbremlists(inp);
                    508:        so->so_pcb = 0;
                    509:        sofree(so);
                    510:        if (inp->inp_options)
                    511:                (void)m_free(inp->inp_options);
                    512:        if (inp->inp_route.ro_rt)
                    513:                rtfree(inp->inp_route.ro_rt);
                    514:        ip_freemoptions(inp->inp_moptions);
                    515:        zfree(ipi->ipi_zone, (vm_offset_t) inp);
                    516: }
                    517: 
                    518: /*
                    519:  * The calling convention of in_setsockaddr() and in_setpeeraddr() was
                    520:  * modified to match the pru_sockaddr() and pru_peeraddr() entry points
                    521:  * in struct pr_usrreqs, so that protocols can just reference then directly
                    522:  * without the need for a wrapper function.  The socket must have a valid
                    523:  * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
                    524:  * except through a kernel programming error, so it is acceptable to panic
                    525:  * (or in this case trap) if the PCB is invalid.  (Actually, we don't trap
                    526:  * because there actually /is/ a programming error somewhere... XXX)
                    527:  */
                    528: int
                    529: in_setsockaddr(so, nam)
                    530:        struct socket *so;
                    531:        struct sockaddr **nam;
                    532: {
                    533:        int s;
                    534:        register struct inpcb *inp;
                    535:        register struct sockaddr_in *sin;
                    536: 
                    537:        /*
                    538:         * Do the malloc first in case it blocks.
                    539:         */
                    540:        MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
                    541:        bzero(sin, sizeof *sin);
                    542:        sin->sin_family = AF_INET;
                    543:        sin->sin_len = sizeof(*sin);
                    544: 
                    545:        s = splnet();
                    546:        inp = sotoinpcb(so);
                    547:        if (!inp) {
                    548:                splx(s);
                    549:                FREE(sin, M_SONAME);
                    550:                return EINVAL;
                    551:        }
                    552:        sin->sin_port = inp->inp_lport;
                    553:        sin->sin_addr = inp->inp_laddr;
                    554:        splx(s);
                    555: 
                    556:        *nam = (struct sockaddr *)sin;
                    557:        return 0;
                    558: }
                    559: 
                    560: int
                    561: in_setpeeraddr(so, nam)
                    562:        struct socket *so;
                    563:        struct sockaddr **nam;
                    564: {
                    565:        int s;
                    566:        struct inpcb *inp;
                    567:        register struct sockaddr_in *sin;
                    568: 
                    569:        /*
                    570:         * Do the malloc first in case it blocks.
                    571:         */
                    572:        MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
                    573:        bzero((caddr_t)sin, sizeof (*sin));
                    574:        sin->sin_family = AF_INET;
                    575:        sin->sin_len = sizeof(*sin);
                    576: 
                    577:        s = splnet();
                    578:        inp = sotoinpcb(so);
                    579:        if (!inp) {
                    580:                splx(s);
                    581:                FREE(sin, M_SONAME);
                    582:                return EINVAL;
                    583:        }
                    584:        sin->sin_port = inp->inp_fport;
                    585:        sin->sin_addr = inp->inp_faddr;
                    586:        splx(s);
                    587: 
                    588:        *nam = (struct sockaddr *)sin;
                    589:        return 0;
                    590: }
                    591: 
                    592: /*
                    593:  * Pass some notification to all connections of a protocol
                    594:  * associated with address dst.  The local address and/or port numbers
                    595:  * may be specified to limit the search.  The "usual action" will be
                    596:  * taken, depending on the ctlinput cmd.  The caller must filter any
                    597:  * cmds that are uninteresting (e.g., no error in the map).
                    598:  * Call the protocol specific routine (if any) to report
                    599:  * any errors for each matching socket.
                    600:  */
                    601: void
                    602: in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
                    603:        struct inpcbhead *head;
                    604:        struct sockaddr *dst;
                    605:        u_int fport_arg, lport_arg;
                    606:        struct in_addr laddr;
                    607:        int cmd;
                    608:        void (*notify) __P((struct inpcb *, int));
                    609: {
                    610:        register struct inpcb *inp, *oinp;
                    611:        struct in_addr faddr;
                    612:        u_short fport = fport_arg, lport = lport_arg;
                    613:        int errno, s;
                    614: 
                    615:        if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
                    616:                return;
                    617:        faddr = ((struct sockaddr_in *)dst)->sin_addr;
                    618:        if (faddr.s_addr == INADDR_ANY)
                    619:                return;
                    620: 
                    621:        /*
                    622:         * Redirects go to all references to the destination,
                    623:         * and use in_rtchange to invalidate the route cache.
                    624:         * Dead host indications: notify all references to the destination.
                    625:         * Otherwise, if we have knowledge of the local port and address,
                    626:         * deliver only to that socket.
                    627:         */
                    628:        if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
                    629:                fport = 0;
                    630:                lport = 0;
                    631:                laddr.s_addr = 0;
                    632:                if (cmd != PRC_HOSTDEAD)
                    633:                        notify = in_rtchange;
                    634:        }
                    635:        errno = inetctlerrmap[cmd];
                    636:        s = splnet();
                    637:        for (inp = head->lh_first; inp != NULL;) {
                    638:                if (inp->inp_faddr.s_addr != faddr.s_addr ||
                    639:                    inp->inp_socket == 0 ||
                    640:                    (lport && inp->inp_lport != lport) ||
                    641:                    (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
                    642:                    (fport && inp->inp_fport != fport)) {
                    643:                        inp = inp->inp_list.le_next;
                    644:                        continue;
                    645:                }
                    646:                oinp = inp;
                    647:                inp = inp->inp_list.le_next;
                    648:                if (notify)
                    649:                        (*notify)(oinp, errno);
                    650:        }
                    651:        splx(s);
                    652: }
                    653: 
                    654: /*
                    655:  * Check for alternatives when higher level complains
                    656:  * about service problems.  For now, invalidate cached
                    657:  * routing information.  If the route was created dynamically
                    658:  * (by a redirect), time to try a default gateway again.
                    659:  */
                    660: void
                    661: in_losing(inp)
                    662:        struct inpcb *inp;
                    663: {
                    664:        register struct rtentry *rt;
                    665:        struct rt_addrinfo info;
                    666: 
                    667:        if ((rt = inp->inp_route.ro_rt)) {
                    668:                inp->inp_route.ro_rt = 0;
                    669:                bzero((caddr_t)&info, sizeof(info));
                    670:                info.rti_info[RTAX_DST] =
                    671:                        (struct sockaddr *)&inp->inp_route.ro_dst;
                    672:                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
                    673:                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
                    674:                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
                    675:                if (rt->rt_flags & RTF_DYNAMIC)
                    676:                        (void) rtrequest(RTM_DELETE, rt_key(rt),
                    677:                                rt->rt_gateway, rt_mask(rt), rt->rt_flags,
                    678:                                (struct rtentry **)0);
                    679:                else
                    680:                /*
                    681:                 * A new route can be allocated
                    682:                 * the next time output is attempted.
                    683:                 */
                    684:                        rtfree(rt);
                    685:        }
                    686: }
                    687: 
                    688: /*
                    689:  * After a routing change, flush old routing
                    690:  * and allocate a (hopefully) better one.
                    691:  */
                    692: static void
                    693: in_rtchange(inp, errno)
                    694:        register struct inpcb *inp;
                    695:        int errno;
                    696: {
                    697:        if (inp->inp_route.ro_rt) {
                    698:                rtfree(inp->inp_route.ro_rt);
                    699:                inp->inp_route.ro_rt = 0;
                    700:                /*
                    701:                 * A new route can be allocated the next time
                    702:                 * output is attempted.
                    703:                 */
                    704:        }
                    705: }
                    706: 
                    707: /*
                    708:  * Lookup a PCB based on the local address and port.
                    709:  */
                    710: struct inpcb *
                    711: in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
                    712:        struct inpcbinfo *pcbinfo;
                    713:        struct in_addr laddr;
                    714:        u_int lport_arg;
                    715:        int wild_okay;
                    716: {
                    717:        register struct inpcb *inp;
                    718:        int matchwild = 3, wildcard;
                    719:        u_short lport = lport_arg;
                    720: 
                    721:        if (!wild_okay) {
                    722:                struct inpcbhead *head;
                    723:                /*
                    724:                 * Look for an unconnected (wildcard foreign addr) PCB that
                    725:                 * matches the local address and port we're looking for.
                    726:                 */
                    727:                head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
                    728:                for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
                    729:                        if (inp->inp_faddr.s_addr == INADDR_ANY &&
                    730:                            inp->inp_laddr.s_addr == laddr.s_addr &&
                    731:                            inp->inp_lport == lport) {
                    732:                                /*
                    733:                                 * Found.
                    734:                                 */
                    735:                                return (inp);
                    736:                        }
                    737:                }
                    738:                /*
                    739:                 * Not found.
                    740:                 */
                    741:                return (NULL);
                    742:        } else {
                    743:                struct inpcbporthead *porthash;
                    744:                struct inpcbport *phd;
                    745:                struct inpcb *match = NULL;
                    746:                /*
                    747:                 * Best fit PCB lookup.
                    748:                 *
                    749:                 * First see if this local port is in use by looking on the
                    750:                 * port hash list.
                    751:                 */
                    752:                porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
                    753:                    pcbinfo->porthashmask)];
                    754:                for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
                    755:                        if (phd->phd_port == lport)
                    756:                                break;
                    757:                }
                    758:                if (phd != NULL) {
                    759:                        /*
                    760:                         * Port is in use by one or more PCBs. Look for best
                    761:                         * fit.
                    762:                         */
                    763:                        for (inp = phd->phd_pcblist.lh_first; inp != NULL;
                    764:                            inp = inp->inp_portlist.le_next) {
                    765:                                wildcard = 0;
                    766:                                if (inp->inp_faddr.s_addr != INADDR_ANY)
                    767:                                        wildcard++;
                    768:                                if (inp->inp_laddr.s_addr != INADDR_ANY) {
                    769:                                        if (laddr.s_addr == INADDR_ANY)
                    770:                                                wildcard++;
                    771:                                        else if (inp->inp_laddr.s_addr != laddr.s_addr)
                    772:                                                continue;
                    773:                                } else {
                    774:                                        if (laddr.s_addr != INADDR_ANY)
                    775:                                                wildcard++;
                    776:                                }
                    777:                                if (wildcard < matchwild) {
                    778:                                        match = inp;
                    779:                                        matchwild = wildcard;
                    780:                                        if (matchwild == 0) {
                    781:                                                break;
                    782:                                        }
                    783:                                }
                    784:                        }
                    785:                }
                    786:                return (match);
                    787:        }
                    788: }
                    789: 
                    790: /*
                    791:  * Lookup PCB in hash list.
                    792:  */
                    793: struct inpcb *
                    794: in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
                    795:        struct inpcbinfo *pcbinfo;
                    796:        struct in_addr faddr, laddr;
                    797:        u_int fport_arg, lport_arg;
                    798:        int wildcard;
                    799: {
                    800:        struct inpcbhead *head;
                    801:        register struct inpcb *inp;
                    802:        u_short fport = fport_arg, lport = lport_arg;
                    803: 
                    804:        /*
                    805:         * We may have found the pcb in the last lookup - check this first.
                    806:         */
                    807: 
                    808:        if ((!IN_MULTICAST(laddr.s_addr)) && (pcbinfo->last_pcb)) {
                    809:            if (faddr.s_addr == pcbinfo->last_pcb->inp_faddr.s_addr &&
                    810:                laddr.s_addr == pcbinfo->last_pcb->inp_laddr.s_addr &&
                    811:                fport_arg    == pcbinfo->last_pcb->inp_fport &&
                    812:                lport_arg    == pcbinfo->last_pcb->inp_lport) {
                    813:                /*
                    814:                 * Found.
                    815:                 */
                    816:                return (pcbinfo->last_pcb);
                    817:            }
                    818: 
                    819:            pcbinfo->last_pcb = 0;
                    820:        }
                    821: 
                    822:        /*
                    823:         * First look for an exact match.
                    824:         */
                    825:        head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
                    826:        for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
                    827:                if (inp->inp_faddr.s_addr == faddr.s_addr &&
                    828:                    inp->inp_laddr.s_addr == laddr.s_addr &&
                    829:                    inp->inp_fport == fport &&
                    830:                    inp->inp_lport == lport) {
                    831:                        /*
                    832:                         * Found.
                    833:                         */
                    834:                        return (inp);
                    835:                }
                    836:        }
                    837:        if (wildcard) {
                    838:                struct inpcb *local_wild = NULL;
                    839: 
                    840:                head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
                    841:                for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
                    842:                        if (inp->inp_faddr.s_addr == INADDR_ANY &&
                    843:                            inp->inp_lport == lport) {
                    844:                                if (inp->inp_laddr.s_addr == laddr.s_addr)
                    845:                                        return (inp);
                    846:                                else if (inp->inp_laddr.s_addr == INADDR_ANY)
                    847:                                        local_wild = inp;
                    848:                        }
                    849:                }
                    850:                return (local_wild);
                    851:        }
                    852: 
                    853:        /*
                    854:         * Not found.
                    855:         */
                    856:        return (NULL);
                    857: }
                    858: 
                    859: /*
                    860:  * Insert PCB onto various hash lists.
                    861:  */
                    862: int
                    863: in_pcbinshash(inp)
                    864:        struct inpcb *inp;
                    865: {
                    866:        struct inpcbhead *pcbhash;
                    867:        struct inpcbporthead *pcbporthash;
                    868:        struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
                    869:        struct inpcbport *phd;
                    870: 
                    871:        pcbhash = &pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
                    872:                 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
                    873: 
                    874:        pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
                    875:            pcbinfo->porthashmask)];
                    876: 
                    877:        /*
                    878:         * Go through port list and look for a head for this lport.
                    879:         */
                    880:        for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
                    881:                if (phd->phd_port == inp->inp_lport)
                    882:                        break;
                    883:        }
                    884:        /*
                    885:         * If none exists, malloc one and tack it on.
                    886:         */
                    887:        if (phd == NULL) {
                    888:                MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);
                    889:                if (phd == NULL) {
                    890:                        return (ENOBUFS); /* XXX */
                    891:                }
                    892:                phd->phd_port = inp->inp_lport;
                    893:                LIST_INIT(&phd->phd_pcblist);
                    894:                LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
                    895:        }
                    896:        inp->inp_phd = phd;
                    897:        LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
                    898:        LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
                    899:        return (0);
                    900: }
                    901: 
                    902: /*
                    903:  * Move PCB to the proper hash bucket when { faddr, fport } have  been
                    904:  * changed. NOTE: This does not handle the case of the lport changing (the
                    905:  * hashed port list would have to be updated as well), so the lport must
                    906:  * not change after in_pcbinshash() has been called.
                    907:  */
                    908: void
                    909: in_pcbrehash(inp)
                    910:        struct inpcb *inp;
                    911: {
                    912:        struct inpcbhead *head;
                    913: 
                    914:        head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
                    915:                inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
                    916: 
                    917:        if (inp == inp->inp_pcbinfo->last_pcb)
                    918:            inp->inp_pcbinfo->last_pcb = 0;
                    919: 
                    920:        LIST_REMOVE(inp, inp_hash);
                    921:        LIST_INSERT_HEAD(head, inp, inp_hash);
                    922: }
                    923: 
                    924: /*
                    925:  * Remove PCB from various lists.
                    926:  */
                    927: static void
                    928: in_pcbremlists(inp)
                    929:        struct inpcb *inp;
                    930: {
                    931:        inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
                    932:        if (inp == inp->inp_pcbinfo->last_pcb)
                    933:            inp->inp_pcbinfo->last_pcb = 0;
                    934: 
                    935:        if (inp->inp_lport) {
                    936:                struct inpcbport *phd = inp->inp_phd;
                    937: 
                    938:                LIST_REMOVE(inp, inp_hash);
                    939:                LIST_REMOVE(inp, inp_portlist);
                    940:                if (phd->phd_pcblist.lh_first == NULL) {
                    941:                        LIST_REMOVE(phd, phd_hash);
                    942:                        FREE(phd, M_PCB);
                    943:                }
                    944:        }
                    945: 
                    946:        LIST_REMOVE(inp, inp_list);
                    947:        inp->inp_pcbinfo->ipi_count--;
                    948: }
                    949: 
                    950: int    
                    951: in_pcb_grab_port  __P((struct inpcbinfo *pcbinfo,
                    952:                       u_short          options,
                    953:                       struct in_addr   laddr, 
                    954:                       u_short          *lport,
                    955:                       struct in_addr   faddr,
                    956:                       u_short          fport,
                    957:                       u_int            cookie, 
                    958:                       u_char           owner_id))
                    959: {
                    960:     struct inpcb  *pcb;
                    961:     struct sockaddr_in sin;
                    962:     struct proc *p = current_proc();
                    963:     int  stat;
                    964: 
                    965: 
                    966:     pcbinfo->nat_dummy_socket.so_pcb = 0;
                    967:     pcbinfo->nat_dummy_socket.so_options = 0;
                    968:     if (*lport) {
                    969:        /* The grabber wants a particular port */
                    970: 
                    971:        if (faddr.s_addr || fport) {
                    972:            /*
                    973:             * This is either the second half of an active connect, or
                    974:             * it's from the acceptance of an incoming connection.
                    975:            */  
                    976:            if (laddr.s_addr == 0) {
                    977:                return EINVAL;
                    978:            }
                    979: 
                    980:            if (in_pcblookup_hash(pcbinfo, faddr, fport,
                    981:                                  laddr, *lport, 0) != NULL) {
                    982:                if (!(IN_MULTICAST(ntohl(laddr.s_addr)))) {
                    983:                    return (EADDRINUSE);
                    984:                }
                    985:            }
                    986:            
                    987:            in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
                    988:            pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
                    989:            pcb->inp_lport = *lport;
                    990:            pcb->inp_laddr.s_addr = laddr.s_addr;
                    991: 
                    992:            pcb->inp_faddr = faddr;
                    993:            pcb->inp_fport = fport;
                    994:            in_pcbinshash(pcb);
                    995:        }
                    996:        else {
                    997:            /*
                    998:             * This is either a bind for a passive socket, or it's the 
                    999:             * first part of bind-connect sequence (not likely since an 
                   1000:             * ephemeral port is usually used in this case). Or, it's
                   1001:             * the result of a connection acceptance when the foreign
                   1002:             * address/port cannot be provided (which requires the SO_REUSEADDR
                   1003:             * flag if laddr is not multicast).
                   1004:             */
                   1005: 
                   1006:            in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
                   1007:            pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
                   1008: 
                   1009:            pcbinfo->nat_dummy_socket.so_options = options; 
                   1010:            bzero(&sin, sizeof(struct sockaddr_in));
                   1011:            sin.sin_len = sizeof(struct sockaddr_in);
                   1012:            sin.sin_family = AF_INET;
                   1013:            sin.sin_addr.s_addr = laddr.s_addr;
                   1014:            sin.sin_port = *lport;
                   1015: 
                   1016:            stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb, 
                   1017:                              (struct sockaddr *) &sin, p);
                   1018:            if (stat) {
                   1019:                in_pcbdetach(pcb);
                   1020:                return stat;
                   1021:            }
                   1022:        }
                   1023:     }
                   1024:     else {
                   1025:        /* The grabber wants an ephemeral port */
                   1026: 
                   1027:        in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
                   1028:        pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
                   1029: 
                   1030:        bzero(&sin, sizeof(struct sockaddr_in));
                   1031:        sin.sin_len = sizeof(struct sockaddr_in);
                   1032:        sin.sin_family = AF_INET;
                   1033:        sin.sin_addr.s_addr = laddr.s_addr;
                   1034:        sin.sin_port = 0;
                   1035: 
                   1036:        if (faddr.s_addr || fport) {
                   1037:            /*
                   1038:             * Not sure if this case will be used - could occur when connect
                   1039:             * is called, skipping the bind.
                   1040:             */
                   1041: 
                   1042:            if (laddr.s_addr == 0) {
                   1043:                in_pcbdetach(pcb);
                   1044:                return EINVAL;
                   1045:            }
                   1046: 
                   1047:            stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb, 
                   1048:                              (struct sockaddr *) &sin, p);
                   1049:            if (stat) {
                   1050:                in_pcbdetach(pcb);
                   1051:                return stat;
                   1052:            }
                   1053: 
                   1054:            if (in_pcblookup_hash(pcbinfo, faddr, fport,
                   1055:                                  pcb->inp_laddr, pcb->inp_lport, 0) != NULL) {
                   1056:                in_pcbdetach(pcb);
                   1057:                return (EADDRINUSE);
                   1058:            }
                   1059:            
                   1060:            pcb->inp_faddr = faddr;
                   1061:            pcb->inp_fport = fport;
                   1062:            in_pcbrehash(pcb);
                   1063:        }
                   1064:        else {
                   1065:            /*
                   1066:             * This is a simple bind of an ephemeral port. The local addr
                   1067:             * may or may not be defined.
                   1068:             */
                   1069:            
                   1070:            stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb, 
                   1071:                              (struct sockaddr *) &sin, p);
                   1072:            if (stat) {
                   1073:                in_pcbdetach(pcb);
                   1074:                return stat;
                   1075:            }
                   1076:        }
                   1077:        *lport = pcb->inp_lport;
                   1078:     }
                   1079:     
                   1080: 
                   1081:     pcb->nat_owner = owner_id;
                   1082:     pcb->nat_cookie = cookie;
                   1083:     pcb->inp_ppcb = (caddr_t) pcbinfo->dummy_cb;
                   1084:     return 0;
                   1085: }
                   1086: 
                   1087: int    
                   1088: in_pcb_letgo_port __P((struct inpcbinfo *pcbinfo, struct in_addr laddr, u_short lport,
                   1089:                       struct in_addr faddr, u_short fport, u_char owner_id))
                   1090: {
                   1091:     struct inpcbhead *head;
                   1092:     register struct inpcb *inp;
                   1093: 
                   1094: 
                   1095:     /*
                   1096:      * First look for an exact match.
                   1097:      */
                   1098:     head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
                   1099:     for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
                   1100:        if (inp->inp_faddr.s_addr == faddr.s_addr &&
                   1101:            inp->inp_laddr.s_addr == laddr.s_addr &&
                   1102:            inp->inp_fport == fport &&
                   1103:            inp->inp_lport == lport &&
                   1104:            inp->nat_owner == owner_id) {
                   1105:            /*
                   1106:             * Found.
                   1107:             */
                   1108:            in_pcbdetach(inp);
                   1109:            return 0;
                   1110:        }
                   1111:     }
                   1112: 
                   1113:     return ENOENT;
                   1114: }
                   1115: 
                   1116: u_char 
                   1117: in_pcb_get_owner(struct inpcbinfo *pcbinfo,
                   1118:                 struct in_addr laddr, u_short lport,
                   1119:                 struct in_addr faddr, u_short fport,
                   1120:                 u_int   *cookie)
                   1121: 
                   1122: {
                   1123:     struct inpcb *inp;
                   1124:     u_char       owner_id = INPCB_NO_OWNER;
                   1125:     struct      inpcbport *phd;
                   1126:     struct inpcbporthead *porthash;
                   1127: 
                   1128: 
                   1129:     if (IN_MULTICAST(laddr.s_addr)) {
                   1130:        /*
                   1131:         * Walk through PCB's looking for registered
                   1132:         * owners.
                   1133:        */
                   1134: 
                   1135:        porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
                   1136:                                                          pcbinfo->porthashmask)];
                   1137:        for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
                   1138:            if (phd->phd_port == lport)
                   1139:                break;
                   1140:        }
                   1141: 
                   1142:        if (phd == 0) {
                   1143:            return INPCB_NO_OWNER;
                   1144:        }
                   1145:                
                   1146:        owner_id = INPCB_NO_OWNER;
                   1147:        for (inp = phd->phd_pcblist.lh_first; inp != NULL;
                   1148:             inp = inp->inp_portlist.le_next) {
                   1149: 
                   1150:            if (inp->inp_laddr.s_addr == laddr.s_addr) {
                   1151:                if (inp->nat_owner == 0) 
                   1152:                    owner_id |= INPCB_OWNED_BY_X;
                   1153:                else
                   1154:                    owner_id |= inp->nat_owner;
                   1155:            }
                   1156:        }
                   1157: 
                   1158:        return owner_id;
                   1159:     }
                   1160:     else {
                   1161:        inp = in_pcblookup_hash(pcbinfo, faddr, fport,
                   1162:                                laddr, lport, 1);
                   1163:        if (inp) {
                   1164:            if (inp->nat_owner) {
                   1165:                owner_id = inp->nat_owner;
                   1166:                *cookie   = inp->nat_cookie;
                   1167:            }
                   1168:            else {
                   1169:                pcbinfo->last_pcb = inp;
                   1170:                owner_id = INPCB_OWNED_BY_X;
                   1171:            }
                   1172:        }
                   1173:        else 
                   1174:            owner_id = INPCB_NO_OWNER;
                   1175: 
                   1176:        return owner_id;
                   1177:     }
                   1178: }
                   1179: 
                   1180: int
                   1181: in_pcb_new_share_client(struct inpcbinfo *pcbinfo, u_char *owner_id)
                   1182: {
                   1183: 
                   1184:     int i;
                   1185: 
                   1186: 
                   1187:     for (i=0; i < INPCB_MAX_IDS; i++) {
                   1188:        if ((pcbinfo->all_owners & (1 << i)) == 0) {
                   1189:            pcbinfo->all_owners |= (1 << i);
                   1190:            *owner_id = (1 << i);
                   1191:            return 0;
                   1192:        }
                   1193:     }
                   1194: 
                   1195:     return ENOSPC;
                   1196: }              
                   1197: 
                   1198: int
                   1199: in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id)
                   1200: {
                   1201:     struct inpcb *inp;
                   1202: 
                   1203: 
                   1204:     if (pcbinfo->all_owners & owner_id) {
                   1205:        pcbinfo->all_owners &= ~owner_id;
                   1206:        for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
                   1207:            if (inp->nat_owner & owner_id) {
                   1208:                if (inp->nat_owner == owner_id) 
                   1209:                    /*
                   1210:                     * Deallocate the pcb
                   1211:                     */
                   1212:                    in_pcbdetach(inp);
                   1213:                else
                   1214:                    inp->nat_owner &= ~owner_id;
                   1215:            }
                   1216:        }
                   1217:     }
                   1218:     else {
                   1219:        return ENOENT;
                   1220:     }
                   1221: 
                   1222:     return 0;
                   1223: }
                   1224: 
                   1225: void  in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily, 
                   1226:                      int pfamily, int protocol)
                   1227: {
                   1228:     bzero(&pcbinfo->nat_dummy_socket, sizeof(struct socket));
                   1229:     pcbinfo->nat_dummy_socket.so_proto = pffindproto(afamily, pfamily, protocol);
                   1230:     pcbinfo->all_owners = 0;
                   1231: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.