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

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