Annotation of kernel/kern/mach_net.c, revision 1.1.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.