Annotation of kernel/ipc/ipc_kmsg.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * 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.