Annotation of Gnu-Mach/ipc/ipc_kmsg.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
                      4:  * Copyright (c) 1993,1994 The University of Utah and
                      5:  * the Computer Systems Laboratory (CSL).
                      6:  * All rights reserved.
                      7:  *
                      8:  * Permission to use, copy, modify and distribute this software and its
                      9:  * documentation is hereby granted, provided that both the copyright
                     10:  * notice and this permission notice appear in all copies of the
                     11:  * software, derivative works or modified versions, and any portions
                     12:  * thereof, and that both notices appear in supporting documentation.
                     13:  *
                     14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
                     15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
                     16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
                     17:  * THIS SOFTWARE.
                     18:  *
                     19:  * Carnegie Mellon requests users of this software to return to
                     20:  *
                     21:  *  Software Distribution Coordinator  or  [email protected]
                     22:  *  School of Computer Science
                     23:  *  Carnegie Mellon University
                     24:  *  Pittsburgh PA 15213-3890
                     25:  *
                     26:  * any improvements or extensions that they make and grant Carnegie Mellon
                     27:  * the rights to redistribute these changes.
                     28:  */
                     29: /*
                     30:  *     File:   ipc/ipc_kmsg.c
                     31:  *     Author: Rich Draves
                     32:  *     Date:   1989
                     33:  *
                     34:  *     Operations on kernel messages.
                     35:  */
                     36: 
1.1.1.3   root       37: #include <kern/printf.h>
                     38: #include <string.h>
1.1       root       39: 
                     40: #include <mach/boolean.h>
                     41: #include <mach/kern_return.h>
                     42: #include <mach/message.h>
                     43: #include <mach/port.h>
1.1.1.3   root       44: #include <machine/locore.h>
1.1       root       45: #include <kern/assert.h>
                     46: #include <kern/kalloc.h>
                     47: #include <vm/vm_map.h>
                     48: #include <vm/vm_object.h>
                     49: #include <vm/vm_kern.h>
1.1.1.3   root       50: #include <vm/vm_user.h>
1.1       root       51: #include <ipc/port.h>
                     52: #include <ipc/ipc_entry.h>
1.1.1.3   root       53: #include <ipc/ipc_hash.h>
1.1       root       54: #include <ipc/ipc_kmsg.h>
                     55: #include <ipc/ipc_thread.h>
                     56: #include <ipc/ipc_marequest.h>
                     57: #include <ipc/ipc_notify.h>
                     58: #include <ipc/ipc_object.h>
                     59: #include <ipc/ipc_space.h>
                     60: #include <ipc/ipc_port.h>
                     61: #include <ipc/ipc_right.h>
                     62: 
                     63: #include <ipc/ipc_machdep.h>
                     64: 
1.1.1.3   root       65: #include <device/net_io.h>
                     66: 
                     67: #if MACH_KDB
                     68: #include <ddb/db_output.h>
                     69: #include <ipc/ipc_print.h>
                     70: #endif
                     71: 
1.1       root       72: #define is_misaligned(x)       ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
                     73: #define ptr_align(x)   \
                     74:        ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
                     75: 
                     76: ipc_kmsg_t ipc_kmsg_cache[NCPUS];
                     77: 
                     78: /*
                     79:  *     Routine:        ipc_kmsg_enqueue
                     80:  *     Purpose:
                     81:  *             Enqueue a kmsg.
                     82:  */
                     83: 
                     84: void
                     85: ipc_kmsg_enqueue(
                     86:        ipc_kmsg_queue_t        queue,
                     87:        ipc_kmsg_t              kmsg)
                     88: {
                     89:        ipc_kmsg_enqueue_macro(queue, kmsg);
                     90: }
                     91: 
                     92: /*
                     93:  *     Routine:        ipc_kmsg_dequeue
                     94:  *     Purpose:
                     95:  *             Dequeue and return a kmsg.
                     96:  */
                     97: 
                     98: ipc_kmsg_t
                     99: ipc_kmsg_dequeue(
                    100:        ipc_kmsg_queue_t        queue)
                    101: {
                    102:        ipc_kmsg_t first;
                    103: 
                    104:        first = ipc_kmsg_queue_first(queue);
                    105: 
                    106:        if (first != IKM_NULL)
                    107:                ipc_kmsg_rmqueue_first_macro(queue, first);
                    108: 
                    109:        return first;
                    110: }
                    111: 
                    112: /*
                    113:  *     Routine:        ipc_kmsg_rmqueue
                    114:  *     Purpose:
                    115:  *             Pull a kmsg out of a queue.
                    116:  */
                    117: 
                    118: void
                    119: ipc_kmsg_rmqueue(
                    120:        ipc_kmsg_queue_t        queue,
                    121:        ipc_kmsg_t              kmsg)
                    122: {
                    123:        ipc_kmsg_t next, prev;
                    124: 
                    125:        assert(queue->ikmq_base != IKM_NULL);
                    126: 
                    127:        next = kmsg->ikm_next;
                    128:        prev = kmsg->ikm_prev;
                    129: 
                    130:        if (next == kmsg) {
                    131:                assert(prev == kmsg);
                    132:                assert(queue->ikmq_base == kmsg);
                    133: 
                    134:                queue->ikmq_base = IKM_NULL;
                    135:        } else {
                    136:                if (queue->ikmq_base == kmsg)
                    137:                        queue->ikmq_base = next;
                    138: 
                    139:                next->ikm_prev = prev;
                    140:                prev->ikm_next = next;
                    141:        }
1.1.1.4 ! root      142:        ikm_mark_bogus (kmsg);
1.1       root      143: }
                    144: 
                    145: /*
                    146:  *     Routine:        ipc_kmsg_queue_next
                    147:  *     Purpose:
                    148:  *             Return the kmsg following the given kmsg.
                    149:  *             (Or IKM_NULL if it is the last one in the queue.)
                    150:  */
                    151: 
                    152: ipc_kmsg_t
                    153: ipc_kmsg_queue_next(
                    154:        ipc_kmsg_queue_t        queue,
                    155:        ipc_kmsg_t              kmsg)
                    156: {
                    157:        ipc_kmsg_t next;
                    158: 
                    159:        assert(queue->ikmq_base != IKM_NULL);
                    160: 
                    161:        next = kmsg->ikm_next;
                    162:        if (queue->ikmq_base == next)
                    163:                next = IKM_NULL;
                    164: 
                    165:        return next;
                    166: }
                    167: 
                    168: /*
                    169:  *     Routine:        ipc_kmsg_destroy
                    170:  *     Purpose:
                    171:  *             Destroys a kernel message.  Releases all rights,
                    172:  *             references, and memory held by the message.
                    173:  *             Frees the message.
                    174:  *     Conditions:
                    175:  *             No locks held.
                    176:  */
                    177: 
                    178: void
                    179: ipc_kmsg_destroy(
                    180:        ipc_kmsg_t      kmsg)
                    181: {
                    182:        ipc_kmsg_queue_t queue;
                    183:        boolean_t empty;
                    184: 
                    185:        /*
                    186:         *      ipc_kmsg_clean can cause more messages to be destroyed.
                    187:         *      Curtail recursion by queueing messages.  If a message
                    188:         *      is already queued, then this is a recursive call.
                    189:         */
                    190: 
                    191:        queue = &current_thread()->ith_messages;
                    192:        empty = ipc_kmsg_queue_empty(queue);
                    193:        ipc_kmsg_enqueue(queue, kmsg);
                    194: 
                    195:        if (empty) {
                    196:                /* must leave kmsg in queue while cleaning it */
                    197: 
                    198:                while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
                    199:                        ipc_kmsg_clean(kmsg);
                    200:                        ipc_kmsg_rmqueue(queue, kmsg);
                    201:                        ikm_free(kmsg);
                    202:                }
                    203:        }
                    204: }
                    205: 
                    206: /*
                    207:  *     Routine:        ipc_kmsg_clean_body
                    208:  *     Purpose:
                    209:  *             Cleans the body of a kernel message.
                    210:  *             Releases all rights, references, and memory.
                    211:  *
                    212:  *             The last type/data pair might stretch past eaddr.
                    213:  *             (See the usage in ipc_kmsg_copyout.)
                    214:  *     Conditions:
                    215:  *             No locks held.
                    216:  */
                    217: 
                    218: void
1.1.1.4 ! root      219: ipc_kmsg_clean_body(
        !           220:        vm_offset_t saddr,
        !           221:        vm_offset_t eaddr)
1.1       root      222: {
                    223:        while (saddr < eaddr) {
                    224:                mach_msg_type_long_t *type;
                    225:                mach_msg_type_name_t name;
                    226:                mach_msg_type_size_t size;
                    227:                mach_msg_type_number_t number;
                    228:                boolean_t is_inline, is_port;
                    229:                vm_size_t length;
                    230: 
                    231:                type = (mach_msg_type_long_t *) saddr;
                    232:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
                    233:                if (((mach_msg_type_t*)type)->msgt_longform) {
                    234:                        /* This must be aligned */
                    235:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                    236:                            (is_misaligned(type))) {
                    237:                                saddr = ptr_align(saddr);
                    238:                                continue;
                    239:                        }
                    240:                        name = type->msgtl_name;
                    241:                        size = type->msgtl_size;
                    242:                        number = type->msgtl_number;
                    243:                        saddr += sizeof(mach_msg_type_long_t);
                    244:                } else {
                    245:                        name = ((mach_msg_type_t*)type)->msgt_name;
                    246:                        size = ((mach_msg_type_t*)type)->msgt_size;
                    247:                        number = ((mach_msg_type_t*)type)->msgt_number;
                    248:                        saddr += sizeof(mach_msg_type_t);
                    249:                }
                    250: 
                    251:                /* padding (ptrs and ports) ? */
                    252:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                    253:                    ((size >> 3) == sizeof(natural_t)))
                    254:                        saddr = ptr_align(saddr);
                    255: 
                    256:                /* calculate length of data in bytes, rounding up */
                    257: 
                    258:                length = ((number * size) + 7) >> 3;
                    259: 
                    260:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
                    261: 
                    262:                if (is_port) {
                    263:                        ipc_object_t *objects;
                    264:                        mach_msg_type_number_t i;
                    265: 
                    266:                        if (is_inline) {
                    267:                                objects = (ipc_object_t *) saddr;
                    268:                                /* sanity check */
                    269:                                while (eaddr < (vm_offset_t)&objects[number]) number--;
                    270:                        } else {
                    271:                                objects = (ipc_object_t *)
                    272:                                                * (vm_offset_t *) saddr;
                    273:                        }
                    274: 
                    275:                        /* destroy port rights carried in the message */
                    276: 
                    277:                        for (i = 0; i < number; i++) {
                    278:                                ipc_object_t object = objects[i];
                    279: 
                    280:                                if (!IO_VALID(object))
                    281:                                        continue;
                    282: 
                    283:                                ipc_object_destroy(object, name);
                    284:                        }
                    285:                }
                    286: 
                    287:                if (is_inline) {
                    288:                        /* inline data sizes round up to int boundaries */
                    289: 
                    290:                        saddr += (length + 3) &~ 3;
                    291:                } else {
                    292:                        vm_offset_t data = * (vm_offset_t *) saddr;
                    293: 
                    294:                        /* destroy memory carried in the message */
                    295: 
                    296:                        if (length == 0)
                    297:                                assert(data == 0);
                    298:                        else if (is_port)
                    299:                                kfree(data, length);
                    300:                        else
                    301:                                vm_map_copy_discard((vm_map_copy_t) data);
                    302: 
                    303:                        saddr += sizeof(vm_offset_t);
                    304:                }
                    305:        }
                    306: }
                    307: 
                    308: /*
                    309:  *     Routine:        ipc_kmsg_clean
                    310:  *     Purpose:
                    311:  *             Cleans a kernel message.  Releases all rights,
                    312:  *             references, and memory held by the message.
                    313:  *     Conditions:
                    314:  *             No locks held.
                    315:  */
                    316: 
                    317: void
1.1.1.4 ! root      318: ipc_kmsg_clean(ipc_kmsg_t kmsg)
1.1       root      319: {
                    320:        ipc_marequest_t marequest;
                    321:        ipc_object_t object;
                    322:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                    323: 
                    324:        marequest = kmsg->ikm_marequest;
                    325:        if (marequest != IMAR_NULL)
                    326:                ipc_marequest_destroy(marequest);
                    327: 
                    328:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                    329:        if (IO_VALID(object))
                    330:                ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
                    331: 
                    332:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                    333:        if (IO_VALID(object))
                    334:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
                    335: 
                    336:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                    337:                vm_offset_t saddr, eaddr;
                    338: 
                    339:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
                    340:                eaddr = (vm_offset_t) &kmsg->ikm_header +
                    341:                                kmsg->ikm_header.msgh_size;
                    342: 
                    343:                ipc_kmsg_clean_body(saddr, eaddr);
                    344:        }
                    345: }
                    346: 
                    347: /*
                    348:  *     Routine:        ipc_kmsg_clean_partial
                    349:  *     Purpose:
                    350:  *             Cleans a partially-acquired kernel message.
                    351:  *             eaddr is the address of the type specification
                    352:  *             in the body of the message that contained the error.
                    353:  *             If dolast, the memory and port rights in this last
                    354:  *             type spec are also cleaned.  In that case, number
                    355:  *             specifies the number of port rights to clean.
                    356:  *     Conditions:
                    357:  *             Nothing locked.
                    358:  */
                    359: 
                    360: void
1.1.1.4 ! root      361: ipc_kmsg_clean_partial(
        !           362:        ipc_kmsg_t              kmsg,
        !           363:        vm_offset_t             eaddr,
        !           364:        boolean_t               dolast,
        !           365:        mach_msg_type_number_t  number)
1.1       root      366: {
                    367:        ipc_object_t object;
                    368:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                    369:        vm_offset_t saddr;
                    370: 
                    371:        assert(kmsg->ikm_marequest == IMAR_NULL);
                    372: 
                    373:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                    374:        assert(IO_VALID(object));
                    375:        ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
                    376: 
                    377:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                    378:        if (IO_VALID(object))
                    379:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
                    380: 
                    381:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
                    382:        ipc_kmsg_clean_body(saddr, eaddr);
                    383: 
                    384:        if (dolast) {
                    385:                mach_msg_type_long_t *type;
                    386:                mach_msg_type_name_t name;
                    387:                mach_msg_type_size_t size;
                    388:                mach_msg_type_number_t rnumber;
                    389:                boolean_t is_inline, is_port;
                    390:                vm_size_t length;
                    391: 
                    392: xxx:           type = (mach_msg_type_long_t *) eaddr;
                    393:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
                    394:                if (((mach_msg_type_t*)type)->msgt_longform) {
                    395:                        /* This must be aligned */
                    396:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                    397:                            (is_misaligned(type))) {
                    398:                                eaddr = ptr_align(eaddr);
                    399:                                goto xxx;
                    400:                        }
                    401:                        name = type->msgtl_name;
                    402:                        size = type->msgtl_size;
                    403:                        rnumber = type->msgtl_number;
                    404:                        eaddr += sizeof(mach_msg_type_long_t);
                    405:                } else {
                    406:                        name = ((mach_msg_type_t*)type)->msgt_name;
                    407:                        size = ((mach_msg_type_t*)type)->msgt_size;
                    408:                        rnumber = ((mach_msg_type_t*)type)->msgt_number;
                    409:                        eaddr += sizeof(mach_msg_type_t);
                    410:                }
                    411: 
                    412:                /* padding (ptrs and ports) ? */
                    413:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                    414:                    ((size >> 3) == sizeof(natural_t)))
                    415:                        eaddr = ptr_align(eaddr);
                    416: 
                    417:                /* calculate length of data in bytes, rounding up */
                    418: 
                    419:                length = ((rnumber * size) + 7) >> 3;
                    420: 
                    421:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
                    422: 
                    423:                if (is_port) {
                    424:                        ipc_object_t *objects;
                    425:                        mach_msg_type_number_t i;
                    426: 
                    427:                        objects = (ipc_object_t *)
                    428:                                (is_inline ? eaddr : * (vm_offset_t *) eaddr);
                    429: 
                    430:                        /* destroy port rights carried in the message */
                    431: 
                    432:                        for (i = 0; i < number; i++) {
                    433:                                ipc_object_t obj = objects[i];
                    434: 
                    435:                                if (!IO_VALID(obj))
                    436:                                        continue;
                    437: 
                    438:                                ipc_object_destroy(obj, name);
                    439:                        }
                    440:                }
                    441: 
                    442:                if (!is_inline) {
                    443:                        vm_offset_t data = * (vm_offset_t *) eaddr;
                    444: 
                    445:                        /* destroy memory carried in the message */
                    446: 
                    447:                        if (length == 0)
                    448:                                assert(data == 0);
                    449:                        else if (is_port)
                    450:                                kfree(data, length);
                    451:                        else
                    452:                                vm_map_copy_discard((vm_map_copy_t) data);
                    453:                }
                    454:        }
                    455: }
                    456: 
                    457: /*
                    458:  *     Routine:        ipc_kmsg_free
                    459:  *     Purpose:
                    460:  *             Free a kernel message buffer.
                    461:  *     Conditions:
                    462:  *             Nothing locked.
                    463:  */
                    464: 
                    465: void
1.1.1.4 ! root      466: ipc_kmsg_free(ipc_kmsg_t kmsg)
1.1       root      467: {
                    468:        vm_size_t size = kmsg->ikm_size;
                    469: 
                    470:        switch (size) {
                    471: 
                    472:            case IKM_SIZE_NETWORK:
                    473:                /* return it to the network code */
                    474:                net_kmsg_put(kmsg);
                    475:                break;
                    476: 
                    477:            default:
                    478:                kfree((vm_offset_t) kmsg, size);
                    479:                break;
                    480:        }
                    481: }
                    482: 
                    483: /*
                    484:  *     Routine:        ipc_kmsg_get
                    485:  *     Purpose:
                    486:  *             Allocates a kernel message buffer.
                    487:  *             Copies a user message to the message buffer.
                    488:  *     Conditions:
                    489:  *             Nothing locked.
                    490:  *     Returns:
                    491:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
                    492:  *             MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
                    493:  *             MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
                    494:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
                    495:  *             MACH_SEND_INVALID_DATA  Couldn't copy message data.
                    496:  */
                    497: 
                    498: mach_msg_return_t
1.1.1.4 ! root      499: ipc_kmsg_get(
        !           500:        mach_msg_header_t       *msg,
        !           501:        mach_msg_size_t         size,
        !           502:        ipc_kmsg_t              *kmsgp)
1.1       root      503: {
                    504:        ipc_kmsg_t kmsg;
                    505: 
                    506:        if ((size < sizeof(mach_msg_header_t)) || (size & 3))
                    507:                return MACH_SEND_MSG_TOO_SMALL;
                    508: 
                    509:        if (size <= IKM_SAVED_MSG_SIZE) {
                    510:                kmsg = ikm_cache();
                    511:                if (kmsg != IKM_NULL) {
                    512:                        ikm_cache() = IKM_NULL;
                    513:                        ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
                    514:                } else {
                    515:                        kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
                    516:                        if (kmsg == IKM_NULL)
                    517:                                return MACH_SEND_NO_BUFFER;
                    518:                        ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
                    519:                }
                    520:        } else {
                    521:                kmsg = ikm_alloc(size);
                    522:                if (kmsg == IKM_NULL)
                    523:                        return MACH_SEND_NO_BUFFER;
                    524:                ikm_init(kmsg, size);
                    525:        }
                    526: 
1.1.1.3   root      527:        if (copyinmsg(msg, &kmsg->ikm_header, size)) {
1.1       root      528:                ikm_free(kmsg);
                    529:                return MACH_SEND_INVALID_DATA;
                    530:        }
                    531: 
                    532:        kmsg->ikm_header.msgh_size = size;
                    533:        *kmsgp = kmsg;
                    534:        return MACH_MSG_SUCCESS;
                    535: }
                    536: 
                    537: /*
                    538:  *     Routine:        ipc_kmsg_get_from_kernel
                    539:  *     Purpose:
                    540:  *             Allocates a kernel message buffer.
                    541:  *             Copies a kernel message to the message buffer.
                    542:  *             Only resource errors are allowed.
                    543:  *     Conditions:
                    544:  *             Nothing locked.
                    545:  *     Returns:
                    546:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
                    547:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
                    548:  */
                    549: 
                    550: extern mach_msg_return_t
1.1.1.4 ! root      551: ipc_kmsg_get_from_kernel(
        !           552:        mach_msg_header_t       *msg,
        !           553:        mach_msg_size_t         size,
        !           554:        ipc_kmsg_t              *kmsgp)
1.1       root      555: {
                    556:        ipc_kmsg_t kmsg;
                    557: 
                    558:        assert(size >= sizeof(mach_msg_header_t));
                    559:        assert((size & 3) == 0);
                    560: 
                    561:        kmsg = ikm_alloc(size);
                    562:        if (kmsg == IKM_NULL)
                    563:                return MACH_SEND_NO_BUFFER;
                    564:        ikm_init(kmsg, size);
                    565: 
1.1.1.3   root      566:        memcpy(&kmsg->ikm_header, msg, size);
1.1       root      567: 
                    568:        kmsg->ikm_header.msgh_size = size;
                    569:        *kmsgp = kmsg;
                    570:        return MACH_MSG_SUCCESS;
                    571: }
                    572: 
                    573: /*
                    574:  *     Routine:        ipc_kmsg_put
                    575:  *     Purpose:
                    576:  *             Copies a message buffer to a user message.
                    577:  *             Copies only the specified number of bytes.
                    578:  *             Frees the message buffer.
                    579:  *     Conditions:
                    580:  *             Nothing locked.  The message buffer must have clean
                    581:  *             header (ikm_marequest) fields.
                    582:  *     Returns:
                    583:  *             MACH_MSG_SUCCESS        Copied data out of message buffer.
                    584:  *             MACH_RCV_INVALID_DATA   Couldn't copy to user message.
                    585:  */
                    586: 
                    587: mach_msg_return_t
1.1.1.4 ! root      588: ipc_kmsg_put(
        !           589:        mach_msg_header_t       *msg,
        !           590:        ipc_kmsg_t              kmsg,
        !           591:        mach_msg_size_t         size)
1.1       root      592: {
                    593:        mach_msg_return_t mr;
                    594: 
                    595:        ikm_check_initialized(kmsg, kmsg->ikm_size);
                    596: 
1.1.1.3   root      597:        if (copyoutmsg(&kmsg->ikm_header, msg, size))
1.1       root      598:                mr = MACH_RCV_INVALID_DATA;
                    599:        else
                    600:                mr = MACH_MSG_SUCCESS;
                    601: 
                    602:        if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
                    603:            (ikm_cache() == IKM_NULL))
                    604:                ikm_cache() = kmsg;
                    605:        else
                    606:                ikm_free(kmsg);
                    607: 
                    608:        return mr;
                    609: }
                    610: 
                    611: /*
                    612:  *     Routine:        ipc_kmsg_put_to_kernel
                    613:  *     Purpose:
                    614:  *             Copies a message buffer to a kernel message.
                    615:  *             Frees the message buffer.
                    616:  *             No errors allowed.
                    617:  *     Conditions:
                    618:  *             Nothing locked.
                    619:  */
                    620: 
                    621: void
                    622: ipc_kmsg_put_to_kernel(
                    623:        mach_msg_header_t       *msg,
                    624:        ipc_kmsg_t              kmsg,
                    625:        mach_msg_size_t         size)
                    626: {
                    627: #if    DIPC
                    628:        assert(!KMSG_IN_DIPC(kmsg));
                    629: #endif /* DIPC */
                    630: 
1.1.1.3   root      631:        memcpy(msg, &kmsg->ikm_header, size);
1.1       root      632: 
                    633:        ikm_free(kmsg);
                    634: }
                    635: 
                    636: /*
                    637:  *     Routine:        ipc_kmsg_copyin_header
                    638:  *     Purpose:
                    639:  *             "Copy-in" port rights in the header of a message.
                    640:  *             Operates atomically; if it doesn't succeed the
                    641:  *             message header and the space are left untouched.
                    642:  *             If it does succeed the remote/local port fields
                    643:  *             contain object pointers instead of port names,
                    644:  *             and the bits field is updated.  The destination port
                    645:  *             will be a valid port pointer.
                    646:  *
                    647:  *             The notify argument implements the MACH_SEND_CANCEL option.
                    648:  *             If it is not MACH_PORT_NULL, it should name a receive right.
                    649:  *             If the processing of the destination port would generate
                    650:  *             a port-deleted notification (because the right for the
                    651:  *             destination port is destroyed and it had a request for
                    652:  *             a dead-name notification registered), and the port-deleted
                    653:  *             notification would be sent to the named receive right,
                    654:  *             then it isn't sent and the send-once right for the notify
                    655:  *             port is quietly destroyed.
                    656:  *     Conditions:
                    657:  *             Nothing locked.
                    658:  *     Returns:
                    659:  *             MACH_MSG_SUCCESS        Successful copyin.
                    660:  *             MACH_SEND_INVALID_HEADER
                    661:  *                     Illegal value in the message header bits.
                    662:  *             MACH_SEND_INVALID_DEST  The space is dead.
                    663:  *             MACH_SEND_INVALID_NOTIFY
                    664:  *                     Notify is non-null and doesn't name a receive right.
                    665:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                    666:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
                    667:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                    668:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
                    669:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                    670:  */
                    671: 
                    672: mach_msg_return_t
1.1.1.4 ! root      673: ipc_kmsg_copyin_header(
        !           674:        mach_msg_header_t       *msg,
        !           675:        ipc_space_t             space,
        !           676:        mach_port_t             notify)
1.1       root      677: {
                    678:        mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
                    679:        mach_port_t dest_name = msg->msgh_remote_port;
                    680:        mach_port_t reply_name = msg->msgh_local_port;
                    681:        kern_return_t kr;
                    682: 
                    683: #ifndef MIGRATING_THREADS
                    684:        /* first check for common cases */
                    685: 
                    686:        if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
                    687:            case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): {
                    688:                ipc_entry_t entry;
                    689:                ipc_entry_bits_t bits;
                    690:                ipc_port_t dest_port;
                    691: 
                    692:                /* sending an asynchronous message */
                    693: 
                    694:                if (reply_name != MACH_PORT_NULL)
                    695:                        break;
                    696: 
                    697:                is_read_lock(space);
                    698:                if (!space->is_active)
                    699:                        goto abort_async;
                    700: 
                    701:                /* optimized ipc_entry_lookup */
                    702: 
                    703:            {
                    704:                mach_port_index_t index = MACH_PORT_INDEX(dest_name);
                    705:                mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
                    706: 
                    707:                if (index >= space->is_table_size)
                    708:                        goto abort_async;
                    709: 
                    710:                entry = &space->is_table[index];
                    711:                bits = entry->ie_bits;
                    712: 
                    713:                /* check generation number and type bit */
                    714: 
                    715:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
                    716:                    (gen | MACH_PORT_TYPE_SEND))
                    717:                        goto abort_async;
                    718:            }
                    719: 
                    720:                /* optimized ipc_right_copyin */
                    721: 
                    722:                assert(IE_BITS_UREFS(bits) > 0);
                    723: 
                    724:                dest_port = (ipc_port_t) entry->ie_object;
                    725:                assert(dest_port != IP_NULL);
                    726: 
                    727:                ip_lock(dest_port);
                    728:                /* can unlock space now without compromising atomicity */
                    729:                is_read_unlock(space);
                    730: 
                    731:                if (!ip_active(dest_port)) {
                    732:                        ip_unlock(dest_port);
                    733:                        break;
                    734:                }
                    735: 
                    736:                assert(dest_port->ip_srights > 0);
                    737:                dest_port->ip_srights++;
                    738:                ip_reference(dest_port);
                    739:                ip_unlock(dest_port);
                    740: 
                    741:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                    742:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
                    743:                msg->msgh_remote_port = (mach_port_t) dest_port;
                    744:                return MACH_MSG_SUCCESS;
                    745: 
                    746:            abort_async:
                    747:                is_read_unlock(space);
                    748:                break;
                    749:            }
                    750: 
                    751:            case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
                    752:                                MACH_MSG_TYPE_MAKE_SEND_ONCE): {
                    753:                ipc_entry_num_t size;
                    754:                ipc_entry_t table;
                    755:                ipc_entry_t entry;
                    756:                ipc_entry_bits_t bits;
                    757:                ipc_port_t dest_port, reply_port;
                    758: 
                    759:                /* sending a request message */
                    760: 
                    761:                is_read_lock(space);
                    762:                if (!space->is_active)
                    763:                        goto abort_request;
                    764: 
                    765:                size = space->is_table_size;
                    766:                table = space->is_table;
                    767: 
                    768:                /* optimized ipc_entry_lookup of dest_name */
                    769: 
                    770:            {
                    771:                mach_port_index_t index = MACH_PORT_INDEX(dest_name);
                    772:                mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
                    773: 
                    774:                if (index >= size)
                    775:                        goto abort_request;
                    776: 
                    777:                entry = &table[index];
                    778:                bits = entry->ie_bits;
                    779: 
                    780:                /* check generation number and type bit */
                    781: 
                    782:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
                    783:                    (gen | MACH_PORT_TYPE_SEND))
                    784:                        goto abort_request;
                    785:            }
                    786: 
                    787:                assert(IE_BITS_UREFS(bits) > 0);
                    788: 
                    789:                dest_port = (ipc_port_t) entry->ie_object;
                    790:                assert(dest_port != IP_NULL);
                    791: 
                    792:                /* optimized ipc_entry_lookup of reply_name */
                    793: 
                    794:            {
                    795:                mach_port_index_t index = MACH_PORT_INDEX(reply_name);
                    796:                mach_port_gen_t gen = MACH_PORT_GEN(reply_name);
                    797: 
                    798:                if (index >= size)
                    799:                        goto abort_request;
                    800: 
                    801:                entry = &table[index];
                    802:                bits = entry->ie_bits;
                    803: 
                    804:                /* check generation number and type bit */
                    805: 
                    806:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) !=
                    807:                    (gen | MACH_PORT_TYPE_RECEIVE))
                    808:                        goto abort_request;
                    809:            }
                    810: 
                    811:                reply_port = (ipc_port_t) entry->ie_object;
                    812:                assert(reply_port != IP_NULL);
                    813: 
                    814:                /*
                    815:                 *      To do an atomic copyin, need simultaneous
                    816:                 *      locks on both ports and the space.  If
                    817:                 *      dest_port == reply_port, and simple locking is
                    818:                 *      enabled, then we will abort.  Otherwise it's
                    819:                 *      OK to unlock twice.
                    820:                 */
                    821: 
                    822:                ip_lock(dest_port);
                    823:                if (!ip_active(dest_port) || !ip_lock_try(reply_port)) {
                    824:                        ip_unlock(dest_port);
                    825:                        goto abort_request;
                    826:                }
                    827:                /* can unlock space now without compromising atomicity */
                    828:                is_read_unlock(space);
                    829: 
                    830:                assert(dest_port->ip_srights > 0);
                    831:                dest_port->ip_srights++;
                    832:                ip_reference(dest_port);
                    833:                ip_unlock(dest_port);
                    834: 
                    835:                assert(ip_active(reply_port));
                    836:                assert(reply_port->ip_receiver_name == reply_name);
                    837:                assert(reply_port->ip_receiver == space);
                    838: 
                    839:                reply_port->ip_sorights++;
                    840:                ip_reference(reply_port);
                    841:                ip_unlock(reply_port);
                    842: 
                    843:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                    844:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                    845:                                       MACH_MSG_TYPE_PORT_SEND_ONCE));
                    846:                msg->msgh_remote_port = (mach_port_t) dest_port;
                    847:                msg->msgh_local_port = (mach_port_t) reply_port;
                    848:                return MACH_MSG_SUCCESS;
                    849: 
                    850:            abort_request:
                    851:                is_read_unlock(space);
                    852:                break;
                    853:            }
                    854: 
                    855:            case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
                    856:                mach_port_index_t index;
                    857:                mach_port_gen_t gen;
                    858:                ipc_entry_t table;
                    859:                ipc_entry_t entry;
                    860:                ipc_entry_bits_t bits;
                    861:                ipc_port_t dest_port;
                    862: 
                    863:                /* sending a reply message */
                    864: 
                    865:                if (reply_name != MACH_PORT_NULL)
                    866:                        break;
                    867: 
                    868:                is_write_lock(space);
                    869:                if (!space->is_active)
                    870:                        goto abort_reply;
                    871: 
                    872:                /* optimized ipc_entry_lookup */
                    873: 
                    874:                table = space->is_table;
                    875: 
                    876:                index = MACH_PORT_INDEX(dest_name);
                    877:                gen = MACH_PORT_GEN(dest_name);
                    878: 
                    879:                if (index >= space->is_table_size)
                    880:                        goto abort_reply;
                    881: 
                    882:                entry = &table[index];
                    883:                bits = entry->ie_bits;
                    884: 
                    885:                /* check generation number, collision bit, and type bit */
                    886: 
                    887:                if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION|
                    888:                             MACH_PORT_TYPE_SEND_ONCE)) !=
                    889:                    (gen | MACH_PORT_TYPE_SEND_ONCE))
                    890:                        goto abort_reply;
                    891: 
                    892:                /* optimized ipc_right_copyin */
                    893: 
                    894:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                    895:                assert(IE_BITS_UREFS(bits) == 1);
                    896:                assert((bits & IE_BITS_MAREQUEST) == 0);
                    897: 
                    898:                if (entry->ie_request != 0)
                    899:                        goto abort_reply;
                    900: 
                    901:                dest_port = (ipc_port_t) entry->ie_object;
                    902:                assert(dest_port != IP_NULL);
                    903: 
                    904:                ip_lock(dest_port);
                    905:                if (!ip_active(dest_port)) {
                    906:                        ip_unlock(dest_port);
                    907:                        goto abort_reply;
                    908:                }
                    909: 
                    910:                assert(dest_port->ip_sorights > 0);
                    911:                ip_unlock(dest_port);
                    912: 
                    913:                /* optimized ipc_entry_dealloc */
                    914: 
                    915:                entry->ie_next = table->ie_next;
                    916:                table->ie_next = index;
                    917:                entry->ie_bits = gen;
                    918:                entry->ie_object = IO_NULL;
                    919:                is_write_unlock(space);
                    920: 
                    921:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                    922:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
                    923:                                                 0));
                    924:                msg->msgh_remote_port = (mach_port_t) dest_port;
                    925:                return MACH_MSG_SUCCESS;
                    926: 
                    927:            abort_reply:
                    928:                is_write_unlock(space);
                    929:                break;
                    930:            }
                    931: 
                    932:            default:
                    933:                /* don't bother optimizing */
                    934:                break;
                    935:        }
                    936: #endif /* MIGRATING_THREADS */
                    937: 
                    938:     {
                    939:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                    940:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                    941:        ipc_object_t dest_port, reply_port;
                    942:        ipc_port_t dest_soright, reply_soright;
                    943:        ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */
                    944: 
                    945:        if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
                    946:                return MACH_SEND_INVALID_HEADER;
                    947: 
                    948:        if ((reply_type == 0) ?
                    949:            (reply_name != MACH_PORT_NULL) :
                    950:            !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
                    951:                return MACH_SEND_INVALID_HEADER;
                    952: 
                    953:        is_write_lock(space);
                    954:        if (!space->is_active)
                    955:                goto invalid_dest;
                    956: 
                    957:        if (notify != MACH_PORT_NULL) {
                    958:                ipc_entry_t entry;
                    959: 
                    960:                if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
                    961:                    ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
                    962:                        is_write_unlock(space);
                    963:                        return MACH_SEND_INVALID_NOTIFY;
                    964:                }
                    965: 
                    966:                notify_port = (ipc_port_t) entry->ie_object;
                    967:        }
                    968: 
                    969:        if (dest_name == reply_name) {
                    970:                ipc_entry_t entry;
                    971:                mach_port_t name = dest_name;
                    972: 
                    973:                /*
                    974:                 *      Destination and reply ports are the same!
                    975:                 *      This is a little tedious to make atomic, because
                    976:                 *      there are 25 combinations of dest_type/reply_type.
                    977:                 *      However, most are easy.  If either is move-sonce,
                    978:                 *      then there must be an error.  If either are
                    979:                 *      make-send or make-sonce, then we must be looking
                    980:                 *      at a receive right so the port can't die.
                    981:                 *      The hard cases are the combinations of
                    982:                 *      copy-send and make-send.
                    983:                 */
                    984: 
                    985:                entry = ipc_entry_lookup(space, name);
                    986:                if (entry == IE_NULL)
                    987:                        goto invalid_dest;
                    988: 
                    989:                assert(reply_type != 0); /* because name not null */
                    990: 
                    991:                if (!ipc_right_copyin_check(space, name, entry, reply_type))
                    992:                        goto invalid_reply;
                    993: 
                    994:                if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
                    995:                    (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
                    996:                        /*
                    997:                         *      Why must there be an error?  To get a valid
                    998:                         *      destination, this entry must name a live
                    999:                         *      port (not a dead name or dead port).  However
                   1000:                         *      a successful move-sonce will destroy a
                   1001:                         *      live entry.  Therefore the other copyin,
                   1002:                         *      whatever it is, would fail.  We've already
                   1003:                         *      checked for reply port errors above,
                   1004:                         *      so report a destination error.
                   1005:                         */
                   1006: 
                   1007:                        goto invalid_dest;
                   1008:                } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
                   1009:                           (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
                   1010:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
                   1011:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
                   1012:                        kr = ipc_right_copyin(space, name, entry,
                   1013:                                              dest_type, FALSE,
                   1014:                                              &dest_port, &dest_soright);
                   1015:                        if (kr != KERN_SUCCESS)
                   1016:                                goto invalid_dest;
                   1017: 
                   1018:                        /*
                   1019:                         *      Either dest or reply needs a receive right.
                   1020:                         *      We know the receive right is there, because
                   1021:                         *      of the copyin_check and copyin calls.  Hence
                   1022:                         *      the port is not in danger of dying.  If dest
                   1023:                         *      used the receive right, then the right needed
                   1024:                         *      by reply (and verified by copyin_check) will
                   1025:                         *      still be there.
                   1026:                         */
                   1027: 
                   1028:                        assert(IO_VALID(dest_port));
                   1029:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                   1030:                        assert(dest_soright == IP_NULL);
                   1031: 
                   1032:                        kr = ipc_right_copyin(space, name, entry,
                   1033:                                              reply_type, TRUE,
                   1034:                                              &reply_port, &reply_soright);
                   1035: 
                   1036:                        assert(kr == KERN_SUCCESS);
                   1037:                        assert(reply_port == dest_port);
                   1038:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                   1039:                        assert(reply_soright == IP_NULL);
                   1040:                } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
                   1041:                           (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
                   1042:                        /*
                   1043:                         *      To make this atomic, just do one copy-send,
                   1044:                         *      and dup the send right we get out.
                   1045:                         */
                   1046: 
                   1047:                        kr = ipc_right_copyin(space, name, entry,
                   1048:                                              dest_type, FALSE,
                   1049:                                              &dest_port, &dest_soright);
                   1050:                        if (kr != KERN_SUCCESS)
                   1051:                                goto invalid_dest;
                   1052: 
                   1053:                        assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
                   1054:                        assert(dest_soright == IP_NULL);
                   1055: 
                   1056:                        /*
                   1057:                         *      It's OK if the port we got is dead now,
                   1058:                         *      so reply_port is IP_DEAD, because the msg
                   1059:                         *      won't go anywhere anyway.
                   1060:                         */
                   1061: 
                   1062:                        reply_port = (ipc_object_t)
                   1063:                                ipc_port_copy_send((ipc_port_t) dest_port);
                   1064:                        reply_soright = IP_NULL;
                   1065:                } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
                   1066:                           (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
                   1067:                        /*
                   1068:                         *      This is an easy case.  Just use our
                   1069:                         *      handy-dandy special-purpose copyin call
                   1070:                         *      to get two send rights for the price of one.
                   1071:                         */
                   1072: 
                   1073:                        kr = ipc_right_copyin_two(space, name, entry,
                   1074:                                                  &dest_port, &dest_soright);
                   1075:                        if (kr != KERN_SUCCESS)
                   1076:                                goto invalid_dest;
                   1077: 
                   1078:                        /* the entry might need to be deallocated */
                   1079: 
                   1080:                        if (IE_BITS_TYPE(entry->ie_bits)
                   1081:                                                == MACH_PORT_TYPE_NONE)
                   1082:                                ipc_entry_dealloc(space, name, entry);
                   1083: 
                   1084:                        reply_port = dest_port;
                   1085:                        reply_soright = IP_NULL;
                   1086:                } else {
                   1087:                        ipc_port_t soright;
                   1088: 
                   1089:                        assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
                   1090:                                (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
                   1091:                               ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
                   1092:                                (reply_type == MACH_MSG_TYPE_COPY_SEND)));
                   1093: 
                   1094:                        /*
                   1095:                         *      To make this atomic, just do a move-send,
                   1096:                         *      and dup the send right we get out.
                   1097:                         */
                   1098: 
                   1099:                        kr = ipc_right_copyin(space, name, entry,
                   1100:                                              MACH_MSG_TYPE_MOVE_SEND, FALSE,
                   1101:                                              &dest_port, &soright);
                   1102:                        if (kr != KERN_SUCCESS)
                   1103:                                goto invalid_dest;
                   1104: 
                   1105:                        /* the entry might need to be deallocated */
                   1106: 
                   1107:                        if (IE_BITS_TYPE(entry->ie_bits)
                   1108:                                                == MACH_PORT_TYPE_NONE)
                   1109:                                ipc_entry_dealloc(space, name, entry);
                   1110: 
                   1111:                        /*
                   1112:                         *      It's OK if the port we got is dead now,
                   1113:                         *      so reply_port is IP_DEAD, because the msg
                   1114:                         *      won't go anywhere anyway.
                   1115:                         */
                   1116: 
                   1117:                        reply_port = (ipc_object_t)
                   1118:                                ipc_port_copy_send((ipc_port_t) dest_port);
                   1119: 
                   1120:                        if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
                   1121:                                dest_soright = soright;
                   1122:                                reply_soright = IP_NULL;
                   1123:                        } else {
                   1124:                                dest_soright = IP_NULL;
                   1125:                                reply_soright = soright;
                   1126:                        }
                   1127:                }
                   1128:        } else if (!MACH_PORT_VALID(reply_name)) {
                   1129:                ipc_entry_t entry;
                   1130: 
                   1131:                /*
                   1132:                 *      No reply port!  This is an easy case
                   1133:                 *      to make atomic.  Just copyin the destination.
                   1134:                 */
                   1135: 
                   1136:                entry = ipc_entry_lookup(space, dest_name);
                   1137:                if (entry == IE_NULL)
                   1138:                        goto invalid_dest;
                   1139: 
                   1140:                kr = ipc_right_copyin(space, dest_name, entry,
                   1141:                                      dest_type, FALSE,
                   1142:                                      &dest_port, &dest_soright);
                   1143:                if (kr != KERN_SUCCESS)
                   1144:                        goto invalid_dest;
                   1145: 
                   1146:                /* the entry might need to be deallocated */
                   1147: 
                   1148:                if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1149:                        ipc_entry_dealloc(space, dest_name, entry);
                   1150: 
                   1151:                reply_port = (ipc_object_t) reply_name;
                   1152:                reply_soright = IP_NULL;
                   1153:        } else {
                   1154:                ipc_entry_t dest_entry, reply_entry;
                   1155:                ipc_port_t saved_reply;
                   1156: 
                   1157:                /*
                   1158:                 *      This is the tough case to make atomic.
                   1159:                 *      The difficult problem is serializing with port death.
                   1160:                 *      At the time we copyin dest_port, it must be alive.
                   1161:                 *      If reply_port is alive when we copyin it, then
                   1162:                 *      we are OK, because we serialize before the death
                   1163:                 *      of both ports.  Assume reply_port is dead at copyin.
                   1164:                 *      Then if dest_port dies/died after reply_port died,
                   1165:                 *      we are OK, because we serialize between the death
                   1166:                 *      of the two ports.  So the bad case is when dest_port
                   1167:                 *      dies after its copyin, reply_port dies before its
                   1168:                 *      copyin, and dest_port dies before reply_port.  Then
                   1169:                 *      the copyins operated as if dest_port was alive
                   1170:                 *      and reply_port was dead, which shouldn't have happened
                   1171:                 *      because they died in the other order.
                   1172:                 *
                   1173:                 *      We handle the bad case by undoing the copyins
                   1174:                 *      (which is only possible because the ports are dead)
                   1175:                 *      and failing with MACH_SEND_INVALID_DEST, serializing
                   1176:                 *      after the death of the ports.
                   1177:                 *
                   1178:                 *      Note that it is easy for a user task to tell if
                   1179:                 *      a copyin happened before or after a port died.
                   1180:                 *      For example, suppose both dest and reply are
                   1181:                 *      send-once rights (types are both move-sonce) and
                   1182:                 *      both rights have dead-name requests registered.
                   1183:                 *      If a port dies before copyin, a dead-name notification
                   1184:                 *      is generated and the dead name's urefs are incremented,
                   1185:                 *      and if the copyin happens first, a port-deleted
                   1186:                 *      notification is generated.
                   1187:                 *
                   1188:                 *      Note that although the entries are different,
                   1189:                 *      dest_port and reply_port might still be the same.
                   1190:                 */
                   1191: 
                   1192:                dest_entry = ipc_entry_lookup(space, dest_name);
                   1193:                if (dest_entry == IE_NULL)
                   1194:                        goto invalid_dest;
                   1195: 
                   1196:                reply_entry = ipc_entry_lookup(space, reply_name);
                   1197:                if (reply_entry == IE_NULL)
                   1198:                        goto invalid_reply;
                   1199: 
                   1200:                assert(dest_entry != reply_entry); /* names are not equal */
                   1201:                assert(reply_type != 0); /* because reply_name not null */
                   1202: 
                   1203:                if (!ipc_right_copyin_check(space, reply_name, reply_entry,
                   1204:                                            reply_type))
                   1205:                        goto invalid_reply;
                   1206: 
                   1207:                kr = ipc_right_copyin(space, dest_name, dest_entry,
                   1208:                                      dest_type, FALSE,
                   1209:                                      &dest_port, &dest_soright);
                   1210:                if (kr != KERN_SUCCESS)
                   1211:                        goto invalid_dest;
                   1212: 
                   1213:                assert(IO_VALID(dest_port));
                   1214: 
                   1215:                saved_reply = (ipc_port_t) reply_entry->ie_object;
                   1216:                /* might be IP_NULL, if this is a dead name */
                   1217:                if (saved_reply != IP_NULL)
                   1218:                        ipc_port_reference(saved_reply);
                   1219: 
                   1220:                kr = ipc_right_copyin(space, reply_name, reply_entry,
                   1221:                                      reply_type, TRUE,
                   1222:                                      &reply_port, &reply_soright);
                   1223:                assert(kr == KERN_SUCCESS);
                   1224: 
                   1225:                if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) {
                   1226:                        ipc_port_t dest = (ipc_port_t) dest_port;
                   1227:                        ipc_port_timestamp_t timestamp;
                   1228:                        boolean_t must_undo;
                   1229: 
                   1230:                        /*
                   1231:                         *      The reply port died before copyin.
                   1232:                         *      Check if dest port died before reply.
                   1233:                         */
                   1234: 
                   1235:                        ip_lock(saved_reply);
                   1236:                        assert(!ip_active(saved_reply));
                   1237:                        timestamp = saved_reply->ip_timestamp;
                   1238:                        ip_unlock(saved_reply);
                   1239: 
                   1240:                        ip_lock(dest);
                   1241:                        must_undo = (!ip_active(dest) &&
                   1242:                                     IP_TIMESTAMP_ORDER(dest->ip_timestamp,
                   1243:                                                        timestamp));
                   1244:                        ip_unlock(dest);
                   1245: 
                   1246:                        if (must_undo) {
                   1247:                                /*
                   1248:                                 *      Our worst nightmares are realized.
                   1249:                                 *      Both destination and reply ports
                   1250:                                 *      are dead, but in the wrong order,
                   1251:                                 *      so we must undo the copyins and
                   1252:                                 *      possibly generate a dead-name notif.
                   1253:                                 */
                   1254: 
                   1255:                                ipc_right_copyin_undo(
                   1256:                                                space, dest_name, dest_entry,
                   1257:                                                dest_type, dest_port,
                   1258:                                                dest_soright);
                   1259:                                /* dest_entry may be deallocated now */
                   1260: 
                   1261:                                ipc_right_copyin_undo(
                   1262:                                                space, reply_name, reply_entry,
                   1263:                                                reply_type, reply_port,
                   1264:                                                reply_soright);
                   1265:                                /* reply_entry may be deallocated now */
                   1266: 
                   1267:                                is_write_unlock(space);
                   1268: 
                   1269:                                if (dest_soright != IP_NULL)
                   1270:                                        ipc_notify_dead_name(dest_soright,
                   1271:                                                             dest_name);
                   1272:                                assert(reply_soright == IP_NULL);
                   1273: 
                   1274:                                ipc_port_release(saved_reply);
                   1275:                                return MACH_SEND_INVALID_DEST;
                   1276:                        }
                   1277:                }
                   1278: 
                   1279:                /* the entries might need to be deallocated */
                   1280: 
                   1281:                if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1282:                        ipc_entry_dealloc(space, reply_name, reply_entry);
                   1283: 
                   1284:                if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1285:                        ipc_entry_dealloc(space, dest_name, dest_entry);
                   1286: 
                   1287:                if (saved_reply != IP_NULL)
                   1288:                        ipc_port_release(saved_reply);
                   1289:        }
                   1290: 
                   1291:        /*
                   1292:         *      At this point, dest_port, reply_port,
                   1293:         *      dest_soright, reply_soright are all initialized.
                   1294:         *      Any defunct entries have been deallocated.
                   1295:         *      The space is still write-locked, and we need to
                   1296:         *      make the MACH_SEND_CANCEL check.  The notify_port pointer
                   1297:         *      is still usable, because the copyin code above won't ever
                   1298:         *      deallocate a receive right, so its entry still exists
                   1299:         *      and holds a ref.  Note notify_port might even equal
                   1300:         *      dest_port or reply_port.
                   1301:         */
                   1302: 
                   1303:        if ((notify != MACH_PORT_NULL) &&
                   1304:            (dest_soright == notify_port)) {
                   1305:                ipc_port_release_sonce(dest_soright);
                   1306:                dest_soright = IP_NULL;
                   1307:        }
                   1308: 
                   1309:        is_write_unlock(space);
                   1310: 
                   1311:        if (dest_soright != IP_NULL)
                   1312:                ipc_notify_port_deleted(dest_soright, dest_name);
                   1313: 
                   1314:        if (reply_soright != IP_NULL)
                   1315:                ipc_notify_port_deleted(reply_soright, reply_name);
                   1316: 
                   1317:        dest_type = ipc_object_copyin_type(dest_type);
                   1318:        reply_type = ipc_object_copyin_type(reply_type);
                   1319: 
                   1320:        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                   1321:                          MACH_MSGH_BITS(dest_type, reply_type));
                   1322:        msg->msgh_remote_port = (mach_port_t) dest_port;
                   1323:        msg->msgh_local_port = (mach_port_t) reply_port;
                   1324:     }
                   1325: 
                   1326:        return MACH_MSG_SUCCESS;
                   1327: 
                   1328:     invalid_dest:
                   1329:        is_write_unlock(space);
                   1330:        return MACH_SEND_INVALID_DEST;
                   1331: 
                   1332:     invalid_reply:
                   1333:        is_write_unlock(space);
                   1334:        return MACH_SEND_INVALID_REPLY;
                   1335: }
                   1336: 
                   1337: mach_msg_return_t
1.1.1.4 ! root     1338: ipc_kmsg_copyin_body(
        !          1339:        ipc_kmsg_t      kmsg,
        !          1340:        ipc_space_t     space,
        !          1341:        vm_map_t        map)
1.1       root     1342: {
                   1343:        ipc_object_t dest;
                   1344:        vm_offset_t saddr, eaddr;
                   1345:        boolean_t complex;
                   1346:        boolean_t use_page_lists, steal_pages;
                   1347: 
                   1348:        dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   1349:        complex = FALSE;
                   1350:        use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
                   1351:        steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
                   1352: 
                   1353:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
                   1354:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
                   1355: 
                   1356:        while (saddr < eaddr) {
                   1357:                vm_offset_t taddr = saddr;
                   1358:                mach_msg_type_long_t *type;
                   1359:                mach_msg_type_name_t name;
                   1360:                mach_msg_type_size_t size;
                   1361:                mach_msg_type_number_t number;
                   1362:                boolean_t is_inline, longform, dealloc, is_port;
                   1363:                vm_offset_t data;
1.1.1.3   root     1364:                unsigned64_t length;
1.1       root     1365:                kern_return_t kr;
                   1366: 
                   1367:                type = (mach_msg_type_long_t *) saddr;
                   1368: 
                   1369:                if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
                   1370:                    ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
                   1371:                     ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
                   1372:                        ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
                   1373:                        return MACH_SEND_MSG_TOO_SMALL;
                   1374:                }
                   1375: 
                   1376:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
                   1377:                dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
                   1378:                if (longform) {
                   1379:                        /* This must be aligned */
                   1380:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   1381:                            (is_misaligned(type))) {
                   1382:                                saddr = ptr_align(saddr);
                   1383:                                continue;
                   1384:                        }
                   1385:                        name = type->msgtl_name;
                   1386:                        size = type->msgtl_size;
                   1387:                        number = type->msgtl_number;
                   1388:                        saddr += sizeof(mach_msg_type_long_t);
                   1389:                } else {
                   1390:                        name = ((mach_msg_type_t*)type)->msgt_name;
                   1391:                        size = ((mach_msg_type_t*)type)->msgt_size;
                   1392:                        number = ((mach_msg_type_t*)type)->msgt_number;
                   1393:                        saddr += sizeof(mach_msg_type_t);
                   1394:                }
                   1395: 
                   1396:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
                   1397: 
                   1398:                if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
                   1399:                    (longform && ((type->msgtl_header.msgt_name != 0) ||
                   1400:                                  (type->msgtl_header.msgt_size != 0) ||
                   1401:                                  (type->msgtl_header.msgt_number != 0))) ||
                   1402:                    (((mach_msg_type_t*)type)->msgt_unused != 0) ||
                   1403:                    (dealloc && is_inline)) {
                   1404:                        ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
                   1405:                        return MACH_SEND_INVALID_TYPE;
                   1406:                }
                   1407: 
                   1408:                /* padding (ptrs and ports) ? */
                   1409:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   1410:                    ((size >> 3) == sizeof(natural_t)))
                   1411:                        saddr = ptr_align(saddr);
                   1412: 
                   1413:                /* calculate length of data in bytes, rounding up */
                   1414: 
1.1.1.3   root     1415:                length = (((unsigned64_t) number * size) + 7) >> 3;
1.1       root     1416: 
                   1417:                if (is_inline) {
                   1418:                        vm_size_t amount;
                   1419: 
                   1420:                        /* inline data sizes round up to int boundaries */
                   1421: 
                   1422:                        amount = (length + 3) &~ 3;
                   1423:                        if ((eaddr - saddr) < amount) {
                   1424:                                ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
                   1425:                                return MACH_SEND_MSG_TOO_SMALL;
                   1426:                        }
                   1427: 
                   1428:                        data = saddr;
                   1429:                        saddr += amount;
                   1430:                } else {
                   1431:                        vm_offset_t addr;
                   1432: 
                   1433:                        if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
                   1434:                                saddr = ptr_align(saddr);
1.1.1.2   root     1435: 
1.1       root     1436:                        if ((eaddr - saddr) < sizeof(vm_offset_t)) {
                   1437:                                ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
                   1438:                                return MACH_SEND_MSG_TOO_SMALL;
                   1439:                        }
                   1440: 
                   1441:                        /* grab the out-of-line data */
                   1442: 
                   1443:                        addr = * (vm_offset_t *) saddr;
                   1444: 
                   1445:                        if (length == 0)
                   1446:                                data = 0;
                   1447:                        else if (is_port) {
                   1448:                                data = kalloc(length);
                   1449:                                if (data == 0)
                   1450:                                        goto invalid_memory;
                   1451: 
                   1452:                                if (copyinmap(map, (char *) addr,
                   1453:                                              (char *) data, length) ||
                   1454:                                    (dealloc &&
                   1455:                                     (vm_deallocate(map, addr, length) !=
                   1456:                                                        KERN_SUCCESS))) {
                   1457:                                        kfree(data, length);
                   1458:                                        goto invalid_memory;
                   1459:                                }
                   1460:                        } else {
                   1461:                                vm_map_copy_t copy;
                   1462: 
                   1463:                                if (use_page_lists) {
                   1464:                                        kr = vm_map_copyin_page_list(map,
                   1465:                                                addr, length, dealloc,
                   1466:                                                steal_pages, &copy, FALSE);
                   1467:                                } else {
                   1468:                                        kr = vm_map_copyin(map, addr, length,
                   1469:                                                           dealloc, &copy);
                   1470:                                }
                   1471:                                if (kr != KERN_SUCCESS) {
                   1472:                                    invalid_memory:
                   1473:                                        ipc_kmsg_clean_partial(kmsg, taddr,
                   1474:                                                               FALSE, 0);
                   1475:                                        return MACH_SEND_INVALID_MEMORY;
                   1476:                                }
                   1477: 
                   1478:                                data = (vm_offset_t) copy;
                   1479:                        }
                   1480: 
                   1481:                        * (vm_offset_t *) saddr = data;
                   1482:                        saddr += sizeof(vm_offset_t);
                   1483:                        complex = TRUE;
                   1484:                }
                   1485: 
                   1486:                if (is_port) {
                   1487:                        mach_msg_type_name_t newname =
                   1488:                                        ipc_object_copyin_type(name);
                   1489:                        ipc_object_t *objects = (ipc_object_t *) data;
                   1490:                        mach_msg_type_number_t i;
                   1491: 
                   1492:                        if (longform)
                   1493:                                type->msgtl_name = newname;
                   1494:                        else
                   1495:                                ((mach_msg_type_t*)type)->msgt_name = newname;
                   1496: 
                   1497:                        for (i = 0; i < number; i++) {
                   1498:                                mach_port_t port = (mach_port_t) objects[i];
                   1499:                                ipc_object_t object;
                   1500: 
                   1501:                                if (!MACH_PORT_VALID(port))
                   1502:                                        continue;
                   1503: 
                   1504:                                kr = ipc_object_copyin(space, port,
                   1505:                                                       name, &object);
                   1506:                                if (kr != KERN_SUCCESS) {
                   1507:                                        ipc_kmsg_clean_partial(kmsg, taddr,
                   1508:                                                               TRUE, i);
                   1509:                                        return MACH_SEND_INVALID_RIGHT;
                   1510:                                }
                   1511: 
                   1512:                                if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
                   1513:                                    ipc_port_check_circularity(
                   1514:                                                        (ipc_port_t) object,
                   1515:                                                        (ipc_port_t) dest))
                   1516:                                        kmsg->ikm_header.msgh_bits |=
                   1517:                                                MACH_MSGH_BITS_CIRCULAR;
                   1518: 
                   1519:                                objects[i] = object;
                   1520:                        }
                   1521: 
                   1522:                        complex = TRUE;
                   1523:                }
                   1524:        }
                   1525: 
                   1526:        if (!complex)
                   1527:                kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
                   1528: 
                   1529:        return MACH_MSG_SUCCESS;
                   1530: }
                   1531: 
                   1532: /*
                   1533:  *     Routine:        ipc_kmsg_copyin
                   1534:  *     Purpose:
                   1535:  *             "Copy-in" port rights and out-of-line memory
                   1536:  *             in the message.
                   1537:  *
                   1538:  *             In all failure cases, the message is left holding
                   1539:  *             no rights or memory.  However, the message buffer
                   1540:  *             is not deallocated.  If successful, the message
                   1541:  *             contains a valid destination port.
                   1542:  *     Conditions:
                   1543:  *             Nothing locked.
                   1544:  *     Returns:
                   1545:  *             MACH_MSG_SUCCESS        Successful copyin.
                   1546:  *             MACH_SEND_INVALID_HEADER
                   1547:  *                     Illegal value in the message header bits.
                   1548:  *             MACH_SEND_INVALID_NOTIFY        Bad notify port.
                   1549:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
                   1550:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
                   1551:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
                   1552:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
                   1553:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
                   1554:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
                   1555:  */
                   1556: 
                   1557: mach_msg_return_t
1.1.1.4 ! root     1558: ipc_kmsg_copyin(
        !          1559:        ipc_kmsg_t      kmsg,
        !          1560:        ipc_space_t     space,
        !          1561:        vm_map_t        map,
        !          1562:        mach_port_t     notify)
1.1       root     1563: {
                   1564:        mach_msg_return_t mr;
                   1565: 
                   1566:        mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
                   1567:        if (mr != MACH_MSG_SUCCESS)
                   1568:                return mr;
                   1569: 
                   1570:        if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
                   1571:                return MACH_MSG_SUCCESS;
                   1572: 
                   1573:        return ipc_kmsg_copyin_body(kmsg, space, map);
                   1574: }
                   1575: 
                   1576: /*
                   1577:  *     Routine:        ipc_kmsg_copyin_from_kernel
                   1578:  *     Purpose:
                   1579:  *             "Copy-in" port rights and out-of-line memory
                   1580:  *             in a message sent from the kernel.
                   1581:  *
                   1582:  *             Because the message comes from the kernel,
                   1583:  *             the implementation assumes there are no errors
                   1584:  *             or peculiarities in the message.
                   1585:  *
                   1586:  *             Returns TRUE if queueing the message
                   1587:  *             would result in a circularity.
                   1588:  *     Conditions:
                   1589:  *             Nothing locked.
                   1590:  */
                   1591: 
                   1592: void
1.1.1.4 ! root     1593: ipc_kmsg_copyin_from_kernel(ipc_kmsg_t kmsg)
1.1       root     1594: {
                   1595:        mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits;
                   1596:        mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
                   1597:        mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
                   1598:        ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   1599:        ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   1600:        vm_offset_t saddr, eaddr;
                   1601: 
                   1602:        /* translate the destination and reply ports */
                   1603: 
                   1604:        ipc_object_copyin_from_kernel(remote, rname);
                   1605:        if (IO_VALID(local))
                   1606:                ipc_object_copyin_from_kernel(local, lname);
                   1607: 
                   1608:        /*
                   1609:         *      The common case is a complex message with no reply port,
                   1610:         *      because that is what the memory_object interface uses.
                   1611:         */
                   1612: 
                   1613:        if (bits == (MACH_MSGH_BITS_COMPLEX |
                   1614:                     MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
                   1615:                bits = (MACH_MSGH_BITS_COMPLEX |
                   1616:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
                   1617: 
                   1618:                kmsg->ikm_header.msgh_bits = bits;
                   1619:        } else {
                   1620:                bits = (MACH_MSGH_BITS_OTHER(bits) |
                   1621:                        MACH_MSGH_BITS(ipc_object_copyin_type(rname),
                   1622:                                       ipc_object_copyin_type(lname)));
                   1623: 
                   1624:                kmsg->ikm_header.msgh_bits = bits;
                   1625:                if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
                   1626:                        return;
                   1627:        }
                   1628: 
                   1629:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
                   1630:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
                   1631: 
                   1632:        while (saddr < eaddr) {
                   1633:                mach_msg_type_long_t *type;
                   1634:                mach_msg_type_name_t name;
                   1635:                mach_msg_type_size_t size;
                   1636:                mach_msg_type_number_t number;
                   1637:                boolean_t is_inline, longform, is_port;
                   1638:                vm_offset_t data;
                   1639:                vm_size_t length;
                   1640: 
                   1641:                type = (mach_msg_type_long_t *) saddr;
                   1642:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
                   1643:                longform = ((mach_msg_type_t*)type)->msgt_longform;
                   1644:                /* type->msgtl_header.msgt_deallocate not used */
                   1645:                if (longform) {
                   1646:                        /* This must be aligned */
                   1647:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   1648:                            (is_misaligned(type))) {
                   1649:                                saddr = ptr_align(saddr);
                   1650:                                continue;
                   1651:                        }
                   1652:                        name = type->msgtl_name;
                   1653:                        size = type->msgtl_size;
                   1654:                        number = type->msgtl_number;
                   1655:                        saddr += sizeof(mach_msg_type_long_t);
                   1656:                } else {
                   1657:                        name = ((mach_msg_type_t*)type)->msgt_name;
                   1658:                        size = ((mach_msg_type_t*)type)->msgt_size;
                   1659:                        number = ((mach_msg_type_t*)type)->msgt_number;
                   1660:                        saddr += sizeof(mach_msg_type_t);
                   1661:                }
                   1662: 
                   1663:                /* padding (ptrs and ports) ? */
                   1664:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   1665:                    ((size >> 3) == sizeof(natural_t)))
                   1666:                        saddr = ptr_align(saddr);
                   1667: 
                   1668:                /* calculate length of data in bytes, rounding up */
                   1669: 
                   1670:                length = ((number * size) + 7) >> 3;
                   1671: 
                   1672:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
                   1673: 
                   1674:                if (is_inline) {
                   1675:                        /* inline data sizes round up to int boundaries */
                   1676: 
                   1677:                        data = saddr;
                   1678:                        saddr += (length + 3) &~ 3;
                   1679:                } else {
                   1680:                        /*
                   1681:                         *      The sender should supply ready-made memory
                   1682:                         *      for us, so we don't need to do anything.
                   1683:                         */
                   1684: 
                   1685:                        data = * (vm_offset_t *) saddr;
                   1686:                        saddr += sizeof(vm_offset_t);
                   1687:                }
                   1688: 
                   1689:                if (is_port) {
                   1690:                        mach_msg_type_name_t newname =
                   1691:                                        ipc_object_copyin_type(name);
                   1692:                        ipc_object_t *objects = (ipc_object_t *) data;
                   1693:                        mach_msg_type_number_t i;
                   1694: 
                   1695:                        if (longform)
                   1696:                                type->msgtl_name = newname;
                   1697:                        else
                   1698:                                ((mach_msg_type_t*)type)->msgt_name = newname;
                   1699:                        for (i = 0; i < number; i++) {
                   1700:                                ipc_object_t object = objects[i];
                   1701: 
                   1702:                                if (!IO_VALID(object))
                   1703:                                        continue;
                   1704: 
                   1705:                                ipc_object_copyin_from_kernel(object, name);
                   1706: 
                   1707:                                if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
                   1708:                                    ipc_port_check_circularity(
                   1709:                                                        (ipc_port_t) object,
                   1710:                                                        (ipc_port_t) remote))
                   1711:                                        kmsg->ikm_header.msgh_bits |=
                   1712:                                                MACH_MSGH_BITS_CIRCULAR;
                   1713:                        }
                   1714:                }
                   1715:        }
                   1716: }
                   1717: 
                   1718: /*
                   1719:  *     Routine:        ipc_kmsg_copyout_header
                   1720:  *     Purpose:
                   1721:  *             "Copy-out" port rights in the header of a message.
                   1722:  *             Operates atomically; if it doesn't succeed the
                   1723:  *             message header and the space are left untouched.
                   1724:  *             If it does succeed the remote/local port fields
                   1725:  *             contain port names instead of object pointers,
                   1726:  *             and the bits field is updated.
                   1727:  *
                   1728:  *             The notify argument implements the MACH_RCV_NOTIFY option.
                   1729:  *             If it is not MACH_PORT_NULL, it should name a receive right.
                   1730:  *             If the process of receiving the reply port creates a
                   1731:  *             new right in the receiving task, then the new right is
                   1732:  *             automatically registered for a dead-name notification,
                   1733:  *             with the notify port supplying the send-once right.
                   1734:  *     Conditions:
                   1735:  *             Nothing locked.
                   1736:  *     Returns:
                   1737:  *             MACH_MSG_SUCCESS        Copied out port rights.
1.1.1.2   root     1738:  *             MACH_RCV_INVALID_NOTIFY
1.1       root     1739:  *                     Notify is non-null and doesn't name a receive right.
                   1740:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                   1741:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
                   1742:  *                     The space is dead.
                   1743:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
                   1744:  *                     No room in space for another name.
                   1745:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
                   1746:  *                     Couldn't allocate memory for the reply port.
                   1747:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
                   1748:  *                     Couldn't allocate memory for the dead-name request.
                   1749:  */
                   1750: 
                   1751: mach_msg_return_t
1.1.1.4 ! root     1752: ipc_kmsg_copyout_header(
        !          1753:        mach_msg_header_t       *msg,
        !          1754:        ipc_space_t             space,
        !          1755:        mach_port_t             notify)
1.1       root     1756: {
                   1757:        mach_msg_bits_t mbits = msg->msgh_bits;
                   1758:        ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
                   1759: 
                   1760:        assert(IP_VALID(dest));
                   1761: 
                   1762: #ifndef MIGRATING_THREADS
                   1763:        /* first check for common cases */
                   1764: 
                   1765:        if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
                   1766:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
                   1767:                mach_port_t dest_name;
                   1768:                ipc_port_t nsrequest;
                   1769: 
                   1770:                /* receiving an asynchronous message */
                   1771: 
                   1772:                ip_lock(dest);
                   1773:                if (!ip_active(dest)) {
                   1774:                        ip_unlock(dest);
                   1775:                        break;
                   1776:                }
                   1777: 
                   1778:                /* optimized ipc_object_copyout_dest */
                   1779: 
                   1780:                assert(dest->ip_srights > 0);
                   1781:                ip_release(dest);
                   1782: 
                   1783:                if (dest->ip_receiver == space)
                   1784:                        dest_name = dest->ip_receiver_name;
                   1785:                else
                   1786:                        dest_name = MACH_PORT_NULL;
                   1787: 
                   1788:                if ((--dest->ip_srights == 0) &&
                   1789:                    ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
                   1790:                        mach_port_mscount_t mscount;
                   1791: 
                   1792:                        dest->ip_nsrequest = IP_NULL;
                   1793:                        mscount = dest->ip_mscount;
                   1794:                        ip_unlock(dest);
                   1795: 
                   1796:                        ipc_notify_no_senders(nsrequest, mscount);
                   1797:                } else
                   1798:                        ip_unlock(dest);
                   1799: 
1.1.1.4 ! root     1800:                if (! ipc_port_flag_protected_payload(dest)) {
        !          1801:                        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1802:                                MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
        !          1803:                        msg->msgh_local_port = dest_name;
        !          1804:                } else {
        !          1805:                        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1806:                                MACH_MSGH_BITS(
        !          1807:                                        0, MACH_MSG_TYPE_PROTECTED_PAYLOAD));
        !          1808:                        msg->msgh_protected_payload =
        !          1809:                                dest->ip_protected_payload;
        !          1810:                }
1.1       root     1811:                msg->msgh_remote_port = MACH_PORT_NULL;
                   1812:                return MACH_MSG_SUCCESS;
                   1813:            }
                   1814: 
                   1815:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                   1816:                                MACH_MSG_TYPE_PORT_SEND_ONCE): {
                   1817:                ipc_entry_t table;
                   1818:                mach_port_index_t index;
                   1819:                ipc_entry_t entry;
                   1820:                ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
                   1821:                mach_port_t dest_name, reply_name;
                   1822:                ipc_port_t nsrequest;
                   1823: 
                   1824:                /* receiving a request message */
                   1825: 
                   1826:                if (!IP_VALID(reply))
                   1827:                        break;
                   1828: 
                   1829:                is_write_lock(space);
                   1830:                if (!space->is_active ||
                   1831:                    ((index = (table = space->is_table)->ie_next) == 0)) {
                   1832:                        is_write_unlock(space);
                   1833:                        break;
                   1834:                }
                   1835: 
                   1836:                /*
                   1837:                 *      To do an atomic copyout, need simultaneous
                   1838:                 *      locks on both ports and the space.  If
                   1839:                 *      dest == reply, and simple locking is
                   1840:                 *      enabled, then we will abort.  Otherwise it's
                   1841:                 *      OK to unlock twice.
                   1842:                 */
                   1843: 
                   1844:                ip_lock(dest);
                   1845:                if (!ip_active(dest) || !ip_lock_try(reply)) {
                   1846:                        ip_unlock(dest);
                   1847:                        is_write_unlock(space);
                   1848:                        break;
                   1849:                }
                   1850: 
                   1851:                if (!ip_active(reply)) {
                   1852:                        ip_unlock(reply);
                   1853:                        ip_unlock(dest);
                   1854:                        is_write_unlock(space);
                   1855:                        break;
                   1856:                }
                   1857: 
                   1858:                assert(reply->ip_sorights > 0);
                   1859:                ip_unlock(reply);
                   1860: 
                   1861:                /* optimized ipc_entry_get */
                   1862: 
                   1863:                entry = &table[index];
                   1864:                table->ie_next = entry->ie_next;
                   1865:                entry->ie_request = 0;
                   1866: 
                   1867:            {
                   1868:                mach_port_gen_t gen;
                   1869: 
                   1870:                assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
                   1871:                gen = entry->ie_bits + IE_BITS_GEN_ONE;
                   1872: 
                   1873:                reply_name = MACH_PORT_MAKE(index, gen);
                   1874: 
                   1875:                /* optimized ipc_right_copyout */
                   1876: 
                   1877:                entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
                   1878:            }
                   1879: 
                   1880:                assert(MACH_PORT_VALID(reply_name));
                   1881:                entry->ie_object = (ipc_object_t) reply;
                   1882:                is_write_unlock(space);
                   1883: 
                   1884:                /* optimized ipc_object_copyout_dest */
                   1885: 
                   1886:                assert(dest->ip_srights > 0);
                   1887:                ip_release(dest);
                   1888: 
                   1889:                if (dest->ip_receiver == space)
                   1890:                        dest_name = dest->ip_receiver_name;
                   1891:                else
                   1892:                        dest_name = MACH_PORT_NULL;
                   1893: 
                   1894:                if ((--dest->ip_srights == 0) &&
                   1895:                    ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
                   1896:                        mach_port_mscount_t mscount;
                   1897: 
                   1898:                        dest->ip_nsrequest = IP_NULL;
                   1899:                        mscount = dest->ip_mscount;
                   1900:                        ip_unlock(dest);
                   1901: 
                   1902:                        ipc_notify_no_senders(nsrequest, mscount);
                   1903:                } else
                   1904:                        ip_unlock(dest);
                   1905: 
1.1.1.4 ! root     1906:                if (! ipc_port_flag_protected_payload(dest)) {
        !          1907:                        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1908:                                MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
        !          1909:                                               MACH_MSG_TYPE_PORT_SEND));
        !          1910:                        msg->msgh_local_port = dest_name;
        !          1911:                } else {
        !          1912:                        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1913:                                MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
        !          1914:                                        MACH_MSG_TYPE_PROTECTED_PAYLOAD));
        !          1915:                        msg->msgh_protected_payload =
        !          1916:                                dest->ip_protected_payload;
        !          1917:                }
1.1       root     1918:                msg->msgh_remote_port = reply_name;
                   1919:                return MACH_MSG_SUCCESS;
                   1920:            }
                   1921: 
                   1922:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
                   1923:                mach_port_t dest_name;
                   1924: 
                   1925:                /* receiving a reply message */
                   1926: 
                   1927:                ip_lock(dest);
                   1928:                if (!ip_active(dest)) {
                   1929:                        ip_unlock(dest);
                   1930:                        break;
                   1931:                }
                   1932: 
                   1933:                /* optimized ipc_object_copyout_dest */
                   1934: 
                   1935:                assert(dest->ip_sorights > 0);
                   1936: 
                   1937:                if (dest->ip_receiver == space) {
                   1938:                        ip_release(dest);
                   1939:                        dest->ip_sorights--;
                   1940:                        dest_name = dest->ip_receiver_name;
                   1941:                        ip_unlock(dest);
                   1942:                } else {
                   1943:                        ip_unlock(dest);
                   1944: 
                   1945:                        ipc_notify_send_once(dest);
                   1946:                        dest_name = MACH_PORT_NULL;
                   1947:                }
                   1948: 
1.1.1.4 ! root     1949:                if (! ipc_port_flag_protected_payload(dest)) {
        !          1950:                        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1951:                                MACH_MSGH_BITS(0,
        !          1952:                                        MACH_MSG_TYPE_PORT_SEND_ONCE));
        !          1953:                        msg->msgh_local_port = dest_name;
        !          1954:                } else {
        !          1955:                        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1956:                                MACH_MSGH_BITS(0,
        !          1957:                                        MACH_MSG_TYPE_PROTECTED_PAYLOAD));
        !          1958:                        msg->msgh_protected_payload =
        !          1959:                                dest->ip_protected_payload;
        !          1960:                }
1.1       root     1961:                msg->msgh_remote_port = MACH_PORT_NULL;
                   1962:                return MACH_MSG_SUCCESS;
                   1963:            }
                   1964: 
                   1965:            default:
                   1966:                /* don't bother optimizing */
                   1967:                break;
                   1968:        }
                   1969: #endif /* MIGRATING_THREADS */
                   1970: 
                   1971:     {
                   1972:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                   1973:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                   1974:        ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
                   1975:        mach_port_t dest_name, reply_name;
                   1976: 
                   1977:        if (IP_VALID(reply)) {
                   1978:                ipc_port_t notify_port;
                   1979:                ipc_entry_t entry;
                   1980:                kern_return_t kr;
                   1981: 
                   1982:                /*
                   1983:                 *      Handling notify (for MACH_RCV_NOTIFY) is tricky.
                   1984:                 *      The problem is atomically making a send-once right
                   1985:                 *      from the notify port and installing it for a
                   1986:                 *      dead-name request in the new entry, because this
                   1987:                 *      requires two port locks (on the notify port and
                   1988:                 *      the reply port).  However, we can safely make
                   1989:                 *      and consume send-once rights for the notify port
                   1990:                 *      as long as we hold the space locked.  This isn't
                   1991:                 *      an atomicity problem, because the only way
                   1992:                 *      to detect that a send-once right has been created
                   1993:                 *      and then consumed if it wasn't needed is by getting
                   1994:                 *      at the receive right to look at ip_sorights, and
                   1995:                 *      because the space is write-locked status calls can't
                   1996:                 *      lookup the notify port receive right.  When we make
                   1997:                 *      the send-once right, we lock the notify port,
                   1998:                 *      so any status calls in progress will be done.
                   1999:                 */
                   2000: 
                   2001:                is_write_lock(space);
                   2002: 
                   2003:                for (;;) {
                   2004:                        ipc_port_request_index_t request;
                   2005: 
                   2006:                        if (!space->is_active) {
                   2007:                                is_write_unlock(space);
                   2008:                                return (MACH_RCV_HEADER_ERROR|
                   2009:                                        MACH_MSG_IPC_SPACE);
                   2010:                        }
                   2011: 
                   2012:                        if (notify != MACH_PORT_NULL) {
                   2013:                                notify_port = ipc_port_lookup_notify(space,
                   2014:                                                                     notify);
                   2015:                                if (notify_port == IP_NULL) {
                   2016:                                        is_write_unlock(space);
                   2017:                                        return MACH_RCV_INVALID_NOTIFY;
                   2018:                                }
                   2019:                        } else
                   2020:                                notify_port = IP_NULL;
                   2021: 
                   2022:                        if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
                   2023:                            ipc_right_reverse(space, (ipc_object_t) reply,
                   2024:                                              &reply_name, &entry)) {
                   2025:                                /* reply port is locked and active */
                   2026: 
                   2027:                                /*
                   2028:                                 *      We don't need the notify_port
                   2029:                                 *      send-once right, but we can't release
                   2030:                                 *      it here because reply port is locked.
                   2031:                                 *      Wait until after the copyout to
                   2032:                                 *      release the notify port right.
                   2033:                                 */
                   2034: 
                   2035:                                assert(entry->ie_bits &
                   2036:                                                MACH_PORT_TYPE_SEND_RECEIVE);
                   2037:                                break;
                   2038:                        }
                   2039: 
                   2040:                        ip_lock(reply);
                   2041:                        if (!ip_active(reply)) {
                   2042:                                ip_release(reply);
                   2043:                                ip_check_unlock(reply);
                   2044: 
                   2045:                                if (notify_port != IP_NULL)
                   2046:                                        ipc_port_release_sonce(notify_port);
                   2047: 
                   2048:                                ip_lock(dest);
                   2049:                                is_write_unlock(space);
                   2050: 
                   2051:                                reply = IP_DEAD;
                   2052:                                reply_name = MACH_PORT_DEAD;
                   2053:                                goto copyout_dest;
                   2054:                        }
                   2055: 
                   2056:                        kr = ipc_entry_get(space, &reply_name, &entry);
                   2057:                        if (kr != KERN_SUCCESS) {
                   2058:                                ip_unlock(reply);
                   2059: 
                   2060:                                if (notify_port != IP_NULL)
                   2061:                                        ipc_port_release_sonce(notify_port);
                   2062: 
                   2063:                                /* space is locked */
                   2064:                                kr = ipc_entry_grow_table(space);
                   2065:                                if (kr != KERN_SUCCESS) {
                   2066:                                        /* space is unlocked */
                   2067: 
                   2068:                                        if (kr == KERN_RESOURCE_SHORTAGE)
                   2069:                                                return (MACH_RCV_HEADER_ERROR|
                   2070:                                                        MACH_MSG_IPC_KERNEL);
                   2071:                                        else
                   2072:                                                return (MACH_RCV_HEADER_ERROR|
                   2073:                                                        MACH_MSG_IPC_SPACE);
                   2074:                                }
                   2075:                                /* space is locked again; start over */
                   2076: 
                   2077:                                continue;
                   2078:                        }
                   2079: 
                   2080:                        assert(IE_BITS_TYPE(entry->ie_bits)
                   2081:                                                == MACH_PORT_TYPE_NONE);
                   2082:                        assert(entry->ie_object == IO_NULL);
                   2083: 
                   2084:                        if (notify_port == IP_NULL) {
                   2085:                                /* not making a dead-name request */
                   2086: 
                   2087:                                entry->ie_object = (ipc_object_t) reply;
                   2088:                                break;
                   2089:                        }
                   2090: 
                   2091:                        kr = ipc_port_dnrequest(reply, reply_name,
                   2092:                                                notify_port, &request);
                   2093:                        if (kr != KERN_SUCCESS) {
                   2094:                                ip_unlock(reply);
                   2095: 
                   2096:                                ipc_port_release_sonce(notify_port);
                   2097: 
                   2098:                                ipc_entry_dealloc(space, reply_name, entry);
                   2099:                                is_write_unlock(space);
                   2100: 
                   2101:                                ip_lock(reply);
                   2102:                                if (!ip_active(reply)) {
                   2103:                                        /* will fail next time around loop */
                   2104: 
                   2105:                                        ip_unlock(reply);
                   2106:                                        is_write_lock(space);
                   2107:                                        continue;
                   2108:                                }
                   2109: 
                   2110:                                kr = ipc_port_dngrow(reply);
                   2111:                                /* port is unlocked */
                   2112:                                if (kr != KERN_SUCCESS)
                   2113:                                        return (MACH_RCV_HEADER_ERROR|
                   2114:                                                MACH_MSG_IPC_KERNEL);
                   2115: 
                   2116:                                is_write_lock(space);
                   2117:                                continue;
                   2118:                        }
                   2119: 
                   2120:                        notify_port = IP_NULL; /* don't release right below */
                   2121: 
                   2122:                        entry->ie_object = (ipc_object_t) reply;
                   2123:                        entry->ie_request = request;
                   2124:                        break;
                   2125:                }
                   2126: 
                   2127:                /* space and reply port are locked and active */
                   2128: 
                   2129:                ip_reference(reply);    /* hold onto the reply port */
                   2130: 
                   2131:                kr = ipc_right_copyout(space, reply_name, entry,
                   2132:                                       reply_type, TRUE, (ipc_object_t) reply);
                   2133:                /* reply port is unlocked */
                   2134:                assert(kr == KERN_SUCCESS);
                   2135: 
                   2136:                if (notify_port != IP_NULL)
                   2137:                        ipc_port_release_sonce(notify_port);
                   2138: 
                   2139:                ip_lock(dest);
                   2140:                is_write_unlock(space);
                   2141:        } else {
                   2142:                /*
                   2143:                 *      No reply port!  This is an easy case.
                   2144:                 *      We only need to have the space locked
                   2145:                 *      when checking notify and when locking
                   2146:                 *      the destination (to ensure atomicity).
                   2147:                 */
                   2148: 
                   2149:                is_read_lock(space);
                   2150:                if (!space->is_active) {
                   2151:                        is_read_unlock(space);
                   2152:                        return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
                   2153:                }
                   2154: 
                   2155:                if (notify != MACH_PORT_NULL) {
                   2156:                        ipc_entry_t entry;
                   2157: 
                   2158:                        /* must check notify even though it won't be used */
                   2159: 
                   2160:                        if (((entry = ipc_entry_lookup(space, notify))
                   2161:                                                                == IE_NULL) ||
                   2162:                            ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
                   2163:                                is_read_unlock(space);
                   2164:                                return MACH_RCV_INVALID_NOTIFY;
                   2165:                        }
                   2166:                }
                   2167: 
                   2168:                ip_lock(dest);
                   2169:                is_read_unlock(space);
                   2170: 
                   2171:                reply_name = (mach_port_t) reply;
                   2172:        }
                   2173: 
                   2174:        /*
                   2175:         *      At this point, the space is unlocked and the destination
                   2176:         *      port is locked.  (Lock taken while space was locked.)
                   2177:         *      reply_name is taken care of; we still need dest_name.
                   2178:         *      We still hold a ref for reply (if it is valid).
                   2179:         *
                   2180:         *      If the space holds receive rights for the destination,
                   2181:         *      we return its name for the right.  Otherwise the task
                   2182:         *      managed to destroy or give away the receive right between
                   2183:         *      receiving the message and this copyout.  If the destination
                   2184:         *      is dead, return MACH_PORT_DEAD, and if the receive right
                   2185:         *      exists somewhere else (another space, in transit)
                   2186:         *      return MACH_PORT_NULL.
                   2187:         *
                   2188:         *      Making this copyout operation atomic with the previous
                   2189:         *      copyout of the reply port is a bit tricky.  If there was
                   2190:         *      no real reply port (it wasn't IP_VALID) then this isn't
                   2191:         *      an issue.  If the reply port was dead at copyout time,
                   2192:         *      then we are OK, because if dest is dead we serialize
                   2193:         *      after the death of both ports and if dest is alive
                   2194:         *      we serialize after reply died but before dest's (later) death.
                   2195:         *      So assume reply was alive when we copied it out.  If dest
                   2196:         *      is alive, then we are OK because we serialize before
                   2197:         *      the ports' deaths.  So assume dest is dead when we look at it.
                   2198:         *      If reply dies/died after dest, then we are OK because
                   2199:         *      we serialize after dest died but before reply dies.
                   2200:         *      So the hard case is when reply is alive at copyout,
                   2201:         *      dest is dead at copyout, and reply died before dest died.
                   2202:         *      In this case pretend that dest is still alive, so
                   2203:         *      we serialize while both ports are alive.
                   2204:         *
                   2205:         *      Because the space lock is held across the copyout of reply
                   2206:         *      and locking dest, the receive right for dest can't move
                   2207:         *      in or out of the space while the copyouts happen, so
                   2208:         *      that isn't an atomicity problem.  In the last hard case
                   2209:         *      above, this implies that when dest is dead that the
                   2210:         *      space couldn't have had receive rights for dest at
                   2211:         *      the time reply was copied-out, so when we pretend
                   2212:         *      that dest is still alive, we can return MACH_PORT_NULL.
                   2213:         *
                   2214:         *      If dest == reply, then we have to make it look like
                   2215:         *      either both copyouts happened before the port died,
                   2216:         *      or both happened after the port died.  This special
                   2217:         *      case works naturally if the timestamp comparison
                   2218:         *      is done correctly.
                   2219:         */
                   2220: 
                   2221:     copyout_dest:
                   2222: 
                   2223:        if (ip_active(dest)) {
                   2224:                ipc_object_copyout_dest(space, (ipc_object_t) dest,
                   2225:                                        dest_type, &dest_name);
                   2226:                /* dest is unlocked */
                   2227:        } else {
                   2228:                ipc_port_timestamp_t timestamp;
                   2229: 
                   2230:                timestamp = dest->ip_timestamp;
                   2231:                ip_release(dest);
                   2232:                ip_check_unlock(dest);
                   2233: 
                   2234:                if (IP_VALID(reply)) {
                   2235:                        ip_lock(reply);
                   2236:                        if (ip_active(reply) ||
                   2237:                            IP_TIMESTAMP_ORDER(timestamp,
                   2238:                                               reply->ip_timestamp))
                   2239:                                dest_name = MACH_PORT_DEAD;
                   2240:                        else
                   2241:                                dest_name = MACH_PORT_NULL;
                   2242:                        ip_unlock(reply);
                   2243:                } else
                   2244:                        dest_name = MACH_PORT_DEAD;
                   2245:        }
                   2246: 
                   2247:        if (IP_VALID(reply))
                   2248:                ipc_port_release(reply);
                   2249: 
1.1.1.4 ! root     2250:        if (! ipc_port_flag_protected_payload(dest)) {
        !          2251:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2252:                                  MACH_MSGH_BITS(reply_type, dest_type));
        !          2253:                msg->msgh_local_port = dest_name;
        !          2254:        } else {
        !          2255:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2256:                                  MACH_MSGH_BITS(reply_type,
        !          2257:                                        MACH_MSG_TYPE_PROTECTED_PAYLOAD));
        !          2258:                msg->msgh_protected_payload = dest->ip_protected_payload;
        !          2259:        }
1.1       root     2260:        msg->msgh_remote_port = reply_name;
                   2261:     }
                   2262: 
                   2263:        return MACH_MSG_SUCCESS;
                   2264: }
                   2265: 
                   2266: /*
                   2267:  *     Routine:        ipc_kmsg_copyout_object
                   2268:  *     Purpose:
                   2269:  *             Copy-out a port right.  Always returns a name,
                   2270:  *             even for unsuccessful return codes.  Always
                   2271:  *             consumes the supplied object.
                   2272:  *     Conditions:
                   2273:  *             Nothing locked.
                   2274:  *     Returns:
                   2275:  *             MACH_MSG_SUCCESS        The space acquired the right
                   2276:  *                     (name is valid) or the object is dead (MACH_PORT_DEAD).
                   2277:  *             MACH_MSG_IPC_SPACE      No room in space for the right,
                   2278:  *                     or the space is dead.  (Name is MACH_PORT_NULL.)
                   2279:  *             MACH_MSG_IPC_KERNEL     Kernel resource shortage.
                   2280:  *                     (Name is MACH_PORT_NULL.)
                   2281:  */
                   2282: 
                   2283: mach_msg_return_t
1.1.1.4 ! root     2284: ipc_kmsg_copyout_object(
        !          2285:        ipc_space_t             space,
        !          2286:        ipc_object_t            object,
        !          2287:        mach_msg_type_name_t    msgt_name,
        !          2288:        mach_port_t             *namep)
1.1       root     2289: {
                   2290:        if (!IO_VALID(object)) {
                   2291:                *namep = (mach_port_t) object;
                   2292:                return MACH_MSG_SUCCESS;
                   2293:        }
                   2294: 
                   2295: #ifndef MIGRATING_THREADS
                   2296:        /*
                   2297:         *      Attempt quick copyout of send rights.  We optimize for a
                   2298:         *      live port for which the receiver holds send (and not
                   2299:         *      receive) rights in his local table.
                   2300:         */
                   2301: 
                   2302:        if (msgt_name != MACH_MSG_TYPE_PORT_SEND)
                   2303:                goto slow_copyout;
                   2304: 
                   2305:     {
1.1.1.4 ! root     2306:        ipc_port_t port = (ipc_port_t) object;
1.1       root     2307:        ipc_entry_t entry;
                   2308: 
                   2309:        is_write_lock(space);
                   2310:        if (!space->is_active) {
                   2311:                is_write_unlock(space);
                   2312:                goto slow_copyout;
                   2313:        }
                   2314: 
                   2315:        ip_lock(port);
                   2316:        if (!ip_active(port) ||
                   2317:            !ipc_hash_local_lookup(space, (ipc_object_t) port,
                   2318:                                   namep, &entry)) {
                   2319:                ip_unlock(port);
                   2320:                is_write_unlock(space);
                   2321:                goto slow_copyout;
                   2322:        }
                   2323: 
                   2324:        /*
                   2325:         *      Copyout the send right, incrementing urefs
                   2326:         *      unless it would overflow, and consume the right.
                   2327:         */
                   2328: 
                   2329:        assert(port->ip_srights > 1);
                   2330:        port->ip_srights--;
                   2331:        ip_release(port);
                   2332:        ip_unlock(port);
                   2333: 
                   2334:        assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
                   2335:        assert(IE_BITS_UREFS(entry->ie_bits) > 0);
                   2336:        assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX);
                   2337: 
                   2338:     {
1.1.1.4 ! root     2339:        ipc_entry_bits_t bits = entry->ie_bits + 1;
1.1       root     2340: 
                   2341:        if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
                   2342:                entry->ie_bits = bits;
                   2343:     }
                   2344: 
                   2345:        is_write_unlock(space);
                   2346:        return MACH_MSG_SUCCESS;
                   2347:     }
                   2348: 
                   2349:     slow_copyout:
                   2350: #endif /* MIGRATING_THREADS */
                   2351: 
                   2352:    {
                   2353:        kern_return_t kr;
                   2354: 
                   2355:        kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
                   2356:        if (kr != KERN_SUCCESS) {
                   2357:                ipc_object_destroy(object, msgt_name);
                   2358: 
                   2359:                if (kr == KERN_INVALID_CAPABILITY)
                   2360:                        *namep = MACH_PORT_DEAD;
                   2361:                else {
                   2362:                        *namep = MACH_PORT_NULL;
                   2363: 
                   2364:                        if (kr == KERN_RESOURCE_SHORTAGE)
                   2365:                                return MACH_MSG_IPC_KERNEL;
                   2366:                        else
                   2367:                                return MACH_MSG_IPC_SPACE;
                   2368:                }
                   2369:        }
                   2370: 
                   2371:        return MACH_MSG_SUCCESS;
                   2372:     }
                   2373: }
                   2374: 
                   2375: /*
                   2376:  *     Routine:        ipc_kmsg_copyout_body
                   2377:  *     Purpose:
                   2378:  *             "Copy-out" port rights and out-of-line memory
                   2379:  *             in the body of a message.
                   2380:  *
                   2381:  *             The error codes are a combination of special bits.
                   2382:  *             The copyout proceeds despite errors.
                   2383:  *     Conditions:
                   2384:  *             Nothing locked.
                   2385:  *     Returns:
                   2386:  *             MACH_MSG_SUCCESS        Successful copyout.
                   2387:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
                   2388:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
                   2389:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
                   2390:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
                   2391:  */
                   2392: 
                   2393: mach_msg_return_t
1.1.1.4 ! root     2394: ipc_kmsg_copyout_body(
        !          2395:        vm_offset_t     saddr, 
        !          2396:        vm_offset_t     eaddr,
        !          2397:        ipc_space_t     space,
        !          2398:        vm_map_t        map)
1.1       root     2399: {
                   2400:        mach_msg_return_t mr = MACH_MSG_SUCCESS;
                   2401:        kern_return_t kr;
                   2402: 
                   2403:        while (saddr < eaddr) {
                   2404:                vm_offset_t taddr = saddr;
                   2405:                mach_msg_type_long_t *type;
                   2406:                mach_msg_type_name_t name;
                   2407:                mach_msg_type_size_t size;
                   2408:                mach_msg_type_number_t number;
                   2409:                boolean_t is_inline, longform, is_port;
1.1.1.3   root     2410:                unsigned64_t length;
1.1       root     2411:                vm_offset_t addr;
                   2412: 
                   2413:                type = (mach_msg_type_long_t *) saddr;
                   2414:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
                   2415:                longform = ((mach_msg_type_t*)type)->msgt_longform;
                   2416:                if (longform) {
                   2417:                        /* This must be aligned */
                   2418:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   2419:                            (is_misaligned(type))) {
                   2420:                                saddr = ptr_align(saddr);
                   2421:                                continue;
                   2422:                        }
                   2423:                        name = type->msgtl_name;
                   2424:                        size = type->msgtl_size;
                   2425:                        number = type->msgtl_number;
                   2426:                        saddr += sizeof(mach_msg_type_long_t);
                   2427:                } else {
                   2428:                        name = ((mach_msg_type_t*)type)->msgt_name;
                   2429:                        size = ((mach_msg_type_t*)type)->msgt_size;
                   2430:                        number = ((mach_msg_type_t*)type)->msgt_number;
                   2431:                        saddr += sizeof(mach_msg_type_t);
                   2432:                }
                   2433: 
                   2434:                /* padding (ptrs and ports) ? */
                   2435:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   2436:                    ((size >> 3) == sizeof(natural_t)))
                   2437:                        saddr = ptr_align(saddr);
                   2438: 
                   2439:                /* calculate length of data in bytes, rounding up */
                   2440: 
1.1.1.3   root     2441:                length = (((unsigned64_t) number * size) + 7) >> 3;
1.1       root     2442: 
                   2443:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
                   2444: 
                   2445:                if (is_port) {
                   2446:                        mach_port_t *objects;
                   2447:                        mach_msg_type_number_t i;
                   2448: 
                   2449:                        if (!is_inline && (length != 0)) {
                   2450:                                /* first allocate memory in the map */
                   2451: 
                   2452:                                kr = vm_allocate(map, &addr, length, TRUE);
                   2453:                                if (kr != KERN_SUCCESS) {
                   2454:                                        ipc_kmsg_clean_body(taddr, saddr);
                   2455:                                        goto vm_copyout_failure;
                   2456:                                }
                   2457:                        }
                   2458: 
                   2459:                        objects = (mach_port_t *)
                   2460:                                (is_inline ? saddr : * (vm_offset_t *) saddr);
                   2461: 
                   2462:                        /* copyout port rights carried in the message */
                   2463: 
                   2464:                        for (i = 0; i < number; i++) {
                   2465:                                ipc_object_t object =
                   2466:                                        (ipc_object_t) objects[i];
                   2467: 
                   2468:                                mr |= ipc_kmsg_copyout_object(space, object,
                   2469:                                                        name, &objects[i]);
                   2470:                        }
                   2471:                }
                   2472: 
                   2473:                if (is_inline) {
                   2474:                        /* inline data sizes round up to int boundaries */
                   2475: 
                   2476:                        ((mach_msg_type_t*)type)->msgt_deallocate = FALSE;
                   2477:                        saddr += (length + 3) &~ 3;
                   2478:                } else {
                   2479:                        vm_offset_t data;
                   2480: 
                   2481:                        if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
                   2482:                                saddr = ptr_align(saddr);
                   2483: 
                   2484:                        data = * (vm_offset_t *) saddr;
                   2485: 
                   2486:                        /* copyout memory carried in the message */
                   2487: 
                   2488:                        if (length == 0) {
                   2489:                                assert(data == 0);
                   2490:                                addr = 0;
                   2491:                        } else if (is_port) {
                   2492:                                /* copyout to memory allocated above */
                   2493: 
                   2494:                                (void) copyoutmap(map, (char *) data,
                   2495:                                                  (char *) addr, length);
                   2496:                                kfree(data, length);
                   2497:                        } else {
                   2498:                                vm_map_copy_t copy = (vm_map_copy_t) data;
                   2499: 
                   2500:                                kr = vm_map_copyout(map, &addr, copy);
                   2501:                                if (kr != KERN_SUCCESS) {
                   2502:                                        vm_map_copy_discard(copy);
                   2503: 
                   2504:                                    vm_copyout_failure:
                   2505: 
                   2506:                                        addr = 0;
                   2507:                                        if (longform)
                   2508:                                                type->msgtl_size = 0;
                   2509:                                        else
                   2510:                                                ((mach_msg_type_t*)type)->msgt_size = 0;
                   2511: 
                   2512:                                        if (kr == KERN_RESOURCE_SHORTAGE)
                   2513:                                                mr |= MACH_MSG_VM_KERNEL;
                   2514:                                        else
                   2515:                                                mr |= MACH_MSG_VM_SPACE;
                   2516:                                }
                   2517:                        }
                   2518: 
                   2519:                        ((mach_msg_type_t*)type)->msgt_deallocate = TRUE;
                   2520:                        * (vm_offset_t *) saddr = addr;
                   2521:                        saddr += sizeof(vm_offset_t);
                   2522:                }
                   2523:        }
                   2524: 
                   2525:        return mr;
                   2526: }
                   2527: 
                   2528: /*
                   2529:  *     Routine:        ipc_kmsg_copyout
                   2530:  *     Purpose:
                   2531:  *             "Copy-out" port rights and out-of-line memory
                   2532:  *             in the message.
                   2533:  *     Conditions:
                   2534:  *             Nothing locked.
                   2535:  *     Returns:
                   2536:  *             MACH_MSG_SUCCESS        Copied out all rights and memory.
                   2537:  *             MACH_RCV_INVALID_NOTIFY Bad notify port.
                   2538:  *                     Rights and memory in the message are intact.
                   2539:  *             MACH_RCV_HEADER_ERROR + special bits
                   2540:  *                     Rights and memory in the message are intact.
                   2541:  *             MACH_RCV_BODY_ERROR + special bits
                   2542:  *                     The message header was successfully copied out.
                   2543:  *                     As much of the body was handled as possible.
                   2544:  */
                   2545: 
                   2546: mach_msg_return_t
1.1.1.4 ! root     2547: ipc_kmsg_copyout(
        !          2548:        ipc_kmsg_t      kmsg,
        !          2549:        ipc_space_t     space,
        !          2550:        vm_map_t        map,
        !          2551:        mach_port_t     notify)
1.1       root     2552: {
                   2553:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                   2554:        mach_msg_return_t mr;
                   2555: 
                   2556:        mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
                   2557:        if (mr != MACH_MSG_SUCCESS)
                   2558:                return mr;
                   2559: 
                   2560:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                   2561:                vm_offset_t saddr, eaddr;
                   2562: 
                   2563:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
                   2564:                eaddr = (vm_offset_t) &kmsg->ikm_header +
                   2565:                                kmsg->ikm_header.msgh_size;
                   2566: 
                   2567:                mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map);
                   2568:                if (mr != MACH_MSG_SUCCESS)
                   2569:                        mr |= MACH_RCV_BODY_ERROR;
                   2570:        }
                   2571: 
                   2572:        return mr;
                   2573: }
                   2574: 
                   2575: /*
                   2576:  *     Routine:        ipc_kmsg_copyout_pseudo
                   2577:  *     Purpose:
                   2578:  *             Does a pseudo-copyout of the message.
                   2579:  *             This is like a regular copyout, except
                   2580:  *             that the ports in the header are handled
                   2581:  *             as if they are in the body.  They aren't reversed.
                   2582:  *
                   2583:  *             The error codes are a combination of special bits.
                   2584:  *             The copyout proceeds despite errors.
                   2585:  *     Conditions:
                   2586:  *             Nothing locked.
                   2587:  *     Returns:
                   2588:  *             MACH_MSG_SUCCESS        Successful copyout.
                   2589:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
                   2590:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
                   2591:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
                   2592:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
                   2593:  */
                   2594: 
                   2595: mach_msg_return_t
                   2596: ipc_kmsg_copyout_pseudo(
                   2597:        ipc_kmsg_t              kmsg,
                   2598:        ipc_space_t             space,
                   2599:        vm_map_t                map)
                   2600: {
                   2601:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                   2602:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   2603:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   2604:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                   2605:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                   2606:        mach_port_t dest_name, reply_name;
                   2607:        mach_msg_return_t mr;
                   2608: 
                   2609:        assert(IO_VALID(dest));
                   2610: 
                   2611:        mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
                   2612:              ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
                   2613: 
                   2614:        kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
                   2615:        kmsg->ikm_header.msgh_remote_port = dest_name;
                   2616:        kmsg->ikm_header.msgh_local_port = reply_name;
                   2617: 
                   2618:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                   2619:                vm_offset_t saddr, eaddr;
                   2620: 
                   2621:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
                   2622:                eaddr = (vm_offset_t) &kmsg->ikm_header +
                   2623:                                kmsg->ikm_header.msgh_size;
                   2624: 
                   2625:                mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map);
                   2626:        }
                   2627: 
                   2628:        return mr;
                   2629: }
                   2630: 
                   2631: /*
                   2632:  *     Routine:        ipc_kmsg_copyout_dest
                   2633:  *     Purpose:
                   2634:  *             Copies out the destination port in the message.
                   2635:  *             Destroys all other rights and memory in the message.
                   2636:  *     Conditions:
                   2637:  *             Nothing locked.
                   2638:  */
                   2639: 
                   2640: void
1.1.1.4 ! root     2641: ipc_kmsg_copyout_dest(
        !          2642:        ipc_kmsg_t      kmsg,
        !          2643:        ipc_space_t     space)
1.1       root     2644: {
                   2645:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                   2646:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   2647:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   2648:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                   2649:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                   2650:        mach_port_t dest_name, reply_name;
                   2651: 
                   2652:        assert(IO_VALID(dest));
                   2653: 
                   2654:        io_lock(dest);
                   2655:        if (io_active(dest)) {
                   2656:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
                   2657:                /* dest is unlocked */
                   2658:        } else {
                   2659:                io_release(dest);
                   2660:                io_check_unlock(dest);
                   2661:                dest_name = MACH_PORT_DEAD;
                   2662:        }
                   2663: 
                   2664:        if (IO_VALID(reply)) {
                   2665:                ipc_object_destroy(reply, reply_type);
                   2666:                reply_name = MACH_PORT_NULL;
                   2667:        } else
                   2668:                reply_name = (mach_port_t) reply;
                   2669: 
                   2670:        kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                   2671:                                      MACH_MSGH_BITS(reply_type, dest_type));
                   2672:        kmsg->ikm_header.msgh_local_port = dest_name;
                   2673:        kmsg->ikm_header.msgh_remote_port = reply_name;
                   2674: 
                   2675:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                   2676:                vm_offset_t saddr, eaddr;
                   2677: 
                   2678:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
                   2679:                eaddr = (vm_offset_t) &kmsg->ikm_header +
                   2680:                                kmsg->ikm_header.msgh_size;
                   2681: 
                   2682:                ipc_kmsg_clean_body(saddr, eaddr);
                   2683:        }
                   2684: }
                   2685: 
                   2686: #if    MACH_KDB
                   2687: 
                   2688: char *
1.1.1.4 ! root     2689: ipc_type_name(
        !          2690:        int             type_name,
        !          2691:        boolean_t       received)
1.1       root     2692: {
                   2693:        switch (type_name) {
                   2694:                case MACH_MSG_TYPE_BOOLEAN:
                   2695:                return "boolean";
1.1.1.2   root     2696: 
1.1       root     2697:                case MACH_MSG_TYPE_INTEGER_16:
                   2698:                return "short";
1.1.1.2   root     2699: 
1.1       root     2700:                case MACH_MSG_TYPE_INTEGER_32:
                   2701:                return "int32";
                   2702: 
                   2703:                case MACH_MSG_TYPE_INTEGER_64:
                   2704:                return "int64";
1.1.1.2   root     2705: 
1.1       root     2706:                case MACH_MSG_TYPE_CHAR:
                   2707:                return "char";
1.1.1.2   root     2708: 
1.1       root     2709:                case MACH_MSG_TYPE_BYTE:
                   2710:                return "byte";
1.1.1.2   root     2711: 
1.1       root     2712:                case MACH_MSG_TYPE_REAL:
                   2713:                return "real";
1.1.1.2   root     2714: 
1.1       root     2715:                case MACH_MSG_TYPE_STRING:
                   2716:                return "string";
1.1.1.2   root     2717: 
1.1       root     2718:                case MACH_MSG_TYPE_PORT_NAME:
                   2719:                return "port_name";
1.1.1.2   root     2720: 
1.1       root     2721:                case MACH_MSG_TYPE_MOVE_RECEIVE:
                   2722:                if (received) {
                   2723:                        return "port_receive";
                   2724:                } else {
                   2725:                        return "move_receive";
                   2726:                }
1.1.1.2   root     2727: 
1.1       root     2728:                case MACH_MSG_TYPE_MOVE_SEND:
                   2729:                if (received) {
                   2730:                        return "port_send";
                   2731:                } else {
                   2732:                        return "move_send";
                   2733:                }
1.1.1.2   root     2734: 
1.1       root     2735:                case MACH_MSG_TYPE_MOVE_SEND_ONCE:
                   2736:                if (received) {
                   2737:                        return "port_send_once";
                   2738:                } else {
                   2739:                        return "move_send_once";
                   2740:                }
1.1.1.2   root     2741: 
1.1       root     2742:                case MACH_MSG_TYPE_COPY_SEND:
                   2743:                return "copy_send";
1.1.1.2   root     2744: 
1.1       root     2745:                case MACH_MSG_TYPE_MAKE_SEND:
                   2746:                return "make_send";
1.1.1.2   root     2747: 
1.1       root     2748:                case MACH_MSG_TYPE_MAKE_SEND_ONCE:
                   2749:                return "make_send_once";
1.1.1.2   root     2750: 
1.1       root     2751:                default:
                   2752:                return (char *) 0;
                   2753:        }
                   2754: }
1.1.1.2   root     2755: 
1.1       root     2756: void
                   2757: ipc_print_type_name(
                   2758:        int     type_name)
                   2759: {
                   2760:        char *name = ipc_type_name(type_name, TRUE);
                   2761:        if (name) {
                   2762:                printf("%s", name);
                   2763:        } else {
                   2764:                printf("type%d", type_name);
                   2765:        }
                   2766: }
                   2767: 
                   2768: /*
                   2769:  * ipc_kmsg_print      [ debug ]
                   2770:  */
                   2771: void
1.1.1.4 ! root     2772: ipc_kmsg_print(ipc_kmsg_t kmsg)
1.1       root     2773: {
                   2774:        db_printf("kmsg=0x%x\n", kmsg);
                   2775:        db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x",
                   2776:                  kmsg->ikm_next,
                   2777:                  kmsg->ikm_prev,
                   2778:                  kmsg->ikm_size,
                   2779:                  kmsg->ikm_marequest);
                   2780:        db_printf("\n");
                   2781:        ipc_msg_print(&kmsg->ikm_header);
                   2782: }
                   2783: 
                   2784: /*
                   2785:  * ipc_msg_print       [ debug ]
                   2786:  */
                   2787: void
1.1.1.4 ! root     2788: ipc_msg_print(mach_msg_header_t *msgh)
1.1       root     2789: {
                   2790:        vm_offset_t saddr, eaddr;
                   2791: 
                   2792:        db_printf("msgh_bits=0x%x: ", msgh->msgh_bits);
                   2793:        if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
                   2794:                db_printf("complex,");
                   2795:        }
                   2796:        if (msgh->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
                   2797:                db_printf("circular,");
                   2798:        }
                   2799:        if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_PORTS) {
                   2800:                db_printf("complex_ports,");
                   2801:        }
                   2802:        if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_DATA) {
                   2803:                db_printf("complex_data,");
                   2804:        }
                   2805:        if (msgh->msgh_bits & MACH_MSGH_BITS_MIGRATED) {
                   2806:                db_printf("migrated,");
                   2807:        }
                   2808:        if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) {
                   2809:                db_printf("unused=0x%x,",
                   2810:                          msgh->msgh_bits & MACH_MSGH_BITS_UNUSED);
                   2811:        }
                   2812:        db_printf("l=0x%x,r=0x%x\n",
                   2813:                  MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
                   2814:                  MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
                   2815: 
                   2816:        db_printf("msgh_id=%d,size=%d,seqno=%d,",
                   2817:                  msgh->msgh_id,
                   2818:                  msgh->msgh_size,
                   2819:                  msgh->msgh_seqno);
                   2820: 
                   2821:        if (msgh->msgh_remote_port) {
                   2822:                db_printf("remote=0x%x(", msgh->msgh_remote_port);
                   2823:                ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
                   2824:                db_printf("),");
                   2825:        } else {
                   2826:                db_printf("remote=null,\n");
                   2827:        }
                   2828: 
                   2829:        if (msgh->msgh_local_port) {
                   2830:                db_printf("local=0x%x(", msgh->msgh_local_port);
                   2831:                ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
                   2832:                db_printf(")\n");
                   2833:        } else {
                   2834:                db_printf("local=null\n");
                   2835:        }
                   2836: 
                   2837:        saddr = (vm_offset_t) (msgh + 1);
                   2838:        eaddr = (vm_offset_t) msgh + msgh->msgh_size;
                   2839: 
                   2840:        while (saddr < eaddr) {
                   2841:                mach_msg_type_long_t *type;
                   2842:                mach_msg_type_name_t name;
                   2843:                mach_msg_type_size_t size;
                   2844:                mach_msg_type_number_t number;
                   2845:                boolean_t is_inline, longform, dealloc, is_port;
                   2846:                vm_size_t length;
                   2847: 
                   2848:                type = (mach_msg_type_long_t *) saddr;
                   2849: 
                   2850:                if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
                   2851:                    ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
                   2852:                     ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
                   2853:                        db_printf("*** msg too small\n");
                   2854:                        return;
                   2855:                }
                   2856: 
                   2857:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
                   2858:                dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
                   2859:                if (longform) {
                   2860:                        /* This must be aligned */
                   2861:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   2862:                            (is_misaligned(type))) {
                   2863:                                saddr = ptr_align(saddr);
                   2864:                                continue;
                   2865:                        }
                   2866:                        name = type->msgtl_name;
                   2867:                        size = type->msgtl_size;
                   2868:                        number = type->msgtl_number;
                   2869:                        saddr += sizeof(mach_msg_type_long_t);
                   2870:                } else {
                   2871:                        name = ((mach_msg_type_t*)type)->msgt_name;
                   2872:                        size = ((mach_msg_type_t*)type)->msgt_size;
                   2873:                        number = ((mach_msg_type_t*)type)->msgt_number;
                   2874:                        saddr += sizeof(mach_msg_type_t);
                   2875:                }
                   2876: 
                   2877:                db_printf("-- type=");
                   2878:                ipc_print_type_name(name);
                   2879:                if (! is_inline) {
                   2880:                        db_printf(",ool");
                   2881:                }
                   2882:                if (dealloc) {
                   2883:                        db_printf(",dealloc");
                   2884:                }
                   2885:                if (longform) {
                   2886:                        db_printf(",longform");
                   2887:                }
                   2888:                db_printf(",size=%d,number=%d,addr=0x%x\n",
                   2889:                       size,
                   2890:                       number,
                   2891:                       saddr);
                   2892: 
                   2893:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
                   2894: 
                   2895:                if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
                   2896:                    (longform && ((type->msgtl_header.msgt_name != 0) ||
                   2897:                                  (type->msgtl_header.msgt_size != 0) ||
                   2898:                                  (type->msgtl_header.msgt_number != 0))) ||
                   2899:                    (((mach_msg_type_t*)type)->msgt_unused != 0) ||
                   2900:                    (dealloc && is_inline)) {
                   2901:                        db_printf("*** invalid type\n");
                   2902:                        return;
                   2903:                }
                   2904: 
                   2905:                /* padding (ptrs and ports) ? */
                   2906:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
                   2907:                    ((size >> 3) == sizeof(natural_t)))
                   2908:                        saddr = ptr_align(saddr);
                   2909: 
                   2910:                /* calculate length of data in bytes, rounding up */
                   2911: 
                   2912:                length = ((number * size) + 7) >> 3;
                   2913: 
                   2914:                if (is_inline) {
                   2915:                        vm_size_t amount;
                   2916:                        int i, numwords;
                   2917: 
                   2918:                        /* inline data sizes round up to int boundaries */
                   2919:                        amount = (length + 3) &~ 3;
                   2920:                        if ((eaddr - saddr) < amount) {
                   2921:                                db_printf("*** too small\n");
                   2922:                                return;
                   2923:                        }
                   2924:                        numwords = amount / sizeof(int);
                   2925:                        if (numwords > 8) {
                   2926:                                numwords = 8;
                   2927:                        }
                   2928:                        for (i = 0; i < numwords; i++) {
                   2929:                                db_printf("0x%x\n", ((int *) saddr)[i]);
                   2930:                        }
                   2931:                        if (numwords < amount / sizeof(int)) {
                   2932:                                db_printf("...\n");
                   2933:                        }
                   2934:                        saddr += amount;
                   2935:                } else {
                   2936:                        if ((eaddr - saddr) < sizeof(vm_offset_t)) {
                   2937:                                db_printf("*** too small\n");
                   2938:                                return;
                   2939:                        }
                   2940:                        db_printf("0x%x\n", * (vm_offset_t *) saddr);
                   2941:                        saddr += sizeof(vm_offset_t);
                   2942:                }
                   2943:        }
                   2944: }
1.1.1.2   root     2945: #endif /* MACH_KDB */

unix.superglobalmegacorp.com

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