Annotation of kernel/kern/mach_net.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: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1989 Carnegie-Mellon University
        !            28:  * Copyright (c) 1988 Carnegie-Mellon University
        !            29:  * Copyright (c) 1987 Carnegie-Mellon University
        !            30:  * All rights reserved.  The CMU software License Agreement specifies
        !            31:  * the terms and conditions for use and redistribution.
        !            32:  */
        !            33: /* 
        !            34:  * HISTORY
        !            35:  * Revision 1.1.1.1  1997/09/30 02:44:31  wsanchez
        !            36:  * Import of kernel from umeshv/kernel
        !            37:  *
        !            38:  *  1-Mar-90  Gregg Kellogg (gk) at NeXT
        !            39:  *     NeXT:   Don't make the mach_net_kmsg_zone quite so big.
        !            40:  *     Turn off optimization around netipc_listen().
        !            41:  *
        !            42:  * Revision 2.11  89/02/25  18:05:43  gm0w
        !            43:  *     Changes for cleanup.
        !            44:  * 
        !            45:  * Revision 2.10  89/01/15  16:24:27  rpd
        !            46:  *     Use decl_simple_lock_data.
        !            47:  *     [89/01/15  15:02:07  rpd]
        !            48:  * 
        !            49:  * Revision 2.8  88/10/11  10:19:58  rpd
        !            50:  *     Removed SEND_KERNEL from the msg_queue operation.
        !            51:  *     Removed redundant log messages.
        !            52:  *     [88/10/09  08:46:23  rpd]
        !            53:  *     
        !            54:  *     Changed "struct KMsg" to "struct kern_msg".
        !            55:  *     Removed redundant "#if MACH_NET/#endif" wrapper.
        !            56:  *     [88/10/04  07:07:58  rpd]
        !            57:  * 
        !            58:  * Revision 2.7  88/10/01  21:57:33  rpd
        !            59:  *     Changed msg_remote_port to msg_local_port, because that is
        !            60:  *     the destination port of a copied-in message now.
        !            61:  *     [88/10/01  21:30:34  rpd]
        !            62:  * 
        !            63:  * Revision 2.6  88/08/24  01:51:51  mwyoung
        !            64:  *     Corrected include file references.
        !            65:  *     [88/08/22  22:06:23  mwyoung]
        !            66:  * 
        !            67:  * 22-Aug-88  Michael Young (mwyoung) at Carnegie-Mellon University
        !            68:  *     Removed ancient history.
        !            69:  *
        !            70:  * 15-Aug-88  Avadis Tevanian (avie) at NeXT
        !            71:  *     Changed number of allocated messages for mach_net from 8 to 4.
        !            72:  *
        !            73:  * Revision 2.5  88/08/06  18:22:03  rpd
        !            74:  * Eliminated use of kern/mach_ipc_defs.h.
        !            75:  * 
        !            76:  * Revision 2.4  88/07/20  16:38:58  rpd
        !            77:  * When queueing a message, bump current and ip_data_grams
        !            78:  * ipc_statistics counters.
        !            79:  * 
        !            80:  * 18-May-88  Daniel Julin (dpj) at Carnegie-Mellon University
        !            81:  *     Added another access check for mach_net_server. Only privileged
        !            82:  *     users should be allowed to send packets this way, because there
        !            83:  *     is little or no check against false source addresses.
        !            84:  *
        !            85:  *  6-May-88  Daniel Julin (dpj) at Carnegie-Mellon University
        !            86:  *     Added an access check for netipc_listen and
        !            87:  *     (from code by rds).
        !            88:  *
        !            89:  *  3-Apr-88  Michael Young (mwyoung) at Carnegie-Mellon University
        !            90:  *     De-linted.
        !            91:  *
        !            92:  *  1-Feb-88  David Golub (dbg) at Carnegie-Mellon University
        !            93:  *     Receive_ip_datagram is called at splnet.  It must drop priority
        !            94:  *     to spl0 to call the IPC routines, and raise back to splnet when
        !            95:  *     it exits.  NOTE that this works ONLY if this is always called
        !            96:  *     from the netisr thread - it will garble interrupt handling
        !            97:  *     horribly.
        !            98:  *
        !            99:  *  8-Dec-87  David Black (dlb) at Carnegie-Mellon University
        !           100:  *     Removed spl check code; interrupt disabling is no longer needed
        !           101:  *     because all network code runs in a thread context.  Removed TT
        !           102:  *     conditionals.
        !           103:  *
        !           104:  *  9-Nov-87  David Golub (dbg) at Carnegie-Mellon University
        !           105:  *     Since network routines now run in a thread context, use
        !           106:  *     msg_queue to send message.
        !           107:  *
        !           108:  */
        !           109:  
        !           110: #import <mach_net.h>
        !           111: 
        !           112: #import <sys/param.h>
        !           113: #import <sys/systm.h>
        !           114: #import <sys/mbuf.h>
        !           115: #import <sys/socket.h>
        !           116: 
        !           117: #import <net/if.h>
        !           118: #import <net/route.h>
        !           119: 
        !           120: #import <netinet/in.h>
        !           121: #import <netinet/in_systm.h>
        !           122: #import <netinet/ip.h>
        !           123: #import <netinet/in_pcb.h>
        !           124: 
        !           125: #import <netinet/ip.h>
        !           126: #import <netinet/ip_var.h>
        !           127: 
        !           128: #import <mach/mach_types.h>
        !           129: #import <mach/mig_errors.h>
        !           130: 
        !           131: #import <kern/zalloc.h>
        !           132: 
        !           133: #import <sys/param.h>          /* NBPG, CLBYTES, etc. */
        !           134: 
        !           135: #import <vm/vm_kern.h> /* kernel_map */
        !           136: #import <kern/parallel.h>
        !           137: 
        !           138: #import <machine/spl.h>
        !           139: 
        !           140: #if    MACH_NET
        !           141: 
        !           142: #define IP_MSG_ID      1959
        !           143: 
        !           144: static
        !           145: void
        !           146: mach_net_output(
        !           147:     ipc_kmsg_t         kmsg
        !           148: )
        !           149: {
        !           150:        struct ip_msg {
        !           151:                mach_msg_header_t       header;
        !           152:                struct ip               ip;
        !           153:        } *ip_msg = (struct ip_msg *) &kmsg->ikm_header;
        !           154: 
        !           155:        struct mbuf             *top;
        !           156:        register struct mbuf    **mp;
        !           157:        register int            size;
        !           158:        register caddr_t        cp;
        !           159:        static struct route     cached_route = { 0 };
        !           160: 
        !           161:        if (!(current_proc()->p_ucred->cr_uid == 0))
        !           162:                return;
        !           163:                
        !           164:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
        !           165:        /*
        !           166:         *      Only accept simple messages large enough
        !           167:         *      to contain an IP header.
        !           168:         */
        !           169: 
        !           170:        if ((ip_msg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
        !           171:            (ip_msg->header.msgh_size < sizeof (struct ip_msg)))
        !           172:                return; 
        !           173: 
        !           174:        /*
        !           175:         *      Check that user has supplied a reasonable IP datagram length.
        !           176:         */
        !           177: 
        !           178:        size = ip_msg->ip.ip_len;
        !           179:        if ((size <= sizeof(struct ip)) || (size > (ip_msg->header.msgh_size - sizeof(mach_msg_header_t))))
        !           180:                return;
        !           181: 
        !           182:        /*
        !           183:         *      Remainder of this procedure must execute on master.
        !           184:         */
        !           185:        unix_master();
        !           186: 
        !           187:        /*
        !           188:         *      Copy data to mbuf chain.
        !           189:         *      This loop is similar to those in sosend() (in sys/uipc_socket.c)
        !           190:         *      and if_ubaget() (in vaxif/if_uba.c).
        !           191:         */
        !           192:        top = 0;
        !           193:        mp = &top;
        !           194:        cp = (caddr_t) &ip_msg->ip;
        !           195:        while (size > 0) {
        !           196:                register struct mbuf *m;
        !           197:                register unsigned int len;
        !           198: 
        !           199:                MGET(m, M_WAIT, MT_DATA);
        !           200:                if (m == 0) {
        !           201:                        m_freem(top);
        !           202:                        unix_release();
        !           203:                        return;
        !           204:                }
        !           205:                if (size >= NBPG/2) {   /* heuristic */
        !           206:                        MCLGET(m);
        !           207:                        if (m->m_len != MCLBYTES)
        !           208:                                m->m_len = len = MIN(MLEN, size);
        !           209:                        else
        !           210:                                m->m_len = len = MIN(MCLBYTES, size);
        !           211:                } else
        !           212:                        m->m_len = len = MIN(MLEN, size);
        !           213: 
        !           214:                bcopy(cp, mtod(m, caddr_t), len);
        !           215:                cp += len;
        !           216:                size -= len;
        !           217:                *mp = m;
        !           218:                mp = &m->m_next;
        !           219:        }
        !           220: 
        !           221:        /*
        !           222:         *      Use cached route if the destination address is the same.
        !           223:         *      Otherwise, zero the route so that ip_output() will find a new one.
        !           224:         *      The use of the cached route decreases the total time to send a datagram
        !           225:         *      by as much as 40%.
        !           226:         */
        !           227:        if (((struct sockaddr_in *) &cached_route.ro_dst)->sin_addr.s_addr
        !           228:            != ip_msg->ip.ip_dst.s_addr) {
        !           229:                if (cached_route.ro_rt)
        !           230:                        RTFREE(cached_route.ro_rt);
        !           231:                cached_route.ro_rt = 0;
        !           232:        }
        !           233: 
        !           234:        /*
        !           235:         *      Send the mbuf chain.
        !           236:         *      We use the IP_FORWARDING option because
        !           237:         *      the user supplies a complete IP header.
        !           238:         *      Deallocation of the mbuf chain is handled by ip_output().
        !           239:         */
        !           240:        if (ip_output(top, (struct mbuf *)0,
        !           241:                      &cached_route, (IP_FORWARDING|IP_ALLOWBROADCAST)) != 0) {
        !           242:                unix_release();
        !           243:                return;
        !           244:        }
        !           245:        unix_release();
        !           246:        return;
        !           247: }
        !           248: 
        !           249: boolean_t
        !           250: netipc_msg_send(
        !           251:     ipc_kmsg_t         kmsg
        !           252: )
        !           253: {
        !           254:     if (kmsg->ikm_header.msgh_id != IP_MSG_ID)
        !           255:        return (FALSE);
        !           256:        
        !           257:     mach_net_output(kmsg);
        !           258:        
        !           259:     return (TRUE);
        !           260: }
        !           261: 
        !           262: 
        !           263: /*
        !           264:  *     Data structures and associated routines
        !           265:  *     to register IPC ports for incoming datagrams.
        !           266:  *
        !           267:  *     Listeners are organized into buckets by the (IP) protocol number
        !           268:  *     for which they are listening. Within a bucket, the listeners
        !           269:  *     are linked in a list that is maintained by a move-to-front strategy.
        !           270:  *
        !           271:  *     A zero entry in any of the source or destination
        !           272:  *     fields indicates a wildcard that matches the corresponding field
        !           273:  *     in any incoming datagram.
        !           274:  *
        !           275:  *     The lock field is used for mutual exclusion when adding listeners.
        !           276:  *     Lookups do not require synchronization because the ipc_port field
        !           277:  *     (used to tell whether a listener is present) is always updated last,
        !           278:  *     in a single operation.
        !           279:  *
        !           280:  *     The routine to add and remove listeners are called by the user
        !           281:  *     via a Matchmaker interface. Remove_listener() is also called by
        !           282:  *     port_deallocate().
        !           283:  */
        !           284: 
        !           285: struct lbucket {
        !           286:        decl_simple_lock_data(, lock)
        !           287:        struct listener         *head;
        !           288: };
        !           289: 
        !           290: #define        LBHSZ   16                      /* kept small -- not many protocols */
        !           291: #define        LBHASH(protocol)        ((protocol) % LBHSZ)
        !           292: struct lbucket listeners[LBHSZ];       /* indexed by hashed protocol */
        !           293: 
        !           294: struct listener {
        !           295:        struct listener *next;
        !           296:        long            src_addr;
        !           297:        long            dst_addr;
        !           298:        unsigned short  src_port;
        !           299:        unsigned short  dst_port;
        !           300:        port_t          ipc_port;
        !           301: };
        !           302: 
        !           303: #define LISTENER_MAX   100
        !           304: #define LISTENER_CHUNK 1
        !           305: 
        !           306: zone_t listener_zone;
        !           307: 
        !           308: #define FOR_EACH_BUCKET(b)     for((b)=listeners; (b) < &listeners[LBHSZ]; (b)++)
        !           309: #define FOR_EACH_LISTENER(lp,b)        for((lp)=(b)->head; (lp) != 0; (lp)=(lp)->next)
        !           310: #define LOCK_BUCKET(b, ipl)    { ipl = splnet(); simple_lock(&(b)->lock); }
        !           311: #define UNLOCK_BUCKET(b, ipl)  { simple_unlock(&(b)->lock); splx(ipl); }
        !           312: 
        !           313: #endif
        !           314: 
        !           315: /*
        !           316:  *     Register a listener.
        !           317:  *     No checking is done to prevent conflict with existing listeners.
        !           318:  */
        !           319: /*ARGSUSED*/
        !           320: #if    m68k
        !           321: /*
        !           322:  * Don't know why this pragme is here.  My guess is an old M68K 
        !           323:  * compiler bug which has probably been fixed. -PFK
        !           324:  */
        !           325: #pragma CC_OPT_OFF
        !           326: #endif m68k
        !           327: kern_return_t  netipc_listen(server_port, _src_addr, _dst_addr,
        !           328:                              _src_port, _dst_port, _protocol, ipc_port)
        !           329:        port_t          server_port;    /* unused */
        !           330:        int             _src_addr;
        !           331:        int             _dst_addr;
        !           332:        int             _src_port;
        !           333:        int             _dst_port;
        !           334:        int             _protocol;
        !           335:        port_t          ipc_port;
        !           336: {
        !           337: #if    MACH_NET
        !           338:        register struct listener *lp;
        !           339:        register struct lbucket *b;
        !           340:        int ipl;
        !           341: 
        !           342:        long            src_addr = _src_addr;
        !           343:        long            dst_addr = _dst_addr;
        !           344:        unsigned short  src_port = _src_port;
        !           345:        unsigned short  dst_port = _dst_port;
        !           346:        u_char          protocol = _protocol;
        !           347: 
        !           348:        if (!(current_proc()->p_ucred->cr_uid == 0))
        !           349:                return(KERN_NO_ACCESS);
        !           350: 
        !           351:        if (ipc_port == PORT_NULL)
        !           352:                return(KERN_INVALID_ARGUMENT);
        !           353:        lp = (struct listener *) zalloc(listener_zone);
        !           354:        lp->src_addr = src_addr;
        !           355:        lp->src_port = src_port;
        !           356:        lp->dst_addr = dst_addr;
        !           357:        lp->dst_port = dst_port;
        !           358:        ipc_port_reference((ipc_port_t)lp->ipc_port = ipc_port);
        !           359:        b = &listeners[LBHASH(protocol)];
        !           360:        LOCK_BUCKET(b, ipl);
        !           361:        lp->next = b->head;
        !           362:        b->head = lp;
        !           363:        UNLOCK_BUCKET(b, ipl);
        !           364:        ipc_kobject_set((ipc_port_t)ipc_port, 0, IKOT_NETIPC);
        !           365:        return(KERN_SUCCESS);
        !           366: #else
        !           367:        return (KERN_FAILURE);
        !           368: #endif
        !           369: }
        !           370: #if    m68k
        !           371: /*
        !           372:  * See comment at beginning of routine.
        !           373:  */
        !           374: #pragma CC_OPT_RESTORE
        !           375: #endif m68k
        !           376: 
        !           377: /*
        !           378:  *     Remove all listeners with the specified port.
        !           379:  */
        !           380: /*ARGSUSED*/
        !           381: kern_return_t  netipc_ignore(server_port, ipc_port)
        !           382:        port_t          server_port;    /* unused */
        !           383:        register port_t ipc_port;
        !           384: {
        !           385: #if    MACH_NET
        !           386:        register struct lbucket *b;
        !           387:        register struct listener *prev, *lp;
        !           388:        kern_return_t result = KERN_FAILURE;
        !           389:        int ipl;
        !           390: 
        !           391:        if (ipc_port == PORT_NULL)
        !           392:                return KERN_INVALID_ARGUMENT;
        !           393:        FOR_EACH_BUCKET (b) {
        !           394:                LOCK_BUCKET(b, ipl);
        !           395:                prev = b->head;
        !           396:                FOR_EACH_LISTENER (lp, b) {
        !           397:                        if (lp->ipc_port == ipc_port) {
        !           398:                                result = KERN_SUCCESS;
        !           399:                                if (lp == b->head) {
        !           400:                                        b->head = lp->next;
        !           401:                                        zfree(listener_zone, (vm_offset_t) lp);
        !           402:                                        if ((prev = lp = b->head) == 0)
        !           403:                                                break;
        !           404:                                } else {
        !           405:                                        prev->next = lp->next;
        !           406:                                        zfree(listener_zone, (vm_offset_t) lp);
        !           407:                                        lp = prev;
        !           408:                                }
        !           409:                                ipc_port_release((ipc_port_t)ipc_port);
        !           410:                        }
        !           411:                        else {
        !           412:                                prev = lp;
        !           413:                        }
        !           414:                }
        !           415:                UNLOCK_BUCKET(b, ipl);
        !           416:        }
        !           417:        return(result);
        !           418: #else
        !           419:        return (KERN_FAILURE);
        !           420: #endif
        !           421: }
        !           422: 
        !           423: #if    MACH_NET
        !           424: /*
        !           425:  *     Find a listener for the given source, destination, and protocol.
        !           426:  */
        !           427: port_t         find_listener(src_addr, src_port, dst_addr, dst_port, protocol)
        !           428:        u_long          src_addr;
        !           429:        u_short         src_port;
        !           430:        u_long          dst_addr;
        !           431:        u_short         dst_port;
        !           432:        u_char          protocol;
        !           433: {
        !           434:        register struct lbucket *b;
        !           435:        register struct listener *prev, *lp;
        !           436: 
        !           437: #define ADDR_MATCH(lp, addr)   ((lp)->addr==INADDR_ANY || (lp)->addr==(addr))
        !           438: #define PORT_MATCH(lp, port)   ((lp)->port==0 || (lp)->port ==(port))
        !           439: 
        !           440:        b = &listeners[LBHASH(protocol)];
        !           441:        prev = b->head;
        !           442:        FOR_EACH_LISTENER(lp, b) {
        !           443:                /*
        !           444:                 *      The following tests should be ordered
        !           445:                 *      in increasing likelihood of success.
        !           446:                 */
        !           447:                if (PORT_MATCH(lp, dst_port) &&
        !           448:                    PORT_MATCH(lp, src_port) &&
        !           449:                    ADDR_MATCH(lp, src_addr) &&
        !           450:                    ADDR_MATCH(lp, dst_addr)) {
        !           451:                        if (lp != b->head) {
        !           452:                                /* move to front */
        !           453:                                prev->next = lp->next;
        !           454:                                lp->next = b->head;
        !           455:                                b->head = lp;
        !           456:                        }
        !           457:                        return(lp->ipc_port);
        !           458:                } else
        !           459:                        prev = lp;
        !           460:        }
        !           461:        return(PORT_NULL);
        !           462: }
        !           463: 
        !           464: /*
        !           465:  *     IP header plus source and destination ports.
        !           466:  *     Common to both UDP datagrams and TCP segments.
        !           467:  */
        !           468: struct ip_plus_ports {
        !           469:        struct ip       ip_header;
        !           470:        u_short         src_port;
        !           471:        u_short         dst_port;
        !           472: };
        !           473: 
        !           474: /*
        !           475:  *     Skeletal IPC message header for fast initialization.
        !           476:  */
        !           477: static mach_msg_header_t ip_msg_template;
        !           478: 
        !           479: #define MACH_NET_MSG_SIZE_MAX  2048
        !           480: zone_t mach_net_kmsg_zone;
        !           481: 
        !           482: void           mach_net_init()
        !           483: {
        !           484:        register struct lbucket *b;
        !           485:        vm_offset_t             zone_data;
        !           486:        
        !           487:        listener_zone = zinit(
        !           488:                                sizeof(struct listener),
        !           489:                                LISTENER_MAX * sizeof(struct listener),
        !           490:                                LISTENER_CHUNK * sizeof(struct listener),
        !           491:                                FALSE,
        !           492:                                "net listener zone"
        !           493:                        );
        !           494:        ip_msg_template.msgh_bits =
        !           495:                MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0) |
        !           496:                                                MACH_MSGH_BITS_OLD_FORMAT;
        !           497:        ip_msg_template.msgh_size = MACH_NET_MSG_SIZE_MAX - IKM_OVERHEAD;
        !           498:        ip_msg_template.msgh_remote_port = MACH_PORT_NULL;
        !           499:        ip_msg_template.msgh_local_port = MACH_PORT_NULL;
        !           500:        ip_msg_template.msgh_id = IP_MSG_ID;
        !           501:        FOR_EACH_BUCKET (b) {
        !           502:                simple_lock_init(&b->lock);
        !           503:        }
        !           504: 
        !           505:        /*
        !           506:         * Create and allocate some space for our private kmsg zone.
        !           507:         */
        !           508:        mach_net_kmsg_zone = zinit(MACH_NET_MSG_SIZE_MAX, 4 * MACH_NET_MSG_SIZE_MAX,
        !           509:                                MACH_NET_MSG_SIZE_MAX, FALSE, "mach_net messages");
        !           510:        zchange(mach_net_kmsg_zone, FALSE, FALSE, FALSE, FALSE);
        !           511:        (void) kmem_alloc_wired(kernel_map,
        !           512:                                        &zone_data, 4 * MACH_NET_MSG_SIZE_MAX);
        !           513:        zcram(mach_net_kmsg_zone, zone_data,
        !           514:                                4 * MACH_NET_MSG_SIZE_MAX);
        !           515: }
        !           516: 
        !           517: void
        !           518: netipc_msg_release(
        !           519:     ipc_kmsg_t         kmsg
        !           520: )
        !           521: {
        !           522:        zfree(mach_net_kmsg_zone, kmsg);
        !           523: }
        !           524: 
        !           525: /*
        !           526:  *     This routine is called from ipintr() (in netinet/ip_input.c)
        !           527:  *     to filter incoming datagrams.
        !           528:  *     Returns TRUE if a listener was found (or the packet was dropped),
        !           529:  *     FALSE if the datagram should be passed on to socket code.
        !           530:  *
        !           531:  *     This routine is always called at splnet, and must return that way.
        !           532:  *     However, it must drop interrupt level to spl0 to use any of the MACH_IPC
        !           533:  *     routines (which do not block interrupts).
        !           534:  */
        !           535: boolean_t      receive_ip_datagram(mp)
        !           536:        struct mbuf **mp;
        !           537: {
        !           538:        register struct mbuf            *m = *mp;
        !           539:        register struct ip_plus_ports   *ipp;
        !           540:        port_t                          port;
        !           541:        ipc_kmsg_t                      kmsg;
        !           542:        register caddr_t                cp;
        !           543:        int                             space;
        !           544: 
        !           545:        /*
        !           546:         *      Get IP header and ports (for UDP or TCP) together in first mbuf.
        !           547:         *      Note: IP leaves IP header in first mbuf.
        !           548:         */
        !           549:        ipp = mtod(m, struct ip_plus_ports *);
        !           550:        if (ipp->ip_header.ip_hl > (sizeof (struct ip) >> 2))
        !           551:                ip_stripoptions(&ipp->ip_header, (struct mbuf *)0);
        !           552:        if (m->m_off > MMAXOFF || m->m_len < sizeof(struct ip_plus_ports)) {
        !           553:                if ((*mp = m = m_pullup(m, sizeof(struct ip_plus_ports))) == 0)
        !           554:                        return(TRUE);
        !           555:                ipp = mtod(m, struct ip_plus_ports *);
        !           556:        }
        !           557: 
        !           558:        port = find_listener(
        !           559:                ipp->ip_header.ip_src.s_addr, ipp->src_port,    /* source addr and port */
        !           560:                ipp->ip_header.ip_dst.s_addr, ipp->dst_port,    /* dest addr and port */
        !           561:                ipp->ip_header.ip_p);                   /* protocol */
        !           562: 
        !           563:        if (port == PORT_NULL) {
        !           564:                /*
        !           565:                 *      No one is listening for this datagram.
        !           566:                 *      Pass it on to the socket code.
        !           567:                 */
        !           568:                return(FALSE);
        !           569:        }
        !           570: 
        !           571:        /*
        !           572:         *      Drop interrupt level to use MACH_IPC.
        !           573:         */
        !           574:        (void) spl0();
        !           575: 
        !           576:        if ((kmsg = (ipc_kmsg_t) zget(mach_net_kmsg_zone)) == IKM_NULL) {
        !           577:                /*
        !           578:                 *      Could not get a buffer - drop the datagram on the floor.
        !           579:                printf("receive_ip_datagram: kern_msg_allocate returns null.\n");
        !           580:                 */
        !           581:                m_freem(m);
        !           582: 
        !           583:                /*
        !           584:                 *      Raise interrupt level to return.
        !           585:                 */
        !           586:                (void) splnet();
        !           587:                return(TRUE);
        !           588:        }
        !           589:        ikm_init_special(kmsg, IKM_SIZE_NETIPC);
        !           590: 
        !           591:        /*
        !           592:         *      Undo changes to IP header made by ipintr()
        !           593:         *      before we were called. Unfortunately, the
        !           594:         *      type of service field is gone for good.
        !           595:         */
        !           596:        ipp->ip_header.ip_len += (ipp->ip_header.ip_hl << 2);
        !           597:        ipp->ip_header.ip_off >>= 3;
        !           598: 
        !           599:        /*
        !           600:         *      Copy mbuf chain to kmsg buffer.
        !           601:         */
        !           602:        space = MACH_NET_MSG_SIZE_MAX - sizeof (struct ipc_kmsg);
        !           603:        cp = (caddr_t)(&kmsg->ikm_header + 1);
        !           604:        while (m && space > 0) {
        !           605:                register unsigned int len;
        !           606: 
        !           607:                len = MIN(m->m_len, space);
        !           608:                bcopy(mtod(m, caddr_t), cp, len);
        !           609:                cp += len;
        !           610:                space -= len;
        !           611:                m = m_free(m);
        !           612:        }
        !           613:        kmsg->ikm_delta = space;
        !           614:        space &= ~3;
        !           615:        kmsg->ikm_delta = space - kmsg->ikm_delta;
        !           616:        /*
        !           617:         *      Fill in message header and deliver it.
        !           618:         */
        !           619:        kmsg->ikm_header = ip_msg_template;
        !           620:        kmsg->ikm_header.msgh_size -= space;
        !           621:        kmsg->ikm_header.msgh_remote_port = port;
        !           622: 
        !           623:        ipc_port_reference((ipc_port_t)port);
        !           624:        ipc_mqueue_send_always(kmsg);
        !           625: 
        !           626:        /*
        !           627:         *      Raise interrupt level to return.
        !           628:         */
        !           629:        (void) splnet();
        !           630:        return(TRUE);
        !           631: }
        !           632: #endif

unix.superglobalmegacorp.com

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