Annotation of kernel/bsd/netinet/in_pcb.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
        !            26: /*
        !            27:  * Copyright (c) 1982, 1986, 1991, 1993, 1995
        !            28:  *     The Regents of the University of California.  All rights reserved.
        !            29:  *
        !            30:  * Redistribution and use in source and binary forms, with or without
        !            31:  * modification, are permitted provided that the following conditions
        !            32:  * are met:
        !            33:  * 1. Redistributions of source code must retain the above copyright
        !            34:  *    notice, this list of conditions and the following disclaimer.
        !            35:  * 2. Redistributions in binary form must reproduce the above copyright
        !            36:  *    notice, this list of conditions and the following disclaimer in the
        !            37:  *    documentation and/or other materials provided with the distribution.
        !            38:  * 3. All advertising materials mentioning features or use of this software
        !            39:  *    must display the following acknowledgement:
        !            40:  *     This product includes software developed by the University of
        !            41:  *     California, Berkeley and its contributors.
        !            42:  * 4. Neither the name of the University nor the names of its contributors
        !            43:  *    may be used to endorse or promote products derived from this software
        !            44:  *    without specific prior written permission.
        !            45:  *
        !            46:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            47:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            48:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            49:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            50:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            51:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            52:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            53:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            54:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            55:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            56:  * SUCH DAMAGE.
        !            57:  *
        !            58:  *     @(#)in_pcb.c    8.4 (Berkeley) 5/24/95
        !            59:  */
        !            60: 
        !            61: #include <sys/param.h>
        !            62: #include <sys/systm.h>
        !            63: #include <sys/malloc.h>
        !            64: #include <sys/mbuf.h>
        !            65: #include <sys/protosw.h>
        !            66: #include <sys/socket.h>
        !            67: #include <sys/socketvar.h>
        !            68: #include <sys/ioctl.h>
        !            69: #include <sys/errno.h>
        !            70: #include <sys/time.h>
        !            71: #include <sys/proc.h>
        !            72: 
        !            73: #include <net/if.h>
        !            74: #include <net/route.h>
        !            75: 
        !            76: #include <netinet/in.h>
        !            77: #include <netinet/in_systm.h>
        !            78: #include <netinet/ip.h>
        !            79: #include <netinet/in_pcb.h>
        !            80: #include <netinet/in_var.h>
        !            81: #include <netinet/ip_var.h>
        !            82: 
        !            83: #include <kern/kdebug.h>
        !            84: 
        !            85: 
        !            86: #if KDEBUG
        !            87: 
        !            88: #define DBG_FNC_PCB_LOOKUP     NETDBG_CODE(DBG_NETTCP, (6 << 8))
        !            89: #define DBG_FNC_PCB_HLOOKUP    NETDBG_CODE(DBG_NETTCP, ((6 << 8) | 1))
        !            90: 
        !            91: #endif
        !            92: 
        !            93: 
        !            94: struct zone   *inpcb_zone;
        !            95: struct in_addr zeroin_addr;
        !            96: 
        !            97: 
        !            98: 
        !            99: 
        !           100: void
        !           101: lport_hash_remove(inp)
        !           102:         register struct inpcb *inp;
        !           103: {
        !           104:        if ((*inp->lport_hash_str->hash_array)[inp->lport_hash_element] == inp)
        !           105:                (*inp->lport_hash_str->hash_array)[inp->lport_hash_element] = inp->lport_hash_next;
        !           106: 
        !           107:        if (inp->lport_hash_prev) 
        !           108:                inp->lport_hash_prev->lport_hash_next = inp->lport_hash_next;
        !           109: 
        !           110:        if (inp->lport_hash_next) 
        !           111:                inp->lport_hash_next->lport_hash_prev = inp->lport_hash_prev;
        !           112: 
        !           113:        inp->lport_hash_next = 0;
        !           114:        inp->lport_hash_prev = 0;
        !           115:        inp->lport_hash_element = -1;
        !           116: }
        !           117: 
        !           118: 
        !           119: 
        !           120: 
        !           121: void
        !           122: lport_hash_insert(inp)
        !           123:        register struct inpcb *inp;
        !           124: 
        !           125: {
        !           126:         register u_long        h_idx;
        !           127: 
        !           128:        if (inp->lport_hash_element != -1)
        !           129:                return;
        !           130:                    
        !           131:        h_idx = inp->inp_lport & inp->lport_hash_str->hash_mask;
        !           132: 
        !           133:        if ((*inp->lport_hash_str->hash_array)[h_idx]) {
        !           134:                (*inp->lport_hash_str->hash_array)[h_idx]->lport_hash_prev = inp;
        !           135:                inp->lport_hash_next = (*inp->lport_hash_str->hash_array)[h_idx];
        !           136:                inp->lport_hash_prev = 0;
        !           137:                (*inp->lport_hash_str->hash_array)[h_idx] = inp;
        !           138:        } else {
        !           139:                (*inp->lport_hash_str->hash_array)[h_idx] = inp;
        !           140:                inp->lport_hash_next = 0;
        !           141:                inp->lport_hash_prev = 0;
        !           142:        }
        !           143: 
        !           144:        inp->lport_hash_element = h_idx;
        !           145: }
        !           146: 
        !           147: 
        !           148: 
        !           149: 
        !           150: void
        !           151: hash_remove(inp)
        !           152:         register struct inpcb *inp;
        !           153: {
        !           154:        if ((*inp->hash_str->hash_array)[inp->hash_element] == inp)
        !           155:                (*inp->hash_str->hash_array)[inp->hash_element] = inp->hash_next;
        !           156: 
        !           157:        if (inp->hash_prev) 
        !           158:                inp->hash_prev->hash_next = inp->hash_next;
        !           159: 
        !           160:        if (inp->hash_next) 
        !           161:                inp->hash_next->hash_prev = inp->hash_prev;
        !           162: 
        !           163:        inp->hash_next = 0;
        !           164:        inp->hash_prev = 0;
        !           165:        inp->hash_element = -1;
        !           166: }
        !           167: 
        !           168: 
        !           169: 
        !           170: void
        !           171: hash_insert(inp)
        !           172:         register struct inpcb *inp;
        !           173: {
        !           174:         register u_long        h_idx;
        !           175: 
        !           176:        if (inp->hash_element != -1)
        !           177:                return;
        !           178: 
        !           179:        h_idx = (inp->inp_lport + inp->inp_fport + inp->inp_faddr.s_addr) & inp->hash_str->hash_mask;
        !           180: 
        !           181:        if ((*inp->hash_str->hash_array)[h_idx]) {
        !           182:                (*inp->hash_str->hash_array)[h_idx]->hash_prev = inp;
        !           183:                inp->hash_next = (*inp->hash_str->hash_array)[h_idx];
        !           184:                inp->hash_prev = 0;
        !           185:                (*inp->hash_str->hash_array)[h_idx] = inp;
        !           186:        } else {
        !           187:                (*inp->hash_str->hash_array)[h_idx] = inp;
        !           188:                inp->hash_next = 0;
        !           189:                inp->hash_prev = 0;
        !           190:        }
        !           191:        inp->hash_element = h_idx;
        !           192: }
        !           193: 
        !           194: 
        !           195: struct inpcb *inet_hash1(hash_str, l_addr, l_port, f_addr, f_port)
        !           196:        struct inpcb_hash_str *hash_str;
        !           197:         u_long l_addr;
        !           198:        u_short l_port;
        !           199:        u_long  f_addr;
        !           200:        u_short f_port;
        !           201: {
        !           202:        return ((*hash_str->hash_array)[(l_port + f_port + f_addr) & hash_str->hash_mask]);
        !           203: }
        !           204: 
        !           205: 
        !           206: struct inpcb *inet_lport_hash1(lport_hash_str, l_port)
        !           207:        struct inpcb_hash_str *lport_hash_str;
        !           208:        u_short  l_port;
        !           209: 
        !           210: {
        !           211:        return ((*lport_hash_str->hash_array)[l_port & lport_hash_str->hash_mask]);
        !           212: }
        !           213: 
        !           214: 
        !           215: 
        !           216: int
        !           217: in_pcballoc(so, head, hash_str, lport_hash_str)
        !           218:        struct socket *so;
        !           219:        struct inpcb *head;
        !           220:        struct inpcb_hash_str *hash_str;
        !           221:        struct inpcb_hash_str *lport_hash_str;
        !           222: {
        !           223:        register struct inpcb *inp;
        !           224:        caddr_t               temp;
        !           225: 
        !           226:        if (so->cached_in_sock_layer == 0) {
        !           227: #if TEMPDEBUG
        !           228:            printf("PCBALLOC calling zalloc for socket %x\n", so);
        !           229: #endif
        !           230:            inp = zalloc(inpcb_zone);
        !           231:            if (inp == NULL)
        !           232:                return (ENOBUFS);
        !           233:            bzero((caddr_t)inp, sizeof(*inp));
        !           234:        }
        !           235:        else {
        !           236: #if TEMPDEBUG
        !           237:            printf("PCBALLOC reusing PCB for socket %x\n", so);
        !           238: #endif
        !           239:            inp = so->so_saved_pcb;
        !           240:            temp = inp->inp_saved_ppcb;
        !           241:            bzero((caddr_t) inp, sizeof(*inp));
        !           242:            inp->inp_saved_ppcb = temp;
        !           243:        }
        !           244: 
        !           245:        inp->hash_element = -1;
        !           246:        inp->lport_hash_element = -1;
        !           247:        inp->inp_head = head;
        !           248:        inp->hash_str = hash_str;
        !           249:        inp->lport_hash_str = lport_hash_str;
        !           250:        inp->inp_socket = so;
        !           251:        if (head)
        !           252:            insque(inp, head);
        !           253:        so->so_pcb = (caddr_t)inp;
        !           254:        return (0);
        !           255: }
        !           256: 
        !           257: int
        !           258: in_pcbbind(inp, nam)
        !           259:        register struct inpcb *inp;
        !           260:        struct mbuf *nam;
        !           261: {
        !           262:        register struct socket *so = inp->inp_socket;
        !           263:        register struct inpcb *head = inp->inp_head;
        !           264:        register struct sockaddr_in *sin;
        !           265:        struct proc *p = current_proc();                /* XXX */
        !           266:        u_short lport = 0;
        !           267:        int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
        !           268:        int error;
        !           269:        register int    loop_count = 0;
        !           270:        struct inpcb    *hash_head;
        !           271: 
        !           272: 
        !           273:        if (in_ifaddr == 0)
        !           274:                return (EADDRNOTAVAIL);
        !           275:        if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
        !           276:                return (EINVAL);
        !           277:        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
        !           278:            ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
        !           279:             (so->so_options & SO_ACCEPTCONN) == 0))
        !           280:                wild = INPLOOKUP_WILDCARD;
        !           281:        if (nam) {
        !           282:                sin = mtod(nam, struct sockaddr_in *);
        !           283:                if (nam->m_len != sizeof (*sin))
        !           284:                        return (EINVAL);
        !           285: #ifdef notdef
        !           286:                /*
        !           287:                 * We should check the family, but old programs
        !           288:                 * incorrectly fail to initialize it.
        !           289:                 */
        !           290:                if (sin->sin_family != AF_INET)
        !           291:                        return (EAFNOSUPPORT);
        !           292: #endif
        !           293:                lport = sin->sin_port;
        !           294:                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
        !           295:                        /*
        !           296:                         * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
        !           297:                         * allow complete duplication of binding if
        !           298:                         * SO_REUSEPORT is set, or if SO_REUSEADDR is set
        !           299:                         * and a multicast address is bound on both
        !           300:                         * new and duplicated sockets.
        !           301:                         */
        !           302:                        if (so->so_options & SO_REUSEADDR)
        !           303:                                reuseport = SO_REUSEADDR|SO_REUSEPORT;
        !           304:                } else if (sin->sin_addr.s_addr != INADDR_ANY) {
        !           305:                        sin->sin_port = 0;              /* yech... */
        !           306:                        if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
        !           307:                                return (EADDRNOTAVAIL);
        !           308:                }
        !           309:                if (lport) {
        !           310:                        struct inpcb *t;
        !           311: 
        !           312:                        /* GROSS */
        !           313:                        if (ntohs(lport) < IPPORT_RESERVED &&
        !           314:                            (error = suser(p->p_ucred, &p->p_acflag)))
        !           315:                                return (EACCES);
        !           316: 
        !           317:                        hash_head = inet_lport_hash1(inp->lport_hash_str, lport);
        !           318:                        t = lport_hash_in_pcbwild(hash_head,
        !           319:                                                  zeroin_addr, 0, sin->sin_addr,
        !           320:                                                  lport, wild);
        !           321: 
        !           322:                        if (t && (reuseport & t->inp_socket->so_options) == 0)
        !           323:                                return (EADDRINUSE);
        !           324:                }
        !           325:                inp->inp_laddr = sin->sin_addr;
        !           326:        }
        !           327:        if (lport == 0) {
        !           328:            for (;;) {
        !           329:                if (++loop_count >= (IPPORT_USERRESERVED - IPPORT_RESERVED))
        !           330:                    return EADDRINUSE;
        !           331: 
        !           332:                if (head->inp_lport++ < IPPORT_RESERVED ||
        !           333:                    head->inp_lport > IPPORT_USERRESERVED) 
        !           334:                    head->inp_lport = IPPORT_RESERVED;
        !           335: 
        !           336:                lport = htons(head->inp_lport);
        !           337: 
        !           338:                hash_head = inet_lport_hash1(inp->lport_hash_str, lport);
        !           339:                if (lport_hash_in_pcbwild(hash_head,
        !           340:                                          zeroin_addr, 0, inp->inp_laddr, lport, wild))
        !           341:                        continue;
        !           342: 
        !           343:                break;
        !           344:            }
        !           345:        }
        !           346: 
        !           347:        inp->inp_lport = lport;
        !           348:        lport_hash_insert(inp);
        !           349: 
        !           350:        return (0);
        !           351: }
        !           352: 
        !           353: /*
        !           354:  * Connect from a socket to a specified address.
        !           355:  * Both address and port must be specified in argument sin.
        !           356:  * If don't have a local address for this socket yet,
        !           357:  * then pick one.
        !           358:  */
        !           359: int
        !           360: in_pcbconnect(inp, nam)
        !           361:        register struct inpcb *inp;
        !           362:        struct mbuf *nam;
        !           363: {
        !           364:     struct inpcb       *hash_head;
        !           365:        struct in_ifaddr *ia;
        !           366:        struct sockaddr_in *ifaddr;
        !           367:        register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
        !           368: 
        !           369:        if (nam->m_len != sizeof (*sin))
        !           370:                return (EINVAL);
        !           371:        if (sin->sin_family != AF_INET)
        !           372:                return (EAFNOSUPPORT);
        !           373:        if (sin->sin_port == 0)
        !           374:                return (EADDRNOTAVAIL);
        !           375:        if (in_ifaddr) {
        !           376:                /*
        !           377:                 * If the destination address is INADDR_ANY,
        !           378:                 * use the primary local address.
        !           379:                 * If the supplied address is INADDR_BROADCAST,
        !           380:                 * and the primary interface supports broadcast,
        !           381:                 * choose the broadcast address for that interface.
        !           382:                 */
        !           383: #define        satosin(sa)     ((struct sockaddr_in *)(sa))
        !           384: #define sintosa(sin)   ((struct sockaddr *)(sin))
        !           385: #define ifatoia(ifa)   ((struct in_ifaddr *)(ifa))
        !           386:                if (sin->sin_addr.s_addr == INADDR_ANY)
        !           387:                    sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
        !           388:                else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
        !           389:                  (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
        !           390:                    sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
        !           391:        }
        !           392:        if (inp->inp_laddr.s_addr == INADDR_ANY) {
        !           393:                register struct route *ro;
        !           394: 
        !           395:                ia = (struct in_ifaddr *)0;
        !           396:                /* 
        !           397:                 * If route is known or can be allocated now,
        !           398:                 * our src addr is taken from the i/f, else punt.
        !           399:                 */
        !           400:                ro = &inp->inp_route;
        !           401:                if (ro->ro_rt &&
        !           402:                    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
        !           403:                        sin->sin_addr.s_addr || 
        !           404:                    inp->inp_socket->so_options & SO_DONTROUTE)) {
        !           405:                        RTFREE(ro->ro_rt);
        !           406:                        ro->ro_rt = (struct rtentry *)0;
        !           407:                }
        !           408:                if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
        !           409:                    (ro->ro_rt == (struct rtentry *)0 ||
        !           410:                    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
        !           411:                        /* No route yet, so try to acquire one */
        !           412:                        ro->ro_dst.sa_family = AF_INET;
        !           413:                        ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
        !           414:                        ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
        !           415:                                sin->sin_addr;
        !           416:                        rtalloc(ro);
        !           417:                }
        !           418:                /*
        !           419:                 * If we found a route, use the address
        !           420:                 * corresponding to the outgoing interface
        !           421:                 * unless it is the loopback (in case a route
        !           422:                 * to our address on another net goes to loopback).
        !           423:                 */
        !           424:                if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
        !           425:                        ia = ifatoia(ro->ro_rt->rt_ifa);
        !           426:                if (ia == 0) {
        !           427:                        u_short fport = sin->sin_port;
        !           428: 
        !           429:                        sin->sin_port = 0;
        !           430:                        ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
        !           431:                        if (ia == 0)
        !           432:                                ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
        !           433:                        sin->sin_port = fport;
        !           434:                        if (ia == 0)
        !           435:                                ia = in_ifaddr;
        !           436:                        if (ia == 0)
        !           437:                                return (EADDRNOTAVAIL);
        !           438:                }
        !           439:                /*
        !           440:                 * If the destination address is multicast and an outgoing
        !           441:                 * interface has been set as a multicast option, use the
        !           442:                 * address of that interface as our source address.
        !           443:                 */
        !           444:                if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
        !           445:                    inp->inp_moptions != NULL) {
        !           446:                        struct ip_moptions *imo;
        !           447:                        struct ifnet *ifp;
        !           448: 
        !           449:                        imo = inp->inp_moptions;
        !           450:                        if (imo->imo_multicast_ifp != NULL) {
        !           451:                                ifp = imo->imo_multicast_ifp;
        !           452:                                for (ia = in_ifaddr; ia; ia = ia->ia_next)
        !           453:                                        if (ia->ia_ifp == ifp)
        !           454:                                                break;
        !           455:                                if (ia == 0)
        !           456:                                        return (EADDRNOTAVAIL);
        !           457:                        }
        !           458:                }
        !           459:                ifaddr = (struct sockaddr_in *)&ia->ia_addr;
        !           460:        }
        !           461: 
        !           462:        if ( !(inp->inp_flags & INP_NOLOOKUP)) {
        !           463:                hash_head = inet_hash1(inp->hash_str,
        !           464:                                       inp->inp_laddr.s_addr ? inp->inp_laddr.s_addr : ifaddr->sin_addr.s_addr,
        !           465:                                       inp->inp_lport,
        !           466:                                       sin->sin_addr.s_addr,
        !           467:                                       sin->sin_port);
        !           468: 
        !           469:                if (hash_in_pcblookup(hash_head,
        !           470:                                      sin->sin_addr,
        !           471:                                      sin->sin_port,
        !           472:                                      inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
        !           473:                                      inp->inp_lport))
        !           474:                        return (EADDRINUSE);
        !           475:        }
        !           476: 
        !           477: 
        !           478:        if (inp->inp_laddr.s_addr == INADDR_ANY) {
        !           479:                if (inp->inp_lport == 0)
        !           480:                        (void)in_pcbbind(inp, (struct mbuf *)0);
        !           481:                inp->inp_laddr = ifaddr->sin_addr;
        !           482:        }
        !           483:        inp->inp_faddr = sin->sin_addr;
        !           484:        inp->inp_fport = sin->sin_port;
        !           485:        hash_insert(inp);
        !           486:        return (0);
        !           487: }
        !           488: 
        !           489: int
        !           490: in_pcbdisconnect(inp)
        !           491:        struct inpcb *inp;
        !           492: {
        !           493: 
        !           494:        inp->inp_faddr.s_addr = INADDR_ANY;
        !           495:        inp->inp_fport = 0;
        !           496: 
        !           497:        if (inp->inp_socket->so_state & SS_NOFDREF)
        !           498:                in_pcbdetach(inp);
        !           499:        else {
        !           500:                if (inp->hash_element >= 0)
        !           501:                        hash_remove(inp);
        !           502:        }
        !           503: }
        !           504: 
        !           505: int
        !           506: in_pcbdetach(inp)
        !           507:        struct inpcb *inp;
        !           508: {
        !           509:        struct socket *so = inp->inp_socket;
        !           510: 
        !           511:        if (inp->hash_element >= 0)
        !           512:                hash_remove(inp);
        !           513: 
        !           514:        if (inp->lport_hash_element >= 0)
        !           515:                lport_hash_remove(inp);
        !           516: #if TEMPDEBUG
        !           517:        if (so->cached_in_sock_layer)
        !           518:            printf("PCB_DETACH for cached socket %x\n", so);
        !           519:        else
        !           520:            printf("PCB_DETACH for allocated socket %x\n", so);
        !           521: #endif
        !           522:        so->so_pcb = 0;
        !           523: 
        !           524:        if (inp->inp_options)
        !           525:                (void)m_free(inp->inp_options);
        !           526:        if (inp->inp_route.ro_rt)
        !           527:                rtfree(inp->inp_route.ro_rt);
        !           528:        ip_freemoptions(inp->inp_moptions);
        !           529:        if ((inp->inp_next) && (inp->inp_prev))
        !           530:            remque(inp);
        !           531: 
        !           532:        if (so->cached_in_sock_layer)
        !           533:                so->so_saved_pcb = inp;
        !           534:        else
        !           535:                zfree(inpcb_zone, (vm_offset_t) inp);
        !           536:        sofree(so);
        !           537: }
        !           538: 
        !           539: int
        !           540: in_setsockaddr(inp, nam)
        !           541:        register struct inpcb *inp;
        !           542:        struct mbuf *nam;
        !           543: {
        !           544:        register struct sockaddr_in *sin;
        !           545:        
        !           546:        nam->m_len = sizeof (*sin);
        !           547:        sin = mtod(nam, struct sockaddr_in *);
        !           548:        bzero((caddr_t)sin, sizeof (*sin));
        !           549:        sin->sin_family = AF_INET;
        !           550:        sin->sin_len = sizeof(*sin);
        !           551:        sin->sin_port = inp->inp_lport;
        !           552:        sin->sin_addr = inp->inp_laddr;
        !           553: }
        !           554: 
        !           555: int
        !           556: in_setpeeraddr(inp, nam)
        !           557:        struct inpcb *inp;
        !           558:        struct mbuf *nam;
        !           559: {
        !           560:        register struct sockaddr_in *sin;
        !           561:        
        !           562:        nam->m_len = sizeof (*sin);
        !           563:        sin = mtod(nam, struct sockaddr_in *);
        !           564:        bzero((caddr_t)sin, sizeof (*sin));
        !           565:        sin->sin_family = AF_INET;
        !           566:        sin->sin_len = sizeof(*sin);
        !           567:        sin->sin_port = inp->inp_fport;
        !           568:        sin->sin_addr = inp->inp_faddr;
        !           569: }
        !           570: 
        !           571: /*
        !           572:  * Pass some notification to all connections of a protocol
        !           573:  * associated with address dst.  The local address and/or port numbers
        !           574:  * may be specified to limit the search.  The "usual action" will be
        !           575:  * taken, depending on the ctlinput cmd.  The caller must filter any
        !           576:  * cmds that are uninteresting (e.g., no error in the map).
        !           577:  * Call the protocol specific routine (if any) to report
        !           578:  * any errors for each matching socket.
        !           579:  *
        !           580:  * Must be called at splnet.
        !           581:  */
        !           582: int
        !           583: in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
        !           584:        struct inpcb *head;
        !           585:        struct sockaddr *dst;
        !           586:        u_int fport_arg, lport_arg;
        !           587:        struct in_addr laddr;
        !           588:        int cmd;
        !           589:        void (*notify) __P((struct inpcb *, int));
        !           590: {
        !           591:        extern u_char inetctlerrmap[];
        !           592:        register struct inpcb *inp, *oinp;
        !           593:        struct in_addr faddr;
        !           594:        u_short fport = fport_arg, lport = lport_arg;
        !           595:        int errno;
        !           596: 
        !           597:        if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
        !           598:                return;
        !           599:        faddr = ((struct sockaddr_in *)dst)->sin_addr;
        !           600:        if (faddr.s_addr == INADDR_ANY)
        !           601:                return;
        !           602: 
        !           603:        /*
        !           604:         * Redirects go to all references to the destination,
        !           605:         * and use in_rtchange to invalidate the route cache.
        !           606:         * Dead host indications: notify all references to the destination.
        !           607:         * Otherwise, if we have knowledge of the local port and address,
        !           608:         * deliver only to that socket.
        !           609:         */
        !           610:        if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
        !           611:                fport = 0;
        !           612:                lport = 0;
        !           613:                laddr.s_addr = 0;
        !           614:                if (cmd != PRC_HOSTDEAD)
        !           615:                        notify = in_rtchange;
        !           616:        }
        !           617:        errno = inetctlerrmap[cmd];
        !           618:        for (inp = head->inp_next; inp != head;) {
        !           619:                if (inp->inp_faddr.s_addr != faddr.s_addr ||
        !           620:                    inp->inp_socket == 0 ||
        !           621:                    (lport && inp->inp_lport != lport) ||
        !           622:                    (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
        !           623:                    (fport && inp->inp_fport != fport)) {
        !           624:                        inp = inp->inp_next;
        !           625:                        continue;
        !           626:                }
        !           627:                oinp = inp;
        !           628:                inp = inp->inp_next;
        !           629:                if (notify)
        !           630:                        (*notify)(oinp, errno);
        !           631:        }
        !           632: }
        !           633: 
        !           634: /*
        !           635:  * Check for alternatives when higher level complains
        !           636:  * about service problems.  For now, invalidate cached
        !           637:  * routing information.  If the route was created dynamically
        !           638:  * (by a redirect), time to try a default gateway again.
        !           639:  */
        !           640: int
        !           641: in_losing(inp)
        !           642:        struct inpcb *inp;
        !           643: {
        !           644:        register struct rtentry *rt;
        !           645:        struct rt_addrinfo info;
        !           646: 
        !           647:        if ((rt = inp->inp_route.ro_rt)) {
        !           648:                inp->inp_route.ro_rt = 0;
        !           649:                bzero((caddr_t)&info, sizeof(info));
        !           650:                info.rti_info[RTAX_DST] =
        !           651:                        (struct sockaddr *)&inp->inp_route.ro_dst;
        !           652:                info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
        !           653:                info.rti_info[RTAX_NETMASK] = rt_mask(rt);
        !           654:                rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
        !           655:                if (rt->rt_flags & RTF_DYNAMIC)
        !           656:                        (void) rtrequest(RTM_DELETE, rt_key(rt),
        !           657:                                rt->rt_gateway, rt_mask(rt), rt->rt_flags, 
        !           658:                                (struct rtentry **)0);
        !           659:                else 
        !           660:                /*
        !           661:                 * A new route can be allocated
        !           662:                 * the next time output is attempted.
        !           663:                 */
        !           664:                        rtfree(rt);
        !           665:        }
        !           666: }
        !           667: 
        !           668: /*
        !           669:  * After a routing change, flush old routing
        !           670:  * and allocate a (hopefully) better one.
        !           671:  */
        !           672: void
        !           673: in_rtchange(inp, errno)
        !           674:        register struct inpcb *inp;
        !           675:        int errno;
        !           676: {
        !           677:        if (inp->inp_route.ro_rt) {
        !           678:                rtfree(inp->inp_route.ro_rt);
        !           679:                inp->inp_route.ro_rt = 0;
        !           680:                /*
        !           681:                 * A new route can be allocated the next time
        !           682:                 * output is attempted.
        !           683:                 */
        !           684:        }
        !           685: }
        !           686: 
        !           687: struct inpcb *
        !           688: in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags)
        !           689:        struct inpcb *head;
        !           690:        struct in_addr faddr, laddr;
        !           691:        u_int fport_arg, lport_arg;
        !           692:        int flags;
        !           693: {
        !           694:        register struct inpcb *inp, *match = 0;
        !           695:        int matchwild = 3, wildcard;
        !           696:        u_short fport = fport_arg, lport = lport_arg;
        !           697: #if KDEBUG
        !           698:        register int checked = 0;
        !           699: #endif
        !           700:        KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,0);
        !           701: 
        !           702:        for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
        !           703: #if KDEBUG
        !           704:                checked++;
        !           705: #endif
        !           706:                if (inp->inp_lport != lport)
        !           707:                        continue;
        !           708:                wildcard = 0;
        !           709:                if (inp->inp_laddr.s_addr != INADDR_ANY) {
        !           710:                        if (laddr.s_addr == INADDR_ANY)
        !           711:                                wildcard++;
        !           712:                        else if (inp->inp_laddr.s_addr != laddr.s_addr)
        !           713:                                continue;
        !           714:                } else {
        !           715:                        if (laddr.s_addr != INADDR_ANY)
        !           716:                                wildcard++;
        !           717:                }
        !           718:                if (inp->inp_faddr.s_addr != INADDR_ANY) {
        !           719:                        if (faddr.s_addr == INADDR_ANY)
        !           720:                                wildcard++;
        !           721:                        else if (inp->inp_faddr.s_addr != faddr.s_addr ||
        !           722:                            inp->inp_fport != fport)
        !           723:                                continue;
        !           724:                } else {
        !           725:                        if (faddr.s_addr != INADDR_ANY)
        !           726:                                wildcard++;
        !           727:                }
        !           728:                if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
        !           729:                        continue;
        !           730:                if (wildcard < matchwild) {
        !           731:                        match = inp;
        !           732:                        matchwild = wildcard;
        !           733:                        if (matchwild == 0)
        !           734:                                break;
        !           735:                }
        !           736:        }
        !           737: #if KDEBUG
        !           738:        KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, checked,match,0,0,0);
        !           739: #endif
        !           740:        return (match);
        !           741: }
        !           742: 
        !           743: 
        !           744: 
        !           745: struct inpcb *
        !           746: hash_in_pcbwild(head, faddr, fport_arg, laddr, lport_arg, flags)
        !           747:        struct inpcb *head;
        !           748:        struct in_addr faddr, laddr;
        !           749:        u_int fport_arg, lport_arg;
        !           750:        int flags;
        !           751: {
        !           752:        register struct inpcb *inp, *match = 0;
        !           753:        int matchwild = 3, wildcard;
        !           754:        u_short fport = fport_arg, lport = lport_arg;
        !           755: #if KDEBUG
        !           756:        register int checked = 0;
        !           757: #endif
        !           758: 
        !           759:        KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,-1);
        !           760: 
        !           761:        for (inp = head; inp != 0; inp = inp->hash_next) {
        !           762: #if KDEBUG
        !           763:                checked++;
        !           764: #endif
        !           765:                if (inp->inp_lport != lport)
        !           766:                        continue;
        !           767:                wildcard = 0;
        !           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 (inp->inp_faddr.s_addr != INADDR_ANY) {
        !           778:                        if (faddr.s_addr == INADDR_ANY)
        !           779:                                wildcard++;
        !           780:                        else if (inp->inp_faddr.s_addr != faddr.s_addr ||
        !           781:                            inp->inp_fport != fport)
        !           782:                                continue;
        !           783:                } else {
        !           784:                        if (faddr.s_addr != INADDR_ANY)
        !           785:                                wildcard++;
        !           786:                }
        !           787:                if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
        !           788:                        continue;
        !           789:                if (wildcard < matchwild) {
        !           790:                        match = inp;
        !           791:                        matchwild = wildcard;
        !           792:                        if (matchwild == 0)
        !           793:                                break;
        !           794:                }
        !           795:        }
        !           796: #if KDEBUG
        !           797:        KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, checked,match,0,0,-1);
        !           798: #endif
        !           799:        return (match);
        !           800: }
        !           801: 
        !           802: 
        !           803: 
        !           804: struct inpcb *
        !           805: lport_hash_in_pcbwild(head, faddr, fport_arg, laddr, lport_arg, flags)
        !           806:        struct inpcb *head;
        !           807:        struct in_addr faddr, laddr;
        !           808:        u_int fport_arg, lport_arg;
        !           809:        int flags;
        !           810: {
        !           811:        register struct inpcb *inp, *match = 0;
        !           812:        int matchwild = 3, wildcard;
        !           813:        u_short fport = fport_arg, lport = lport_arg;
        !           814: #if KDEBUG
        !           815:        register int checked = 0;
        !           816: #endif
        !           817: 
        !           818:        KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,-1);
        !           819: 
        !           820:        for (inp = head; inp != 0; inp = inp->lport_hash_next) {
        !           821: #if KDEBUG
        !           822:                checked++;
        !           823: #endif
        !           824:                if (inp->inp_lport != lport)
        !           825:                        continue;
        !           826:                wildcard = 0;
        !           827:                if (inp->inp_laddr.s_addr != INADDR_ANY) {
        !           828:                        if (laddr.s_addr == INADDR_ANY)
        !           829:                                wildcard++;
        !           830:                        else if (inp->inp_laddr.s_addr != laddr.s_addr)
        !           831:                                continue;
        !           832:                } else {
        !           833:                        if (laddr.s_addr != INADDR_ANY)
        !           834:                                wildcard++;
        !           835:                }
        !           836:                if (inp->inp_faddr.s_addr != INADDR_ANY) {
        !           837:                        if (faddr.s_addr == INADDR_ANY)
        !           838:                                wildcard++;
        !           839:                        else if (inp->inp_faddr.s_addr != faddr.s_addr ||
        !           840:                            inp->inp_fport != fport)
        !           841:                                continue;
        !           842:                } else {
        !           843:                        if (faddr.s_addr != INADDR_ANY)
        !           844:                                wildcard++;
        !           845:                }
        !           846:                if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
        !           847:                        continue;
        !           848:                if (wildcard < matchwild) {
        !           849:                        match = inp;
        !           850:                        matchwild = wildcard;
        !           851:                        if (matchwild == 0)
        !           852:                                break;
        !           853:                }
        !           854:        }
        !           855: #if KDEBUG
        !           856:        KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, checked,match,0,0,-1);
        !           857: #endif
        !           858:        return (match);
        !           859: }
        !           860: 
        !           861: 
        !           862: 
        !           863: 
        !           864: 
        !           865: struct inpcb *
        !           866: hash_in_pcblookup(head, faddr, fport_arg, laddr, lport_arg)
        !           867:        struct inpcb *head;
        !           868:        struct in_addr faddr, laddr;
        !           869:        u_int fport_arg, lport_arg;
        !           870: {
        !           871:        register struct inpcb *inp;
        !           872:        u_short fport = fport_arg, lport = lport_arg;
        !           873: #if KDEBUG
        !           874:        register int checked = 0;
        !           875: #endif
        !           876:        KERNEL_DEBUG(DBG_FNC_PCB_HLOOKUP | DBG_FUNC_START, 0,0,0,0,0);
        !           877: 
        !           878:        for (inp = head; inp != 0; inp = inp->hash_next) {
        !           879: #if KDEBUG
        !           880:                checked++;
        !           881: #endif
        !           882:                if (inp->inp_lport == lport && inp->inp_laddr.s_addr == laddr.s_addr &&
        !           883:                    inp->inp_faddr.s_addr == faddr.s_addr && inp->inp_fport == fport)
        !           884:                        break;
        !           885:        }
        !           886: #if KDEBUG
        !           887:        KERNEL_DEBUG(DBG_FNC_PCB_HLOOKUP | DBG_FUNC_END, checked,inp,0,0,0);
        !           888: #endif
        !           889:         return (inp);
        !           890: }

unix.superglobalmegacorp.com

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