[BACK]Return to in_pcb.c CVS log [TXT][DIR] Up to [local] / sys / netinet

Annotation of sys/netinet/in_pcb.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: in_pcb.c,v 1.89 2007/04/10 17:47:55 miod Exp $        */
        !             2: /*     $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $     */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1982, 1986, 1991, 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. Neither the name of the University nor the names of its contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  *
        !            32:  *     @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
        !            33:  *
        !            34:  * NRL grants permission for redistribution and use in source and binary
        !            35:  * forms, with or without modification, of the software and documentation
        !            36:  * created at NRL provided that the following conditions are met:
        !            37:  *
        !            38:  * 1. Redistributions of source code must retain the above copyright
        !            39:  *    notice, this list of conditions and the following disclaimer.
        !            40:  * 2. Redistributions in binary form must reproduce the above copyright
        !            41:  *    notice, this list of conditions and the following disclaimer in the
        !            42:  *    documentation and/or other materials provided with the distribution.
        !            43:  * 3. All advertising materials mentioning features or use of this software
        !            44:  *    must display the following acknowledgements:
        !            45:  *     This product includes software developed by the University of
        !            46:  *     California, Berkeley and its contributors.
        !            47:  *     This product includes software developed at the Information
        !            48:  *     Technology Division, US Naval Research Laboratory.
        !            49:  * 4. Neither the name of the NRL nor the names of its contributors
        !            50:  *    may be used to endorse or promote products derived from this software
        !            51:  *    without specific prior written permission.
        !            52:  *
        !            53:  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
        !            54:  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            55:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
        !            56:  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
        !            57:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        !            58:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        !            59:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        !            60:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        !            61:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
        !            62:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
        !            63:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            64:  *
        !            65:  * The views and conclusions contained in the software and documentation
        !            66:  * are those of the authors and should not be interpreted as representing
        !            67:  * official policies, either expressed or implied, of the US Naval
        !            68:  * Research Laboratory (NRL).
        !            69:  */
        !            70:
        !            71: #include <sys/param.h>
        !            72: #include <sys/systm.h>
        !            73: #include <sys/mbuf.h>
        !            74: #include <sys/protosw.h>
        !            75: #include <sys/socket.h>
        !            76: #include <sys/socketvar.h>
        !            77: #include <sys/proc.h>
        !            78: #include <sys/domain.h>
        !            79:
        !            80: #include <net/if.h>
        !            81: #include <net/route.h>
        !            82:
        !            83: #include <netinet/in.h>
        !            84: #include <netinet/in_systm.h>
        !            85: #include <netinet/ip.h>
        !            86: #include <netinet/in_pcb.h>
        !            87: #include <netinet/in_var.h>
        !            88: #include <netinet/ip_var.h>
        !            89: #include <dev/rndvar.h>
        !            90:
        !            91: #include <sys/mount.h>
        !            92: #include <nfs/nfsproto.h>
        !            93:
        !            94: #ifdef INET6
        !            95: #include <netinet6/ip6_var.h>
        !            96: #endif /* INET6 */
        !            97: #ifdef IPSEC
        !            98: #include <netinet/ip_esp.h>
        !            99: #endif /* IPSEC */
        !           100:
        !           101: struct in_addr zeroin_addr;
        !           102:
        !           103: extern int ipsec_auth_default_level;
        !           104: extern int ipsec_esp_trans_default_level;
        !           105: extern int ipsec_esp_network_default_level;
        !           106: extern int ipsec_ipcomp_default_level;
        !           107:
        !           108: /*
        !           109:  * These configure the range of local port addresses assigned to
        !           110:  * "unspecified" outgoing connections/packets/whatever.
        !           111:  */
        !           112: int ipport_firstauto = IPPORT_RESERVED;
        !           113: int ipport_lastauto = IPPORT_USERRESERVED;
        !           114: int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;
        !           115: int ipport_hilastauto = IPPORT_HILASTAUTO;
        !           116:
        !           117: struct pool inpcb_pool;
        !           118: int inpcb_pool_initalized = 0;
        !           119:
        !           120: #define        INPCBHASH(table, faddr, fport, laddr, lport) \
        !           121:        &(table)->inpt_hashtbl[(ntohl((faddr)->s_addr) + \
        !           122:        ntohs((fport)) + ntohs((lport))) & (table->inpt_hash)]
        !           123:
        !           124: #define        IN6PCBHASH(table, faddr, fport, laddr, lport) \
        !           125:        &(table)->inpt_hashtbl[(ntohl((faddr)->s6_addr32[0] ^ \
        !           126:        (faddr)->s6_addr32[3]) + ntohs((fport)) + ntohs((lport))) & \
        !           127:        (table->inpt_hash)]
        !           128:
        !           129: #define        INPCBLHASH(table, lport) \
        !           130:        &(table)->inpt_lhashtbl[lport & table->inpt_lhash]
        !           131:
        !           132: void
        !           133: in_pcbinit(table, hashsize)
        !           134:        struct inpcbtable *table;
        !           135:        int hashsize;
        !           136: {
        !           137:
        !           138:        CIRCLEQ_INIT(&table->inpt_queue);
        !           139:        table->inpt_hashtbl = hashinit(hashsize, M_PCB, M_NOWAIT,
        !           140:            &table->inpt_hash);
        !           141:        if (table->inpt_hashtbl == NULL)
        !           142:                panic("in_pcbinit: hashinit failed");
        !           143:        table->inpt_lhashtbl = hashinit(hashsize, M_PCB, M_NOWAIT,
        !           144:            &table->inpt_lhash);
        !           145:        if (table->inpt_lhashtbl == NULL)
        !           146:                panic("in_pcbinit: hashinit failed for lport");
        !           147:        table->inpt_lastport = 0;
        !           148: }
        !           149:
        !           150: struct baddynamicports baddynamicports;
        !           151:
        !           152: /*
        !           153:  * Check if the specified port is invalid for dynamic allocation.
        !           154:  */
        !           155: int
        !           156: in_baddynamic(port, proto)
        !           157:        u_int16_t port;
        !           158:        u_int16_t proto;
        !           159: {
        !           160:
        !           161:
        !           162:        switch (proto) {
        !           163:        case IPPROTO_TCP:
        !           164:                if (port == NFS_PORT)
        !           165:                        return (1);
        !           166:                if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
        !           167:                        return (0);
        !           168:                return (DP_ISSET(baddynamicports.tcp, port));
        !           169:        case IPPROTO_UDP:
        !           170: #ifdef IPSEC
        !           171:                if (port == udpencap_port)
        !           172:                        return (1);
        !           173: #endif
        !           174:                if (port == NFS_PORT)
        !           175:                        return (1);
        !           176:                if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
        !           177:                        return (0);
        !           178:                return (DP_ISSET(baddynamicports.udp, port));
        !           179:        default:
        !           180:                return (0);
        !           181:        }
        !           182: }
        !           183:
        !           184: int
        !           185: in_pcballoc(so, v)
        !           186:        struct socket *so;
        !           187:        void *v;
        !           188: {
        !           189:        struct inpcbtable *table = v;
        !           190:        struct inpcb *inp;
        !           191:        int s;
        !           192:
        !           193:        if (inpcb_pool_initalized == 0) {
        !           194:                pool_init(&inpcb_pool, sizeof(struct inpcb), 0, 0, 0,
        !           195:                    "inpcbpl", NULL);
        !           196:                inpcb_pool_initalized = 1;
        !           197:        }
        !           198:        inp = pool_get(&inpcb_pool, PR_NOWAIT);
        !           199:        if (inp == NULL)
        !           200:                return (ENOBUFS);
        !           201:        bzero((caddr_t)inp, sizeof(*inp));
        !           202:        inp->inp_table = table;
        !           203:        inp->inp_socket = so;
        !           204:        inp->inp_seclevel[SL_AUTH] = ipsec_auth_default_level;
        !           205:        inp->inp_seclevel[SL_ESP_TRANS] = ipsec_esp_trans_default_level;
        !           206:        inp->inp_seclevel[SL_ESP_NETWORK] = ipsec_esp_network_default_level;
        !           207:        inp->inp_seclevel[SL_IPCOMP] = ipsec_ipcomp_default_level;
        !           208:        s = splnet();
        !           209:        CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
        !           210:        LIST_INSERT_HEAD(INPCBLHASH(table, inp->inp_lport), inp, inp_lhash);
        !           211:        LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr, inp->inp_fport,
        !           212:            &inp->inp_laddr, inp->inp_lport), inp, inp_hash);
        !           213:        splx(s);
        !           214:        so->so_pcb = inp;
        !           215:        inp->inp_hops = -1;
        !           216:
        !           217: #ifdef INET6
        !           218:        /*
        !           219:         * Small change in this function to set the INP_IPV6 flag so routines
        !           220:         * outside pcb-specific routines don't need to use sotopf(), and all
        !           221:         * of its pointer chasing, later.
        !           222:         */
        !           223:        if (sotopf(so) == PF_INET6)
        !           224:                inp->inp_flags = INP_IPV6;
        !           225:        inp->in6p_cksum = -1;
        !           226: #endif /* INET6 */
        !           227:        return (0);
        !           228: }
        !           229:
        !           230: int
        !           231: in_pcbbind(v, nam)
        !           232:        void *v;
        !           233:        struct mbuf *nam;
        !           234: {
        !           235:        struct inpcb *inp = v;
        !           236:        struct socket *so = inp->inp_socket;
        !           237:        struct inpcbtable *table = inp->inp_table;
        !           238:        u_int16_t *lastport = &inp->inp_table->inpt_lastport;
        !           239:        struct sockaddr_in *sin;
        !           240:        struct proc *p = curproc;               /* XXX */
        !           241:        u_int16_t lport = 0;
        !           242:        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
        !           243:        int error;
        !           244:
        !           245: #ifdef INET6
        !           246:        if (sotopf(so) == PF_INET6)
        !           247:                return in6_pcbbind(inp, nam);
        !           248: #endif /* INET6 */
        !           249:
        !           250:        if (TAILQ_EMPTY(&in_ifaddr))
        !           251:                return (EADDRNOTAVAIL);
        !           252:        if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
        !           253:                return (EINVAL);
        !           254:        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
        !           255:            ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
        !           256:             (so->so_options & SO_ACCEPTCONN) == 0))
        !           257:                wild = INPLOOKUP_WILDCARD;
        !           258:        if (nam) {
        !           259:                sin = mtod(nam, struct sockaddr_in *);
        !           260:                if (nam->m_len != sizeof (*sin))
        !           261:                        return (EINVAL);
        !           262: #ifdef notdef
        !           263:                /*
        !           264:                 * We should check the family, but old programs
        !           265:                 * incorrectly fail to initialize it.
        !           266:                 */
        !           267:                if (sin->sin_family != AF_INET)
        !           268:                        return (EAFNOSUPPORT);
        !           269: #endif
        !           270:                lport = sin->sin_port;
        !           271:                if (IN_MULTICAST(sin->sin_addr.s_addr)) {
        !           272:                        /*
        !           273:                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
        !           274:                         * allow complete duplication of binding if
        !           275:                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
        !           276:                         * and a multicast address is bound on both
        !           277:                         * new and duplicated sockets.
        !           278:                         */
        !           279:                        if (so->so_options & SO_REUSEADDR)
        !           280:                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
        !           281:                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
        !           282:                        sin->sin_port = 0;              /* yech... */
        !           283:                        if (in_iawithaddr(sin->sin_addr, NULL) == 0)
        !           284:                                return (EADDRNOTAVAIL);
        !           285:                }
        !           286:                if (lport) {
        !           287:                        struct inpcb *t;
        !           288:
        !           289:                        /* GROSS */
        !           290:                        if (ntohs(lport) < IPPORT_RESERVED &&
        !           291:                            (error = suser(p, 0)))
        !           292:                                return (EACCES);
        !           293:                        if (so->so_euid) {
        !           294:                                t = in_pcblookup(table, &zeroin_addr, 0,
        !           295:                                    &sin->sin_addr, lport, INPLOOKUP_WILDCARD);
        !           296:                                if (t && (so->so_euid != t->inp_socket->so_euid))
        !           297:                                        return (EADDRINUSE);
        !           298:                        }
        !           299:                        t = in_pcblookup(table, &zeroin_addr, 0,
        !           300:                            &sin->sin_addr, lport, wild);
        !           301:                        if (t && (reuseport & t->inp_socket->so_options) == 0)
        !           302:                                return (EADDRINUSE);
        !           303:                }
        !           304:                inp->inp_laddr = sin->sin_addr;
        !           305:        }
        !           306:        if (lport == 0) {
        !           307:                u_int16_t first, last;
        !           308:                int count;
        !           309:
        !           310:                if (inp->inp_flags & INP_HIGHPORT) {
        !           311:                        first = ipport_hifirstauto;     /* sysctl */
        !           312:                        last = ipport_hilastauto;
        !           313:                } else if (inp->inp_flags & INP_LOWPORT) {
        !           314:                        if ((error = suser(p, 0)))
        !           315:                                return (EACCES);
        !           316:                        first = IPPORT_RESERVED-1; /* 1023 */
        !           317:                        last = 600;                /* not IPPORT_RESERVED/2 */
        !           318:                } else {
        !           319:                        first = ipport_firstauto;       /* sysctl */
        !           320:                        last  = ipport_lastauto;
        !           321:                }
        !           322:
        !           323:                /*
        !           324:                 * Simple check to ensure all ports are not used up causing
        !           325:                 * a deadlock here.
        !           326:                 *
        !           327:                 * We split the two cases (up and down) so that the direction
        !           328:                 * is not being tested on each round of the loop.
        !           329:                 */
        !           330:
        !           331:                if (first > last) {
        !           332:                        /*
        !           333:                         * counting down
        !           334:                         */
        !           335:                        count = first - last;
        !           336:                        if (count)
        !           337:                                *lastport = first - (arc4random() % count);
        !           338:
        !           339:                        do {
        !           340:                                if (count-- < 0)        /* completely used? */
        !           341:                                        return (EADDRNOTAVAIL);
        !           342:                                --*lastport;
        !           343:                                if (*lastport > first || *lastport < last)
        !           344:                                        *lastport = first;
        !           345:                                lport = htons(*lastport);
        !           346:                        } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
        !           347:                            in_pcblookup(table, &zeroin_addr, 0,
        !           348:                            &inp->inp_laddr, lport, wild));
        !           349:                } else {
        !           350:                        /*
        !           351:                         * counting up
        !           352:                         */
        !           353:                        count = last - first;
        !           354:                        if (count)
        !           355:                                *lastport = first + (arc4random() % count);
        !           356:
        !           357:                        do {
        !           358:                                if (count-- < 0)        /* completely used? */
        !           359:                                        return (EADDRNOTAVAIL);
        !           360:                                ++*lastport;
        !           361:                                if (*lastport < first || *lastport > last)
        !           362:                                        *lastport = first;
        !           363:                                lport = htons(*lastport);
        !           364:                        } while (in_baddynamic(*lastport, so->so_proto->pr_protocol) ||
        !           365:                            in_pcblookup(table, &zeroin_addr, 0,
        !           366:                            &inp->inp_laddr, lport, wild));
        !           367:                }
        !           368:        }
        !           369:        inp->inp_lport = lport;
        !           370:        in_pcbrehash(inp);
        !           371:        return (0);
        !           372: }
        !           373:
        !           374: /*
        !           375:  * Connect from a socket to a specified address.
        !           376:  * Both address and port must be specified in argument sin.
        !           377:  * If don't have a local address for this socket yet,
        !           378:  * then pick one.
        !           379:  */
        !           380: int
        !           381: in_pcbconnect(v, nam)
        !           382:        void *v;
        !           383:        struct mbuf *nam;
        !           384: {
        !           385:        struct inpcb *inp = v;
        !           386:        struct sockaddr_in *ifaddr = NULL;
        !           387:        struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
        !           388:
        !           389: #ifdef INET6
        !           390:        if (sotopf(inp->inp_socket) == PF_INET6)
        !           391:                return (in6_pcbconnect(inp, nam));
        !           392:        if ((inp->inp_flags & INP_IPV6) != 0)
        !           393:                panic("IPv6 pcb passed into in_pcbconnect");
        !           394: #endif /* INET6 */
        !           395:
        !           396:        if (nam->m_len != sizeof (*sin))
        !           397:                return (EINVAL);
        !           398:        if (sin->sin_family != AF_INET)
        !           399:                return (EAFNOSUPPORT);
        !           400:        if (sin->sin_port == 0)
        !           401:                return (EADDRNOTAVAIL);
        !           402:        if (!TAILQ_EMPTY(&in_ifaddr)) {
        !           403:                /*
        !           404:                 * If the destination address is INADDR_ANY,
        !           405:                 * use the primary local address.
        !           406:                 * If the supplied address is INADDR_BROADCAST,
        !           407:                 * and the primary interface supports broadcast,
        !           408:                 * choose the broadcast address for that interface.
        !           409:                 */
        !           410:                if (sin->sin_addr.s_addr == INADDR_ANY)
        !           411:                        sin->sin_addr = TAILQ_FIRST(&in_ifaddr)->ia_addr.sin_addr;
        !           412:                else if (sin->sin_addr.s_addr == INADDR_BROADCAST &&
        !           413:                  (TAILQ_FIRST(&in_ifaddr)->ia_ifp->if_flags & IFF_BROADCAST))
        !           414:                        sin->sin_addr = TAILQ_FIRST(&in_ifaddr)->ia_broadaddr.sin_addr;
        !           415:        }
        !           416:        if (inp->inp_laddr.s_addr == INADDR_ANY) {
        !           417:                int error;
        !           418:                ifaddr = in_selectsrc(sin, &inp->inp_route,
        !           419:                        inp->inp_socket->so_options, inp->inp_moptions, &error);
        !           420:                if (ifaddr == NULL) {
        !           421:                        if (error == 0)
        !           422:                                error = EADDRNOTAVAIL;
        !           423:                        return error;
        !           424:                }
        !           425:        }
        !           426:        if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
        !           427:            inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
        !           428:            inp->inp_lport) != 0)
        !           429:                return (EADDRINUSE);
        !           430:        if (inp->inp_laddr.s_addr == INADDR_ANY) {
        !           431:                if (inp->inp_lport == 0 &&
        !           432:                    in_pcbbind(inp, (struct mbuf *)0) == EADDRNOTAVAIL)
        !           433:                        return (EADDRNOTAVAIL);
        !           434:                inp->inp_laddr = ifaddr->sin_addr;
        !           435:        }
        !           436:        inp->inp_faddr = sin->sin_addr;
        !           437:        inp->inp_fport = sin->sin_port;
        !           438:        in_pcbrehash(inp);
        !           439: #ifdef IPSEC
        !           440:        {
        !           441:                int error; /* This is just ignored */
        !           442:
        !           443:                /* Cause an IPsec SA to be established. */
        !           444:                ipsp_spd_inp(NULL, AF_INET, 0, &error, IPSP_DIRECTION_OUT,
        !           445:                    NULL, inp, NULL);
        !           446:        }
        !           447: #endif
        !           448:        return (0);
        !           449: }
        !           450:
        !           451: void
        !           452: in_pcbdisconnect(v)
        !           453:        void *v;
        !           454: {
        !           455:        struct inpcb *inp = v;
        !           456:
        !           457:        switch (sotopf(inp->inp_socket)) {
        !           458: #ifdef INET6
        !           459:        case PF_INET6:
        !           460:                inp->inp_faddr6 = in6addr_any;
        !           461:                break;
        !           462: #endif
        !           463:        case PF_INET:
        !           464:                inp->inp_faddr.s_addr = INADDR_ANY;
        !           465:                break;
        !           466:        }
        !           467:
        !           468:        inp->inp_fport = 0;
        !           469:        in_pcbrehash(inp);
        !           470:        if (inp->inp_socket->so_state & SS_NOFDREF)
        !           471:                in_pcbdetach(inp);
        !           472: }
        !           473:
        !           474: void
        !           475: in_pcbdetach(v)
        !           476:        void *v;
        !           477: {
        !           478:        struct inpcb *inp = v;
        !           479:        struct socket *so = inp->inp_socket;
        !           480:        int s;
        !           481:
        !           482:        so->so_pcb = 0;
        !           483:        sofree(so);
        !           484:        if (inp->inp_options)
        !           485:                (void)m_freem(inp->inp_options);
        !           486:        if (inp->inp_route.ro_rt)
        !           487:                rtfree(inp->inp_route.ro_rt);
        !           488: #ifdef INET6
        !           489:        if (inp->inp_flags & INP_IPV6)
        !           490:                ip6_freemoptions(inp->inp_moptions6);
        !           491:        else
        !           492: #endif
        !           493:                ip_freemoptions(inp->inp_moptions);
        !           494: #ifdef IPSEC
        !           495:        /* IPsec cleanup here */
        !           496:        s = spltdb();
        !           497:        if (inp->inp_tdb_in)
        !           498:                TAILQ_REMOVE(&inp->inp_tdb_in->tdb_inp_in,
        !           499:                             inp, inp_tdb_in_next);
        !           500:        if (inp->inp_tdb_out)
        !           501:                TAILQ_REMOVE(&inp->inp_tdb_out->tdb_inp_out, inp,
        !           502:                             inp_tdb_out_next);
        !           503:        if (inp->inp_ipsec_remotecred)
        !           504:                ipsp_reffree(inp->inp_ipsec_remotecred);
        !           505:        if (inp->inp_ipsec_remoteauth)
        !           506:                ipsp_reffree(inp->inp_ipsec_remoteauth);
        !           507:        if (inp->inp_ipo)
        !           508:                ipsec_delete_policy(inp->inp_ipo);
        !           509:        splx(s);
        !           510: #endif
        !           511:        s = splnet();
        !           512:        LIST_REMOVE(inp, inp_lhash);
        !           513:        LIST_REMOVE(inp, inp_hash);
        !           514:        CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
        !           515:        splx(s);
        !           516:        pool_put(&inpcb_pool, inp);
        !           517: }
        !           518:
        !           519: void
        !           520: in_setsockaddr(inp, nam)
        !           521:        struct inpcb *inp;
        !           522:        struct mbuf *nam;
        !           523: {
        !           524:        struct sockaddr_in *sin;
        !           525:
        !           526:        nam->m_len = sizeof (*sin);
        !           527:        sin = mtod(nam, struct sockaddr_in *);
        !           528:        bzero((caddr_t)sin, sizeof (*sin));
        !           529:        sin->sin_family = AF_INET;
        !           530:        sin->sin_len = sizeof(*sin);
        !           531:        sin->sin_port = inp->inp_lport;
        !           532:        sin->sin_addr = inp->inp_laddr;
        !           533: }
        !           534:
        !           535: void
        !           536: in_setpeeraddr(inp, nam)
        !           537:        struct inpcb *inp;
        !           538:        struct mbuf *nam;
        !           539: {
        !           540:        struct sockaddr_in *sin;
        !           541:
        !           542: #ifdef INET6
        !           543:        if (sotopf(inp->inp_socket) == PF_INET6) {
        !           544:                in6_setpeeraddr(inp, nam);
        !           545:                return;
        !           546:        }
        !           547: #endif /* INET6 */
        !           548:
        !           549:        nam->m_len = sizeof (*sin);
        !           550:        sin = mtod(nam, struct sockaddr_in *);
        !           551:        bzero((caddr_t)sin, sizeof (*sin));
        !           552:        sin->sin_family = AF_INET;
        !           553:        sin->sin_len = sizeof(*sin);
        !           554:        sin->sin_port = inp->inp_fport;
        !           555:        sin->sin_addr = inp->inp_faddr;
        !           556: }
        !           557:
        !           558: /*
        !           559:  * Pass some notification to all connections of a protocol
        !           560:  * associated with address dst.  The "usual action" will be
        !           561:  * taken, depending on the ctlinput cmd.  The caller must filter any
        !           562:  * cmds that are uninteresting (e.g., no error in the map).
        !           563:  * Call the protocol specific routine (if any) to report
        !           564:  * any errors for each matching socket.
        !           565:  *
        !           566:  * Must be called at splsoftnet.
        !           567:  */
        !           568: void
        !           569: in_pcbnotifyall(table, dst, errno, notify)
        !           570:        struct inpcbtable *table;
        !           571:        struct sockaddr *dst;
        !           572:        int errno;
        !           573:        void (*notify)(struct inpcb *, int);
        !           574: {
        !           575:        struct inpcb *inp, *oinp;
        !           576:        struct in_addr faddr;
        !           577:
        !           578:        splassert(IPL_SOFTNET);
        !           579:
        !           580: #ifdef INET6
        !           581:        /*
        !           582:         * See in6_pcbnotify() for IPv6 codepath.  By the time this
        !           583:         * gets called, the addresses passed are either definitely IPv4 or
        !           584:         * IPv6; *_pcbnotify() never gets called with v4-mapped v6 addresses.
        !           585:         */
        !           586: #endif /* INET6 */
        !           587:
        !           588:        if (dst->sa_family != AF_INET)
        !           589:                return;
        !           590:        faddr = satosin(dst)->sin_addr;
        !           591:        if (faddr.s_addr == INADDR_ANY)
        !           592:                return;
        !           593:
        !           594:        for (inp = CIRCLEQ_FIRST(&table->inpt_queue);
        !           595:            inp != CIRCLEQ_END(&table->inpt_queue);) {
        !           596: #ifdef INET6
        !           597:                if (inp->inp_flags & INP_IPV6) {
        !           598:                        inp = CIRCLEQ_NEXT(inp, inp_queue);
        !           599:                        continue;
        !           600:                }
        !           601: #endif
        !           602:                if (inp->inp_faddr.s_addr != faddr.s_addr ||
        !           603:                    inp->inp_socket == 0) {
        !           604:                        inp = CIRCLEQ_NEXT(inp, inp_queue);
        !           605:                        continue;
        !           606:                }
        !           607:                oinp = inp;
        !           608:                inp = CIRCLEQ_NEXT(inp, inp_queue);
        !           609:                if (notify)
        !           610:                        (*notify)(oinp, errno);
        !           611:        }
        !           612: }
        !           613:
        !           614: /*
        !           615:  * Check for alternatives when higher level complains
        !           616:  * about service problems.  For now, invalidate cached
        !           617:  * routing information.  If the route was created dynamically
        !           618:  * (by a redirect), time to try a default gateway again.
        !           619:  */
        !           620: void
        !           621: in_losing(inp)
        !           622:        struct inpcb *inp;
        !           623: {
        !           624:        struct rtentry *rt;
        !           625:        struct rt_addrinfo info;
        !           626:
        !           627:        if ((rt = inp->inp_route.ro_rt)) {
        !           628:                inp->inp_route.ro_rt = 0;
        !           629:                bzero((caddr_t)&info, sizeof(info));
        !           630:                info.rti_info[RTAX_DST] = &inp->inp_route.ro_dst;
        !           631:                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
        !           632:                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
        !           633:                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, rt->rt_ifp, 0, 0);
        !           634:                if (rt->rt_flags & RTF_DYNAMIC)
        !           635:                        (void) rtrequest(RTM_DELETE, rt_key(rt),
        !           636:                                rt->rt_gateway, rt_mask(rt), rt->rt_flags,
        !           637:                                (struct rtentry **)0, 0);
        !           638:                /*
        !           639:                 * A new route can be allocated
        !           640:                 * the next time output is attempted.
        !           641:                 * rtfree() needs to be called in anycase because the inp
        !           642:                 * is still holding a reference to rt.
        !           643:                 */
        !           644:                rtfree(rt);
        !           645:        }
        !           646: }
        !           647:
        !           648: /*
        !           649:  * After a routing change, flush old routing
        !           650:  * and allocate a (hopefully) better one.
        !           651:  */
        !           652: void
        !           653: in_rtchange(inp, errno)
        !           654:        struct inpcb *inp;
        !           655:        int errno;
        !           656: {
        !           657:        if (inp->inp_route.ro_rt) {
        !           658:                rtfree(inp->inp_route.ro_rt);
        !           659:                inp->inp_route.ro_rt = 0;
        !           660:                /*
        !           661:                 * A new route can be allocated the next time
        !           662:                 * output is attempted.
        !           663:                 */
        !           664:        }
        !           665: }
        !           666:
        !           667: struct inpcb *
        !           668: in_pcblookup(table, faddrp, fport_arg, laddrp, lport_arg, flags)
        !           669:        struct inpcbtable *table;
        !           670:        void *faddrp, *laddrp;
        !           671:        u_int fport_arg, lport_arg;
        !           672:        int flags;
        !           673: {
        !           674:        struct inpcb *inp, *match = 0;
        !           675:        int matchwild = 3, wildcard;
        !           676:        u_int16_t fport = fport_arg, lport = lport_arg;
        !           677:        struct in_addr faddr = *(struct in_addr *)faddrp;
        !           678:        struct in_addr laddr = *(struct in_addr *)laddrp;
        !           679:
        !           680:        for (inp = LIST_FIRST(INPCBLHASH(table, lport)); inp;
        !           681:            inp = LIST_NEXT(inp, inp_lhash)) {
        !           682:                if (inp->inp_lport != lport)
        !           683:                        continue;
        !           684:                wildcard = 0;
        !           685: #ifdef INET6
        !           686:                if (flags & INPLOOKUP_IPV6) {
        !           687:                        struct in6_addr *laddr6 = (struct in6_addr *)laddrp;
        !           688:                        struct in6_addr *faddr6 = (struct in6_addr *)faddrp;
        !           689:
        !           690:                        if (!(inp->inp_flags & INP_IPV6))
        !           691:                                continue;
        !           692:
        !           693:                        if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
        !           694:                                if (IN6_IS_ADDR_UNSPECIFIED(laddr6))
        !           695:                                        wildcard++;
        !           696:                                else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr6))
        !           697:                                        continue;
        !           698:                        } else {
        !           699:                                if (!IN6_IS_ADDR_UNSPECIFIED(laddr6))
        !           700:                                        wildcard++;
        !           701:                        }
        !           702:
        !           703:                        if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) {
        !           704:                                if (IN6_IS_ADDR_UNSPECIFIED(faddr6))
        !           705:                                        wildcard++;
        !           706:                                else if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
        !           707:                                    faddr6) || inp->inp_fport != fport)
        !           708:                                        continue;
        !           709:                        } else {
        !           710:                                if (!IN6_IS_ADDR_UNSPECIFIED(faddr6))
        !           711:                                        wildcard++;
        !           712:                        }
        !           713:                } else
        !           714: #endif /* INET6 */
        !           715:                {
        !           716: #ifdef INET6
        !           717:                        if (inp->inp_flags & INP_IPV6)
        !           718:                                continue;
        !           719: #endif /* INET6 */
        !           720:
        !           721:                        if (inp->inp_faddr.s_addr != INADDR_ANY) {
        !           722:                                if (faddr.s_addr == INADDR_ANY)
        !           723:                                        wildcard++;
        !           724:                                else if (inp->inp_faddr.s_addr != faddr.s_addr ||
        !           725:                                    inp->inp_fport != fport)
        !           726:                                        continue;
        !           727:                        } else {
        !           728:                                if (faddr.s_addr != INADDR_ANY)
        !           729:                                        wildcard++;
        !           730:                        }
        !           731:                        if (inp->inp_laddr.s_addr != INADDR_ANY) {
        !           732:                                if (laddr.s_addr == INADDR_ANY)
        !           733:                                        wildcard++;
        !           734:                                else if (inp->inp_laddr.s_addr != laddr.s_addr)
        !           735:                                        continue;
        !           736:                        } else {
        !           737:                                if (laddr.s_addr != INADDR_ANY)
        !           738:                                        wildcard++;
        !           739:                        }
        !           740:                }
        !           741:                if ((!wildcard || (flags & INPLOOKUP_WILDCARD)) &&
        !           742:                    wildcard < matchwild) {
        !           743:                        match = inp;
        !           744:                        if ((matchwild = wildcard) == 0)
        !           745:                                break;
        !           746:                }
        !           747:        }
        !           748:        return (match);
        !           749: }
        !           750:
        !           751: struct rtentry *
        !           752: in_pcbrtentry(inp)
        !           753:        struct inpcb *inp;
        !           754: {
        !           755:        struct route *ro;
        !           756:
        !           757:        ro = &inp->inp_route;
        !           758:
        !           759:        /*
        !           760:         * No route yet, so try to acquire one.
        !           761:         */
        !           762:        if (ro->ro_rt == NULL) {
        !           763: #ifdef INET6
        !           764:                bzero(ro, sizeof(struct route_in6));
        !           765: #else
        !           766:                bzero(ro, sizeof(struct route));
        !           767: #endif
        !           768:
        !           769:                switch(sotopf(inp->inp_socket)) {
        !           770: #ifdef INET6
        !           771:                case PF_INET6:
        !           772:                        if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
        !           773:                                break;
        !           774:                        ro->ro_dst.sa_family = AF_INET6;
        !           775:                        ro->ro_dst.sa_len = sizeof(struct sockaddr_in6);
        !           776:                        ((struct sockaddr_in6 *) &ro->ro_dst)->sin6_addr =
        !           777:                            inp->inp_faddr6;
        !           778:                        rtalloc_mpath(ro, &inp->inp_laddr6.s6_addr32[0], 0);
        !           779:                        break;
        !           780: #endif /* INET6 */
        !           781:                case PF_INET:
        !           782:                        if (inp->inp_faddr.s_addr == INADDR_ANY)
        !           783:                                break;
        !           784:                        ro->ro_dst.sa_family = AF_INET;
        !           785:                        ro->ro_dst.sa_len = sizeof(ro->ro_dst);
        !           786:                        satosin(&ro->ro_dst)->sin_addr = inp->inp_faddr;
        !           787:                        rtalloc_mpath(ro, &inp->inp_laddr.s_addr, 0);
        !           788:                        break;
        !           789:                }
        !           790:        }
        !           791:        return (ro->ro_rt);
        !           792: }
        !           793:
        !           794: struct sockaddr_in *
        !           795: in_selectsrc(sin, ro, soopts, mopts, errorp)
        !           796:        struct sockaddr_in *sin;
        !           797:        struct route *ro;
        !           798:        int soopts;
        !           799:        struct ip_moptions *mopts;
        !           800:        int *errorp;
        !           801: {
        !           802:        struct sockaddr_in *sin2;
        !           803:        struct in_ifaddr *ia;
        !           804:
        !           805:        ia = (struct in_ifaddr *)0;
        !           806:        /*
        !           807:         * If route is known or can be allocated now,
        !           808:         * our src addr is taken from the i/f, else punt.
        !           809:         */
        !           810:        if (ro->ro_rt &&
        !           811:            (satosin(&ro->ro_dst)->sin_addr.s_addr !=
        !           812:                sin->sin_addr.s_addr ||
        !           813:            soopts & SO_DONTROUTE)) {
        !           814:                RTFREE(ro->ro_rt);
        !           815:                ro->ro_rt = (struct rtentry *)0;
        !           816:        }
        !           817:        if ((soopts & SO_DONTROUTE) == 0 && /*XXX*/
        !           818:            (ro->ro_rt == (struct rtentry *)0 ||
        !           819:            ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
        !           820:                /* No route yet, so try to acquire one */
        !           821:                ro->ro_dst.sa_family = AF_INET;
        !           822:                ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
        !           823:                satosin(&ro->ro_dst)->sin_addr = sin->sin_addr;
        !           824:                rtalloc_mpath(ro, NULL, 0);
        !           825:
        !           826:                /*
        !           827:                 * It is important to bzero out the rest of the
        !           828:                 * struct sockaddr_in when mixing v6 & v4!
        !           829:                 */
        !           830:                sin2 = (struct sockaddr_in *)&ro->ro_dst;
        !           831:                bzero(sin2->sin_zero, sizeof(sin2->sin_zero));
        !           832:        }
        !           833:        /*
        !           834:         * If we found a route, use the address
        !           835:         * corresponding to the outgoing interface
        !           836:         * unless it is the loopback (in case a route
        !           837:         * to our address on another net goes to loopback).
        !           838:         */
        !           839:        if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
        !           840:                ia = ifatoia(ro->ro_rt->rt_ifa);
        !           841:        if (ia == 0) {
        !           842:                u_int16_t fport = sin->sin_port;
        !           843:
        !           844:                sin->sin_port = 0;
        !           845:                ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
        !           846:                if (ia == 0)
        !           847:                        ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
        !           848:                sin->sin_port = fport;
        !           849:                if (ia == 0)
        !           850:                        ia = TAILQ_FIRST(&in_ifaddr);
        !           851:                if (ia == 0) {
        !           852:                        *errorp = EADDRNOTAVAIL;
        !           853:                        return NULL;
        !           854:                }
        !           855:        }
        !           856:        /*
        !           857:         * If the destination address is multicast and an outgoing
        !           858:         * interface has been set as a multicast option, use the
        !           859:         * address of that interface as our source address.
        !           860:         */
        !           861:        if (IN_MULTICAST(sin->sin_addr.s_addr) && mopts != NULL) {
        !           862:                struct ip_moptions *imo;
        !           863:                struct ifnet *ifp;
        !           864:
        !           865:                imo = mopts;
        !           866:                if (imo->imo_multicast_ifp != NULL) {
        !           867:                        ifp = imo->imo_multicast_ifp;
        !           868:                        TAILQ_FOREACH(ia, &in_ifaddr, ia_list)
        !           869:                                if (ia->ia_ifp == ifp)
        !           870:                                        break;
        !           871:                        if (ia == 0) {
        !           872:                                *errorp = EADDRNOTAVAIL;
        !           873:                                return NULL;
        !           874:                        }
        !           875:                }
        !           876:        }
        !           877:        return satosin(&ia->ia_addr);
        !           878: }
        !           879:
        !           880: void
        !           881: in_pcbrehash(inp)
        !           882:        struct inpcb *inp;
        !           883: {
        !           884:        struct inpcbtable *table = inp->inp_table;
        !           885:        int s;
        !           886:
        !           887:        s = splnet();
        !           888:        LIST_REMOVE(inp, inp_lhash);
        !           889:        LIST_INSERT_HEAD(INPCBLHASH(table, inp->inp_lport), inp, inp_lhash);
        !           890:        LIST_REMOVE(inp, inp_hash);
        !           891: #ifdef INET6
        !           892:        if (inp->inp_flags & INP_IPV6) {
        !           893:                LIST_INSERT_HEAD(IN6PCBHASH(table, &inp->inp_faddr6,
        !           894:                    inp->inp_fport, &inp->inp_laddr6, inp->inp_lport),
        !           895:                    inp, inp_hash);
        !           896:        } else {
        !           897: #endif /* INET6 */
        !           898:                LIST_INSERT_HEAD(INPCBHASH(table, &inp->inp_faddr,
        !           899:                    inp->inp_fport, &inp->inp_laddr, inp->inp_lport),
        !           900:                    inp, inp_hash);
        !           901: #ifdef INET6
        !           902:        }
        !           903: #endif /* INET6 */
        !           904:        splx(s);
        !           905: }
        !           906:
        !           907: #ifdef DIAGNOSTIC
        !           908: int    in_pcbnotifymiss = 0;
        !           909: #endif
        !           910:
        !           911: /*
        !           912:  * The in(6)_pcbhashlookup functions are used to locate connected sockets
        !           913:  * quickly:
        !           914:  *             faddr.fport <-> laddr.lport
        !           915:  * No wildcard matching is done so that listening sockets are not found.
        !           916:  * If the functions return NULL in(6)_pcblookup_listen can be used to
        !           917:  * find a listening/bound socket that may accept the connection.
        !           918:  * After those two lookups no other are necessary.
        !           919:  */
        !           920: struct inpcb *
        !           921: in_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
        !           922:        struct inpcbtable *table;
        !           923:        struct in_addr faddr, laddr;
        !           924:        u_int fport_arg, lport_arg;
        !           925: {
        !           926:        struct inpcbhead *head;
        !           927:        struct inpcb *inp;
        !           928:        u_int16_t fport = fport_arg, lport = lport_arg;
        !           929:
        !           930:        head = INPCBHASH(table, &faddr, fport, &laddr, lport);
        !           931:        LIST_FOREACH(inp, head, inp_hash) {
        !           932: #ifdef INET6
        !           933:                if (inp->inp_flags & INP_IPV6)
        !           934:                        continue;       /*XXX*/
        !           935: #endif
        !           936:                if (inp->inp_faddr.s_addr == faddr.s_addr &&
        !           937:                    inp->inp_fport == fport &&
        !           938:                    inp->inp_lport == lport &&
        !           939:                    inp->inp_laddr.s_addr == laddr.s_addr) {
        !           940:                        /*
        !           941:                         * Move this PCB to the head of hash chain so that
        !           942:                         * repeated accesses are quicker.  This is analogous to
        !           943:                         * the historic single-entry PCB cache.
        !           944:                         */
        !           945:                        if (inp != LIST_FIRST(head)) {
        !           946:                                LIST_REMOVE(inp, inp_hash);
        !           947:                                LIST_INSERT_HEAD(head, inp, inp_hash);
        !           948:                        }
        !           949:                        break;
        !           950:                }
        !           951:        }
        !           952: #ifdef DIAGNOSTIC
        !           953:        if (inp == NULL && in_pcbnotifymiss) {
        !           954:                printf("in_pcbhashlookup: faddr=%08x fport=%d laddr=%08x lport=%d\n",
        !           955:                    ntohl(faddr.s_addr), ntohs(fport),
        !           956:                    ntohl(laddr.s_addr), ntohs(lport));
        !           957:        }
        !           958: #endif
        !           959:        return (inp);
        !           960: }
        !           961:
        !           962: #ifdef INET6
        !           963: struct inpcb *
        !           964: in6_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
        !           965:        struct inpcbtable *table;
        !           966:        struct in6_addr *faddr, *laddr;
        !           967:        u_int fport_arg, lport_arg;
        !           968: {
        !           969:        struct inpcbhead *head;
        !           970:        struct inpcb *inp;
        !           971:        u_int16_t fport = fport_arg, lport = lport_arg;
        !           972:
        !           973:        head = IN6PCBHASH(table, faddr, fport, laddr, lport);
        !           974:        LIST_FOREACH(inp, head, inp_hash) {
        !           975:                if (!(inp->inp_flags & INP_IPV6))
        !           976:                        continue;
        !           977:                if (IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) &&
        !           978:                    inp->inp_fport == fport && inp->inp_lport == lport &&
        !           979:                    IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr)) {
        !           980:                        /*
        !           981:                         * Move this PCB to the head of hash chain so that
        !           982:                         * repeated accesses are quicker.  This is analogous to
        !           983:                         * the historic single-entry PCB cache.
        !           984:                         */
        !           985:                        if (inp != LIST_FIRST(head)) {
        !           986:                                LIST_REMOVE(inp, inp_hash);
        !           987:                                LIST_INSERT_HEAD(head, inp, inp_hash);
        !           988:                        }
        !           989:                        break;
        !           990:                }
        !           991:        }
        !           992: #ifdef DIAGNOSTIC
        !           993:        if (inp == NULL && in_pcbnotifymiss) {
        !           994:                printf("in6_pcbhashlookup: faddr=");
        !           995:                printf(" fport=%d laddr=", ntohs(fport));
        !           996:                printf(" lport=%d\n", ntohs(lport));
        !           997:        }
        !           998: #endif
        !           999:        return (inp);
        !          1000: }
        !          1001: #endif /* INET6 */
        !          1002:
        !          1003: /*
        !          1004:  * The in(6)_pcblookup_listen functions are used to locate listening
        !          1005:  * sockets quickly.  This are sockets with unspecified foreign address
        !          1006:  * and port:
        !          1007:  *             *.*     <-> laddr.lport
        !          1008:  *             *.*     <->     *.lport
        !          1009:  */
        !          1010: struct inpcb *
        !          1011: in_pcblookup_listen(table, laddr, lport_arg, reverse)
        !          1012:        struct inpcbtable *table;
        !          1013:        struct in_addr laddr;
        !          1014:        u_int lport_arg;
        !          1015:        int reverse;
        !          1016: {
        !          1017:        struct inpcbhead *head;
        !          1018:        struct in_addr *key1, *key2;
        !          1019:        struct inpcb *inp;
        !          1020:        u_int16_t lport = lport_arg;
        !          1021:
        !          1022:        if (reverse) {
        !          1023:                key1 = &zeroin_addr;
        !          1024:                key2 = &laddr;
        !          1025:        } else {
        !          1026:                key1 = &laddr;
        !          1027:                key2 = &zeroin_addr;
        !          1028:        }
        !          1029:
        !          1030:        head = INPCBHASH(table, &zeroin_addr, 0, key1, lport);
        !          1031:        LIST_FOREACH(inp, head, inp_hash) {
        !          1032: #ifdef INET6
        !          1033:                if (inp->inp_flags & INP_IPV6)
        !          1034:                        continue;       /*XXX*/
        !          1035: #endif
        !          1036:                if (inp->inp_lport == lport && inp->inp_fport == 0 &&
        !          1037:                    inp->inp_laddr.s_addr == key1->s_addr &&
        !          1038:                    inp->inp_faddr.s_addr == INADDR_ANY)
        !          1039:                        break;
        !          1040:        }
        !          1041:        if (inp == NULL && key1->s_addr != key2->s_addr) {
        !          1042:                head = INPCBHASH(table, &zeroin_addr, 0, key2, lport);
        !          1043:                LIST_FOREACH(inp, head, inp_hash) {
        !          1044: #ifdef INET6
        !          1045:                        if (inp->inp_flags & INP_IPV6)
        !          1046:                                continue;       /*XXX*/
        !          1047: #endif
        !          1048:                        if (inp->inp_lport == lport && inp->inp_fport == 0 &&
        !          1049:                            inp->inp_laddr.s_addr == key2->s_addr &&
        !          1050:                            inp->inp_faddr.s_addr == INADDR_ANY)
        !          1051:                                break;
        !          1052:                }
        !          1053:        }
        !          1054: #ifdef DIAGNOSTIC
        !          1055:        if (inp == NULL && in_pcbnotifymiss) {
        !          1056:                printf("in_pcblookup_listen: laddr=%08x lport=%d\n",
        !          1057:                    ntohl(laddr.s_addr), ntohs(lport));
        !          1058:        }
        !          1059: #endif
        !          1060:        /*
        !          1061:         * Move this PCB to the head of hash chain so that
        !          1062:         * repeated accesses are quicker.  This is analogous to
        !          1063:         * the historic single-entry PCB cache.
        !          1064:         */
        !          1065:        if (inp != NULL && inp != LIST_FIRST(head)) {
        !          1066:                LIST_REMOVE(inp, inp_hash);
        !          1067:                LIST_INSERT_HEAD(head, inp, inp_hash);
        !          1068:        }
        !          1069:        return (inp);
        !          1070: }
        !          1071:
        !          1072: #ifdef INET6
        !          1073: struct inpcb *
        !          1074: in6_pcblookup_listen(table, laddr, lport_arg, reverse)
        !          1075:        struct inpcbtable *table;
        !          1076:        struct in6_addr *laddr;
        !          1077:        u_int lport_arg;
        !          1078:        int reverse;
        !          1079: {
        !          1080:        struct inpcbhead *head;
        !          1081:        struct in6_addr *key1, *key2;
        !          1082:        struct inpcb *inp;
        !          1083:        u_int16_t lport = lport_arg;
        !          1084:
        !          1085:        if (reverse) {
        !          1086:                key1 = &zeroin6_addr;
        !          1087:                key2 = laddr;
        !          1088:        } else {
        !          1089:                key1 = laddr;
        !          1090:                key2 = &zeroin6_addr;
        !          1091:        }
        !          1092:
        !          1093:        head = IN6PCBHASH(table, &zeroin6_addr, 0, key1, lport);
        !          1094:        LIST_FOREACH(inp, head, inp_hash) {
        !          1095:                if (!(inp->inp_flags & INP_IPV6))
        !          1096:                        continue;
        !          1097:                if (inp->inp_lport == lport && inp->inp_fport == 0 &&
        !          1098:                    IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key1) &&
        !          1099:                    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
        !          1100:                        break;
        !          1101:        }
        !          1102:        if (inp == NULL && ! IN6_ARE_ADDR_EQUAL(key1, key2)) {
        !          1103:                head = IN6PCBHASH(table, &zeroin6_addr, 0, key2, lport);
        !          1104:                LIST_FOREACH(inp, head, inp_hash) {
        !          1105:                        if (!(inp->inp_flags & INP_IPV6))
        !          1106:                                continue;
        !          1107:                        if (inp->inp_lport == lport && inp->inp_fport == 0 &&
        !          1108:                            IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key2) &&
        !          1109:                            IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
        !          1110:                                break;
        !          1111:                }
        !          1112:        }
        !          1113: #ifdef DIAGNOSTIC
        !          1114:        if (inp == NULL && in_pcbnotifymiss) {
        !          1115:                printf("in6_pcblookup_listen: laddr= lport=%d\n",
        !          1116:                    ntohs(lport));
        !          1117:        }
        !          1118: #endif
        !          1119:        /*
        !          1120:         * Move this PCB to the head of hash chain so that
        !          1121:         * repeated accesses are quicker.  This is analogous to
        !          1122:         * the historic single-entry PCB cache.
        !          1123:         */
        !          1124:        if (inp != NULL && inp != LIST_FIRST(head)) {
        !          1125:                LIST_REMOVE(inp, inp_hash);
        !          1126:                LIST_INSERT_HEAD(head, inp, inp_hash);
        !          1127:        }
        !          1128:        return (inp);
        !          1129: }
        !          1130: #endif /* INET6 */

CVSweb