Annotation of XNU/bsd/netinet/in_pcb.c, revision 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.