Annotation of kernel/ipc/ipc_kmsg.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:  * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990  
        !            27:  * Open Software Foundation, Inc. 
        !            28:  *  
        !            29:  * Permission to use, copy, modify, and distribute this software and 
        !            30:  * its documentation for any purpose and without fee is hereby granted, 
        !            31:  * provided that the above copyright notice appears in all copies and 
        !            32:  * that both the copyright notice and this permission notice appear in 
        !            33:  * supporting documentation, and that the name of ("OSF") or Open Software 
        !            34:  * Foundation not be used in advertising or publicity pertaining to 
        !            35:  * distribution of the software without specific, written prior permission. 
        !            36:  *  
        !            37:  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
        !            38:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
        !            39:  * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY 
        !            40:  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
        !            41:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
        !            42:  * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING 
        !            43:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE 
        !            44:  */
        !            45: /*
        !            46:  * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
        !            47:  */
        !            48: /* 
        !            49:  * Mach Operating System
        !            50:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
        !            51:  * All Rights Reserved.
        !            52:  * 
        !            53:  * Permission to use, copy, modify and distribute this software and its
        !            54:  * documentation is hereby granted, provided that both the copyright
        !            55:  * notice and this permission notice appear in all copies of the
        !            56:  * software, derivative works or modified versions, and any portions
        !            57:  * thereof, and that both notices appear in supporting documentation.
        !            58:  * 
        !            59:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            60:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            61:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            62:  * 
        !            63:  * Carnegie Mellon requests users of this software to return to
        !            64:  * 
        !            65:  *  Software Distribution Coordinator  or  [email protected]
        !            66:  *  School of Computer Science
        !            67:  *  Carnegie Mellon University
        !            68:  *  Pittsburgh PA 15213-3890
        !            69:  * 
        !            70:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            71:  * the rights to redistribute these changes.
        !            72:  */
        !            73: /*
        !            74:  *     File:   ipc/ipc_kmsg.c
        !            75:  *     Author: Rich Draves
        !            76:  *     Date:   1989
        !            77:  *
        !            78:  *     Operations on kernel messages.
        !            79:  */
        !            80: 
        !            81: #import <mach/features.h>
        !            82: 
        !            83: #include <mach/boolean.h>
        !            84: #include <mach/kern_return.h>
        !            85: #include <mach/message.h>
        !            86: #include <mach/port.h>
        !            87: #include <kern/assert.h>
        !            88: #include <kern/kalloc.h>
        !            89: #include <vm/vm_map.h>
        !            90: #include <vm/vm_object.h>
        !            91: #include <vm/vm_kern.h>
        !            92: #include <ipc/port.h>
        !            93: #include <ipc/ipc_entry.h>
        !            94: #include <ipc/ipc_kmsg.h>
        !            95: #include <ipc/ipc_thread.h>
        !            96: #include <ipc/ipc_marequest.h>
        !            97: #include <ipc/ipc_notify.h>
        !            98: #include <ipc/ipc_object.h>
        !            99: #include <ipc/ipc_space.h>
        !           100: #include <ipc/ipc_port.h>
        !           101: #include <ipc/ipc_right.h>
        !           102: 
        !           103: #include <ipc/ipc_machdep.h>
        !           104: 
        !           105: #define MSG_OOL_SIZE_SMALL     (PAGE_SIZE >> 2)
        !           106: 
        !           107: extern int copyinmap();
        !           108: extern int copyoutmap();
        !           109: 
        !           110: #define is_misaligned(x)       \
        !           111:        ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
        !           112: #define ptr_align(x)           \
        !           113:        ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) &    \
        !           114:                        ~(sizeof(vm_offset_t)-1) )
        !           115: 
        !           116: ipc_kmsg_t ipc_kmsg_cache[NCPUS];
        !           117: 
        !           118: /*
        !           119:  * Forward declarations
        !           120:  */
        !           121: 
        !           122: void ipc_kmsg_clean(
        !           123:        ipc_kmsg_t      kmsg);
        !           124: 
        !           125: void ipc_kmsg_clean_body(
        !           126:        ipc_kmsg_t      kmsg,
        !           127:        int             number);
        !           128: 
        !           129: void ipc_kmsg_clean_partial(
        !           130:        ipc_kmsg_t              kmsg,
        !           131:        mach_msg_type_number_t  number,
        !           132:        vm_offset_t             paddr,
        !           133:        vm_size_t               length);
        !           134: 
        !           135: mach_msg_return_t ipc_kmsg_copyout_body(
        !           136:        ipc_kmsg_t              kmsg,
        !           137:        ipc_space_t             space,
        !           138:        vm_map_t                map,
        !           139:        ipc_kmsg_t              list);
        !           140: 
        !           141: mach_msg_return_t ipc_kmsg_copyin_body(
        !           142:        ipc_kmsg_t              kmsg,
        !           143:        ipc_space_t             space,
        !           144:        vm_map_t                map);
        !           145: 
        !           146: /*
        !           147:  *     Routine:        ipc_kmsg_enqueue
        !           148:  *     Purpose:
        !           149:  *             Enqueue a kmsg.
        !           150:  */
        !           151: 
        !           152: void
        !           153: ipc_kmsg_enqueue(
        !           154:        ipc_kmsg_queue_t        queue,
        !           155:        ipc_kmsg_t              kmsg)
        !           156: {
        !           157:        ipc_kmsg_enqueue_macro(queue, kmsg);
        !           158: }
        !           159: 
        !           160: /*
        !           161:  *     Routine:        ipc_kmsg_dequeue
        !           162:  *     Purpose:
        !           163:  *             Dequeue and return a kmsg.
        !           164:  */
        !           165: 
        !           166: ipc_kmsg_t
        !           167: ipc_kmsg_dequeue(
        !           168:        ipc_kmsg_queue_t        queue)
        !           169: {
        !           170:        ipc_kmsg_t first;
        !           171: 
        !           172:        first = ipc_kmsg_queue_first(queue);
        !           173: 
        !           174:        if (first != IKM_NULL)
        !           175:                ipc_kmsg_rmqueue_first_macro(queue, first);
        !           176: 
        !           177:        return first;
        !           178: }
        !           179: 
        !           180: /*
        !           181:  *     Routine:        ipc_kmsg_rmqueue
        !           182:  *     Purpose:
        !           183:  *             Pull a kmsg out of a queue.
        !           184:  */
        !           185: 
        !           186: void
        !           187: ipc_kmsg_rmqueue(
        !           188:        ipc_kmsg_queue_t        queue,
        !           189:        ipc_kmsg_t              kmsg)
        !           190: {
        !           191:        ipc_kmsg_t next, prev;
        !           192: 
        !           193:        assert(queue->ikmq_base != IKM_NULL);
        !           194: 
        !           195:        next = kmsg->ikm_next;
        !           196:        prev = kmsg->ikm_prev;
        !           197: 
        !           198:        if (next == kmsg) {
        !           199:                assert(prev == kmsg);
        !           200:                assert(queue->ikmq_base == kmsg);
        !           201: 
        !           202:                queue->ikmq_base = IKM_NULL;
        !           203:        } else {
        !           204:                if (queue->ikmq_base == kmsg)
        !           205:                        queue->ikmq_base = next;
        !           206: 
        !           207:                next->ikm_prev = prev;
        !           208:                prev->ikm_next = next;
        !           209:        }
        !           210: }
        !           211: 
        !           212: /*
        !           213:  *     Routine:        ipc_kmsg_queue_next
        !           214:  *     Purpose:
        !           215:  *             Return the kmsg following the given kmsg.
        !           216:  *             (Or IKM_NULL if it is the last one in the queue.)
        !           217:  */
        !           218: 
        !           219: ipc_kmsg_t
        !           220: ipc_kmsg_queue_next(
        !           221:        ipc_kmsg_queue_t        queue,
        !           222:        ipc_kmsg_t              kmsg)
        !           223: {
        !           224:        ipc_kmsg_t next;
        !           225: 
        !           226:        assert(queue->ikmq_base != IKM_NULL);
        !           227: 
        !           228:        next = kmsg->ikm_next;
        !           229:        if (queue->ikmq_base == next)
        !           230:                next = IKM_NULL;
        !           231: 
        !           232:        return next;
        !           233: }
        !           234: 
        !           235: /*
        !           236:  *     Routine:        ipc_kmsg_destroy
        !           237:  *     Purpose:
        !           238:  *             Destroys a kernel message.  Releases all rights,
        !           239:  *             references, and memory held by the message.
        !           240:  *             Frees the message.
        !           241:  *     Conditions:
        !           242:  *             No locks held.
        !           243:  */
        !           244: 
        !           245: void
        !           246: ipc_kmsg_destroy(
        !           247:        ipc_kmsg_t      kmsg)
        !           248: {
        !           249:        ipc_kmsg_queue_t queue;
        !           250:        boolean_t empty;
        !           251: 
        !           252:        /*
        !           253:         *      ipc_kmsg_clean can cause more messages to be destroyed.
        !           254:         *      Curtail recursion by queueing messages.  If a message
        !           255:         *      is already queued, then this is a recursive call.
        !           256:         */
        !           257: 
        !           258:        queue = &current_thread()->ith_messages;
        !           259:        empty = ipc_kmsg_queue_empty(queue);
        !           260:        ipc_kmsg_enqueue(queue, kmsg);
        !           261: 
        !           262:        if (empty) {
        !           263:                /* must leave kmsg in queue while cleaning it */
        !           264: 
        !           265:                while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
        !           266:                        ipc_kmsg_clean(kmsg);
        !           267:                        ipc_kmsg_rmqueue(queue, kmsg);
        !           268:                        ikm_free(kmsg);
        !           269:                }
        !           270:        }
        !           271: }
        !           272: 
        !           273: /*
        !           274:  *     Routine:        ipc_kmsg_clean_body
        !           275:  *     Purpose:
        !           276:  *             Cleans the body of a kernel message.
        !           277:  *             Releases all rights, references, and memory.
        !           278:  *
        !           279:  *     Conditions:
        !           280:  *             No locks held.
        !           281:  */
        !           282: 
        !           283: void
        !           284: ipc_kmsg_clean_body(
        !           285:        ipc_kmsg_t      kmsg,
        !           286:        int             number)
        !           287: {
        !           288:     mach_msg_descriptor_t      *saddr, *eaddr;
        !           289: 
        !           290:     if ( number == 0 )
        !           291:        return;
        !           292: 
        !           293:     saddr = (mach_msg_descriptor_t *) 
        !           294:                        ((mach_msg_base_t *) &kmsg->ikm_header + 1);
        !           295:     eaddr = saddr + number;
        !           296: 
        !           297:     for ( ; saddr < eaddr; saddr++ ) {
        !           298:        
        !           299:        switch (saddr->type.type) {
        !           300:            
        !           301:            case MACH_MSG_PORT_DESCRIPTOR: {
        !           302:                mach_msg_port_descriptor_t *dsc;
        !           303: 
        !           304:                dsc = &saddr->port;
        !           305: 
        !           306:                /* 
        !           307:                 * Destroy port rights carried in the message 
        !           308:                 */
        !           309:                if (!IO_VALID((ipc_object_t) dsc->name))
        !           310:                    continue;
        !           311:                ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
        !           312:                break;
        !           313:            }
        !           314:            case MACH_MSG_OOL_DESCRIPTOR : {
        !           315:                mach_msg_ool_descriptor_t *dsc;
        !           316: 
        !           317:                dsc = &saddr->out_of_line;
        !           318:                
        !           319:                /* 
        !           320:                 * Destroy memory carried in the message 
        !           321:                 */
        !           322:                if (dsc->size == 0) {
        !           323:                    assert(dsc->address == (void *) 0);
        !           324:                } else {
        !           325: #if    MACH_OLD_VM_COPY
        !           326:                    (void) vm_deallocate(
        !           327:                                        ipc_soft_map,
        !           328:                                        (vm_offset_t)dsc->address,
        !           329:                                        (vm_size_t)dsc->size);
        !           330: #else
        !           331:                    if (dsc->copy == MACH_MSG_PHYSICAL_COPY &&
        !           332:                            dsc->size <= MSG_OOL_SIZE_SMALL) {
        !           333:                        kfree((vm_offset_t)dsc->address,
        !           334:                             (vm_size_t)dsc->size);
        !           335:                    } else {
        !           336:                        vm_map_copy_discard((vm_map_copy_t) dsc->address);
        !           337:                    }
        !           338: #endif
        !           339:                }
        !           340:                break;
        !           341:            }
        !           342:            case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
        !           343:                ipc_object_t                    *objects;
        !           344:                mach_msg_type_number_t          j;
        !           345:                mach_msg_ool_ports_descriptor_t *dsc;
        !           346: 
        !           347:                dsc = &saddr->ool_ports;
        !           348:                objects = (ipc_object_t *) dsc->address;
        !           349: 
        !           350:                if (dsc->count == 0) {
        !           351:                        break;
        !           352:                }
        !           353: 
        !           354:                assert(objects != (ipc_object_t *) 0);
        !           355:                
        !           356:                /* destroy port rights carried in the message */
        !           357:                
        !           358:                for (j = 0; j < dsc->count; j++) {
        !           359:                    ipc_object_t object = objects[j];
        !           360:                    
        !           361:                    if (!IO_VALID(object))
        !           362:                        continue;
        !           363:                    
        !           364:                    ipc_object_destroy(object, dsc->disposition);
        !           365:                }
        !           366: 
        !           367:                /* destroy memory carried in the message */
        !           368: 
        !           369:                assert(dsc->count != 0);
        !           370: 
        !           371:                kfree((vm_offset_t) dsc->address, 
        !           372:                     (vm_size_t) dsc->count * sizeof(mach_port_t));
        !           373:                break;
        !           374:            }
        !           375:            default : {
        !           376:                panic("ipc_kmsg_clean_body: bad descriptor type %d",
        !           377:                                        saddr->type.type);
        !           378:            }
        !           379:        }
        !           380:     }
        !           381: }
        !           382: 
        !           383: void
        !           384: ipc_kmsg_clean_body_compat(
        !           385:        vm_offset_t             saddr,
        !           386:        vm_offset_t             eaddr)
        !           387: {
        !           388:        while (saddr < eaddr) {
        !           389:                mach_msg_type_long_t *type;
        !           390:                mach_msg_type_name_t name;
        !           391:                mach_msg_type_size_t size;
        !           392:                mach_msg_type_number_t number;
        !           393:                boolean_t is_inline, is_port;
        !           394:                vm_size_t length;
        !           395: 
        !           396:                type = (mach_msg_type_long_t *) saddr;
        !           397:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !           398:                if (((mach_msg_type_t*)type)->msgt_longform) {
        !           399:                        /* This must be aligned */
        !           400:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           401:                            (is_misaligned(type))) {
        !           402:                                saddr = ptr_align(saddr);
        !           403:                                continue;
        !           404:                        }
        !           405:                        name = type->msgtl_name;
        !           406:                        size = type->msgtl_size;
        !           407:                        number = type->msgtl_number;
        !           408:                        saddr += sizeof(mach_msg_type_long_t);
        !           409:                } else {
        !           410:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !           411:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !           412:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !           413:                        saddr += sizeof(mach_msg_type_t);
        !           414:                }
        !           415: 
        !           416:                /* padding (ptrs and ports) ? */
        !           417:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           418:                    ((size >> 3) == sizeof(natural_t)))
        !           419:                        saddr = ptr_align(saddr);
        !           420: 
        !           421:                /* calculate length of data in bytes, rounding up */
        !           422: 
        !           423:                length = ((number * size) + 7) >> 3;
        !           424: 
        !           425:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !           426: 
        !           427:                if (is_port) {
        !           428:                        ipc_object_t *objects;
        !           429:                        mach_msg_type_number_t i;
        !           430: 
        !           431:                        if (is_inline) {
        !           432:                                objects = (ipc_object_t *) saddr;
        !           433:                                /* sanity check */
        !           434:                                while (eaddr < (vm_offset_t)&objects[number]) number--;
        !           435:                        } else {
        !           436:                                objects = (ipc_object_t *)
        !           437:                                                * (vm_offset_t *) saddr;
        !           438:                        }
        !           439: 
        !           440:                        /* destroy port rights carried in the message */
        !           441: 
        !           442:                        for (i = 0; i < number; i++) {
        !           443:                                ipc_object_t object = objects[i];
        !           444: 
        !           445:                                if (!IO_VALID(object))
        !           446:                                        continue;
        !           447: 
        !           448:                                ipc_object_destroy(object, name);
        !           449:                        }
        !           450:                }
        !           451: 
        !           452:                if (is_inline) {
        !           453:                        /* inline data sizes round up to int boundaries */
        !           454: 
        !           455:                        saddr += (length + 3) &~ 3;
        !           456:                } else {
        !           457:                        vm_offset_t data = * (vm_offset_t *) saddr;
        !           458: 
        !           459:                        /* destroy memory carried in the message */
        !           460: 
        !           461:                        if (length == 0)
        !           462:                                assert(data == 0);
        !           463:                        else if (is_port)
        !           464:                                kfree(data, length);
        !           465:                        else
        !           466: #if    MACH_OLD_VM_COPY
        !           467:                                (void) vm_deallocate(
        !           468:                                                ipc_soft_map, data, length);
        !           469: #else
        !           470:                                vm_map_copy_discard((vm_map_copy_t) data);
        !           471: #endif
        !           472: 
        !           473:                        saddr += sizeof(vm_offset_t);
        !           474:                }
        !           475:        }
        !           476: }
        !           477: 
        !           478: /*
        !           479:  *     Routine:        ipc_kmsg_clean_partial
        !           480:  *     Purpose:
        !           481:  *             Cleans a partially-acquired kernel message.
        !           482:  *     Conditions:
        !           483:  *             Nothing locked.
        !           484:  */
        !           485: 
        !           486: void
        !           487: ipc_kmsg_clean_partial(
        !           488:        ipc_kmsg_t              kmsg,
        !           489:        mach_msg_type_number_t  number,
        !           490:        vm_offset_t             paddr,
        !           491:        vm_size_t               length)
        !           492: {
        !           493:        ipc_object_t object;
        !           494:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !           495: 
        !           496:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !           497:        assert(IO_VALID(object));
        !           498:        ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
        !           499: 
        !           500:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !           501:        if (IO_VALID(object))
        !           502:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
        !           503: 
        !           504:        if (paddr) {
        !           505:                (void) vm_deallocate(ipc_kernel_copy_map, paddr, length);
        !           506:        }
        !           507: 
        !           508:        ipc_kmsg_clean_body(kmsg, number);
        !           509: }
        !           510: 
        !           511: void
        !           512: ipc_kmsg_clean_partial_compat(
        !           513:        ipc_kmsg_t              kmsg,
        !           514:        vm_offset_t             eaddr,
        !           515:        boolean_t               dolast,
        !           516:        mach_msg_type_number_t  number)
        !           517: {
        !           518:        ipc_object_t object;
        !           519:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !           520:        vm_offset_t saddr;
        !           521: 
        !           522:        assert(kmsg->ikm_marequest == IMAR_NULL);
        !           523: 
        !           524:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !           525:        assert(IO_VALID(object));
        !           526:        ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
        !           527: 
        !           528:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !           529:        if (IO_VALID(object))
        !           530:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
        !           531: 
        !           532:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !           533:        ipc_kmsg_clean_body_compat(saddr, eaddr);
        !           534: 
        !           535:        if (dolast) {
        !           536:                mach_msg_type_long_t *type;
        !           537:                mach_msg_type_name_t name;
        !           538:                mach_msg_type_size_t size;
        !           539:                mach_msg_type_number_t rnumber;
        !           540:                boolean_t is_inline, is_port;
        !           541:                vm_size_t length;
        !           542: 
        !           543: xxx:           type = (mach_msg_type_long_t *) eaddr;
        !           544:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !           545:                if (((mach_msg_type_t*)type)->msgt_longform) {
        !           546:                        /* This must be aligned */
        !           547:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           548:                            (is_misaligned(type))) {
        !           549:                                eaddr = ptr_align(eaddr);
        !           550:                                goto xxx;
        !           551:                        }
        !           552:                        name = type->msgtl_name;
        !           553:                        size = type->msgtl_size;
        !           554:                        rnumber = type->msgtl_number;
        !           555:                        eaddr += sizeof(mach_msg_type_long_t);
        !           556:                } else {
        !           557:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !           558:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !           559:                        rnumber = ((mach_msg_type_t*)type)->msgt_number;
        !           560:                        eaddr += sizeof(mach_msg_type_t);
        !           561:                }
        !           562: 
        !           563:                /* padding (ptrs and ports) ? */
        !           564:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           565:                    ((size >> 3) == sizeof(natural_t)))
        !           566:                        eaddr = ptr_align(eaddr);
        !           567: 
        !           568:                /* calculate length of data in bytes, rounding up */
        !           569: 
        !           570:                length = ((rnumber * size) + 7) >> 3;
        !           571: 
        !           572:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !           573: 
        !           574:                if (is_port) {
        !           575:                        ipc_object_t *objects;
        !           576:                        mach_msg_type_number_t i;
        !           577: 
        !           578:                        objects = (ipc_object_t *)
        !           579:                                (is_inline ? eaddr : * (vm_offset_t *) eaddr);
        !           580: 
        !           581:                        /* destroy port rights carried in the message */
        !           582: 
        !           583:                        for (i = 0; i < number; i++) {
        !           584:                                ipc_object_t obj = objects[i];
        !           585: 
        !           586:                                if (!IO_VALID(obj))
        !           587:                                        continue;
        !           588: 
        !           589:                                ipc_object_destroy(obj, name);
        !           590:                        }
        !           591:                }
        !           592: 
        !           593:                if (!is_inline) {
        !           594:                        vm_offset_t data = * (vm_offset_t *) eaddr;
        !           595: 
        !           596:                        /* destroy memory carried in the message */
        !           597: 
        !           598:                        if (length == 0)
        !           599:                                assert(data == 0);
        !           600:                        else if (is_port)
        !           601:                                kfree(data, length);
        !           602:                        else
        !           603: #if    MACH_OLD_VM_COPY
        !           604:                                (void) vm_deallocate(
        !           605:                                                ipc_soft_map, data, length);
        !           606: #else
        !           607:                                vm_map_copy_discard((vm_map_copy_t) data);
        !           608: #endif
        !           609:                }
        !           610:        }
        !           611: }
        !           612: 
        !           613: /*
        !           614:  *     Routine:        ipc_kmsg_clean
        !           615:  *     Purpose:
        !           616:  *             Cleans a kernel message.  Releases all rights,
        !           617:  *             references, and memory held by the message.
        !           618:  *     Conditions:
        !           619:  *             No locks held.
        !           620:  */
        !           621: 
        !           622: void
        !           623: ipc_kmsg_clean(
        !           624:        ipc_kmsg_t      kmsg)
        !           625: {
        !           626:        ipc_marequest_t marequest;
        !           627:        ipc_object_t object;
        !           628:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !           629: 
        !           630:        marequest = kmsg->ikm_marequest;
        !           631:        if (marequest != IMAR_NULL)
        !           632:                ipc_marequest_destroy(marequest);
        !           633: 
        !           634:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !           635:        if (IO_VALID(object))
        !           636:                ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
        !           637: 
        !           638:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !           639:        if (IO_VALID(object))
        !           640:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
        !           641: 
        !           642:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !           643:            if (mbits & MACH_MSGH_BITS_OLD_FORMAT) {
        !           644:                vm_offset_t saddr, eaddr;
        !           645: 
        !           646:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !           647:                eaddr = (vm_offset_t) &kmsg->ikm_header +
        !           648:                                kmsg->ikm_header.msgh_size;
        !           649: 
        !           650:                ipc_kmsg_clean_body_compat(saddr, eaddr);
        !           651:            }
        !           652:            else {
        !           653:                mach_msg_body_t *body;
        !           654: 
        !           655:                body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
        !           656:                ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count);
        !           657:            }
        !           658:        }
        !           659: }
        !           660: 
        !           661: /*
        !           662:  *     Routine:        ipc_kmsg_free
        !           663:  *     Purpose:
        !           664:  *             Free a kernel message buffer.
        !           665:  *     Conditions:
        !           666:  *             Nothing locked.
        !           667:  */
        !           668: 
        !           669: void
        !           670: ipc_kmsg_free(
        !           671:        ipc_kmsg_t      kmsg)
        !           672: {
        !           673:        vm_size_t size = kmsg->ikm_size;
        !           674: 
        !           675:        switch (size) {
        !           676:            case IKM_SIZE_NETWORK:
        !           677:                /* return it to the network code */
        !           678:                break;
        !           679: 
        !           680: #if    DRIVERKIT
        !           681:            case IKM_SIZE_DEVICE:
        !           682:                KernDeviceInterruptMsgRelease(kmsg);
        !           683:                break;
        !           684: #endif
        !           685: 
        !           686: #if    MACH_NET                
        !           687:            case IKM_SIZE_NETIPC:
        !           688:                netipc_msg_release(kmsg);
        !           689:                break;
        !           690: #endif
        !           691: 
        !           692:            default:
        !           693:                kfree((vm_offset_t) kmsg, size);
        !           694:                break;
        !           695:        }
        !           696: }
        !           697: 
        !           698: /*
        !           699:  *     Routine:        ipc_kmsg_get
        !           700:  *     Purpose:
        !           701:  *             Allocates a kernel message buffer.
        !           702:  *             Copies a user message to the message buffer.
        !           703:  *     Conditions:
        !           704:  *             Nothing locked.
        !           705:  *     Returns:
        !           706:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
        !           707:  *             MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
        !           708:  *             MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
        !           709:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
        !           710:  *             MACH_SEND_INVALID_DATA  Couldn't copy message data.
        !           711:  */
        !           712: 
        !           713: mach_msg_return_t
        !           714: ipc_kmsg_get(
        !           715:        mach_msg_header_t       *msg,
        !           716:        mach_msg_option_t       option,
        !           717:        mach_msg_size_t         size,
        !           718:        integer_t               delta,
        !           719:        ipc_kmsg_t              *kmsgp)
        !           720: {
        !           721:        ipc_kmsg_t              kmsg;
        !           722:        mach_msg_size_t         send_size, msg_size;
        !           723: 
        !           724:        if ((size < sizeof(mach_msg_header_t)) || (size & 3))
        !           725:                return MACH_SEND_MSG_TOO_SMALL;
        !           726: 
        !           727:        /*
        !           728:         * Three different notions of message size:
        !           729:         * 1)   'size' is the value passed through the API,
        !           730:         *      which is the actual size of the message to the
        !           731:         *      sender.  In the case of the old API, this value
        !           732:         *      will have been rounded up to a 4 byte boundary,
        !           733:         *      and delta will be set to a negative value such
        !           734:         *      that (size + delta) is the original value passed
        !           735:         *      through the API.
        !           736:         * 2)   'msg_size' is the minimum sized kmsg needed to
        !           737:         *      hold the message.  This is equal to the size of
        !           738:         *      the message plus the *maximum* sized trailer which
        !           739:         *      can be generated by this kernel.  In the case of
        !           740:         *      the old API, this will be equal to 'size'.
        !           741:         * 3)   'send_size' is the actual amount of data which
        !           742:         *      will be copied from the sender.  In the case of
        !           743:         *      MACH_SEND_TRAILER, this will include a *minimum*
        !           744:         *      sized trailer in order to acquire the size and
        !           745:         *      type fields of the entire trailer.  The actual
        !           746:         *      trailer data will then be fetched using a separate
        !           747:         *      copy operation.
        !           748:         */
        !           749:        if (delta <= 0) {
        !           750:                msg_size = size;
        !           751:                send_size = size + delta;
        !           752:        }
        !           753:        else {
        !           754:                if ((delta & 3) ||
        !           755:                    delta < MACH_MSG_TRAILER_MINIMUM_SIZE ||
        !           756:                    delta > MAX_TRAILER_SIZE)
        !           757:                        return MACH_SEND_INVALID_TRAILER;
        !           758: 
        !           759:                msg_size = size + delta;
        !           760:                send_size = size + ((option & MACH_SEND_TRAILER) ?
        !           761:                                        sizeof (mach_msg_trailer_t) : 0);
        !           762:        }
        !           763: 
        !           764:        if (msg_size <= IKM_SAVED_MSG_SIZE) {
        !           765:                kmsg = ikm_cache();
        !           766:                if (kmsg != IKM_NULL) {
        !           767:                        ikm_cache() = IKM_NULL;
        !           768:                        ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
        !           769:                } else {
        !           770:                        kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
        !           771:                        if (kmsg == IKM_NULL)
        !           772:                                return MACH_SEND_NO_BUFFER;
        !           773:                        ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
        !           774:                }
        !           775:        } else {
        !           776:                kmsg = ikm_alloc(msg_size);
        !           777:                if (kmsg == IKM_NULL)
        !           778:                        return MACH_SEND_NO_BUFFER;
        !           779:                ikm_init(kmsg, msg_size);
        !           780:        }
        !           781: 
        !           782:        if (copyinmsg(
        !           783:                    (char *) msg, (char *) &kmsg->ikm_header, send_size)) {
        !           784:                ikm_free(kmsg);
        !           785:                return MACH_SEND_INVALID_DATA;
        !           786:        }
        !           787: 
        !           788:        /*
        !           789:         * Process trailers, excepting old
        !           790:         * message format.
        !           791:         */
        !           792:        if (delta > 0) {
        !           793:                if (option & MACH_SEND_TRAILER) {
        !           794:                    /*
        !           795:                     * The send operation includes the
        !           796:                     * MACH_SEND_TRAILER option.
        !           797:                     */
        !           798:                    mach_msg_trailer_t          *trailer;
        !           799:                    mach_msg_trailer_size_t     trailer_size;
        !           800: 
        !           801:                    trailer = (mach_msg_trailer_t *)
        !           802:                                ((vm_offset_t)&kmsg->ikm_header + size);
        !           803: 
        !           804:                    if (trailer->msgh_trailer_type != 0) {
        !           805:                            ikm_free(kmsg);
        !           806:                            return MACH_SEND_INVALID_TRAILER;
        !           807:                    }
        !           808: 
        !           809:                    trailer_size = trailer->msgh_trailer_size;
        !           810:                    if (trailer_size > delta || (trailer_size & 3) ||
        !           811:                        trailer_size < MACH_MSG_TRAILER_MINIMUM_SIZE ||
        !           812:                        trailer_size > MACH_MSG_TRAILER_FORMAT_0_SIZE) {
        !           813:                            ikm_free(kmsg);
        !           814:                            return MACH_SEND_INVALID_TRAILER;
        !           815:                    }
        !           816: 
        !           817:                    if (trailer_size > sizeof (*trailer) &&
        !           818:                            copyinmsg(
        !           819:                                (char *)((vm_offset_t)msg + size +
        !           820:                                                        sizeof (*trailer)),
        !           821:                                (char *)((vm_offset_t)trailer +
        !           822:                                                        sizeof (*trailer)),
        !           823:                                trailer_size - sizeof (*trailer))) {
        !           824:                            ikm_free(kmsg);
        !           825:                            return MACH_SEND_INVALID_TRAILER;
        !           826:                    }
        !           827: 
        !           828:                    delta = trailer_size;
        !           829:                }
        !           830:                else
        !           831:                    delta = 0;
        !           832:        }
        !           833: 
        !           834:        kmsg->ikm_delta = delta;
        !           835:        kmsg->ikm_header.msgh_size = size;
        !           836: 
        !           837:        *kmsgp = kmsg;
        !           838:        return MACH_MSG_SUCCESS;
        !           839: }
        !           840: 
        !           841: /*
        !           842:  *     Routine:        ipc_kmsg_get_from_kernel
        !           843:  *     Purpose:
        !           844:  *             Allocates a kernel message buffer.
        !           845:  *             Copies a kernel message to the message buffer.
        !           846:  *             Only resource errors are allowed.
        !           847:  *     Conditions:
        !           848:  *             Nothing locked.
        !           849:  *     Returns:
        !           850:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
        !           851:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
        !           852:  */
        !           853: 
        !           854: extern mach_msg_return_t
        !           855: ipc_kmsg_get_from_kernel(
        !           856:        mach_msg_header_t       *msg,
        !           857:        mach_msg_option_t       option,
        !           858:        mach_msg_size_t         size,
        !           859:        integer_t               delta,
        !           860:        ipc_kmsg_t              *kmsgp)
        !           861: {
        !           862:        ipc_kmsg_t              kmsg;
        !           863:        mach_msg_size_t         send_size, msg_size;
        !           864: 
        !           865:        assert(size >= sizeof(mach_msg_header_t));
        !           866:        assert((size & 3) == 0 && (delta <= 0));
        !           867: 
        !           868:        if (delta <= 0) {
        !           869:                msg_size = size;
        !           870:                send_size = size + delta;
        !           871:        }
        !           872:        else {
        !           873:                if ((delta & 3) ||
        !           874:                    delta < MACH_MSG_TRAILER_MINIMUM_SIZE ||
        !           875:                    delta > MAX_TRAILER_SIZE)
        !           876:                        return MACH_SEND_INVALID_TRAILER;
        !           877: 
        !           878:                msg_size = size + delta;
        !           879:                send_size = size + ((option & MACH_SEND_TRAILER) ?
        !           880:                                        sizeof (mach_msg_trailer_t) : 0);
        !           881:        }
        !           882: 
        !           883:        kmsg = ikm_alloc(msg_size);
        !           884: 
        !           885:        if (kmsg == IKM_NULL)
        !           886:                return MACH_SEND_NO_BUFFER;
        !           887:        ikm_init(kmsg, msg_size);
        !           888:        kmsg->ikm_sender = KERNEL_SECURITY_ID_VALUE;
        !           889: 
        !           890:        bcopy((char *) msg, (char *) &kmsg->ikm_header, send_size);
        !           891: 
        !           892:        /*
        !           893:         * Process trailers, excepting old
        !           894:         * message format.
        !           895:         */
        !           896:        if (delta > 0) {
        !           897:                if (option & MACH_SEND_TRAILER) {
        !           898:                    /*
        !           899:                     * The send operation includes the
        !           900:                     * MACH_SEND_TRAILER option.
        !           901:                     */
        !           902:                    mach_msg_trailer_t          *trailer;
        !           903:                    mach_msg_trailer_size_t     trailer_size;
        !           904: 
        !           905:                    trailer = (mach_msg_trailer_t *)
        !           906:                                ((vm_offset_t)&kmsg->ikm_header + size);
        !           907: 
        !           908:                    if (trailer->msgh_trailer_type != 0) {
        !           909:                            ikm_free(kmsg);
        !           910:                            return MACH_SEND_INVALID_TRAILER;
        !           911:                    }
        !           912: 
        !           913:                    trailer_size = trailer->msgh_trailer_size;
        !           914:                    if (trailer_size > delta || (trailer_size & 3) ||
        !           915:                        trailer_size < MACH_MSG_TRAILER_MINIMUM_SIZE ||
        !           916:                        trailer_size > MACH_MSG_TRAILER_FORMAT_0_SIZE) {
        !           917:                            ikm_free(kmsg);
        !           918:                            return MACH_SEND_INVALID_TRAILER;
        !           919:                    }
        !           920: 
        !           921:                    if (trailer_size > sizeof (*trailer)) {
        !           922:                            bcopy(
        !           923:                                (char *)((vm_offset_t)msg + size +
        !           924:                                                        sizeof (*trailer)),
        !           925:                                (char *)((vm_offset_t)trailer +
        !           926:                                                        sizeof (*trailer)),
        !           927:                                trailer_size - sizeof (*trailer));
        !           928:                    }
        !           929: 
        !           930:                    delta = trailer_size;
        !           931:                }
        !           932:                else
        !           933:                    delta = 0;
        !           934:        }
        !           935: 
        !           936:        kmsg->ikm_delta = delta;
        !           937:        kmsg->ikm_header.msgh_size = size;
        !           938: 
        !           939:        *kmsgp = kmsg;
        !           940:        return MACH_MSG_SUCCESS;
        !           941: }
        !           942: 
        !           943: /*
        !           944:  *     Routine:        ipc_kmsg_put
        !           945:  *     Purpose:
        !           946:  *             Copies a message buffer to a user message.
        !           947:  *             Copies only the specified number of bytes.
        !           948:  *             Frees the message buffer.
        !           949:  *     Conditions:
        !           950:  *             Nothing locked.  The message buffer must have clean
        !           951:  *             header (ikm_marequest) fields.
        !           952:  *     Returns:
        !           953:  *             MACH_MSG_SUCCESS        Copied data out of message buffer.
        !           954:  *             MACH_RCV_INVALID_DATA   Couldn't copy to user message.
        !           955:  */
        !           956: 
        !           957: mach_msg_return_t
        !           958: ipc_kmsg_put(
        !           959:        mach_msg_header_t       *msg,
        !           960:        ipc_kmsg_t              kmsg,
        !           961:        mach_msg_size_t         size)
        !           962: {
        !           963:        mach_msg_return_t mr;
        !           964: 
        !           965:        ikm_check_initialized(kmsg, kmsg->ikm_size);
        !           966: 
        !           967:        if (copyoutmsg((const char *) &kmsg->ikm_header, (char *) msg, size))
        !           968:                mr = MACH_RCV_INVALID_DATA;
        !           969:        else
        !           970:                mr = MACH_MSG_SUCCESS;
        !           971: 
        !           972:        if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
        !           973:            (ikm_cache() == IKM_NULL))
        !           974:                ikm_cache() = kmsg;
        !           975:        else
        !           976:                ikm_free(kmsg);
        !           977: 
        !           978:        return mr;
        !           979: }
        !           980: 
        !           981: /*
        !           982:  *     Routine:        ipc_kmsg_put_to_kernel
        !           983:  *     Purpose:
        !           984:  *             Copies a message buffer to a kernel message.
        !           985:  *             Frees the message buffer.
        !           986:  *             No errors allowed.
        !           987:  *     Conditions:
        !           988:  *             Nothing locked.
        !           989:  */
        !           990: 
        !           991: void
        !           992: ipc_kmsg_put_to_kernel(
        !           993:        mach_msg_header_t       *msg,
        !           994:        ipc_kmsg_t              kmsg,
        !           995:        mach_msg_size_t         size)
        !           996: {
        !           997:        bcopy((char *) &kmsg->ikm_header, (char *) msg, size);
        !           998: 
        !           999:        ikm_free(kmsg);
        !          1000: }
        !          1001: 
        !          1002: /*
        !          1003:  *     Routine:        ipc_kmsg_copyin_header
        !          1004:  *     Purpose:
        !          1005:  *             "Copy-in" port rights in the header of a message.
        !          1006:  *             Operates atomically; if it doesn't succeed the
        !          1007:  *             message header and the space are left untouched.
        !          1008:  *             If it does succeed the remote/local port fields
        !          1009:  *             contain object pointers instead of port names,
        !          1010:  *             and the bits field is updated.  The destination port
        !          1011:  *             will be a valid port pointer.
        !          1012:  *
        !          1013:  *             The notify argument implements the MACH_SEND_CANCEL option.
        !          1014:  *             If it is not MACH_PORT_NULL, it should name a receive right.
        !          1015:  *             If the processing of the destination port would generate
        !          1016:  *             a port-deleted notification (because the right for the
        !          1017:  *             destination port is destroyed and it had a request for
        !          1018:  *             a dead-name notification registered), and the port-deleted
        !          1019:  *             notification would be sent to the named receive right,
        !          1020:  *             then it isn't sent and the send-once right for the notify
        !          1021:  *             port is quietly destroyed.
        !          1022:  *
        !          1023:  *             [MACH_IPC_COMPAT] There is an atomicity problem if the
        !          1024:  *             reply port is a compat entry and dies at an inopportune
        !          1025:  *             time.  This doesn't have any serious consequences
        !          1026:  *             (an observant user task might conceivably notice that
        !          1027:  *             the destination and reply ports were handled inconsistently),
        !          1028:  *             only happens in compat mode, and is extremely unlikely.
        !          1029:  *     Conditions:
        !          1030:  *             Nothing locked.
        !          1031:  *     Returns:
        !          1032:  *             MACH_MSG_SUCCESS        Successful copyin.
        !          1033:  *             MACH_SEND_INVALID_HEADER
        !          1034:  *                     Illegal value in the message header bits.
        !          1035:  *             MACH_SEND_INVALID_DEST  The space is dead.
        !          1036:  *             MACH_SEND_INVALID_NOTIFY
        !          1037:  *                     Notify is non-null and doesn't name a receive right.
        !          1038:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !          1039:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
        !          1040:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !          1041:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
        !          1042:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !          1043:  */
        !          1044: 
        !          1045: mach_msg_return_t
        !          1046: ipc_kmsg_copyin_header(
        !          1047:        mach_msg_header_t       *msg,
        !          1048:        ipc_space_t             space,
        !          1049:        mach_port_t             notify)
        !          1050: {
        !          1051:        mach_msg_bits_t mbits = msg->msgh_bits &~
        !          1052:                (MACH_MSGH_BITS_CIRCULAR | MACH_MSGH_BITS_OLD_FORMAT);
        !          1053:        mach_port_t dest_name = msg->msgh_remote_port;
        !          1054:        mach_port_t reply_name = msg->msgh_local_port;
        !          1055:        kern_return_t kr;
        !          1056: 
        !          1057:        /* first check for common cases */
        !          1058: 
        !          1059:        if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
        !          1060:            case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): {
        !          1061:                ipc_entry_t entry;
        !          1062:                ipc_entry_bits_t bits;
        !          1063:                ipc_port_t dest_port;
        !          1064: 
        !          1065:                /* sending an asynchronous message */
        !          1066: 
        !          1067:                if (reply_name != MACH_PORT_NULL)
        !          1068:                        break;
        !          1069: 
        !          1070:                is_read_lock(space);
        !          1071:                if (!space->is_active)
        !          1072:                        goto abort_async;
        !          1073: 
        !          1074:                /* optimized ipc_entry_lookup */
        !          1075: 
        !          1076:            {
        !          1077:                mach_port_index_t index = MACH_PORT_INDEX(dest_name);
        !          1078:                mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
        !          1079: 
        !          1080:                if (index >= space->is_table_size)
        !          1081:                        goto abort_async;
        !          1082: 
        !          1083:                entry = &space->is_table[index];
        !          1084:                bits = entry->ie_bits;
        !          1085: 
        !          1086:                /* check generation number and type bit */
        !          1087: 
        !          1088:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
        !          1089:                    (gen | MACH_PORT_TYPE_SEND))
        !          1090:                        goto abort_async;
        !          1091:            }
        !          1092: 
        !          1093:                /* optimized ipc_right_copyin */
        !          1094: 
        !          1095:                assert(IE_BITS_UREFS(bits) > 0);
        !          1096: 
        !          1097:                dest_port = (ipc_port_t) entry->ie_object;
        !          1098:                assert(dest_port != IP_NULL);
        !          1099: 
        !          1100:                ip_lock(dest_port);
        !          1101:                /* can unlock space now without compromising atomicity */
        !          1102:                is_read_unlock(space);
        !          1103: 
        !          1104:                if (!ip_active(dest_port)) {
        !          1105:                        ip_unlock(dest_port);
        !          1106:                        break;
        !          1107:                }
        !          1108: 
        !          1109:                assert(dest_port->ip_srights > 0);
        !          1110:                dest_port->ip_srights++;
        !          1111:                ip_reference(dest_port);
        !          1112:                ip_unlock(dest_port);
        !          1113: 
        !          1114:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1115:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
        !          1116:                msg->msgh_remote_port = (mach_port_t) dest_port;
        !          1117:                return MACH_MSG_SUCCESS;
        !          1118: 
        !          1119:            abort_async:
        !          1120:                is_read_unlock(space);
        !          1121:                break;
        !          1122:            }
        !          1123: 
        !          1124:            case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
        !          1125:                                MACH_MSG_TYPE_MAKE_SEND_ONCE): {
        !          1126:                ipc_entry_num_t size;
        !          1127:                ipc_entry_t table;
        !          1128:                ipc_entry_t entry;
        !          1129:                ipc_entry_bits_t bits;
        !          1130:                ipc_port_t dest_port, reply_port;
        !          1131: 
        !          1132:                /* sending a request message */
        !          1133: 
        !          1134:                is_read_lock(space);
        !          1135:                if (!space->is_active)
        !          1136:                        goto abort_request;
        !          1137: 
        !          1138:                size = space->is_table_size;
        !          1139:                table = space->is_table;
        !          1140: 
        !          1141:                /* optimized ipc_entry_lookup of dest_name */
        !          1142: 
        !          1143:            {
        !          1144:                mach_port_index_t index = MACH_PORT_INDEX(dest_name);
        !          1145:                mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
        !          1146: 
        !          1147:                if (index >= size)
        !          1148:                        goto abort_request;
        !          1149: 
        !          1150:                entry = &table[index];
        !          1151:                bits = entry->ie_bits;
        !          1152: 
        !          1153:                /* check generation number and type bit */
        !          1154: 
        !          1155:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
        !          1156:                    (gen | MACH_PORT_TYPE_SEND))
        !          1157:                        goto abort_request;
        !          1158:            }
        !          1159: 
        !          1160:                assert(IE_BITS_UREFS(bits) > 0);
        !          1161: 
        !          1162:                dest_port = (ipc_port_t) entry->ie_object;
        !          1163:                assert(dest_port != IP_NULL);
        !          1164: 
        !          1165:                /* optimized ipc_entry_lookup of reply_name */
        !          1166: 
        !          1167:            {
        !          1168:                mach_port_index_t index = MACH_PORT_INDEX(reply_name);
        !          1169:                mach_port_gen_t gen = MACH_PORT_GEN(reply_name);
        !          1170: 
        !          1171:                if (index >= size)
        !          1172:                        goto abort_request;
        !          1173: 
        !          1174:                entry = &table[index];
        !          1175:                bits = entry->ie_bits;
        !          1176: 
        !          1177:                /* check generation number and type bit */
        !          1178: 
        !          1179:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) !=
        !          1180:                    (gen | MACH_PORT_TYPE_RECEIVE))
        !          1181:                        goto abort_request;
        !          1182:            }
        !          1183: 
        !          1184:                reply_port = (ipc_port_t) entry->ie_object;
        !          1185:                assert(reply_port != IP_NULL);
        !          1186: 
        !          1187:                /*
        !          1188:                 *      To do an atomic copyin, need simultaneous
        !          1189:                 *      locks on both ports and the space.  If
        !          1190:                 *      dest_port == reply_port, and simple locking is
        !          1191:                 *      enabled, then we will abort.  Otherwise it's
        !          1192:                 *      OK to unlock twice.
        !          1193:                 */
        !          1194: 
        !          1195:                ip_lock(dest_port);
        !          1196:                if (!ip_active(dest_port) || !ip_lock_try(reply_port)) {
        !          1197:                        ip_unlock(dest_port);
        !          1198:                        goto abort_request;
        !          1199:                }
        !          1200:                /* can unlock space now without compromising atomicity */
        !          1201:                is_read_unlock(space);
        !          1202: 
        !          1203:                assert(dest_port->ip_srights > 0);
        !          1204:                dest_port->ip_srights++;
        !          1205:                ip_reference(dest_port);
        !          1206:                ip_unlock(dest_port);
        !          1207: 
        !          1208:                assert(ip_active(reply_port));
        !          1209:                assert(reply_port->ip_receiver_name == reply_name);
        !          1210:                assert(reply_port->ip_receiver == space);
        !          1211: 
        !          1212:                reply_port->ip_sorights++;
        !          1213:                ip_reference(reply_port);
        !          1214:                ip_unlock(reply_port);
        !          1215: 
        !          1216:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1217:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
        !          1218:                                       MACH_MSG_TYPE_PORT_SEND_ONCE));
        !          1219:                msg->msgh_remote_port = (mach_port_t) dest_port;
        !          1220:                msg->msgh_local_port = (mach_port_t) reply_port;
        !          1221:                return MACH_MSG_SUCCESS;
        !          1222: 
        !          1223:            abort_request:
        !          1224:                is_read_unlock(space);
        !          1225:                break;
        !          1226:            }
        !          1227: 
        !          1228:            case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
        !          1229:                mach_port_index_t index;
        !          1230:                mach_port_gen_t gen;
        !          1231:                ipc_entry_t table;
        !          1232:                ipc_entry_t entry;
        !          1233:                ipc_entry_bits_t bits;
        !          1234:                ipc_port_t dest_port;
        !          1235: 
        !          1236:                /* sending a reply message */
        !          1237: 
        !          1238:                if (reply_name != MACH_PORT_NULL)
        !          1239:                        break;
        !          1240: 
        !          1241:                is_write_lock(space);
        !          1242:                if (!space->is_active)
        !          1243:                        goto abort_reply;
        !          1244: 
        !          1245:                /* optimized ipc_entry_lookup */
        !          1246: 
        !          1247:                table = space->is_table;
        !          1248: 
        !          1249:                index = MACH_PORT_INDEX(dest_name);
        !          1250:                gen = MACH_PORT_GEN(dest_name);
        !          1251: 
        !          1252:                if (index >= space->is_table_size)
        !          1253:                        goto abort_reply;
        !          1254: 
        !          1255:                entry = &table[index];
        !          1256:                bits = entry->ie_bits;
        !          1257: 
        !          1258:                /* check generation number, collision bit, and type bit */
        !          1259: 
        !          1260:                if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION|
        !          1261:                             MACH_PORT_TYPE_SEND_ONCE)) !=
        !          1262:                    (gen | MACH_PORT_TYPE_SEND_ONCE))
        !          1263:                        goto abort_reply;
        !          1264: 
        !          1265:                /* optimized ipc_right_copyin */
        !          1266: 
        !          1267:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
        !          1268:                assert(IE_BITS_UREFS(bits) == 1);
        !          1269:                assert((bits & IE_BITS_MAREQUEST) == 0);
        !          1270: 
        !          1271:                if (entry->ie_request != 0)
        !          1272:                        goto abort_reply;
        !          1273: 
        !          1274:                dest_port = (ipc_port_t) entry->ie_object;
        !          1275:                assert(dest_port != IP_NULL);
        !          1276: 
        !          1277:                ip_lock(dest_port);
        !          1278:                if (!ip_active(dest_port)) {
        !          1279:                        ip_unlock(dest_port);
        !          1280:                        goto abort_reply;
        !          1281:                }
        !          1282: 
        !          1283:                assert(dest_port->ip_sorights > 0);
        !          1284:                ip_unlock(dest_port);
        !          1285: 
        !          1286:                /* optimized ipc_entry_dealloc */
        !          1287: 
        !          1288:                entry->ie_next = table->ie_next;
        !          1289:                table->ie_next = index;
        !          1290:                entry->ie_bits = gen;
        !          1291:                entry->ie_object = IO_NULL;
        !          1292:                is_write_unlock(space);
        !          1293: 
        !          1294:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1295:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
        !          1296:                                                 0));
        !          1297:                msg->msgh_remote_port = (mach_port_t) dest_port;
        !          1298:                return MACH_MSG_SUCCESS;
        !          1299: 
        !          1300:            abort_reply:
        !          1301:                is_write_unlock(space);
        !          1302:                break;
        !          1303:            }
        !          1304: 
        !          1305:            default:
        !          1306:                /* don't bother optimizing */
        !          1307:                break;
        !          1308:        }
        !          1309: 
        !          1310:     {
        !          1311:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          1312:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          1313:        ipc_object_t dest_port, reply_port;
        !          1314:        ipc_port_t dest_soright, reply_soright;
        !          1315:        ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */
        !          1316: 
        !          1317:        if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
        !          1318:                return MACH_SEND_INVALID_HEADER;
        !          1319: 
        !          1320:        if ((reply_type == 0) ?
        !          1321:            (reply_name != MACH_PORT_NULL) :
        !          1322:            !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
        !          1323:                return MACH_SEND_INVALID_HEADER;
        !          1324: 
        !          1325:        is_write_lock(space);
        !          1326:        if (!space->is_active)
        !          1327:                goto invalid_dest;
        !          1328: 
        !          1329:        if (notify != MACH_PORT_NULL) {
        !          1330:                ipc_entry_t entry;
        !          1331: 
        !          1332:                if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
        !          1333:                    ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
        !          1334:                        is_write_unlock(space);
        !          1335:                        return MACH_SEND_INVALID_NOTIFY;
        !          1336:                }
        !          1337: 
        !          1338:                notify_port = (ipc_port_t) entry->ie_object;
        !          1339:        }
        !          1340: 
        !          1341:        if (dest_name == reply_name) {
        !          1342:                ipc_entry_t entry;
        !          1343:                mach_port_t name = dest_name;
        !          1344: 
        !          1345:                /*
        !          1346:                 *      Destination and reply ports are the same!
        !          1347:                 *      This is a little tedious to make atomic, because
        !          1348:                 *      there are 25 combinations of dest_type/reply_type.
        !          1349:                 *      However, most are easy.  If either is move-sonce,
        !          1350:                 *      then there must be an error.  If either are
        !          1351:                 *      make-send or make-sonce, then we must be looking
        !          1352:                 *      at a receive right so the port can't die.
        !          1353:                 *      The hard cases are the combinations of
        !          1354:                 *      copy-send and make-send.
        !          1355:                 */
        !          1356: 
        !          1357:                entry = ipc_entry_lookup(space, name);
        !          1358:                if (entry == IE_NULL)
        !          1359:                        goto invalid_dest;
        !          1360: 
        !          1361:                assert(reply_type != 0); /* because name not null */
        !          1362: 
        !          1363:                if (!ipc_right_copyin_check(space, name, entry, reply_type))
        !          1364:                        goto invalid_reply;
        !          1365: 
        !          1366:                if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
        !          1367:                    (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
        !          1368:                        /*
        !          1369:                         *      Why must there be an error?  To get a valid
        !          1370:                         *      destination, this entry must name a live
        !          1371:                         *      port (not a dead name or dead port).  However
        !          1372:                         *      a successful move-sonce will destroy a
        !          1373:                         *      live entry.  Therefore the other copyin,
        !          1374:                         *      whatever it is, would fail.  We've already
        !          1375:                         *      checked for reply port errors above,
        !          1376:                         *      so report a destination error.
        !          1377:                         */
        !          1378: 
        !          1379:                        goto invalid_dest;
        !          1380:                } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
        !          1381:                           (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
        !          1382:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
        !          1383:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
        !          1384:                        kr = ipc_right_copyin(space, name, entry,
        !          1385:                                              dest_type, FALSE,
        !          1386:                                              &dest_port, &dest_soright);
        !          1387:                        if (kr != KERN_SUCCESS)
        !          1388:                                goto invalid_dest;
        !          1389: 
        !          1390:                        /*
        !          1391:                         *      Either dest or reply needs a receive right.
        !          1392:                         *      We know the receive right is there, because
        !          1393:                         *      of the copyin_check and copyin calls.  Hence
        !          1394:                         *      the port is not in danger of dying.  If dest
        !          1395:                         *      used the receive right, then the right needed
        !          1396:                         *      by reply (and verified by copyin_check) will
        !          1397:                         *      still be there.
        !          1398:                         */
        !          1399: 
        !          1400:                        assert(IO_VALID(dest_port));
        !          1401:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
        !          1402:                        assert(dest_soright == IP_NULL);
        !          1403: 
        !          1404:                        kr = ipc_right_copyin(space, name, entry,
        !          1405:                                              reply_type, TRUE,
        !          1406:                                              &reply_port, &reply_soright);
        !          1407: 
        !          1408:                        assert(kr == KERN_SUCCESS);
        !          1409:                        assert(reply_port == dest_port);
        !          1410:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
        !          1411:                        assert(reply_soright == IP_NULL);
        !          1412:                } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
        !          1413:                           (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
        !          1414:                        /*
        !          1415:                         *      To make this atomic, just do one copy-send,
        !          1416:                         *      and dup the send right we get out.
        !          1417:                         */
        !          1418: 
        !          1419:                        kr = ipc_right_copyin(space, name, entry,
        !          1420:                                              dest_type, FALSE,
        !          1421:                                              &dest_port, &dest_soright);
        !          1422:                        if (kr != KERN_SUCCESS)
        !          1423:                                goto invalid_dest;
        !          1424: 
        !          1425:                        assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
        !          1426:                        assert(dest_soright == IP_NULL);
        !          1427: 
        !          1428:                        /*
        !          1429:                         *      It's OK if the port we got is dead now,
        !          1430:                         *      so reply_port is IP_DEAD, because the msg
        !          1431:                         *      won't go anywhere anyway.
        !          1432:                         */
        !          1433: 
        !          1434:                        reply_port = (ipc_object_t)
        !          1435:                                ipc_port_copy_send((ipc_port_t) dest_port);
        !          1436:                        reply_soright = IP_NULL;
        !          1437:                } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
        !          1438:                           (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
        !          1439:                        /*
        !          1440:                         *      This is an easy case.  Just use our
        !          1441:                         *      handy-dandy special-purpose copyin call
        !          1442:                         *      to get two send rights for the price of one.
        !          1443:                         */
        !          1444: 
        !          1445:                        kr = ipc_right_copyin_two(space, name, entry,
        !          1446:                                                  &dest_port, &dest_soright);
        !          1447:                        if (kr != KERN_SUCCESS)
        !          1448:                                goto invalid_dest;
        !          1449: 
        !          1450:                        /* the entry might need to be deallocated */
        !          1451: 
        !          1452:                        if (IE_BITS_TYPE(entry->ie_bits)
        !          1453:                                                == MACH_PORT_TYPE_NONE)
        !          1454:                                ipc_entry_dealloc(space, name, entry);
        !          1455: 
        !          1456:                        reply_port = dest_port;
        !          1457:                        reply_soright = IP_NULL;
        !          1458:                } else {
        !          1459:                        ipc_port_t soright;
        !          1460: 
        !          1461:                        assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
        !          1462:                                (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
        !          1463:                               ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
        !          1464:                                (reply_type == MACH_MSG_TYPE_COPY_SEND)));
        !          1465: 
        !          1466:                        /*
        !          1467:                         *      To make this atomic, just do a move-send,
        !          1468:                         *      and dup the send right we get out.
        !          1469:                         */
        !          1470: 
        !          1471:                        kr = ipc_right_copyin(space, name, entry,
        !          1472:                                              MACH_MSG_TYPE_MOVE_SEND, FALSE,
        !          1473:                                              &dest_port, &soright);
        !          1474:                        if (kr != KERN_SUCCESS)
        !          1475:                                goto invalid_dest;
        !          1476: 
        !          1477:                        /* the entry might need to be deallocated */
        !          1478: 
        !          1479:                        if (IE_BITS_TYPE(entry->ie_bits)
        !          1480:                                                == MACH_PORT_TYPE_NONE)
        !          1481:                                ipc_entry_dealloc(space, name, entry);
        !          1482: 
        !          1483:                        /*
        !          1484:                         *      It's OK if the port we got is dead now,
        !          1485:                         *      so reply_port is IP_DEAD, because the msg
        !          1486:                         *      won't go anywhere anyway.
        !          1487:                         */
        !          1488: 
        !          1489:                        reply_port = (ipc_object_t)
        !          1490:                                ipc_port_copy_send((ipc_port_t) dest_port);
        !          1491: 
        !          1492:                        if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
        !          1493:                                dest_soright = soright;
        !          1494:                                reply_soright = IP_NULL;
        !          1495:                        } else {
        !          1496:                                dest_soright = IP_NULL;
        !          1497:                                reply_soright = soright;
        !          1498:                        }
        !          1499:                }
        !          1500:        } else if (!MACH_PORT_VALID(reply_name)) {
        !          1501:                ipc_entry_t entry;
        !          1502: 
        !          1503:                /*
        !          1504:                 *      No reply port!  This is an easy case
        !          1505:                 *      to make atomic.  Just copyin the destination.
        !          1506:                 */
        !          1507: 
        !          1508:                entry = ipc_entry_lookup(space, dest_name);
        !          1509:                if (entry == IE_NULL)
        !          1510:                        goto invalid_dest;
        !          1511: 
        !          1512:                kr = ipc_right_copyin(space, dest_name, entry,
        !          1513:                                      dest_type, FALSE,
        !          1514:                                      &dest_port, &dest_soright);
        !          1515:                if (kr != KERN_SUCCESS)
        !          1516:                        goto invalid_dest;
        !          1517: 
        !          1518:                /* the entry might need to be deallocated */
        !          1519: 
        !          1520:                if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
        !          1521:                        ipc_entry_dealloc(space, dest_name, entry);
        !          1522: 
        !          1523:                reply_port = (ipc_object_t) reply_name;
        !          1524:                reply_soright = IP_NULL;
        !          1525:        } else {
        !          1526:                ipc_entry_t dest_entry, reply_entry;
        !          1527:                ipc_port_t saved_reply;
        !          1528: 
        !          1529:                /*
        !          1530:                 *      This is the tough case to make atomic.
        !          1531:                 *      The difficult problem is serializing with port death.
        !          1532:                 *      At the time we copyin dest_port, it must be alive.
        !          1533:                 *      If reply_port is alive when we copyin it, then
        !          1534:                 *      we are OK, because we serialize before the death
        !          1535:                 *      of both ports.  Assume reply_port is dead at copyin.
        !          1536:                 *      Then if dest_port dies/died after reply_port died,
        !          1537:                 *      we are OK, because we serialize between the death
        !          1538:                 *      of the two ports.  So the bad case is when dest_port
        !          1539:                 *      dies after its copyin, reply_port dies before its
        !          1540:                 *      copyin, and dest_port dies before reply_port.  Then
        !          1541:                 *      the copyins operated as if dest_port was alive
        !          1542:                 *      and reply_port was dead, which shouldn't have happened
        !          1543:                 *      because they died in the other order.
        !          1544:                 *
        !          1545:                 *      We handle the bad case by undoing the copyins
        !          1546:                 *      (which is only possible because the ports are dead)
        !          1547:                 *      and failing with MACH_SEND_INVALID_DEST, serializing
        !          1548:                 *      after the death of the ports.
        !          1549:                 *
        !          1550:                 *      Note that it is easy for a user task to tell if
        !          1551:                 *      a copyin happened before or after a port died.
        !          1552:                 *      For example, suppose both dest and reply are
        !          1553:                 *      send-once rights (types are both move-sonce) and
        !          1554:                 *      both rights have dead-name requests registered.
        !          1555:                 *      If a port dies before copyin, a dead-name notification
        !          1556:                 *      is generated and the dead name's urefs are incremented,
        !          1557:                 *      and if the copyin happens first, a port-deleted
        !          1558:                 *      notification is generated.
        !          1559:                 *
        !          1560:                 *      Note that although the entries are different,
        !          1561:                 *      dest_port and reply_port might still be the same.
        !          1562:                 */
        !          1563: 
        !          1564:                dest_entry = ipc_entry_lookup(space, dest_name);
        !          1565:                if (dest_entry == IE_NULL)
        !          1566:                        goto invalid_dest;
        !          1567: 
        !          1568:                reply_entry = ipc_entry_lookup(space, reply_name);
        !          1569:                if (reply_entry == IE_NULL)
        !          1570:                        goto invalid_reply;
        !          1571: 
        !          1572:                assert(dest_entry != reply_entry); /* names are not equal */
        !          1573:                assert(reply_type != 0); /* because reply_name not null */
        !          1574: 
        !          1575:                if (!ipc_right_copyin_check(space, reply_name, reply_entry,
        !          1576:                                            reply_type))
        !          1577:                        goto invalid_reply;
        !          1578: 
        !          1579:                kr = ipc_right_copyin(space, dest_name, dest_entry,
        !          1580:                                      dest_type, FALSE,
        !          1581:                                      &dest_port, &dest_soright);
        !          1582:                if (kr != KERN_SUCCESS)
        !          1583:                        goto invalid_dest;
        !          1584: 
        !          1585:                assert(IO_VALID(dest_port));
        !          1586: 
        !          1587:                saved_reply = (ipc_port_t) reply_entry->ie_object;
        !          1588:                /* might be IP_NULL, if this is a dead name */
        !          1589:                if (saved_reply != IP_NULL)
        !          1590:                        ipc_port_reference(saved_reply);
        !          1591: 
        !          1592:                kr = ipc_right_copyin(space, reply_name, reply_entry,
        !          1593:                                      reply_type, TRUE,
        !          1594:                                      &reply_port, &reply_soright);
        !          1595: #if    MACH_IPC_COMPAT
        !          1596:                if (kr != KERN_SUCCESS) {
        !          1597:                        assert(kr == KERN_INVALID_NAME);
        !          1598: 
        !          1599:                        /*
        !          1600:                         *      Oops.  This must have been a compat entry
        !          1601:                         *      and the port died after the check above.
        !          1602:                         *      We should back out the copyin of dest_port,
        !          1603:                         *      and report MACH_SEND_INVALID_REPLY, but
        !          1604:                         *      if dest_port is alive we can't always do that.
        !          1605:                         *      Punt and pretend we got IO_DEAD, skipping
        !          1606:                         *      further hairy atomicity problems.
        !          1607:                         */
        !          1608: 
        !          1609:                        reply_port = IO_DEAD;
        !          1610:                        reply_soright = IP_NULL;
        !          1611:                        goto skip_reply_checks;
        !          1612:                }
        !          1613: #else  MACH_IPC_COMPAT
        !          1614:                assert(kr == KERN_SUCCESS);
        !          1615: #endif MACH_IPC_COMPAT
        !          1616: 
        !          1617:                if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) {
        !          1618:                        ipc_port_t dest = (ipc_port_t) dest_port;
        !          1619:                        ipc_port_timestamp_t timestamp;
        !          1620:                        boolean_t must_undo;
        !          1621: 
        !          1622:                        /*
        !          1623:                         *      The reply port died before copyin.
        !          1624:                         *      Check if dest port died before reply.
        !          1625:                         */
        !          1626: 
        !          1627:                        ip_lock(saved_reply);
        !          1628:                        assert(!ip_active(saved_reply));
        !          1629:                        timestamp = saved_reply->ip_timestamp;
        !          1630:                        ip_unlock(saved_reply);
        !          1631: 
        !          1632:                        ip_lock(dest);
        !          1633:                        must_undo = (!ip_active(dest) &&
        !          1634:                                     IP_TIMESTAMP_ORDER(dest->ip_timestamp,
        !          1635:                                                        timestamp));
        !          1636:                        ip_unlock(dest);
        !          1637: 
        !          1638:                        if (must_undo) {
        !          1639:                                /*
        !          1640:                                 *      Our worst nightmares are realized.
        !          1641:                                 *      Both destination and reply ports
        !          1642:                                 *      are dead, but in the wrong order,
        !          1643:                                 *      so we must undo the copyins and
        !          1644:                                 *      possibly generate a dead-name notif.
        !          1645:                                 */
        !          1646: 
        !          1647:                                ipc_right_copyin_undo(
        !          1648:                                                space, dest_name, dest_entry,
        !          1649:                                                dest_type, dest_port,
        !          1650:                                                dest_soright);
        !          1651:                                /* dest_entry may be deallocated now */
        !          1652: 
        !          1653:                                ipc_right_copyin_undo(
        !          1654:                                                space, reply_name, reply_entry,
        !          1655:                                                reply_type, reply_port,
        !          1656:                                                reply_soright);
        !          1657:                                /* reply_entry may be deallocated now */
        !          1658: 
        !          1659:                                is_write_unlock(space);
        !          1660: 
        !          1661:                                if (dest_soright != IP_NULL)
        !          1662:                                        ipc_notify_dead_name(dest_soright,
        !          1663:                                                             dest_name);
        !          1664:                                assert(reply_soright == IP_NULL);
        !          1665: 
        !          1666:                                ipc_port_release(saved_reply);
        !          1667:                                return MACH_SEND_INVALID_DEST;
        !          1668:                        }
        !          1669:                }
        !          1670: 
        !          1671:                /* the entries might need to be deallocated */
        !          1672: 
        !          1673:                if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
        !          1674:                        ipc_entry_dealloc(space, reply_name, reply_entry);
        !          1675: 
        !          1676: #if    MACH_IPC_COMPAT
        !          1677:            skip_reply_checks:
        !          1678:                /*
        !          1679:                 *      We jump here if the reply entry was a compat entry
        !          1680:                 *      and the port died on us.  In this case, the copyin
        !          1681:                 *      code already deallocated reply_entry.
        !          1682:                 */
        !          1683: #endif MACH_IPC_COMPAT
        !          1684: 
        !          1685:                if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
        !          1686:                        ipc_entry_dealloc(space, dest_name, dest_entry);
        !          1687: 
        !          1688:                if (saved_reply != IP_NULL)
        !          1689:                        ipc_port_release(saved_reply);
        !          1690:        }
        !          1691: 
        !          1692:        /*
        !          1693:         *      At this point, dest_port, reply_port,
        !          1694:         *      dest_soright, reply_soright are all initialized.
        !          1695:         *      Any defunct entries have been deallocated.
        !          1696:         *      The space is still write-locked, and we need to
        !          1697:         *      make the MACH_SEND_CANCEL check.  The notify_port pointer
        !          1698:         *      is still usable, because the copyin code above won't ever
        !          1699:         *      deallocate a receive right, so its entry still exists
        !          1700:         *      and holds a ref.  Note notify_port might even equal
        !          1701:         *      dest_port or reply_port.
        !          1702:         */
        !          1703: 
        !          1704:        if ((notify != MACH_PORT_NULL) &&
        !          1705:            (dest_soright == notify_port)) {
        !          1706:                ipc_port_release_sonce(dest_soright);
        !          1707:                dest_soright = IP_NULL;
        !          1708:        }
        !          1709: 
        !          1710:        is_write_unlock(space);
        !          1711: 
        !          1712:        if (dest_soright != IP_NULL)
        !          1713:                ipc_notify_port_deleted(dest_soright, dest_name);
        !          1714: 
        !          1715:        if (reply_soright != IP_NULL)
        !          1716:                ipc_notify_port_deleted(reply_soright, reply_name);
        !          1717: 
        !          1718:        dest_type = ipc_object_copyin_type(dest_type);
        !          1719:        reply_type = ipc_object_copyin_type(reply_type);
        !          1720: 
        !          1721:        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1722:                          MACH_MSGH_BITS(dest_type, reply_type));
        !          1723:        msg->msgh_remote_port = (mach_port_t) dest_port;
        !          1724:        msg->msgh_local_port = (mach_port_t) reply_port;
        !          1725:     }
        !          1726: 
        !          1727:        return MACH_MSG_SUCCESS;
        !          1728: 
        !          1729:     invalid_dest:
        !          1730:        is_write_unlock(space);
        !          1731:        return MACH_SEND_INVALID_DEST;
        !          1732: 
        !          1733:     invalid_reply:
        !          1734:        is_write_unlock(space);
        !          1735:        return MACH_SEND_INVALID_REPLY;
        !          1736: }
        !          1737: 
        !          1738: /*
        !          1739:  *     Routine:        ipc_kmsg_copyin_body
        !          1740:  *     Purpose:
        !          1741:  *             "Copy-in" port rights and out-of-line memory
        !          1742:  *             in the message body.
        !          1743:  *
        !          1744:  *             In all failure cases, the message is left holding
        !          1745:  *             no rights or memory.  However, the message buffer
        !          1746:  *             is not deallocated.  If successful, the message
        !          1747:  *             contains a valid destination port.
        !          1748:  *     Conditions:
        !          1749:  *             Nothing locked.
        !          1750:  *     Returns:
        !          1751:  *             MACH_MSG_SUCCESS        Successful copyin.
        !          1752:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
        !          1753:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
        !          1754:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
        !          1755:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
        !          1756:  */
        !          1757: 
        !          1758: mach_msg_return_t
        !          1759: ipc_kmsg_copyin_body(
        !          1760:        ipc_kmsg_t      kmsg,
        !          1761:        ipc_space_t     space,
        !          1762:        vm_map_t        map)
        !          1763: {
        !          1764:     ipc_object_t                       dest;
        !          1765:     mach_msg_body_t            *body;
        !          1766:     mach_msg_descriptor_t      *saddr, *eaddr;
        !          1767:     boolean_t                  complex;
        !          1768:     boolean_t                  use_page_lists, steal_pages;
        !          1769:     int                                i;
        !          1770:     kern_return_t              kr;
        !          1771:     vm_size_t                  space_needed = 0;
        !          1772:     vm_offset_t                        paddr = 0;
        !          1773:     mach_msg_descriptor_t      *sstart;
        !          1774:     vm_map_copy_t              copy = VM_MAP_COPY_NULL;
        !          1775:     
        !          1776:     /*
        !          1777:      * Determine if the target is a kernel port.
        !          1778:      */
        !          1779:     dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          1780:     complex = FALSE;
        !          1781:     use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
        !          1782:     steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
        !          1783:     
        !          1784:     body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
        !          1785:     saddr = (mach_msg_descriptor_t *) (body + 1);
        !          1786:     eaddr = saddr + body->msgh_descriptor_count;
        !          1787:     
        !          1788:     /* make sure the message does not ask for more msg descriptors
        !          1789:      * than the message can hold.
        !          1790:      */
        !          1791:     
        !          1792:     if (eaddr <= saddr ||
        !          1793:        eaddr > (mach_msg_descriptor_t *) (&kmsg->ikm_header + 
        !          1794:                            kmsg->ikm_header.msgh_size)) {
        !          1795:        ipc_kmsg_clean_partial(kmsg, 0, 0, 0);
        !          1796:        return MACH_SEND_MSG_TOO_SMALL;
        !          1797:     }
        !          1798:     
        !          1799:     /*
        !          1800:      * Make an initial pass to determine kernal VM space requirements for
        !          1801:      * physical copies.
        !          1802:      */
        !          1803:     for (sstart = saddr; sstart <  eaddr; sstart++) {
        !          1804: 
        !          1805:        if (sstart->type.type == MACH_MSG_OOL_DESCRIPTOR) {
        !          1806: 
        !          1807:                assert(!(sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY &&
        !          1808:                       (use_page_lists || steal_pages)));
        !          1809: 
        !          1810:                if (sstart->out_of_line.copy != MACH_MSG_PHYSICAL_COPY &&
        !          1811:                    sstart->out_of_line.copy != MACH_MSG_VIRTUAL_COPY) {
        !          1812:                    /*
        !          1813:                     * Invalid copy option
        !          1814:                     */
        !          1815:                    ipc_kmsg_clean_partial(kmsg, 0, 0, 0);
        !          1816:                    return MACH_SEND_INVALID_TYPE;
        !          1817:                }
        !          1818:                
        !          1819:                if (sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY && 
        !          1820: #if    MACH_OLD_VM_COPY
        !          1821: #else
        !          1822:                    sstart->out_of_line.size > MSG_OOL_SIZE_SMALL &&
        !          1823: #endif
        !          1824:                    !sstart->out_of_line.deallocate) {
        !          1825: 
        !          1826:                        /*
        !          1827:                         * Out-of-line memory descriptor, accumulate kernel
        !          1828:                         * memory requirements
        !          1829:                         */
        !          1830:                        space_needed += round_page(sstart->out_of_line.size);
        !          1831:                }
        !          1832:        }
        !          1833:     }
        !          1834: 
        !          1835:     /*
        !          1836:      * Allocate space in the pageable kernel ipc copy map for all the
        !          1837:      * ool data that is to be physically copied.  Map is marked wait for
        !          1838:      * space.
        !          1839:      */
        !          1840:     if (space_needed > 0) {
        !          1841:        if (vm_allocate(ipc_kernel_copy_map, &paddr, space_needed, 
        !          1842:                                TRUE) != KERN_SUCCESS) {
        !          1843:                ipc_kmsg_clean_partial(kmsg, 0, 0, 0);
        !          1844:                return MACH_MSG_VM_KERNEL;
        !          1845:        }
        !          1846:     }
        !          1847: 
        !          1848:     /* 
        !          1849:      * handle the OOL regions and port descriptors.
        !          1850:      * the check for complex messages was done earlier.
        !          1851:      */
        !          1852:     
        !          1853:     for (i = 0, sstart = saddr; sstart <  eaddr; sstart++) {
        !          1854:        
        !          1855:        switch (sstart->type.type) {
        !          1856:            
        !          1857:            case MACH_MSG_PORT_DESCRIPTOR: {
        !          1858:                mach_msg_type_name_t            name;
        !          1859:                ipc_object_t                    object;
        !          1860:                mach_msg_port_descriptor_t      *dsc;
        !          1861:                
        !          1862:                dsc = &sstart->port;
        !          1863:                
        !          1864:                /* this is really the type SEND, SEND_ONCE, etc. */
        !          1865:                name = dsc->disposition;
        !          1866:                if (!MACH_MSG_TYPE_PORT_ANY(name)) {
        !          1867:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
        !          1868:                    return MACH_SEND_INVALID_TYPE;
        !          1869:                }
        !          1870:                dsc->disposition = ipc_object_copyin_type(name);
        !          1871:                
        !          1872:                if (!MACH_PORT_VALID(dsc->name)) {
        !          1873:                    complex = TRUE;
        !          1874:                    break;
        !          1875:                }
        !          1876:                kr = ipc_object_copyin(space, dsc->name, name, &object);
        !          1877:                if (kr != KERN_SUCCESS) {
        !          1878:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
        !          1879:                    return MACH_SEND_INVALID_RIGHT;
        !          1880:                }
        !          1881:                if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          1882:                    ipc_port_check_circularity((ipc_port_t) object,
        !          1883:                                               (ipc_port_t) dest)) {
        !          1884:                    kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
        !          1885:                }
        !          1886:                dsc->name = (mach_port_t) object;
        !          1887:                complex = TRUE;
        !          1888:                break;
        !          1889:            }
        !          1890:            case MACH_MSG_OOL_DESCRIPTOR: {
        !          1891:                vm_size_t                       length;
        !          1892:                boolean_t                       dealloc;
        !          1893:                vm_offset_t                     addr;
        !          1894:                vm_offset_t                     kaddr;
        !          1895:                mach_msg_ool_descriptor_t       *dsc;
        !          1896:                
        !          1897:                dsc = &sstart->out_of_line;
        !          1898:                dealloc = dsc->deallocate;
        !          1899:                addr = (vm_offset_t) dsc->address;
        !          1900:                
        !          1901:                length = dsc->size;
        !          1902:                
        !          1903:                if (length == 0) {
        !          1904:                    dsc->address = 0;
        !          1905: #if    OLD_VM_CODE
        !          1906: #else
        !          1907:                } else if (use_page_lists) {
        !          1908:                    int options;
        !          1909: 
        !          1910:                    /*
        !          1911:                     * Use page list copy mechanism if specified. Since the
        !          1912:                     * destination is a kernel port, no RT handling is
        !          1913:                     * necessary. 
        !          1914:                     */
        !          1915:                    if (steal_pages == FALSE) {
        !          1916:                        /*
        !          1917:                         * XXX Temporary Hackaround.
        !          1918:                         * XXX Because the same page
        !          1919:                         * XXX might be in more than one
        !          1920:                         * XXX out of line region, steal
        !          1921:                         * XXX (busy) pages from previous
        !          1922:                         * XXX region so that this copyin
        !          1923:                         * XXX won't block (permanently).
        !          1924:                         */
        !          1925:                        if (copy != VM_MAP_COPY_NULL)
        !          1926:                            vm_map_copy_steal_pages(copy);
        !          1927:                    }
        !          1928: 
        !          1929:                    /*
        !          1930:                     *  Set up options for copying in page list.
        !          1931:                     *  If deallocating, steal pages to prevent
        !          1932:                     *  vm code from lazy evaluating deallocation.
        !          1933:                     */
        !          1934:                    options = VM_PROT_READ;
        !          1935:                    if (dealloc) {
        !          1936:                        options |= VM_MAP_COPYIN_OPT_SRC_DESTROY |
        !          1937:                                        VM_MAP_COPYIN_OPT_STEAL_PAGES;
        !          1938:                    }
        !          1939:                    else if (steal_pages) {
        !          1940:                        options |= VM_MAP_COPYIN_OPT_STEAL_PAGES;
        !          1941:                    }
        !          1942: 
        !          1943:                    if (vm_map_copyin_page_list(map, addr, length, options,
        !          1944:                                                &copy, FALSE)
        !          1945:                        != KERN_SUCCESS) {
        !          1946: 
        !          1947:                        ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          1948:                                                       space_needed);
        !          1949:                        return MACH_SEND_INVALID_MEMORY;
        !          1950:                    }
        !          1951: 
        !          1952:                    dsc->address = (void *) copy;
        !          1953:                    dsc->copy = MACH_MSG_PAGE_LIST_COPY_T;
        !          1954: #endif
        !          1955: #if    MACH_OLD_VM_COPY
        !          1956: #else
        !          1957:                } else if (length <= MSG_OOL_SIZE_SMALL &&
        !          1958:                           dsc->copy == MACH_MSG_PHYSICAL_COPY) {
        !          1959: 
        !          1960:                    /*
        !          1961:                     * If the data is 'small' enough, always kalloc space for
        !          1962:                     * it and copy it in.  The data will be copied out
        !          1963:                     * on the  message receive.  This is a performance
        !          1964:                     * optimization that assumes the cost of VM operations
        !          1965:                     * dominates the copyin/copyout overhead for 'small'
        !          1966:                     * regions.
        !          1967:                     * If the kernel is the message target, a consistent data
        !          1968:                     * repesentation is needed for ool data since kernel 
        !          1969:                     * functions may deallocate the ool data.  In this case
        !          1970:                     * a vm_map_copy_t is allocated along with the space for
        !          1971:                     * the data as an optimization. No RT handling is needed.
        !          1972:                     */ 
        !          1973:                    if (is_ipc_kobject(ip_kotype((ipc_port_t)dest))) {
        !          1974:                        vm_map_copy_t copy;
        !          1975: 
        !          1976:                        copy = (vm_map_copy_t) kalloc(
        !          1977:                                        sizeof(struct vm_map_copy) + length);
        !          1978:                        if (copy == VM_MAP_COPY_NULL) {
        !          1979:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          1980:                                                        space_needed);
        !          1981:                            return MACH_MSG_VM_KERNEL;
        !          1982:                        }
        !          1983:                        copy->type = VM_MAP_COPY_KERNEL_BUFFER;
        !          1984:                        if (copyin((const char *) addr, (char *) (copy + 1), 
        !          1985:                                                                length)) {
        !          1986:                            kfree((vm_offset_t) copy,
        !          1987:                                  sizeof(struct vm_map_copy) + length);
        !          1988:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          1989:                                                        space_needed);
        !          1990:                            return MACH_SEND_INVALID_MEMORY;
        !          1991:                        }       
        !          1992:                        dsc->address = (void *) copy;
        !          1993:                        dsc->copy = MACH_MSG_KALLOC_COPY_T;
        !          1994:                        copy->size = length;
        !          1995:                        copy->offset = 0;
        !          1996:                        copy->cpy_data = (vm_offset_t) (copy + 1);
        !          1997:                    } else {
        !          1998:                        if ((kaddr = kalloc(length)) == (vm_offset_t) 0) {
        !          1999:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2000:                                                        space_needed);
        !          2001:                            return MACH_MSG_VM_KERNEL;
        !          2002:                        }
        !          2003: 
        !          2004:                        if (copyin((const char *) addr, (char *) kaddr, 
        !          2005:                                                                length)) {
        !          2006:                            kfree(kaddr, length);
        !          2007:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2008:                                                        space_needed);
        !          2009:                            return MACH_SEND_INVALID_MEMORY;
        !          2010:                        }       
        !          2011:                        dsc->address = (void *) kaddr;
        !          2012:                    }
        !          2013:                    if (dealloc) {
        !          2014: #if    OLD_VM_CODE
        !          2015:                        (void) vm_deallocate(map, addr, length);
        !          2016: #else
        !          2017:                        (void) vm_map_remove(map, trunc_page(addr), 
        !          2018:                                             round_page(addr + length),
        !          2019:                                             VM_MAP_REMOVE_WAIT_FOR_KWIRE|
        !          2020:                                             VM_MAP_REMOVE_INTERRUPTIBLE);
        !          2021: #endif
        !          2022:                    }
        !          2023: #endif
        !          2024:                } else {
        !          2025:                    if ((dsc->copy == MACH_MSG_PHYSICAL_COPY) && !dealloc) {
        !          2026: 
        !          2027:                        /*
        !          2028:                         * If the request is a physical copy and the source
        !          2029:                         * is not being deallocated, then allocate space
        !          2030:                         * in the kernel's pageable ipc copy map and copy
        !          2031:                         * the data in.  The semantics guarantee that the
        !          2032:                         * data will have been physically copied before
        !          2033:                         * the send operation terminates.  Thus if the data
        !          2034:                         * is not being deallocated, we must be prepared
        !          2035:                         * to page if the region is sufficiently large.
        !          2036:                         */
        !          2037:                        if (copyin((const char *) addr, (char *) paddr, 
        !          2038:                                                                length)) {
        !          2039:                                ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2040:                                                           space_needed);
        !          2041:                                return MACH_SEND_INVALID_MEMORY;
        !          2042:                        }       
        !          2043: 
        !          2044:                        /*
        !          2045:                         * The kernel ipc copy map is marked no_zero_fill.
        !          2046:                         * If the transfer is not a page multiple, we need
        !          2047:                         * to zero fill the balance.
        !          2048:                         */
        !          2049:                        if (!page_aligned(length)) {
        !          2050:                                (void) bzero((void *) (paddr + length),
        !          2051:                                        round_page(length) - length);
        !          2052:                        }
        !          2053: #if    MACH_OLD_VM_COPY
        !          2054:                        if (vm_move(
        !          2055:                                ipc_kernel_copy_map, paddr,
        !          2056:                                ipc_soft_map, length, FALSE,
        !          2057:                                (vm_offset_t *)&copy) != KERN_SUCCESS) {
        !          2058:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2059:                                                       space_needed);
        !          2060:                            return MACH_MSG_VM_KERNEL;
        !          2061:                        }
        !          2062:                        (void) vm_deallocate(
        !          2063:                                        ipc_kernel_copy_map, paddr, length);
        !          2064: #else
        !          2065:                        if (vm_map_copyin(ipc_kernel_copy_map, paddr, length,
        !          2066:                                           TRUE, &copy) != KERN_SUCCESS) {
        !          2067:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2068:                                                       space_needed);
        !          2069:                            return MACH_MSG_VM_KERNEL;
        !          2070:                        }
        !          2071: #endif
        !          2072:                        paddr += round_page(length);
        !          2073:                        space_needed -= round_page(length);
        !          2074:                    } else {
        !          2075: 
        !          2076:                        /*
        !          2077:                         * Make a virtual copy of the of the data if requested
        !          2078:                         * or if a physical copy was requested but the source
        !          2079:                         * is being deallocated.
        !          2080:                         */
        !          2081: #if    MACH_OLD_VM_COPY
        !          2082:                        if (vm_move(
        !          2083:                                map, addr,
        !          2084:                                ipc_soft_map, length, FALSE,
        !          2085:                                (vm_offset_t *)&copy) != KERN_SUCCESS) {
        !          2086:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2087:                                                       space_needed);
        !          2088:                            return MACH_SEND_INVALID_MEMORY;
        !          2089:                        }
        !          2090:                        if (dealloc)
        !          2091:                                (void) vm_deallocate(
        !          2092:                                                map, addr, length);
        !          2093: #else
        !          2094:                        if (vm_map_copyin(map, addr, length,
        !          2095:                                           dealloc, &copy) != KERN_SUCCESS) {
        !          2096:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2097:                                                       space_needed);
        !          2098:                            return MACH_SEND_INVALID_MEMORY;
        !          2099:                        }
        !          2100: #endif
        !          2101:                    }
        !          2102:                    dsc->address = (void *) copy;
        !          2103:                }
        !          2104:                complex = TRUE;
        !          2105:                break;
        !          2106:            }
        !          2107:            case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
        !          2108:                vm_size_t                               length;
        !          2109:                vm_offset_t                             data;
        !          2110:                vm_offset_t                             addr;
        !          2111:                ipc_object_t                            *objects;
        !          2112:                int                                     j;
        !          2113:                mach_msg_type_name_t                    name;
        !          2114:                mach_msg_ool_ports_descriptor_t         *dsc;
        !          2115:                
        !          2116:                dsc = &sstart->ool_ports;
        !          2117:                addr = (vm_offset_t) dsc->address;
        !          2118: 
        !          2119:                /* calculate length of data in bytes, rounding up */
        !          2120:                length = dsc->count * sizeof(mach_port_t);
        !          2121:                
        !          2122:                if (length == 0) {
        !          2123:                    complex = TRUE;
        !          2124:                    dsc->address = (void *) 0;
        !          2125:                    break;
        !          2126:                }
        !          2127: 
        !          2128:                data = kalloc(length);
        !          2129: 
        !          2130:                if (data == 0) {
        !          2131:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
        !          2132:                    return MACH_SEND_NO_BUFFER;
        !          2133:                }
        !          2134:                
        !          2135:                if (copyinmap(map, addr, data, length)) {
        !          2136:                    kfree(data, length);
        !          2137:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
        !          2138:                    return MACH_SEND_INVALID_MEMORY;
        !          2139:                }
        !          2140:                
        !          2141:                /* this is really the type SEND, SEND_ONCE, etc. */
        !          2142:                name = dsc->disposition;
        !          2143:                if (!MACH_MSG_TYPE_PORT_ANY(name)) {
        !          2144:                    kfree(data, length);
        !          2145:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
        !          2146:                    return MACH_SEND_INVALID_TYPE;
        !          2147:                }
        !          2148:                dsc->disposition = ipc_object_copyin_type(name);
        !          2149: 
        !          2150:                if (dsc->deallocate) {
        !          2151:                        (void) vm_deallocate(map, addr, length);
        !          2152:                }
        !          2153:                
        !          2154:                dsc->address = (void *) data;
        !          2155:                objects = (ipc_object_t *) data;
        !          2156:                
        !          2157:                for ( j = 0; j < dsc->count; j++) {
        !          2158:                    mach_port_t port = (mach_port_t) objects[j];
        !          2159:                    ipc_object_t object;
        !          2160:                    
        !          2161:                    if (!MACH_PORT_VALID(port))
        !          2162:                        continue;
        !          2163:                    
        !          2164:                    kr = ipc_object_copyin(space, port, name, &object);
        !          2165: 
        !          2166:                    if (kr != KERN_SUCCESS) {
        !          2167:                        int k;
        !          2168: 
        !          2169:                        for(k = 0; k < j; k++) {
        !          2170:                            object = objects[k];
        !          2171:                            if (!MACH_PORT_VALID(port))
        !          2172:                                continue;
        !          2173:                            ipc_object_destroy(object, dsc->disposition);
        !          2174:                        }
        !          2175:                        kfree(data, length);
        !          2176:                        ipc_kmsg_clean_partial(kmsg, i, paddr, 
        !          2177:                                                   space_needed);
        !          2178:                        return MACH_SEND_INVALID_RIGHT;
        !          2179:                    }
        !          2180:                    
        !          2181:                    if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          2182:                        ipc_port_check_circularity(
        !          2183:                                                   (ipc_port_t) object,
        !          2184:                                                   (ipc_port_t) dest))
        !          2185:                        kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
        !          2186:                    
        !          2187:                    objects[j] = object;
        !          2188:                }
        !          2189:                
        !          2190:                complex = TRUE;
        !          2191:                break;
        !          2192:            }
        !          2193:            default: {
        !          2194:                /*
        !          2195:                 * Invalid descriptor
        !          2196:                 */
        !          2197:                ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
        !          2198:                return MACH_SEND_INVALID_TYPE;
        !          2199:            }
        !          2200:        }
        !          2201:        i++ ;
        !          2202:     }
        !          2203:     
        !          2204:     if (!complex)
        !          2205:        kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
        !          2206:     
        !          2207:     return MACH_MSG_SUCCESS;
        !          2208: }
        !          2209: 
        !          2210: 
        !          2211: /*
        !          2212:  *     Routine:        ipc_kmsg_copyin
        !          2213:  *     Purpose:
        !          2214:  *             "Copy-in" port rights and out-of-line memory
        !          2215:  *             in the message.
        !          2216:  *
        !          2217:  *             In all failure cases, the message is left holding
        !          2218:  *             no rights or memory.  However, the message buffer
        !          2219:  *             is not deallocated.  If successful, the message
        !          2220:  *             contains a valid destination port.
        !          2221:  *     Conditions:
        !          2222:  *             Nothing locked.
        !          2223:  *     Returns:
        !          2224:  *             MACH_MSG_SUCCESS        Successful copyin.
        !          2225:  *             MACH_SEND_INVALID_HEADER
        !          2226:  *                     Illegal value in the message header bits.
        !          2227:  *             MACH_SEND_INVALID_NOTIFY        Bad notify port.
        !          2228:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
        !          2229:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
        !          2230:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
        !          2231:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
        !          2232:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
        !          2233:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
        !          2234:  */
        !          2235: 
        !          2236: mach_msg_return_t
        !          2237: ipc_kmsg_copyin(
        !          2238:        ipc_kmsg_t      kmsg,
        !          2239:        ipc_space_t     space,
        !          2240:        vm_map_t        map,
        !          2241:        mach_port_t     notify)
        !          2242: {
        !          2243:     mach_msg_return_t          mr;
        !          2244:     
        !          2245:     mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
        !          2246:     if (mr != MACH_MSG_SUCCESS)
        !          2247:        return mr;
        !          2248:     
        !          2249:     if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
        !          2250:        return MACH_MSG_SUCCESS;
        !          2251:     
        !          2252:     return( ipc_kmsg_copyin_body( kmsg, space, map ) );
        !          2253: }
        !          2254: 
        !          2255: /*
        !          2256:  *     Routine:        ipc_kmsg_copyin_from_kernel
        !          2257:  *     Purpose:
        !          2258:  *             "Copy-in" port rights and out-of-line memory
        !          2259:  *             in a message sent from the kernel.
        !          2260:  *
        !          2261:  *             Because the message comes from the kernel,
        !          2262:  *             the implementation assumes there are no errors
        !          2263:  *             or peculiarities in the message.
        !          2264:  *
        !          2265:  *             Returns TRUE if queueing the message
        !          2266:  *             would result in a circularity.
        !          2267:  *     Conditions:
        !          2268:  *             Nothing locked.
        !          2269:  */
        !          2270: 
        !          2271: void
        !          2272: ipc_kmsg_copyin_from_kernel(
        !          2273:        ipc_kmsg_t      kmsg)
        !          2274: {
        !          2275:        mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits &~
        !          2276:                        MACH_MSGH_BITS_OLD_FORMAT;
        !          2277:        mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
        !          2278:        mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
        !          2279:        ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          2280:        ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          2281: 
        !          2282:        /* translate the destination and reply ports */
        !          2283: 
        !          2284:        ipc_object_copyin_from_kernel(remote, rname);
        !          2285:        if (IO_VALID(local))
        !          2286:                ipc_object_copyin_from_kernel(local, lname);
        !          2287: 
        !          2288:        /*
        !          2289:         *      The common case is a complex message with no reply port,
        !          2290:         *      because that is what the memory_object interface uses.
        !          2291:         */
        !          2292: 
        !          2293:        if (bits == (MACH_MSGH_BITS_COMPLEX |
        !          2294:                     MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
        !          2295:                bits = (MACH_MSGH_BITS_COMPLEX |
        !          2296:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
        !          2297: 
        !          2298:                kmsg->ikm_header.msgh_bits = bits;
        !          2299:        } else {
        !          2300:                bits = (MACH_MSGH_BITS_OTHER(bits) |
        !          2301:                        MACH_MSGH_BITS(ipc_object_copyin_type(rname),
        !          2302:                                       ipc_object_copyin_type(lname)));
        !          2303: 
        !          2304:                kmsg->ikm_header.msgh_bits = bits;
        !          2305:                if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
        !          2306:                        return;
        !          2307:        }
        !          2308:     {
        !          2309:        mach_msg_descriptor_t   *saddr, *eaddr;
        !          2310:        mach_msg_body_t         *body;
        !          2311: 
        !          2312:        body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
        !          2313:        saddr = (mach_msg_descriptor_t *) (body + 1);
        !          2314:        eaddr = (mach_msg_descriptor_t *) saddr + body->msgh_descriptor_count;
        !          2315: 
        !          2316:        for ( ; saddr <  eaddr; saddr++) {
        !          2317: 
        !          2318:            switch (saddr->type.type) {
        !          2319:            
        !          2320:                case MACH_MSG_PORT_DESCRIPTOR: {
        !          2321:                    mach_msg_type_name_t        name;
        !          2322:                    ipc_object_t                object;
        !          2323:                    mach_msg_port_descriptor_t  *dsc;
        !          2324:                
        !          2325:                    dsc = &saddr->port;
        !          2326:                
        !          2327:                    /* this is really the type SEND, SEND_ONCE, etc. */
        !          2328:                    name = dsc->disposition;
        !          2329:                    object = (ipc_object_t) dsc->name;
        !          2330:                    dsc->disposition = ipc_object_copyin_type(name);
        !          2331:                
        !          2332:                    if (!IO_VALID(object)) {
        !          2333:                        break;
        !          2334:                    }
        !          2335: 
        !          2336:                    ipc_object_copyin_from_kernel(object, name);
        !          2337:                    
        !          2338:                    if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          2339:                        ipc_port_check_circularity((ipc_port_t) object, 
        !          2340:                                                (ipc_port_t) remote)) {
        !          2341:                        kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
        !          2342:                    }
        !          2343:                    break;
        !          2344:                }
        !          2345:                case MACH_MSG_OOL_DESCRIPTOR: {
        !          2346:                    /*
        !          2347:                     * The sender should supply ready-made memory, i.e.
        !          2348:                     * a vm_map_copy_t, so we don't need to do anything.
        !          2349:                     */
        !          2350:                    break;
        !          2351:                }
        !          2352:                case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
        !          2353:                    ipc_object_t                        *objects;
        !          2354:                    int                                 j;
        !          2355:                    mach_msg_type_name_t                name;
        !          2356:                    mach_msg_ool_ports_descriptor_t     *dsc;
        !          2357:                
        !          2358:                    dsc = &saddr->ool_ports;
        !          2359: 
        !          2360:                    /* this is really the type SEND, SEND_ONCE, etc. */
        !          2361:                    name = dsc->disposition;
        !          2362:                    dsc->disposition = ipc_object_copyin_type(name);
        !          2363:                
        !          2364:                    objects = (ipc_object_t *) dsc->address;
        !          2365:                
        !          2366:                    for ( j = 0; j < dsc->count; j++) {
        !          2367:                        ipc_object_t object = objects[j];
        !          2368:                        
        !          2369:                        if (!IO_VALID(object))
        !          2370:                            continue;
        !          2371:                        
        !          2372:                        ipc_object_copyin_from_kernel(object, name);
        !          2373:     
        !          2374:                        if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          2375:                            ipc_port_check_circularity(
        !          2376:                                                       (ipc_port_t) object,
        !          2377:                                                       (ipc_port_t) remote))
        !          2378:                            kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
        !          2379:                    }
        !          2380:                    break;
        !          2381:                }
        !          2382:                default: {
        !          2383: #if    MACH_ASSERT
        !          2384:                   panic("ipc_kmsg_copyin_from_kernel: bad descriptor type %d",
        !          2385:                                                saddr->type.type);
        !          2386: #endif /* MACH_ASSERT */
        !          2387:                }
        !          2388:            }
        !          2389:        }
        !          2390:     }
        !          2391: }
        !          2392: 
        !          2393: /*
        !          2394:  *     Routine:        ipc_kmsg_copyout_header
        !          2395:  *     Purpose:
        !          2396:  *             "Copy-out" port rights in the header of a message.
        !          2397:  *             Operates atomically; if it doesn't succeed the
        !          2398:  *             message header and the space are left untouched.
        !          2399:  *             If it does succeed the remote/local port fields
        !          2400:  *             contain port names instead of object pointers,
        !          2401:  *             and the bits field is updated.
        !          2402:  *
        !          2403:  *             The notify argument implements the MACH_RCV_NOTIFY option.
        !          2404:  *             If it is not MACH_PORT_NULL, it should name a receive right.
        !          2405:  *             If the process of receiving the reply port creates a
        !          2406:  *             new right in the receiving task, then the new right is
        !          2407:  *             automatically registered for a dead-name notification,
        !          2408:  *             with the notify port supplying the send-once right.
        !          2409:  *     Conditions:
        !          2410:  *             Nothing locked.
        !          2411:  *     Returns:
        !          2412:  *             MACH_MSG_SUCCESS        Copied out port rights.
        !          2413:  *             MACH_RCV_INVALID_NOTIFY 
        !          2414:  *                     Notify is non-null and doesn't name a receive right.
        !          2415:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !          2416:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
        !          2417:  *                     The space is dead.
        !          2418:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
        !          2419:  *                     No room in space for another name.
        !          2420:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
        !          2421:  *                     Couldn't allocate memory for the reply port.
        !          2422:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
        !          2423:  *                     Couldn't allocate memory for the dead-name request.
        !          2424:  */
        !          2425: 
        !          2426: mach_msg_return_t
        !          2427: ipc_kmsg_copyout_header(
        !          2428:        mach_msg_header_t       *msg,
        !          2429:        ipc_space_t             space,
        !          2430:        mach_port_t             notify)
        !          2431: {
        !          2432:        mach_msg_bits_t mbits = msg->msgh_bits;
        !          2433:        ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
        !          2434: 
        !          2435:        assert(IP_VALID(dest));
        !          2436: 
        !          2437:        /* first check for common cases */
        !          2438: 
        !          2439:        if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
        !          2440:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
        !          2441:                mach_port_t dest_name;
        !          2442:                ipc_port_t nsrequest;
        !          2443: 
        !          2444:                /* receiving an asynchronous message */
        !          2445: 
        !          2446:                ip_lock(dest);
        !          2447:                if (!ip_active(dest)) {
        !          2448:                        ip_unlock(dest);
        !          2449:                        break;
        !          2450:                }
        !          2451: 
        !          2452:                /* optimized ipc_object_copyout_dest */
        !          2453: 
        !          2454:                assert(dest->ip_srights > 0);
        !          2455:                ip_release(dest);
        !          2456: 
        !          2457:                if (dest->ip_receiver == space)
        !          2458:                        dest_name = dest->ip_receiver_name;
        !          2459:                else
        !          2460:                        dest_name = MACH_PORT_NULL;
        !          2461: 
        !          2462:                if ((--dest->ip_srights == 0) &&
        !          2463:                    ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
        !          2464:                        mach_port_mscount_t mscount;
        !          2465: 
        !          2466:                        dest->ip_nsrequest = IP_NULL;
        !          2467:                        mscount = dest->ip_mscount;
        !          2468:                        ip_unlock(dest);
        !          2469: 
        !          2470:                        ipc_notify_no_senders(nsrequest, mscount);
        !          2471:                } else
        !          2472:                        ip_unlock(dest);
        !          2473: 
        !          2474:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2475:                                  MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
        !          2476:                msg->msgh_local_port = dest_name;
        !          2477:                msg->msgh_remote_port = MACH_PORT_NULL;
        !          2478:                return MACH_MSG_SUCCESS;
        !          2479:            }
        !          2480: 
        !          2481:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
        !          2482:                                MACH_MSG_TYPE_PORT_SEND_ONCE): {
        !          2483:                ipc_entry_t table;
        !          2484:                mach_port_index_t index;
        !          2485:                ipc_entry_t entry;
        !          2486:                ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
        !          2487:                mach_port_t dest_name, reply_name;
        !          2488:                ipc_port_t nsrequest;
        !          2489: 
        !          2490:                /* receiving a request message */
        !          2491: 
        !          2492:                if (!IP_VALID(reply))
        !          2493:                        break;
        !          2494: 
        !          2495:                is_write_lock(space);
        !          2496:                if (!space->is_active ||
        !          2497:                    ((index = (table = space->is_table)->ie_next) == 0)) {
        !          2498:                        is_write_unlock(space);
        !          2499:                        break;
        !          2500:                }
        !          2501: 
        !          2502:                /*
        !          2503:                 *      To do an atomic copyout, need simultaneous
        !          2504:                 *      locks on both ports and the space.  If
        !          2505:                 *      dest == reply, and simple locking is
        !          2506:                 *      enabled, then we will abort.  Otherwise it's
        !          2507:                 *      OK to unlock twice.
        !          2508:                 */
        !          2509: 
        !          2510:                ip_lock(dest);
        !          2511:                if (!ip_active(dest) || !ip_lock_try(reply)) {
        !          2512:                        ip_unlock(dest);
        !          2513:                        is_write_unlock(space);
        !          2514:                        break;
        !          2515:                }
        !          2516: 
        !          2517:                if (!ip_active(reply)) {
        !          2518:                        ip_unlock(reply);
        !          2519:                        ip_unlock(dest);
        !          2520:                        is_write_unlock(space);
        !          2521:                        break;
        !          2522:                }
        !          2523: 
        !          2524:                assert(reply->ip_sorights > 0);
        !          2525:                ip_unlock(reply);
        !          2526: 
        !          2527:                /* optimized ipc_entry_get */
        !          2528: 
        !          2529:                entry = &table[index];
        !          2530:                table->ie_next = entry->ie_next;
        !          2531:                entry->ie_request = 0;
        !          2532: 
        !          2533:            {
        !          2534:                mach_port_gen_t gen;
        !          2535: 
        !          2536:                assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
        !          2537:                gen = entry->ie_bits + IE_BITS_GEN_ONE;
        !          2538: 
        !          2539:                reply_name = MACH_PORT_MAKE(index, gen);
        !          2540: 
        !          2541:                /* optimized ipc_right_copyout */
        !          2542: 
        !          2543:                entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
        !          2544:            }
        !          2545: 
        !          2546:                assert(MACH_PORT_VALID(reply_name));
        !          2547:                entry->ie_object = (ipc_object_t) reply;
        !          2548:                is_write_unlock(space);
        !          2549: 
        !          2550:                /* optimized ipc_object_copyout_dest */
        !          2551: 
        !          2552:                assert(dest->ip_srights > 0);
        !          2553:                ip_release(dest);
        !          2554: 
        !          2555:                if (dest->ip_receiver == space)
        !          2556:                        dest_name = dest->ip_receiver_name;
        !          2557:                else
        !          2558:                        dest_name = MACH_PORT_NULL;
        !          2559: 
        !          2560:                if ((--dest->ip_srights == 0) &&
        !          2561:                    ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
        !          2562:                        mach_port_mscount_t mscount;
        !          2563: 
        !          2564:                        dest->ip_nsrequest = IP_NULL;
        !          2565:                        mscount = dest->ip_mscount;
        !          2566:                        ip_unlock(dest);
        !          2567: 
        !          2568:                        ipc_notify_no_senders(nsrequest, mscount);
        !          2569:                } else
        !          2570:                        ip_unlock(dest);
        !          2571: 
        !          2572:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2573:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
        !          2574:                                                 MACH_MSG_TYPE_PORT_SEND));
        !          2575:                msg->msgh_local_port = dest_name;
        !          2576:                msg->msgh_remote_port = reply_name;
        !          2577:                return MACH_MSG_SUCCESS;
        !          2578:            }
        !          2579: 
        !          2580:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
        !          2581:                mach_port_t dest_name;
        !          2582: 
        !          2583:                /* receiving a reply message */
        !          2584: 
        !          2585:                ip_lock(dest);
        !          2586:                if (!ip_active(dest)) {
        !          2587:                        ip_unlock(dest);
        !          2588:                        break;
        !          2589:                }
        !          2590: 
        !          2591:                /* optimized ipc_object_copyout_dest */
        !          2592: 
        !          2593:                assert(dest->ip_sorights > 0);
        !          2594: 
        !          2595:                if (dest->ip_receiver == space) {
        !          2596:                        ip_release(dest);
        !          2597:                        dest->ip_sorights--;
        !          2598:                        dest_name = dest->ip_receiver_name;
        !          2599:                        ip_unlock(dest);
        !          2600:                } else {
        !          2601:                        ip_unlock(dest);
        !          2602: 
        !          2603:                        ipc_notify_send_once(dest);
        !          2604:                        dest_name = MACH_PORT_NULL;
        !          2605:                }
        !          2606: 
        !          2607:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2608:                        MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE));
        !          2609:                msg->msgh_local_port = dest_name;
        !          2610:                msg->msgh_remote_port = MACH_PORT_NULL;
        !          2611:                return MACH_MSG_SUCCESS;
        !          2612:            }
        !          2613: 
        !          2614:            default:
        !          2615:                /* don't bother optimizing */
        !          2616:                break;
        !          2617:        }
        !          2618: 
        !          2619:     {
        !          2620:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          2621:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          2622:        ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
        !          2623:        mach_port_t dest_name, reply_name;
        !          2624: 
        !          2625:        if (IP_VALID(reply)) {
        !          2626:                ipc_port_t notify_port;
        !          2627:                ipc_entry_t entry;
        !          2628:                kern_return_t kr;
        !          2629: 
        !          2630:                /*
        !          2631:                 *      Handling notify (for MACH_RCV_NOTIFY) is tricky.
        !          2632:                 *      The problem is atomically making a send-once right
        !          2633:                 *      from the notify port and installing it for a
        !          2634:                 *      dead-name request in the new entry, because this
        !          2635:                 *      requires two port locks (on the notify port and
        !          2636:                 *      the reply port).  However, we can safely make
        !          2637:                 *      and consume send-once rights for the notify port
        !          2638:                 *      as long as we hold the space locked.  This isn't
        !          2639:                 *      an atomicity problem, because the only way
        !          2640:                 *      to detect that a send-once right has been created
        !          2641:                 *      and then consumed if it wasn't needed is by getting
        !          2642:                 *      at the receive right to look at ip_sorights, and
        !          2643:                 *      because the space is write-locked status calls can't
        !          2644:                 *      lookup the notify port receive right.  When we make
        !          2645:                 *      the send-once right, we lock the notify port,
        !          2646:                 *      so any status calls in progress will be done.
        !          2647:                 */
        !          2648: 
        !          2649:                is_write_lock(space);
        !          2650: 
        !          2651:                for (;;) {
        !          2652:                        ipc_port_request_index_t request;
        !          2653: 
        !          2654:                        if (!space->is_active) {
        !          2655:                                is_write_unlock(space);
        !          2656:                                return (MACH_RCV_HEADER_ERROR|
        !          2657:                                        MACH_MSG_IPC_SPACE);
        !          2658:                        }
        !          2659: 
        !          2660:                        if (notify != MACH_PORT_NULL) {
        !          2661:                                notify_port = ipc_port_lookup_notify(space,
        !          2662:                                                                     notify);
        !          2663:                                if (notify_port == IP_NULL) {
        !          2664:                                        is_write_unlock(space);
        !          2665:                                        return MACH_RCV_INVALID_NOTIFY;
        !          2666:                                }
        !          2667:                        } else
        !          2668:                                notify_port = IP_NULL;
        !          2669: 
        !          2670:                        if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
        !          2671:                            ipc_right_reverse(space, (ipc_object_t) reply,
        !          2672:                                              &reply_name, &entry)) {
        !          2673:                                /* reply port is locked and active */
        !          2674: 
        !          2675:                                /*
        !          2676:                                 *      We don't need the notify_port
        !          2677:                                 *      send-once right, but we can't release
        !          2678:                                 *      it here because reply port is locked.
        !          2679:                                 *      Wait until after the copyout to
        !          2680:                                 *      release the notify port right.
        !          2681:                                 */
        !          2682: 
        !          2683:                                assert(entry->ie_bits &
        !          2684:                                                MACH_PORT_TYPE_SEND_RECEIVE);
        !          2685:                                break;
        !          2686:                        }
        !          2687: 
        !          2688:                        ip_lock(reply);
        !          2689:                        if (!ip_active(reply)) {
        !          2690:                                ip_release(reply);
        !          2691:                                ip_check_unlock(reply);
        !          2692: 
        !          2693:                                if (notify_port != IP_NULL)
        !          2694:                                        ipc_port_release_sonce(notify_port);
        !          2695: 
        !          2696:                                ip_lock(dest);
        !          2697:                                is_write_unlock(space);
        !          2698: 
        !          2699:                                reply = IP_DEAD;
        !          2700:                                reply_name = MACH_PORT_DEAD;
        !          2701:                                goto copyout_dest;
        !          2702:                        }
        !          2703: 
        !          2704:                        kr = ipc_entry_get(space, &reply_name, &entry);
        !          2705:                        if (kr != KERN_SUCCESS) {
        !          2706:                                ip_unlock(reply);
        !          2707: 
        !          2708:                                if (notify_port != IP_NULL)
        !          2709:                                        ipc_port_release_sonce(notify_port);
        !          2710: 
        !          2711:                                /* space is locked */
        !          2712:                                kr = ipc_entry_grow_table(space,
        !          2713:                                                          ITS_SIZE_NONE);
        !          2714:                                if (kr != KERN_SUCCESS) {
        !          2715:                                        /* space is unlocked */
        !          2716: 
        !          2717:                                        if (kr == KERN_RESOURCE_SHORTAGE)
        !          2718:                                                return (MACH_RCV_HEADER_ERROR|
        !          2719:                                                        MACH_MSG_IPC_KERNEL);
        !          2720:                                        else
        !          2721:                                                return (MACH_RCV_HEADER_ERROR|
        !          2722:                                                        MACH_MSG_IPC_SPACE);
        !          2723:                                }
        !          2724:                                /* space is locked again; start over */
        !          2725: 
        !          2726:                                continue;
        !          2727:                        }
        !          2728: 
        !          2729:                        assert(IE_BITS_TYPE(entry->ie_bits)
        !          2730:                                                == MACH_PORT_TYPE_NONE);
        !          2731:                        assert(entry->ie_object == IO_NULL);
        !          2732: 
        !          2733:                        if (notify_port == IP_NULL) {
        !          2734:                                /* not making a dead-name request */
        !          2735: 
        !          2736:                                entry->ie_object = (ipc_object_t) reply;
        !          2737:                                break;
        !          2738:                        }
        !          2739: 
        !          2740:                        kr = ipc_port_dnrequest(reply, reply_name,
        !          2741:                                                notify_port, &request);
        !          2742:                        if (kr != KERN_SUCCESS) {
        !          2743:                                ip_unlock(reply);
        !          2744: 
        !          2745:                                ipc_port_release_sonce(notify_port);
        !          2746: 
        !          2747:                                ipc_entry_dealloc(space, reply_name, entry);
        !          2748:                                is_write_unlock(space);
        !          2749: 
        !          2750:                                ip_lock(reply);
        !          2751:                                if (!ip_active(reply)) {
        !          2752:                                        /* will fail next time around loop */
        !          2753: 
        !          2754:                                        ip_unlock(reply);
        !          2755:                                        is_write_lock(space);
        !          2756:                                        continue;
        !          2757:                                }
        !          2758: 
        !          2759:                                kr = ipc_port_dngrow(reply, ITS_SIZE_NONE);
        !          2760:                                /* port is unlocked */
        !          2761:                                if (kr != KERN_SUCCESS)
        !          2762:                                        return (MACH_RCV_HEADER_ERROR|
        !          2763:                                                MACH_MSG_IPC_KERNEL);
        !          2764: 
        !          2765:                                is_write_lock(space);
        !          2766:                                continue;
        !          2767:                        }
        !          2768: 
        !          2769:                        notify_port = IP_NULL; /* don't release right below */
        !          2770: 
        !          2771:                        entry->ie_object = (ipc_object_t) reply;
        !          2772:                        entry->ie_request = request;
        !          2773:                        break;
        !          2774:                }
        !          2775: 
        !          2776:                /* space and reply port are locked and active */
        !          2777: 
        !          2778:                ip_reference(reply);    /* hold onto the reply port */
        !          2779: 
        !          2780:                kr = ipc_right_copyout(space, reply_name, entry,
        !          2781:                                       reply_type, TRUE, (ipc_object_t) reply);
        !          2782:                /* reply port is unlocked */
        !          2783:                assert(kr == KERN_SUCCESS);
        !          2784: 
        !          2785:                if (notify_port != IP_NULL)
        !          2786:                        ipc_port_release_sonce(notify_port);
        !          2787: 
        !          2788:                ip_lock(dest);
        !          2789:                is_write_unlock(space);
        !          2790:        } else {
        !          2791:                /*
        !          2792:                 *      No reply port!  This is an easy case.
        !          2793:                 *      We only need to have the space locked
        !          2794:                 *      when checking notify and when locking
        !          2795:                 *      the destination (to ensure atomicity).
        !          2796:                 */
        !          2797: 
        !          2798:                is_read_lock(space);
        !          2799:                if (!space->is_active) {
        !          2800:                        is_read_unlock(space);
        !          2801:                        return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
        !          2802:                }
        !          2803: 
        !          2804:                if (notify != MACH_PORT_NULL) {
        !          2805:                        ipc_entry_t entry;
        !          2806: 
        !          2807:                        /* must check notify even though it won't be used */
        !          2808: 
        !          2809:                        if (((entry = ipc_entry_lookup(space, notify))
        !          2810:                                                                == IE_NULL) ||
        !          2811:                            ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
        !          2812:                                is_read_unlock(space);
        !          2813:                                return MACH_RCV_INVALID_NOTIFY;
        !          2814:                        }
        !          2815:                }
        !          2816: 
        !          2817:                ip_lock(dest);
        !          2818:                is_read_unlock(space);
        !          2819: 
        !          2820:                reply_name = (mach_port_t) reply;
        !          2821:        }
        !          2822: 
        !          2823:        /*
        !          2824:         *      At this point, the space is unlocked and the destination
        !          2825:         *      port is locked.  (Lock taken while space was locked.)
        !          2826:         *      reply_name is taken care of; we still need dest_name.
        !          2827:         *      We still hold a ref for reply (if it is valid).
        !          2828:         *
        !          2829:         *      If the space holds receive rights for the destination,
        !          2830:         *      we return its name for the right.  Otherwise the task
        !          2831:         *      managed to destroy or give away the receive right between
        !          2832:         *      receiving the message and this copyout.  If the destination
        !          2833:         *      is dead, return MACH_PORT_DEAD, and if the receive right
        !          2834:         *      exists somewhere else (another space, in transit)
        !          2835:         *      return MACH_PORT_NULL.
        !          2836:         *
        !          2837:         *      Making this copyout operation atomic with the previous
        !          2838:         *      copyout of the reply port is a bit tricky.  If there was
        !          2839:         *      no real reply port (it wasn't IP_VALID) then this isn't
        !          2840:         *      an issue.  If the reply port was dead at copyout time,
        !          2841:         *      then we are OK, because if dest is dead we serialize
        !          2842:         *      after the death of both ports and if dest is alive
        !          2843:         *      we serialize after reply died but before dest's (later) death.
        !          2844:         *      So assume reply was alive when we copied it out.  If dest
        !          2845:         *      is alive, then we are OK because we serialize before
        !          2846:         *      the ports' deaths.  So assume dest is dead when we look at it.
        !          2847:         *      If reply dies/died after dest, then we are OK because
        !          2848:         *      we serialize after dest died but before reply dies.
        !          2849:         *      So the hard case is when reply is alive at copyout,
        !          2850:         *      dest is dead at copyout, and reply died before dest died.
        !          2851:         *      In this case pretend that dest is still alive, so
        !          2852:         *      we serialize while both ports are alive.
        !          2853:         *
        !          2854:         *      Because the space lock is held across the copyout of reply
        !          2855:         *      and locking dest, the receive right for dest can't move
        !          2856:         *      in or out of the space while the copyouts happen, so
        !          2857:         *      that isn't an atomicity problem.  In the last hard case
        !          2858:         *      above, this implies that when dest is dead that the
        !          2859:         *      space couldn't have had receive rights for dest at
        !          2860:         *      the time reply was copied-out, so when we pretend
        !          2861:         *      that dest is still alive, we can return MACH_PORT_NULL.
        !          2862:         *
        !          2863:         *      If dest == reply, then we have to make it look like
        !          2864:         *      either both copyouts happened before the port died,
        !          2865:         *      or both happened after the port died.  This special
        !          2866:         *      case works naturally if the timestamp comparison
        !          2867:         *      is done correctly.
        !          2868:         */
        !          2869: 
        !          2870:     copyout_dest:
        !          2871: 
        !          2872:        if (ip_active(dest)) {
        !          2873:                ipc_object_copyout_dest(space, (ipc_object_t) dest,
        !          2874:                                        dest_type, &dest_name);
        !          2875:                /* dest is unlocked */
        !          2876:        } else {
        !          2877:                ipc_port_timestamp_t timestamp;
        !          2878: 
        !          2879:                timestamp = dest->ip_timestamp;
        !          2880:                ip_release(dest);
        !          2881:                ip_check_unlock(dest);
        !          2882: 
        !          2883:                if (IP_VALID(reply)) {
        !          2884:                        ip_lock(reply);
        !          2885:                        if (ip_active(reply) ||
        !          2886:                            IP_TIMESTAMP_ORDER(timestamp,
        !          2887:                                               reply->ip_timestamp))
        !          2888:                                dest_name = MACH_PORT_DEAD;
        !          2889:                        else
        !          2890:                                dest_name = MACH_PORT_NULL;
        !          2891:                        ip_unlock(reply);
        !          2892:                } else
        !          2893:                        dest_name = MACH_PORT_DEAD;
        !          2894:        }
        !          2895: 
        !          2896:        if (IP_VALID(reply))
        !          2897:                ipc_port_release(reply);
        !          2898: 
        !          2899:        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2900:                          MACH_MSGH_BITS(reply_type, dest_type));
        !          2901:        msg->msgh_local_port = dest_name;
        !          2902:        msg->msgh_remote_port = reply_name;
        !          2903:     }
        !          2904: 
        !          2905:        return MACH_MSG_SUCCESS;
        !          2906: }
        !          2907: 
        !          2908: /*
        !          2909:  *     Routine:        ipc_kmsg_copyout_object
        !          2910:  *     Purpose:
        !          2911:  *             Copy-out a port right.  Always returns a name,
        !          2912:  *             even for unsuccessful return codes.  Always
        !          2913:  *             consumes the supplied object.
        !          2914:  *     Conditions:
        !          2915:  *             Nothing locked.
        !          2916:  *     Returns:
        !          2917:  *             MACH_MSG_SUCCESS        The space acquired the right
        !          2918:  *                     (name is valid) or the object is dead (MACH_PORT_DEAD).
        !          2919:  *             MACH_MSG_IPC_SPACE      No room in space for the right,
        !          2920:  *                     or the space is dead.  (Name is MACH_PORT_NULL.)
        !          2921:  *             MACH_MSG_IPC_KERNEL     Kernel resource shortage.
        !          2922:  *                     (Name is MACH_PORT_NULL.)
        !          2923:  */
        !          2924: 
        !          2925: mach_msg_return_t
        !          2926: ipc_kmsg_copyout_object(
        !          2927:        ipc_space_t             space,
        !          2928:        ipc_object_t            object,
        !          2929:        mach_msg_type_name_t    msgt_name,
        !          2930:        mach_port_t             *namep)
        !          2931: {
        !          2932:        if (!IO_VALID(object)) {
        !          2933:                *namep = (mach_port_t) object;
        !          2934:                return MACH_MSG_SUCCESS;
        !          2935:        }
        !          2936: 
        !          2937:        /*
        !          2938:         *      Attempt quick copyout of send rights.  We optimize for a
        !          2939:         *      live port for which the receiver holds send (and not
        !          2940:         *      receive) rights in his local table.
        !          2941:         */
        !          2942: 
        !          2943:        if (msgt_name != MACH_MSG_TYPE_PORT_SEND)
        !          2944:                goto slow_copyout;
        !          2945: 
        !          2946:     {
        !          2947:        register ipc_port_t port = (ipc_port_t) object;
        !          2948:        ipc_entry_t entry;
        !          2949: 
        !          2950:        is_write_lock(space);
        !          2951:        if (!space->is_active) {
        !          2952:                is_write_unlock(space);
        !          2953:                goto slow_copyout;
        !          2954:        }
        !          2955: 
        !          2956:        ip_lock(port);
        !          2957:        if (!ip_active(port) ||
        !          2958:            !ipc_hash_local_lookup(space, (ipc_object_t) port,
        !          2959:                                   namep, &entry)) {
        !          2960:                ip_unlock(port);
        !          2961:                is_write_unlock(space);
        !          2962:                goto slow_copyout;
        !          2963:        }
        !          2964: 
        !          2965:        /*
        !          2966:         *      Copyout the send right, incrementing urefs
        !          2967:         *      unless it would overflow, and consume the right.
        !          2968:         */
        !          2969: 
        !          2970:        assert(port->ip_srights > 1);
        !          2971:        port->ip_srights--;
        !          2972:        ip_release(port);
        !          2973:        ip_unlock(port);
        !          2974: 
        !          2975:        assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
        !          2976:        assert(IE_BITS_UREFS(entry->ie_bits) > 0);
        !          2977:        assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX);
        !          2978: 
        !          2979:     {
        !          2980:        register ipc_entry_bits_t bits = entry->ie_bits + 1;
        !          2981: 
        !          2982:        if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
        !          2983:                entry->ie_bits = bits;
        !          2984:     }
        !          2985: 
        !          2986:        is_write_unlock(space);
        !          2987:        return MACH_MSG_SUCCESS;
        !          2988:     }
        !          2989: 
        !          2990:     slow_copyout: {
        !          2991:        kern_return_t kr;
        !          2992: 
        !          2993:        kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
        !          2994:        if (kr != KERN_SUCCESS) {
        !          2995:                ipc_object_destroy(object, msgt_name);
        !          2996: 
        !          2997:                if (kr == KERN_INVALID_CAPABILITY)
        !          2998:                        *namep = MACH_PORT_DEAD;
        !          2999:                else {
        !          3000:                        *namep = MACH_PORT_NULL;
        !          3001: 
        !          3002:                        if (kr == KERN_RESOURCE_SHORTAGE)
        !          3003:                                return MACH_MSG_IPC_KERNEL;
        !          3004:                        else
        !          3005:                                return MACH_MSG_IPC_SPACE;
        !          3006:                }
        !          3007:        }
        !          3008: 
        !          3009:        return MACH_MSG_SUCCESS;
        !          3010:     }
        !          3011: }
        !          3012: 
        !          3013: #define SKIP_PORT_DESCRIPTORS(s, e)                                    \
        !          3014: MACRO_BEGIN                                                            \
        !          3015:        if ((s) != MACH_MSG_DESCRIPTOR_NULL) {                          \
        !          3016:                while ((s) < (e)) {                                     \
        !          3017:                        if ((s)->type.type != MACH_MSG_PORT_DESCRIPTOR) \
        !          3018:                                break;                                  \
        !          3019:                        (s)++;                                          \
        !          3020:                }                                                       \
        !          3021:                if ((s) >= (e))                                         \
        !          3022:                        (s) = MACH_MSG_DESCRIPTOR_NULL;                 \
        !          3023:        }                                                               \
        !          3024: MACRO_END
        !          3025: 
        !          3026: #define INCREMENT_SCATTER(s)                                           \
        !          3027: MACRO_BEGIN                                                            \
        !          3028:        if ((s) != MACH_MSG_DESCRIPTOR_NULL) {                          \
        !          3029:                (s)++;                                                  \
        !          3030:        }                                                               \
        !          3031: MACRO_END
        !          3032: 
        !          3033: /*
        !          3034:  *     Routine:        ipc_kmsg_copyout_body
        !          3035:  *     Purpose:
        !          3036:  *             "Copy-out" port rights and out-of-line memory
        !          3037:  *             in the body of a message.
        !          3038:  *
        !          3039:  *             The error codes are a combination of special bits.
        !          3040:  *             The copyout proceeds despite errors.
        !          3041:  *     Conditions:
        !          3042:  *             Nothing locked.
        !          3043:  *     Returns:
        !          3044:  *             MACH_MSG_SUCCESS        Successfull copyout.
        !          3045:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
        !          3046:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
        !          3047:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
        !          3048:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
        !          3049:  */
        !          3050: 
        !          3051: mach_msg_return_t
        !          3052: ipc_kmsg_copyout_body(
        !          3053:        ipc_kmsg_t              kmsg,
        !          3054:        ipc_space_t             space,
        !          3055:        vm_map_t                map,
        !          3056:        ipc_kmsg_t              list)
        !          3057: {
        !          3058:     mach_msg_body_t            *body;
        !          3059:     mach_msg_descriptor_t      *saddr, *eaddr;
        !          3060:     mach_msg_return_t          mr = MACH_MSG_SUCCESS;
        !          3061:     kern_return_t              kr;
        !          3062:     vm_offset_t                data;
        !          3063:     mach_msg_descriptor_t      *sstart, *send;
        !          3064: 
        !          3065:     body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
        !          3066:     saddr = (mach_msg_descriptor_t *) (body + 1);
        !          3067:     eaddr = saddr + body->msgh_descriptor_count;
        !          3068: 
        !          3069:     /*
        !          3070:      * Do scatter list setup
        !          3071:      */
        !          3072:     if (list != IKM_NULL) {
        !          3073:        mach_msg_body_t         *sbody =
        !          3074:                (mach_msg_body_t *)(&list->ikm_header + 1);
        !          3075: 
        !          3076:        sstart = (mach_msg_descriptor_t *) (sbody + 1);
        !          3077:        send = sstart + sbody->msgh_descriptor_count;
        !          3078:     }
        !          3079:     else
        !          3080:        sstart = MACH_MSG_DESCRIPTOR_NULL;
        !          3081: 
        !          3082:     for ( ; saddr < eaddr; saddr++ ) {
        !          3083:        
        !          3084:        switch (saddr->type.type) {
        !          3085:            
        !          3086:            case MACH_MSG_PORT_DESCRIPTOR: {
        !          3087:                mach_msg_port_descriptor_t *dsc;
        !          3088:                
        !          3089:                /* 
        !          3090:                 * Copyout port right carried in the message 
        !          3091:                 */
        !          3092:                dsc = &saddr->port;
        !          3093:                mr |= ipc_kmsg_copyout_object(space, 
        !          3094:                                              (ipc_object_t) dsc->name, 
        !          3095:                                              dsc->disposition, 
        !          3096:                                              (mach_port_t *) &dsc->name);
        !          3097: 
        !          3098:                break;
        !          3099:            }
        !          3100:            case MACH_MSG_OOL_DESCRIPTOR : {
        !          3101:                vm_offset_t                     rcv_addr;
        !          3102:                vm_offset_t                     snd_addr;
        !          3103:                mach_msg_ool_descriptor_t       *dsc;
        !          3104:                mach_msg_copy_options_t         copy_option;
        !          3105: 
        !          3106:                SKIP_PORT_DESCRIPTORS(sstart, send);
        !          3107: 
        !          3108:                dsc = &saddr->out_of_line;
        !          3109: 
        !          3110:                assert(dsc->copy != MACH_MSG_KALLOC_COPY_T);
        !          3111:                assert(dsc->copy != MACH_MSG_PAGE_LIST_COPY_T);
        !          3112: 
        !          3113:                copy_option = dsc->copy;
        !          3114: 
        !          3115:                if ((snd_addr = (vm_offset_t) dsc->address) != 0) {
        !          3116:                    if (sstart != MACH_MSG_DESCRIPTOR_NULL &&
        !          3117:                        sstart->out_of_line.copy == MACH_MSG_OVERWRITE) {
        !          3118: 
        !          3119:                        /*
        !          3120:                         * There is an overwrite descriptor specified in the
        !          3121:                         * scatter list for this ool data.  The descriptor
        !          3122:                         * has already been verified
        !          3123:                         */
        !          3124:                        rcv_addr = (vm_offset_t) sstart->out_of_line.address;
        !          3125:                        dsc->copy = MACH_MSG_OVERWRITE;
        !          3126:                    } else {
        !          3127:                        dsc->copy = MACH_MSG_ALLOCATE;
        !          3128:                    }
        !          3129: 
        !          3130: #if    MACH_OLD_VM_COPY
        !          3131:                    if (dsc->copy == MACH_MSG_OVERWRITE) {
        !          3132:                        kr = vm_map_copy(
        !          3133:                                        map, ipc_soft_map,
        !          3134:                                        rcv_addr, dsc->size, snd_addr,
        !          3135:                                        FALSE, FALSE);
        !          3136:                    }
        !          3137:                    else {
        !          3138:                        kr = vm_move(
        !          3139:                                ipc_soft_map, snd_addr,
        !          3140:                                map, dsc->size, FALSE, &rcv_addr);
        !          3141:                    }
        !          3142:                    (void) vm_deallocate(ipc_soft_map, snd_addr, dsc->size);
        !          3143:                    if (kr != KERN_SUCCESS) {
        !          3144:                        if (kr == KERN_RESOURCE_SHORTAGE)
        !          3145:                            mr |= MACH_MSG_VM_KERNEL;
        !          3146:                        else
        !          3147:                            mr |= MACH_MSG_VM_SPACE;
        !          3148:                        dsc->address = 0;
        !          3149:                        INCREMENT_SCATTER(sstart);
        !          3150:                        break;
        !          3151:                    }
        !          3152: #else
        !          3153:                    if (copy_option == MACH_MSG_PHYSICAL_COPY &&
        !          3154:                            dsc->size <= MSG_OOL_SIZE_SMALL(rt)) {
        !          3155: 
        !          3156:                        /* 
        !          3157:                         * Sufficiently 'small' data was copied into a kalloc'ed
        !          3158:                         * buffer copy was requested.  Just copy it out and 
        !          3159:                         * free the buffer.
        !          3160:                         */
        !          3161:                        if (dsc->copy == MACH_MSG_ALLOCATE) {
        !          3162: 
        !          3163:                            /*
        !          3164:                             * If there is no overwrite region, allocate
        !          3165:                             * space in receiver's address space for the
        !          3166:                             * data
        !          3167:                             */
        !          3168:                            if ((kr = vm_allocate(map, &rcv_addr, dsc->size, 
        !          3169:                                        TRUE)) != KERN_SUCCESS) {
        !          3170:                                if (kr == KERN_RESOURCE_SHORTAGE)
        !          3171:                                        mr |= MACH_MSG_VM_KERNEL;
        !          3172:                                else
        !          3173:                                        mr |= MACH_MSG_VM_SPACE;
        !          3174:                                kfree(snd_addr, dsc->size);
        !          3175:                                dsc->address = (void *) 0;
        !          3176:                                INCREMENT_SCATTER(sstart);
        !          3177:                                break;
        !          3178:                            }
        !          3179:                        }
        !          3180:                        (void) copyoutmap(map, snd_addr, rcv_addr, dsc->size);
        !          3181:                        kfree(snd_addr, dsc->size);
        !          3182:                    } else {
        !          3183: 
        !          3184:                        /*
        !          3185:                         * Whether the data was virtually or physically
        !          3186:                         * copied we have a vm_map_copy_t for it.
        !          3187:                         * If there's an overwrite region specified
        !          3188:                         * overwrite it, otherwise do a virtual copy out.
        !          3189:                         */
        !          3190:                        if (dsc->copy == MACH_MSG_OVERWRITE) {
        !          3191:                            kr = vm_map_copy_overwrite(map, rcv_addr,
        !          3192:                                        (vm_map_copy_t) dsc->address, TRUE);
        !          3193:                        } else {
        !          3194:                            kr = vm_map_copyout(map, &rcv_addr, 
        !          3195:                                                (vm_map_copy_t) dsc->address);
        !          3196:                        }       
        !          3197:                        if (kr != KERN_SUCCESS) {
        !          3198:                            if (kr == KERN_RESOURCE_SHORTAGE)
        !          3199:                                mr |= MACH_MSG_VM_KERNEL;
        !          3200:                            else
        !          3201:                                mr |= MACH_MSG_VM_SPACE;
        !          3202:                            vm_map_copy_discard((vm_map_copy_t) dsc->address);
        !          3203:                            dsc->address = 0;
        !          3204:                            INCREMENT_SCATTER(sstart);
        !          3205:                            break;
        !          3206:                        }
        !          3207:                    }
        !          3208: #endif
        !          3209:                    dsc->address = (void *) rcv_addr;
        !          3210:                }
        !          3211:                INCREMENT_SCATTER(sstart);
        !          3212:                break;
        !          3213:            }
        !          3214:            case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
        !          3215:                vm_offset_t                     addr;
        !          3216:                mach_port_t                     *objects;
        !          3217:                mach_msg_type_number_t          j;
        !          3218:                vm_size_t                       length;
        !          3219:                mach_msg_ool_ports_descriptor_t *dsc;
        !          3220: 
        !          3221:                SKIP_PORT_DESCRIPTORS(sstart, send);
        !          3222: 
        !          3223:                dsc = &saddr->ool_ports;
        !          3224: 
        !          3225:                length = dsc->count * sizeof(mach_port_t);
        !          3226: 
        !          3227:                if (length != 0) {
        !          3228:                    if (sstart != MACH_MSG_DESCRIPTOR_NULL &&
        !          3229:                        sstart->ool_ports.copy == MACH_MSG_OVERWRITE) {
        !          3230: 
        !          3231:                        /*
        !          3232:                         * There is an overwrite descriptor specified in the
        !          3233:                         * scatter list for this ool data.  The descriptor
        !          3234:                         * has already been verified
        !          3235:                         */
        !          3236:                        addr = (vm_offset_t) sstart->out_of_line.address;
        !          3237:                        dsc->copy = MACH_MSG_OVERWRITE;
        !          3238:                    } 
        !          3239:                    else {
        !          3240: 
        !          3241:                        /*
        !          3242:                         * Dynamically allocate the region
        !          3243:                         */
        !          3244:                        dsc->copy = MACH_MSG_ALLOCATE;
        !          3245:                        if ((kr = vm_allocate(map, &addr, length, TRUE)) !=
        !          3246:                                                                KERN_SUCCESS) {
        !          3247:                            ipc_kmsg_clean_body(kmsg,
        !          3248:                                                body->msgh_descriptor_count);
        !          3249:                            dsc->address = 0;
        !          3250: 
        !          3251:                            if (kr == KERN_RESOURCE_SHORTAGE){
        !          3252:                                mr |= MACH_MSG_VM_KERNEL;
        !          3253:                            } else {
        !          3254:                                mr |= MACH_MSG_VM_SPACE;
        !          3255:                            }
        !          3256:                            INCREMENT_SCATTER(sstart);
        !          3257:                            break;
        !          3258:                        }
        !          3259:                    }
        !          3260:                } else {
        !          3261:                    assert(dsc->address == 0);
        !          3262:                    INCREMENT_SCATTER(sstart);
        !          3263:                    break;
        !          3264:                }
        !          3265: 
        !          3266:                
        !          3267:                objects = (mach_port_t *) dsc->address ;
        !          3268:                
        !          3269:                /* copyout port rights carried in the message */
        !          3270:                
        !          3271:                for ( j = 0; j < dsc->count ; j++) {
        !          3272:                    ipc_object_t object =
        !          3273:                        (ipc_object_t) objects[j];
        !          3274:                    
        !          3275:                    mr |= ipc_kmsg_copyout_object(space, object,
        !          3276:                                        dsc->disposition, &objects[j]);
        !          3277:                }
        !          3278: 
        !          3279:                /* copyout to memory allocated above */
        !          3280:                
        !          3281:                data = (vm_offset_t) dsc->address;
        !          3282:                (void) copyoutmap(map, data, addr, length);
        !          3283:                kfree(data, length);
        !          3284:                
        !          3285:                dsc->address = (void *) addr;
        !          3286:                INCREMENT_SCATTER(sstart);
        !          3287:                break;
        !          3288:            }
        !          3289:            default : {
        !          3290:                panic("ipc_kmsg_copyout_body: bad descriptor type %d",
        !          3291:                                                saddr->type.type);
        !          3292:            }
        !          3293:        }
        !          3294:     }
        !          3295:     return mr;
        !          3296: }
        !          3297: 
        !          3298: /*
        !          3299:  *     Routine:        ipc_kmsg_copyout
        !          3300:  *     Purpose:
        !          3301:  *             "Copy-out" port rights and out-of-line memory
        !          3302:  *             in the message.
        !          3303:  *     Conditions:
        !          3304:  *             Nothing locked.
        !          3305:  *     Returns:
        !          3306:  *             MACH_MSG_SUCCESS        Copied out all rights and memory.
        !          3307:  *             MACH_RCV_INVALID_NOTIFY Bad notify port.
        !          3308:  *                     Rights and memory in the message are intact.
        !          3309:  *             MACH_RCV_HEADER_ERROR + special bits
        !          3310:  *                     Rights and memory in the message are intact.
        !          3311:  *             MACH_RCV_BODY_ERROR + special bits
        !          3312:  *                     The message header was successfully copied out.
        !          3313:  *                     As much of the body was handled as possible.
        !          3314:  */
        !          3315: 
        !          3316: mach_msg_return_t
        !          3317: ipc_kmsg_copyout(
        !          3318:        ipc_kmsg_t              kmsg,
        !          3319:        ipc_space_t             space,
        !          3320:        vm_map_t                map,
        !          3321:        mach_port_t             notify,
        !          3322:        ipc_kmsg_t              list)
        !          3323: {
        !          3324:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          3325:        mach_msg_return_t mr;
        !          3326: 
        !          3327:        mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
        !          3328:        if (mr != MACH_MSG_SUCCESS)
        !          3329:                return mr;
        !          3330: 
        !          3331:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !          3332:                mr = ipc_kmsg_copyout_body(kmsg, space, map, list);
        !          3333: 
        !          3334:                if (mr != MACH_MSG_SUCCESS)
        !          3335:                        mr |= MACH_RCV_BODY_ERROR;
        !          3336:        }
        !          3337: 
        !          3338:        return mr;
        !          3339: }
        !          3340: 
        !          3341: /*
        !          3342:  *     Routine:        ipc_kmsg_copyout_pseudo
        !          3343:  *     Purpose:
        !          3344:  *             Does a pseudo-copyout of the message.
        !          3345:  *             This is like a regular copyout, except
        !          3346:  *             that the ports in the header are handled
        !          3347:  *             as if they are in the body.  They aren't reversed.
        !          3348:  *
        !          3349:  *             The error codes are a combination of special bits.
        !          3350:  *             The copyout proceeds despite errors.
        !          3351:  *     Conditions:
        !          3352:  *             Nothing locked.
        !          3353:  *     Returns:
        !          3354:  *             MACH_MSG_SUCCESS        Successful copyout.
        !          3355:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
        !          3356:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
        !          3357:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
        !          3358:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
        !          3359:  */
        !          3360: 
        !          3361: mach_msg_return_t
        !          3362: ipc_kmsg_copyout_pseudo(
        !          3363:        ipc_kmsg_t              kmsg,
        !          3364:        ipc_space_t             space,
        !          3365:        vm_map_t                map,
        !          3366:        ipc_kmsg_t              list)
        !          3367: {
        !          3368:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          3369:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          3370:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          3371:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          3372:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          3373:        mach_port_t dest_name, reply_name;
        !          3374:        mach_msg_return_t mr;
        !          3375: 
        !          3376:        assert(IO_VALID(dest));
        !          3377: 
        !          3378:        mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
        !          3379:              ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
        !          3380: 
        !          3381:        kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
        !          3382:        kmsg->ikm_header.msgh_remote_port = dest_name;
        !          3383:        kmsg->ikm_header.msgh_local_port = reply_name;
        !          3384: 
        !          3385:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !          3386:                mr |= ipc_kmsg_copyout_body(kmsg, space, map, list);
        !          3387:        }
        !          3388: 
        !          3389:        return mr;
        !          3390: }
        !          3391: 
        !          3392: /*
        !          3393:  *     Routine:        ipc_kmsg_copyout_dest
        !          3394:  *     Purpose:
        !          3395:  *             Copies out the destination port in the message.
        !          3396:  *             Destroys all other rights and memory in the message.
        !          3397:  *     Conditions:
        !          3398:  *             Nothing locked.
        !          3399:  */
        !          3400: 
        !          3401: void
        !          3402: ipc_kmsg_copyout_dest(
        !          3403:        ipc_kmsg_t      kmsg,
        !          3404:        ipc_space_t     space)
        !          3405: {
        !          3406:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          3407:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          3408:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          3409:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          3410:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          3411:        mach_port_t dest_name, reply_name;
        !          3412: 
        !          3413:        assert(IO_VALID(dest));
        !          3414: 
        !          3415:        io_lock(dest);
        !          3416:        if (io_active(dest)) {
        !          3417:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
        !          3418:                /* dest is unlocked */
        !          3419:        } else {
        !          3420:                io_release(dest);
        !          3421:                io_check_unlock(dest);
        !          3422:                dest_name = MACH_PORT_DEAD;
        !          3423:        }
        !          3424: 
        !          3425:        if (IO_VALID(reply)) {
        !          3426:                ipc_object_destroy(reply, reply_type);
        !          3427:                reply_name = MACH_PORT_NULL;
        !          3428:        } else
        !          3429:                reply_name = (mach_port_t) reply;
        !          3430: 
        !          3431:        kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          3432:                                      MACH_MSGH_BITS(reply_type, dest_type));
        !          3433:        kmsg->ikm_header.msgh_local_port = dest_name;
        !          3434:        kmsg->ikm_header.msgh_remote_port = reply_name;
        !          3435: 
        !          3436:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !          3437:            if (mbits & MACH_MSGH_BITS_OLD_FORMAT) {
        !          3438:                vm_offset_t saddr, eaddr;
        !          3439: 
        !          3440:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          3441:                eaddr = (vm_offset_t) &kmsg->ikm_header +
        !          3442:                                kmsg->ikm_header.msgh_size;
        !          3443: 
        !          3444:                ipc_kmsg_clean_body_compat(saddr, eaddr);
        !          3445:            }
        !          3446:            else {
        !          3447:                mach_msg_body_t *body;
        !          3448: 
        !          3449:                body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
        !          3450:                ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count);
        !          3451:            }
        !          3452:        }
        !          3453: }
        !          3454: 
        !          3455: /*
        !          3456:  *     Routine:        ipc_kmsg_check_scatter
        !          3457:  *     Purpose:
        !          3458:  *             Checks scatter and gather lists for consistency.
        !          3459:  *             
        !          3460:  *     Algorithm:
        !          3461:  *             The gather is assumed valid since it has been copied in.
        !          3462:  *             The scatter list has only been range checked.
        !          3463:  *             Gather list descriptors are sequentially paired with scatter 
        !          3464:  *             list descriptors, with port descriptors in either list ignored.
        !          3465:  *             Descriptors are consistent if the type fileds match and size
        !          3466:  *             of the scatter descriptor is less than or equal to the
        !          3467:  *             size of the gather descriptor.  A MACH_MSG_ALLOCATE copy 
        !          3468:  *             strategy in a scatter descriptor matches any size in the 
        !          3469:  *             corresponding gather descriptor assuming they are the same type.
        !          3470:  *             Either list may be larger than the other.  During the
        !          3471:  *             subsequent copy out, excess scatter descriptors are ignored
        !          3472:  *             and excess gather descriptors default to dynamic allocation.
        !          3473:  *             
        !          3474:  *             In the case of a size error, a new scatter list is formed
        !          3475:  *             from the gather list copying only the size and type fields.
        !          3476:  *             
        !          3477:  *     Conditions:
        !          3478:  *             Nothing locked.
        !          3479:  *     Returns:
        !          3480:  *             MACH_MSG_SUCCESS                Lists are consistent
        !          3481:  *             MACH_RCV_INVALID_TYPE           Scatter type does not match
        !          3482:  *                                             gather type
        !          3483:  *             MACH_RCV_SCATTER_SMALL          Scatter size less than gather
        !          3484:  *                                             size
        !          3485:  */
        !          3486: 
        !          3487: mach_msg_return_t
        !          3488: ipc_kmsg_check_scatter(
        !          3489:        ipc_kmsg_t              kmsg,
        !          3490:        mach_msg_option_t       option,
        !          3491:        ipc_kmsg_t              *list)
        !          3492: {
        !          3493:        mach_msg_body_t         *gbody, *sbody;
        !          3494:        mach_msg_descriptor_t   *gstart, *gend;
        !          3495:        mach_msg_descriptor_t   *sstart, *send;
        !          3496:        boolean_t               size_error = FALSE;
        !          3497: 
        !          3498:        assert(*list != IKM_NULL);
        !          3499: 
        !          3500:        gbody = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
        !          3501:        gstart = (mach_msg_descriptor_t *) (gbody + 1);
        !          3502:        gend = gstart + gbody->msgh_descriptor_count;
        !          3503: 
        !          3504:        sbody = (mach_msg_body_t *) (&(*list)->ikm_header + 1);
        !          3505:        sstart = (mach_msg_descriptor_t *) (sbody + 1);
        !          3506:        send = sstart + sbody->msgh_descriptor_count;
        !          3507: 
        !          3508:        while (gstart < gend) {
        !          3509: 
        !          3510:            /*
        !          3511:             * Skip port descriptors in gather list. 
        !          3512:             */
        !          3513:            if (gstart->type.type != MACH_MSG_PORT_DESCRIPTOR) {
        !          3514: 
        !          3515:                /*
        !          3516:                 * A scatter list with a 0 descriptor count is treated as an
        !          3517:                 * automatic size mismatch.
        !          3518:                 */
        !          3519:                 if (sbody->msgh_descriptor_count == 0) {
        !          3520:                    if ((option & MACH_RCV_LARGE) == 0)
        !          3521:                        return MACH_RCV_SCATTER_SMALL;
        !          3522:                    size_error = TRUE;
        !          3523:                    break;
        !          3524:                 }
        !          3525: 
        !          3526:                /*
        !          3527:                 * Skip port descriptors in  scatter list.
        !          3528:                 */
        !          3529:                while (sstart < send) {
        !          3530:                    if (sstart->type.type != MACH_MSG_PORT_DESCRIPTOR)
        !          3531:                        break;
        !          3532:                    sstart++;
        !          3533:                }
        !          3534: 
        !          3535:                /*
        !          3536:                 * No more scatter descriptors, we're done
        !          3537:                 */
        !          3538:                if (sstart >= send)
        !          3539:                    break;
        !          3540: 
        !          3541:                /*
        !          3542:                 * Check type, copy and size fields
        !          3543:                 */
        !          3544:                if (gstart->type.type == MACH_MSG_OOL_DESCRIPTOR) {
        !          3545:                    if (sstart->type.type != MACH_MSG_OOL_DESCRIPTOR)
        !          3546:                        return MACH_RCV_INVALID_TYPE;
        !          3547: 
        !          3548:                    if (sstart->out_of_line.copy == MACH_MSG_OVERWRITE && 
        !          3549:                        gstart->out_of_line.size > sstart->out_of_line.size) {
        !          3550:                        if ((option & MACH_RCV_LARGE) == 0)
        !          3551:                                return MACH_RCV_SCATTER_SMALL;
        !          3552:                        size_error = TRUE;
        !          3553:                    }
        !          3554:                }
        !          3555:                else {
        !          3556:                    if (sstart->type.type != MACH_MSG_OOL_PORTS_DESCRIPTOR)
        !          3557:                        return MACH_RCV_INVALID_TYPE;
        !          3558: 
        !          3559:                    if (sstart->ool_ports.copy == MACH_MSG_OVERWRITE &&
        !          3560:                        gstart->ool_ports.count > sstart->ool_ports.count) {
        !          3561:                        if ((option & MACH_RCV_LARGE) == 0)
        !          3562:                                return MACH_RCV_SCATTER_SMALL;
        !          3563:                        size_error = TRUE;
        !          3564:                    }
        !          3565:                }
        !          3566:                sstart++;
        !          3567:            }
        !          3568:            gstart++;
        !          3569:        }
        !          3570: 
        !          3571:        /*
        !          3572:         * If there is a size error, form a new scatter list from the
        !          3573:         * gather list.
        !          3574:         */
        !          3575:        if (size_error) {
        !          3576:            ipc_kmsg_t          new_list;
        !          3577:            mach_msg_size_t     new_size = (unsigned)gend - (unsigned)gbody;
        !          3578: 
        !          3579:            new_list = ikm_alloc(new_size);
        !          3580:            if (new_list == IKM_NULL)
        !          3581:                return MACH_MSG_VM_KERNEL|MACH_RCV_BODY_ERROR;
        !          3582: 
        !          3583:            new_list->ikm_header = (*list)->ikm_header;
        !          3584:            new_list->ikm_header.msgh_size = new_size;
        !          3585: 
        !          3586:            ikm_free(*list); (*list) = new_list;
        !          3587: 
        !          3588:            /*
        !          3589:             * Now fill in the  descriptor count and the type and size 
        !          3590:             * fields for each descriptor
        !          3591:             */
        !          3592:            sbody = (mach_msg_body_t *)(&new_list->ikm_header + 1);
        !          3593:            sbody->msgh_descriptor_count = gbody->msgh_descriptor_count;
        !          3594:            sstart = (mach_msg_descriptor_t *) (sbody + 1);
        !          3595: 
        !          3596:            gstart = (mach_msg_descriptor_t *) (gbody + 1);
        !          3597:            gend = gstart + gbody->msgh_descriptor_count;
        !          3598: 
        !          3599:            for (; gstart < gend; gstart++, sstart++) {
        !          3600:                sstart->type.type = gstart->type.type;
        !          3601:                switch (gstart->type.type) {
        !          3602:                    case MACH_MSG_PORT_DESCRIPTOR:
        !          3603:                        break;
        !          3604:                    case MACH_MSG_OOL_DESCRIPTOR:
        !          3605:                        sstart->out_of_line.size = gstart->out_of_line.size;
        !          3606:                        break;
        !          3607:                    case MACH_MSG_OOL_PORTS_DESCRIPTOR:
        !          3608:                        sstart->ool_ports.count = gstart->ool_ports.count;
        !          3609:                        break;
        !          3610:                }
        !          3611:            }
        !          3612: 
        !          3613:            return MACH_RCV_SCATTER_SMALL;
        !          3614:        }
        !          3615: 
        !          3616:        return MACH_MSG_SUCCESS;
        !          3617: }
        !          3618: 
        !          3619: /*
        !          3620:  *     Routine:        ipc_kmsg_copyout_to_kernel
        !          3621:  *     Purpose:
        !          3622:  *             Copies out the destination and reply ports in the message.
        !          3623:  *             Leaves all other rights and memory in the message alone.
        !          3624:  *     Conditions:
        !          3625:  *             Nothing locked.
        !          3626:  *
        !          3627:  *     Derived from ipc_kmsg_copyout_dest.
        !          3628:  *     Use by mach_msg_rpc_from_kernel (which used to use copyout_dest).
        !          3629:  *     We really do want to save rights and memory.
        !          3630:  */
        !          3631: 
        !          3632: void
        !          3633: ipc_kmsg_copyout_to_kernel(
        !          3634:        ipc_kmsg_t      kmsg,
        !          3635:        ipc_space_t     space)
        !          3636: {
        !          3637:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          3638:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          3639:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          3640:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          3641:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          3642:        mach_port_t dest_name, reply_name;
        !          3643: 
        !          3644:        assert(IO_VALID(dest));
        !          3645: 
        !          3646:        io_lock(dest);
        !          3647:        if (io_active(dest)) {
        !          3648:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
        !          3649:                /* dest is unlocked */
        !          3650:        } else {
        !          3651:                io_release(dest);
        !          3652:                io_check_unlock(dest);
        !          3653:                dest_name = MACH_PORT_DEAD;
        !          3654:        }
        !          3655: 
        !          3656:        reply_name = (mach_port_t) reply;
        !          3657: 
        !          3658:        kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          3659:                                      MACH_MSGH_BITS(reply_type, dest_type));
        !          3660:        kmsg->ikm_header.msgh_local_port = dest_name;
        !          3661:        kmsg->ikm_header.msgh_remote_port = reply_name;
        !          3662: }
        !          3663: 
        !          3664: #if    MACH_IPC_COMPAT
        !          3665: 
        !          3666: /*
        !          3667:  *     Routine:        ipc_kmsg_copyin_compat
        !          3668:  *     Purpose:
        !          3669:  *             "Copy-in" port rights and out-of-line memory
        !          3670:  *             in the message.
        !          3671:  *
        !          3672:  *             In all failure cases, the message is left holding
        !          3673:  *             no rights or memory.  However, the message buffer
        !          3674:  *             is not deallocated.  If successful, the message
        !          3675:  *             contains a valid destination port.
        !          3676:  *     Conditions:
        !          3677:  *             Nothing locked.
        !          3678:  *     Returns:
        !          3679:  *             MACH_MSG_SUCCESS        Successful copyin.
        !          3680:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
        !          3681:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
        !          3682:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
        !          3683:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
        !          3684:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
        !          3685:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
        !          3686:  */
        !          3687: 
        !          3688: mach_msg_return_t
        !          3689: ipc_kmsg_copyin_compat(kmsg, space, map)
        !          3690:        ipc_kmsg_t kmsg;
        !          3691:        ipc_space_t space;
        !          3692:        vm_map_t map;
        !          3693: {
        !          3694:        msg_header_t msg;
        !          3695:        mach_port_t dest_name;
        !          3696:        mach_port_t reply_name;
        !          3697:        ipc_object_t dest, reply;
        !          3698:        mach_msg_type_name_t dest_type, reply_type;
        !          3699:        vm_offset_t saddr, eaddr;
        !          3700:        boolean_t complex;
        !          3701:        kern_return_t kr;
        !          3702:        boolean_t use_page_lists, steal_pages;
        !          3703: 
        !          3704:        msg = * (msg_header_t *) &kmsg->ikm_header;
        !          3705:        dest_name = (mach_port_t) msg.msg_remote_port;
        !          3706:        reply_name = (mach_port_t) msg.msg_local_port;
        !          3707: 
        !          3708:        /* translate the destination and reply ports */
        !          3709: 
        !          3710:        kr = ipc_object_copyin_header(space, dest_name, &dest, &dest_type);
        !          3711:        if (kr != KERN_SUCCESS)
        !          3712:                return MACH_SEND_INVALID_DEST;
        !          3713: 
        !          3714:        if (reply_name == MACH_PORT_NULL) {
        !          3715:                reply = IO_NULL;
        !          3716:                reply_type = 0;
        !          3717:        } else {
        !          3718:                kr = ipc_object_copyin_header(space, reply_name,
        !          3719:                                              &reply, &reply_type);
        !          3720:                if (kr != KERN_SUCCESS) {
        !          3721:                        ipc_object_destroy(dest, dest_type);
        !          3722:                        return MACH_SEND_INVALID_REPLY;
        !          3723:                }
        !          3724:        }
        !          3725: 
        !          3726:        kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(dest_type, reply_type) |
        !          3727:                        MACH_MSGH_BITS_OLD_FORMAT;
        !          3728:        kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size;
        !          3729:        kmsg->ikm_header.msgh_remote_port = (mach_port_t) dest;
        !          3730:        kmsg->ikm_header.msgh_local_port = (mach_port_t) reply;
        !          3731:        kmsg->ikm_header.msgh_reserved = (mach_port_seqno_t) msg.msg_type;
        !          3732:        kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id;
        !          3733: 
        !          3734:        if (msg.msg_simple)
        !          3735:                return MACH_MSG_SUCCESS;
        !          3736: 
        !          3737:        complex = FALSE;
        !          3738:        use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
        !          3739:        steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
        !          3740: 
        !          3741:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          3742:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
        !          3743: 
        !          3744:        while (saddr < eaddr) {
        !          3745:                vm_offset_t taddr = saddr;
        !          3746:                mach_msg_type_long_t *type;
        !          3747:                mach_msg_type_name_t name;
        !          3748:                mach_msg_type_size_t size;
        !          3749:                mach_msg_type_number_t number;
        !          3750:                boolean_t is_inline, longform, dealloc, is_port;
        !          3751:                vm_offset_t data;
        !          3752:                vm_size_t length;
        !          3753: 
        !          3754:                type = (mach_msg_type_long_t *) saddr;
        !          3755: 
        !          3756:                if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
        !          3757:                    ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
        !          3758:                     ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
        !          3759:                        ipc_kmsg_clean_partial_compat(kmsg, taddr, FALSE, 0);
        !          3760:                        return MACH_SEND_MSG_TOO_SMALL;
        !          3761:                }
        !          3762: 
        !          3763:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          3764:                dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
        !          3765:                if (longform) {
        !          3766:                        /* This must be aligned */
        !          3767:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          3768:                            (is_misaligned(type))) {
        !          3769:                                saddr = ptr_align(saddr);
        !          3770:                                continue;
        !          3771:                        }
        !          3772:                        name = type->msgtl_name;
        !          3773:                        size = type->msgtl_size;
        !          3774:                        number = type->msgtl_number;
        !          3775:                        saddr += sizeof(mach_msg_type_long_t);
        !          3776:                } else {
        !          3777:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          3778:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          3779:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          3780:                        saddr += sizeof(mach_msg_type_t);
        !          3781:                }
        !          3782: 
        !          3783:                is_port = MSG_TYPE_PORT_ANY(name);
        !          3784: 
        !          3785:                if (is_port && (size != PORT_T_SIZE_IN_BITS)) {
        !          3786:                        ipc_kmsg_clean_partial_compat(kmsg, taddr, FALSE, 0);
        !          3787:                        return MACH_SEND_INVALID_TYPE;
        !          3788:                }
        !          3789: 
        !          3790:                /*
        !          3791:                 *      New IPC says these should be zero, but old IPC
        !          3792:                 *      tasks often leave them with random values.  So
        !          3793:                 *      we have to clear them.
        !          3794:                 */
        !          3795: 
        !          3796:                ((mach_msg_type_t*)type)->msgt_unused = 0;
        !          3797:                if (longform) {
        !          3798:                        type->msgtl_header.msgt_name = 0;
        !          3799:                        type->msgtl_header.msgt_size = 0;
        !          3800:                        type->msgtl_header.msgt_number = 0;
        !          3801:                }
        !          3802: 
        !          3803:                /* padding (ptrs and ports) ? */
        !          3804:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          3805:                    ((size >> 3) == sizeof(natural_t)))
        !          3806:                        saddr = ptr_align(saddr);
        !          3807: 
        !          3808:                /* calculate length of data in bytes, rounding up */
        !          3809: 
        !          3810:                length = ((number * size) + 7) >> 3;
        !          3811: 
        !          3812:                if (is_inline) {
        !          3813:                        vm_size_t amount;
        !          3814: 
        !          3815:                        /* inline data sizes round up to int boundaries */
        !          3816: 
        !          3817:                        amount = (length + 3) &~ 3;
        !          3818:                        if ((eaddr - saddr) < amount) {
        !          3819:                                ipc_kmsg_clean_partial_compat(
        !          3820:                                                        kmsg, taddr, FALSE, 0);
        !          3821:                                return MACH_SEND_MSG_TOO_SMALL;
        !          3822:                        }
        !          3823: 
        !          3824:                        data = saddr;
        !          3825:                        saddr += amount;
        !          3826:                } else {
        !          3827:                        vm_offset_t addr;
        !          3828: 
        !          3829:                        if ((eaddr - saddr) < sizeof(vm_offset_t)) {
        !          3830:                                ipc_kmsg_clean_partial_compat(
        !          3831:                                                        kmsg, taddr, FALSE, 0);
        !          3832:                                return MACH_SEND_MSG_TOO_SMALL;
        !          3833:                        }
        !          3834: 
        !          3835:                        /* grab the out-of-line data */
        !          3836: 
        !          3837:                        addr = * (vm_offset_t *) saddr;
        !          3838: 
        !          3839:                        if (length == 0)
        !          3840:                                data = 0;
        !          3841:                        else if (is_port) {
        !          3842:                                data = kalloc(length);
        !          3843:                                if (data == 0)
        !          3844:                                        goto invalid_memory;
        !          3845: 
        !          3846:                                if (copyinmap(map, (char *) addr,
        !          3847:                                              (char *) data, length) ||
        !          3848:                                    (dealloc &&
        !          3849:                                     (vm_deallocate(map, addr, length) !=
        !          3850:                                                        KERN_SUCCESS))) {
        !          3851:                                        kfree(data, length);
        !          3852:                                        goto invalid_memory;
        !          3853:                                }
        !          3854:                        } else {
        !          3855: #if    MACH_OLD_VM_COPY
        !          3856:                                vm_offset_t copy;
        !          3857:                                
        !          3858:                                kr = vm_move(map, addr,
        !          3859:                                                ipc_soft_map, length,
        !          3860:                                                dealloc, &copy);
        !          3861: #else
        !          3862:                                vm_map_copy_t copy;
        !          3863: 
        !          3864:                                if (use_page_lists) {
        !          3865:                                        kr = vm_map_copyin_page_list(map,
        !          3866:                                                addr, length, dealloc,
        !          3867:                                                steal_pages, &copy, FALSE);
        !          3868:                                } else {
        !          3869:                                        kr = vm_map_copyin(map, addr, length,
        !          3870:                                                           dealloc,
        !          3871:                                                           &copy);
        !          3872:                                }
        !          3873: #endif
        !          3874:                                if (kr != KERN_SUCCESS) {
        !          3875:                                    invalid_memory:
        !          3876:                                        ipc_kmsg_clean_partial_compat(
        !          3877:                                                        kmsg, taddr, FALSE, 0);
        !          3878:                                        return MACH_SEND_INVALID_MEMORY;
        !          3879:                                }
        !          3880: 
        !          3881:                                data = (vm_offset_t) copy;
        !          3882:                        }
        !          3883: 
        !          3884:                        * (vm_offset_t *) saddr = data;
        !          3885:                        saddr += sizeof(vm_offset_t);
        !          3886:                        complex = TRUE;
        !          3887:                }
        !          3888: 
        !          3889:                if (is_port) {
        !          3890:                        mach_msg_type_name_t newname =
        !          3891:                                        ipc_object_copyin_type(name);
        !          3892:                        ipc_object_t *objects = (ipc_object_t *) data;
        !          3893:                        mach_msg_type_number_t i;
        !          3894: 
        !          3895:                        if (longform)
        !          3896:                                type->msgtl_name = newname;
        !          3897:                        else
        !          3898:                                ((mach_msg_type_t*)type)->msgt_name = newname;
        !          3899: 
        !          3900:                        for (i = 0; i < number; i++) {
        !          3901:                                mach_port_t port = (mach_port_t) objects[i];
        !          3902:                                ipc_object_t object;
        !          3903: 
        !          3904:                                if (!MACH_PORT_VALID(port))
        !          3905:                                        continue;
        !          3906: 
        !          3907:                                kr = ipc_object_copyin_compat(space, port,
        !          3908:                                                name, dealloc, &object);
        !          3909:                                if (kr != KERN_SUCCESS) {
        !          3910:                                        ipc_kmsg_clean_partial_compat(
        !          3911:                                                        kmsg, taddr, TRUE, i);
        !          3912:                                        return MACH_SEND_INVALID_RIGHT;
        !          3913:                                }
        !          3914: 
        !          3915:                                if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          3916:                                    ipc_port_check_circularity(
        !          3917:                                                        (ipc_port_t) object,
        !          3918:                                                        (ipc_port_t) dest))
        !          3919:                                        kmsg->ikm_header.msgh_bits |=
        !          3920:                                                MACH_MSGH_BITS_CIRCULAR;
        !          3921: 
        !          3922:                                objects[i] = object;
        !          3923:                        }
        !          3924: 
        !          3925:                        complex = TRUE;
        !          3926:                }
        !          3927:        }
        !          3928: 
        !          3929:        if (complex)
        !          3930:                kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
        !          3931: 
        !          3932:        return MACH_MSG_SUCCESS;
        !          3933: }
        !          3934: 
        !          3935: void
        !          3936: ipc_kmsg_copyin_compat_from_kernel(kmsg)
        !          3937:        ipc_kmsg_t kmsg;
        !          3938: {
        !          3939:        msg_header_t msg;
        !          3940:        ipc_object_t remote, local;
        !          3941:        mach_msg_type_name_t rname, lname;
        !          3942:        vm_offset_t saddr, eaddr;
        !          3943:        boolean_t complex;
        !          3944: 
        !          3945:        msg = * (msg_header_t *) &kmsg->ikm_header;
        !          3946:        remote = (ipc_object_t) msg.msg_remote_port;
        !          3947:        rname = MACH_MSG_TYPE_COPY_SEND;
        !          3948:        local = (ipc_object_t) msg.msg_local_port;
        !          3949:        lname = MACH_MSG_TYPE_MAKE_SEND;
        !          3950: 
        !          3951:        /* translate the destination and reply ports */
        !          3952: 
        !          3953:        ipc_object_copyin_from_kernel(remote, rname);
        !          3954:        if (IO_VALID(local))
        !          3955:                ipc_object_copyin_from_kernel(local, lname);
        !          3956: 
        !          3957:        kmsg->ikm_header.msgh_bits =
        !          3958:                        MACH_MSGH_BITS(
        !          3959:                                ipc_object_copyin_type(rname),
        !          3960:                                ipc_object_copyin_type(lname)) |
        !          3961:                        MACH_MSGH_BITS_OLD_FORMAT;
        !          3962:        kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size;
        !          3963:        kmsg->ikm_header.msgh_remote_port = (mach_port_t) remote;
        !          3964:        kmsg->ikm_header.msgh_local_port = (mach_port_t) local;
        !          3965:        kmsg->ikm_header.msgh_reserved = (mach_port_seqno_t) msg.msg_type;
        !          3966:        kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id;
        !          3967: 
        !          3968:        if (msg.msg_simple)
        !          3969:                return;
        !          3970: 
        !          3971:        complex = FALSE;
        !          3972: 
        !          3973:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          3974:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
        !          3975: 
        !          3976:        while (saddr < eaddr) {
        !          3977:                mach_msg_type_long_t *type;
        !          3978:                mach_msg_type_name_t name;
        !          3979:                mach_msg_type_size_t size;
        !          3980:                mach_msg_type_number_t number;
        !          3981:                boolean_t is_inline, longform, is_port;
        !          3982:                vm_offset_t data;
        !          3983:                vm_size_t length;
        !          3984: 
        !          3985:                type = (mach_msg_type_long_t *) saddr;
        !          3986:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          3987:                longform = ((mach_msg_type_t*)type)->msgt_longform;
        !          3988:                /* type->msgtl_header.msgt_deallocate not used */
        !          3989:                if (longform) {
        !          3990:                        /* This must be aligned */
        !          3991:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          3992:                            (is_misaligned(type))) {
        !          3993:                                saddr = ptr_align(saddr);
        !          3994:                                continue;
        !          3995:                        }
        !          3996:                        name = type->msgtl_name;
        !          3997:                        size = type->msgtl_size;
        !          3998:                        number = type->msgtl_number;
        !          3999:                        saddr += sizeof(mach_msg_type_long_t);
        !          4000:                } else {
        !          4001:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          4002:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          4003:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          4004:                        saddr += sizeof(mach_msg_type_t);
        !          4005:                }
        !          4006: 
        !          4007:                is_port = MSG_TYPE_PORT_ANY(name);
        !          4008: 
        !          4009:                /*
        !          4010:                 *      New IPC says these should be zero, but old IPC
        !          4011:                 *      tasks often leave them with random values.  So
        !          4012:                 *      we have to clear them.
        !          4013:                 */
        !          4014: 
        !          4015:                ((mach_msg_type_t*)type)->msgt_unused = 0;
        !          4016:                if (longform) {
        !          4017:                        type->msgtl_header.msgt_name = 0;
        !          4018:                        type->msgtl_header.msgt_size = 0;
        !          4019:                        type->msgtl_header.msgt_number = 0;
        !          4020:                }
        !          4021: 
        !          4022:                /* padding (ptrs and ports) ? */
        !          4023:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          4024:                    ((size >> 3) == sizeof(natural_t)))
        !          4025:                        saddr = ptr_align(saddr);
        !          4026: 
        !          4027:                /* calculate length of data in bytes, rounding up */
        !          4028: 
        !          4029:                length = ((number * size) + 7) >> 3;
        !          4030: 
        !          4031:                if (is_inline) {
        !          4032:                        /* inline data sizes round up to int boundaries */
        !          4033: 
        !          4034:                        data = saddr;
        !          4035:                        saddr += (length + 3) &~ 3;
        !          4036:                } else {
        !          4037:                        /*
        !          4038:                         *      The sender should supply ready-made memory
        !          4039:                         *      for us, so we don't need to do anything.
        !          4040:                         */
        !          4041: 
        !          4042:                        data = * (vm_offset_t *) saddr;
        !          4043:                        saddr += sizeof(vm_offset_t);
        !          4044:                        complex = TRUE;
        !          4045:                }
        !          4046: 
        !          4047:                if (is_port) {
        !          4048:                        mach_msg_type_name_t newname =
        !          4049:                                        ipc_object_copyin_type(name);
        !          4050:                        ipc_object_t *objects = (ipc_object_t *) data;
        !          4051:                        mach_msg_type_number_t i;
        !          4052: 
        !          4053:                        if (longform)
        !          4054:                                type->msgtl_name = newname;
        !          4055:                        else
        !          4056:                                ((mach_msg_type_t*)type)->msgt_name = newname;
        !          4057: 
        !          4058:                        for (i = 0; i < number; i++) {
        !          4059:                                ipc_object_t object = objects[i];
        !          4060: 
        !          4061:                                if (!IO_VALID(object))
        !          4062:                                        continue;
        !          4063: 
        !          4064:                                ipc_object_copyin_from_kernel(object, name);
        !          4065: 
        !          4066:                                if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          4067:                                    ipc_port_check_circularity(
        !          4068:                                                        (ipc_port_t) object,
        !          4069:                                                        (ipc_port_t) remote))
        !          4070:                                        kmsg->ikm_header.msgh_bits |=
        !          4071:                                                MACH_MSGH_BITS_CIRCULAR;
        !          4072:                        }
        !          4073: 
        !          4074:                        complex = TRUE;
        !          4075:                }
        !          4076:        }
        !          4077: 
        !          4078:        if (complex)
        !          4079:                kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
        !          4080: }
        !          4081: 
        !          4082: /*
        !          4083:  *     Routine:        ipc_kmsg_copyout_compat
        !          4084:  *     Purpose:
        !          4085:  *             "Copy-out" port rights and out-of-line memory
        !          4086:  *             in the message, producing an old IPC message.
        !          4087:  *
        !          4088:  *             Doesn't bother to handle the header atomically.
        !          4089:  *             Skips over errors.  Problem ports produce MACH_PORT_NULL
        !          4090:  *             (MACH_PORT_DEAD is never produced), and problem memory
        !          4091:  *             produces a zero address.
        !          4092:  *     Conditions:
        !          4093:  *             Nothing locked.
        !          4094:  *     Returns:
        !          4095:  *             MACH_MSG_SUCCESS        Copied out rights and memory.
        !          4096:  */
        !          4097: 
        !          4098: mach_msg_return_t
        !          4099: ipc_kmsg_copyout_compat(kmsg, space, map)
        !          4100:        ipc_kmsg_t kmsg;
        !          4101:        ipc_space_t space;
        !          4102:        vm_map_t map;
        !          4103: {
        !          4104:        msg_header_t msg;
        !          4105:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          4106:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          4107:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          4108:        mach_port_t dest_name, reply_name;
        !          4109:        vm_offset_t saddr, eaddr;
        !          4110:        kern_return_t kr;
        !          4111: 
        !          4112:        assert(IO_VALID(dest));
        !          4113: 
        !          4114:        io_lock(dest);
        !          4115:        if (io_active(dest)) {
        !          4116:                mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          4117: 
        !          4118:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
        !          4119:                /* dest is unlocked */
        !          4120:        } else {
        !          4121:                io_release(dest);
        !          4122:                io_check_unlock(dest);
        !          4123:                dest_name = MACH_PORT_NULL;
        !          4124:        }
        !          4125: 
        !          4126:        if (IO_VALID(reply)) {
        !          4127:                mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          4128: 
        !          4129:                kr = ipc_object_copyout_compat(space, reply, reply_type,
        !          4130:                                               &reply_name);
        !          4131:                if (kr != KERN_SUCCESS) {
        !          4132:                        ipc_object_destroy(reply, reply_type);
        !          4133:                        reply_name = MACH_PORT_NULL;
        !          4134:                }
        !          4135:        } else
        !          4136:                reply_name = MACH_PORT_NULL;
        !          4137: 
        !          4138:        msg.msg_unused = 0;
        !          4139:        msg.msg_simple = (mbits & MACH_MSGH_BITS_COMPLEX) ? FALSE : TRUE;
        !          4140:        msg.msg_size = (msg_size_t) kmsg->ikm_header.msgh_size;
        !          4141:        msg.msg_type = (integer_t) kmsg->ikm_header.msgh_reserved;
        !          4142:        msg.msg_local_port = (port_name_t) dest_name;
        !          4143:        msg.msg_remote_port = (port_name_t) reply_name;
        !          4144:        msg.msg_id = (integer_t) kmsg->ikm_header.msgh_id;
        !          4145:        * (msg_header_t *) &kmsg->ikm_header = msg;
        !          4146: 
        !          4147:        if (msg.msg_simple)
        !          4148:                return MACH_MSG_SUCCESS;
        !          4149: 
        !          4150:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          4151:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
        !          4152: 
        !          4153:        while (saddr < eaddr) {
        !          4154:                vm_offset_t taddr = saddr;
        !          4155:                mach_msg_type_long_t *type;
        !          4156:                mach_msg_type_name_t name;
        !          4157:                mach_msg_type_size_t size;
        !          4158:                mach_msg_type_number_t number;
        !          4159:                boolean_t is_inline, longform, is_port;
        !          4160:                vm_size_t length;
        !          4161:                vm_offset_t addr;
        !          4162: 
        !          4163:                type = (mach_msg_type_long_t *) saddr;
        !          4164:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          4165:                longform = ((mach_msg_type_t*)type)->msgt_longform;
        !          4166:                if (longform) {
        !          4167:                        /* This must be aligned */
        !          4168:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          4169:                            (is_misaligned(type))) {
        !          4170:                                saddr = ptr_align(saddr);
        !          4171:                                continue;
        !          4172:                        }
        !          4173:                        name = type->msgtl_name;
        !          4174:                        size = type->msgtl_size;
        !          4175:                        number = type->msgtl_number;
        !          4176:                        saddr += sizeof(mach_msg_type_long_t);
        !          4177:                } else {
        !          4178:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          4179:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          4180:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          4181:                        saddr += sizeof(mach_msg_type_t);
        !          4182:                }
        !          4183: 
        !          4184:                /* padding (ptrs and ports) ? */
        !          4185:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          4186:                    ((size >> 3) == sizeof(natural_t)))
        !          4187:                        saddr = ptr_align(saddr);
        !          4188: 
        !          4189:                /* calculate length of data in bytes, rounding up */
        !          4190: 
        !          4191:                length = ((number * size) + 7) >> 3;
        !          4192: 
        !          4193:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !          4194: 
        !          4195:                if (is_port) {
        !          4196:                        mach_port_t *objects;
        !          4197:                        mach_msg_type_number_t i;
        !          4198:                        mach_msg_type_name_t newname;
        !          4199: 
        !          4200:                        if (!is_inline && (length != 0)) {
        !          4201:                                /* first allocate memory in the map */
        !          4202: 
        !          4203:                                kr = vm_allocate(map, &addr, length, TRUE);
        !          4204:                                if (kr != KERN_SUCCESS) {
        !          4205:                                        ipc_kmsg_clean_body_compat(
        !          4206:                                                                taddr, saddr);
        !          4207:                                        goto vm_copyout_failure;
        !          4208:                                }
        !          4209:                        }
        !          4210: 
        !          4211:                        newname = ipc_object_copyout_type_compat(name);
        !          4212:                        if (longform)
        !          4213:                                type->msgtl_name = newname;
        !          4214:                        else
        !          4215:                                ((mach_msg_type_t*)type)->msgt_name = newname;
        !          4216: 
        !          4217:                        objects = (mach_port_t *)
        !          4218:                                (is_inline ? saddr : * (vm_offset_t *) saddr);
        !          4219: 
        !          4220:                        /* copyout port rights carried in the message */
        !          4221: 
        !          4222:                        for (i = 0; i < number; i++) {
        !          4223:                                ipc_object_t object =
        !          4224:                                        (ipc_object_t) objects[i];
        !          4225: 
        !          4226:                                if (!IO_VALID(object)) {
        !          4227:                                        objects[i] = MACH_PORT_NULL;
        !          4228:                                        continue;
        !          4229:                                }
        !          4230: 
        !          4231:                                kr = ipc_object_copyout_compat(space, object,
        !          4232:                                                        name, &objects[i]);
        !          4233:                                if (kr != KERN_SUCCESS) {
        !          4234:                                        ipc_object_destroy(object, name);
        !          4235:                                        objects[i] = MACH_PORT_NULL;
        !          4236:                                }
        !          4237:                        }
        !          4238:                }
        !          4239: 
        !          4240:                if (is_inline) {
        !          4241:                        /* inline data sizes round up to int boundaries */
        !          4242: 
        !          4243:                        saddr += (length + 3) &~ 3;
        !          4244:                } else {
        !          4245:                        vm_offset_t data = * (vm_offset_t *) saddr;
        !          4246: 
        !          4247:                        /* copyout memory carried in the message */
        !          4248: 
        !          4249:                        if (length == 0) {
        !          4250:                                assert(data == 0);
        !          4251:                                addr = 0;
        !          4252:                        } else if (is_port) {
        !          4253:                                /* copyout to memory allocated above */
        !          4254: 
        !          4255:                                (void) copyoutmap(map, (char *) data,
        !          4256:                                                  (char *) addr, length);
        !          4257:                                kfree(data, length);
        !          4258:                        } else {
        !          4259: #if    MACH_OLD_VM_COPY
        !          4260:                                kr = vm_move(
        !          4261:                                        ipc_soft_map, data,
        !          4262:                                        map, length,
        !          4263:                                        FALSE, &addr);
        !          4264:                                (void) vm_deallocate(
        !          4265:                                                ipc_soft_map, data, length);
        !          4266:                                if (kr != KERN_SUCCESS) {
        !          4267: #else
        !          4268:                                vm_map_copy_t copy = (vm_map_copy_t) data;
        !          4269: 
        !          4270:                                kr = vm_map_copyout(map, &addr, copy);
        !          4271:                                if (kr != KERN_SUCCESS) {
        !          4272:                                        vm_map_copy_discard(copy);
        !          4273: #endif
        !          4274: 
        !          4275:                                    vm_copyout_failure:
        !          4276: 
        !          4277:                                        addr = 0;
        !          4278:                                }
        !          4279:                        }
        !          4280: 
        !          4281:                        * (vm_offset_t *) saddr = addr;
        !          4282:                        saddr += sizeof(vm_offset_t);
        !          4283:                }
        !          4284:        }
        !          4285: 
        !          4286:        return MACH_MSG_SUCCESS;
        !          4287: }
        !          4288: 
        !          4289: #endif MACH_IPC_COMPAT

unix.superglobalmegacorp.com

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