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

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990  
                     27:  * Open Software Foundation, Inc. 
                     28:  *  
                     29:  * Permission to use, copy, modify, and distribute this software and 
                     30:  * its documentation for any purpose and without fee is hereby granted, 
                     31:  * provided that the above copyright notice appears in all copies and 
                     32:  * that both the copyright notice and this permission notice appear in 
                     33:  * supporting documentation, and that the name of ("OSF") or Open Software 
                     34:  * Foundation not be used in advertising or publicity pertaining to 
                     35:  * distribution of the software without specific, written prior permission. 
                     36:  *  
                     37:  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
                     38:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
                     39:  * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY 
                     40:  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
                     41:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
                     42:  * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING 
                     43:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE 
                     44:  */
                     45: /*
                     46:  * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
                     47:  */
                     48: /* 
                     49:  * Mach Operating System
                     50:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
                     51:  * All Rights Reserved.
                     52:  * 
                     53:  * Permission to use, copy, modify and distribute this software and its
                     54:  * documentation is hereby granted, provided that both the copyright
                     55:  * notice and this permission notice appear in all copies of the
                     56:  * software, derivative works or modified versions, and any portions
                     57:  * thereof, and that both notices appear in supporting documentation.
                     58:  * 
                     59:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     60:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     61:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     62:  * 
                     63:  * Carnegie Mellon requests users of this software to return to
                     64:  * 
                     65:  *  Software Distribution Coordinator  or  [email protected]
                     66:  *  School of Computer Science
                     67:  *  Carnegie Mellon University
                     68:  *  Pittsburgh PA 15213-3890
                     69:  * 
                     70:  * any improvements or extensions that they make and grant Carnegie Mellon
                     71:  * the rights to redistribute these changes.
                     72:  */
                     73: /*
                     74:  *     File:   ipc/mach_port.c
                     75:  *     Author: Rich Draves
                     76:  *     Date:   1989
                     77:  *
                     78:  *     Exported kernel calls.  See mach/mach_port.defs.
                     79:  */
                     80: 
                     81: #import <mach/features.h>
                     82: 
                     83: #include <mach/port.h>
                     84: #include <mach/kern_return.h>
                     85: #include <mach/notify.h>
                     86: #include <mach/vm_param.h>
                     87: #include <mach/vm_prot.h>
                     88: #include <vm/vm_map.h>
                     89: #include <vm/vm_kern.h>
                     90: #include <vm/vm_user.h>
                     91: #include <ipc/ipc_entry.h>
                     92: #include <ipc/ipc_space.h>
                     93: #include <ipc/ipc_object.h>
                     94: #include <ipc/ipc_notify.h>
                     95: #include <ipc/ipc_port.h>
                     96: #include <ipc/ipc_pset.h>
                     97: #include <ipc/ipc_right.h>
                     98: 
                     99: /*
                    100:  * Forward declarations
                    101:  */
                    102: void mach_port_names_helper(
                    103:        ipc_port_timestamp_t    timestamp,
                    104:        ipc_entry_t             entry,
                    105:        mach_port_t             name,
                    106:        mach_port_t             *names,
                    107:        mach_port_type_t        *types,
                    108:        ipc_entry_num_t         *actualp);
                    109: 
                    110: void mach_port_gst_helper(
                    111:        ipc_pset_t              pset,
                    112:        ipc_port_t              port,
                    113:        ipc_entry_num_t         maxnames,
                    114:        mach_port_t             *names,
                    115:        ipc_entry_num_t         *actualp);
                    116: 
                    117: 
                    118: /*
                    119:  *     Routine:        mach_port_names_helper
                    120:  *     Purpose:
                    121:  *             A helper function for mach_port_names.
                    122:  */
                    123: 
                    124: void
                    125: mach_port_names_helper(
                    126:        ipc_port_timestamp_t    timestamp,
                    127:        ipc_entry_t             entry,
                    128:        mach_port_t             name,
                    129:        mach_port_t             *names,
                    130:        mach_port_type_t        *types,
                    131:        ipc_entry_num_t         *actualp)
                    132: {
                    133:        ipc_entry_bits_t bits = entry->ie_bits;
                    134:        ipc_port_request_index_t request = entry->ie_request;
                    135:        mach_port_type_t type;
                    136:        ipc_entry_num_t actual;
                    137: 
                    138:        if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
                    139:                ipc_port_t port;
                    140:                boolean_t died;
                    141: 
                    142:                port = (ipc_port_t) entry->ie_object;
                    143:                assert(port != IP_NULL);
                    144: 
                    145:                /*
                    146:                 *      The timestamp serializes mach_port_names
                    147:                 *      with ipc_port_destroy.  If the port died,
                    148:                 *      but after mach_port_names started, pretend
                    149:                 *      that it isn't dead.
                    150:                 */
                    151: 
                    152:                ip_lock(port);
                    153:                died = (!ip_active(port) &&
                    154:                        IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
                    155:                ip_unlock(port);
                    156: 
                    157:                if (died) {
                    158: #if    MACH_IPC_COMPAT
                    159:                        if (bits & IE_BITS_COMPAT)
                    160:                                return;
                    161: #endif /* MACH_IPC_COMPAT */
                    162: 
                    163:                        /* pretend this is a dead-name entry */
                    164: 
                    165:                        bits &= ~(IE_BITS_TYPE_MASK|IE_BITS_MAREQUEST);
                    166:                        bits |= MACH_PORT_TYPE_DEAD_NAME;
                    167:                        if (request != 0)
                    168:                                bits++;
                    169:                        request = 0;
                    170:                }
                    171:        }
                    172: 
                    173:        type = IE_BITS_TYPE(bits);
                    174: #if    MACH_IPC_COMPAT
                    175:        if (bits & IE_BITS_COMPAT)
                    176:                type |= MACH_PORT_TYPE_COMPAT;
                    177:        else
                    178: #endif /* MACH_IPC_COMPAT */
                    179:        if (request != 0)
                    180:                type |= MACH_PORT_TYPE_DNREQUEST;
                    181:        if (bits & IE_BITS_MAREQUEST)
                    182:                type |= MACH_PORT_TYPE_MAREQUEST;
                    183: 
                    184:        actual = *actualp;
                    185:        names[actual] = name;
                    186:        types[actual] = type;
                    187:        *actualp = actual+1;
                    188: }
                    189: 
                    190: /*
                    191:  *     Routine:        mach_port_names [kernel call]
                    192:  *     Purpose:
                    193:  *             Retrieves a list of the rights present in the space,
                    194:  *             along with type information.  (Same as returned
                    195:  *             by mach_port_type.)  The names are returned in
                    196:  *             no particular order, but they (and the type info)
                    197:  *             are an accurate snapshot of the space.
                    198:  *     Conditions:
                    199:  *             Nothing locked.
                    200:  *     Returns:
                    201:  *             KERN_SUCCESS            Arrays of names and types returned.
                    202:  *             KERN_INVALID_TASK       The space is null.
                    203:  *             KERN_INVALID_TASK       The space is dead.
                    204:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    205:  */
                    206: 
                    207: kern_return_t
                    208: mach_port_names(
                    209:        ipc_space_t             space,
                    210:        mach_port_t             **namesp,
                    211:        mach_msg_type_number_t  *namesCnt,
                    212:        mach_port_type_t        **typesp,
                    213:        mach_msg_type_number_t  *typesCnt)
                    214: {
                    215:        ipc_tree_entry_t tentry;
                    216:        ipc_entry_t table;
                    217:        ipc_entry_num_t tsize;
                    218:        mach_port_index_t index;
                    219:        ipc_entry_num_t actual; /* this many names */
                    220:        ipc_port_timestamp_t timestamp; /* logical time of this operation */
                    221:        mach_port_t *names;
                    222:        mach_port_type_t *types;
                    223:        kern_return_t kr;
                    224: 
                    225:        vm_size_t size;         /* size of allocated memory */
                    226:        vm_offset_t addr1;      /* allocated memory, for names */
                    227:        vm_offset_t addr2;      /* allocated memory, for types */
                    228: #if    MACH_OLD_VM_COPY
                    229:        vm_offset_t memory1;    /* copied-in memory, for names */
                    230:        vm_offset_t memory2;    /* copied-in memory, for types */
                    231: #else  /* MACH_OLD_VM_COPY */
                    232:        vm_map_copy_t memory1;  /* copied-in memory, for names */
                    233:        vm_map_copy_t memory2;  /* copied-in memory, for types */
                    234: #endif /* MACH_OLD_VM_COPY */
                    235: 
                    236:        /* safe simplifying assumption */
                    237:        assert_static(sizeof(mach_port_t) == sizeof(mach_port_type_t));
                    238: 
                    239:        if (space == IS_NULL)
                    240:                return KERN_INVALID_TASK;
                    241: 
                    242:        size = 0;
                    243: 
                    244:        for (;;) {
                    245:                ipc_entry_num_t bound;
                    246:                vm_size_t size_needed;
                    247: 
                    248:                is_read_lock(space);
                    249:                if (!space->is_active) {
                    250:                        is_read_unlock(space);
                    251:                        if (size != 0) {
                    252:                                kmem_free(ipc_kernel_map, addr1, size);
                    253:                                kmem_free(ipc_kernel_map, addr2, size);
                    254:                        }
                    255:                        return KERN_INVALID_TASK;
                    256:                }
                    257: 
                    258:                /* upper bound on number of names in the space */
                    259: 
                    260:                bound = space->is_table_size + space->is_tree_total;
                    261:                size_needed = round_page(bound * sizeof(mach_port_t));
                    262: 
                    263:                if (size_needed <= size)
                    264:                        break;
                    265: 
                    266:                is_read_unlock(space);
                    267: 
                    268:                if (size != 0) {
                    269:                        kmem_free(ipc_kernel_map, addr1, size);
                    270:                        kmem_free(ipc_kernel_map, addr2, size);
                    271:                }
                    272:                size = size_needed;
                    273: 
                    274:                kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE);
                    275:                if (kr != KERN_SUCCESS)
                    276:                        return KERN_RESOURCE_SHORTAGE;
                    277: 
                    278:                kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE);
                    279:                if (kr != KERN_SUCCESS) {
                    280:                        kmem_free(ipc_kernel_map, addr1, size);
                    281:                        return KERN_RESOURCE_SHORTAGE;
                    282:                }
                    283: 
                    284:                /* can't fault while we hold locks */
                    285: 
                    286: #if    MACH_OLD_VM_COPY
                    287:                kr = vm_map_pageable(ipc_kernel_map, addr1, addr1 + size,
                    288:                                     FALSE);
                    289:                assert(kr == KERN_SUCCESS);
                    290: 
                    291:                kr = vm_map_pageable(ipc_kernel_map, addr2, addr2 + size,
                    292:                                     FALSE);
                    293:                assert(kr == KERN_SUCCESS);
                    294: #else  /* MACH_OLD_VM_COPY */
                    295:                kr = vm_map_wire(ipc_kernel_map, addr1, addr1 + size,
                    296:                                     VM_PROT_READ|VM_PROT_WRITE, FALSE);
                    297:                assert(kr == KERN_SUCCESS);
                    298: 
                    299:                kr = vm_map_wire(ipc_kernel_map, addr2, addr2 + size,
                    300:                                     VM_PROT_READ|VM_PROT_WRITE, FALSE);
                    301:                assert(kr == KERN_SUCCESS);
                    302: #endif /* MACH_OLD_VM_COPY */
                    303:        }
                    304:        /* space is read-locked and active */
                    305: 
                    306:        names = (mach_port_t *) addr1;
                    307:        types = (mach_port_type_t *) addr2;
                    308:        actual = 0;
                    309: 
                    310:        timestamp = ipc_port_timestamp();
                    311: 
                    312:        table = space->is_table;
                    313:        tsize = space->is_table_size;
                    314: 
                    315:        for (index = 0; index < tsize; index++) {
                    316:                ipc_entry_t entry = &table[index];
                    317:                ipc_entry_bits_t bits = entry->ie_bits;
                    318: 
                    319:                if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
                    320:                        mach_port_t name = MACH_PORT_MAKEB(index, bits);
                    321: 
                    322:                        mach_port_names_helper(timestamp, entry, name,
                    323:                                               names, types, &actual);
                    324:                }
                    325:        }
                    326: 
                    327:        for (tentry = ipc_splay_traverse_start(&space->is_tree);
                    328:             tentry != ITE_NULL;
                    329:             tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
                    330:                ipc_entry_t entry = &tentry->ite_entry;
                    331:                mach_port_t name = tentry->ite_name;
                    332: 
                    333:                assert(IE_BITS_TYPE(tentry->ite_bits) !=
                    334:                        MACH_PORT_TYPE_NONE);
                    335: 
                    336:                mach_port_names_helper(timestamp, entry, name,
                    337:                                       names, types, &actual);
                    338:        }
                    339:        ipc_splay_traverse_finish(&space->is_tree);
                    340:        is_read_unlock(space);
                    341: 
                    342:        if (actual == 0) {
                    343: #if    MACH_OLD_VM_COPY
                    344:                memory1 = 0;
                    345:                memory2 = 0;
                    346: #else  /* MACH_OLD_VM_COPY */
                    347:                memory1 = VM_MAP_COPY_NULL;
                    348:                memory2 = VM_MAP_COPY_NULL;
                    349: #endif /* MACH_OLD_VM_COPY */
                    350: 
                    351:                if (size != 0) {
                    352:                        kmem_free(ipc_kernel_map, addr1, size);
                    353:                        kmem_free(ipc_kernel_map, addr2, size);
                    354:                }
                    355:        } else {
                    356:                vm_size_t size_used;
                    357:                vm_size_t vm_size_used;
                    358: 
                    359:                size_used = actual * sizeof(mach_port_t);
                    360:                vm_size_used = round_page(size_used);
                    361: 
                    362:                /*
                    363:                 *      Make used memory pageable and get it into
                    364:                 *      copied-in form.  Free any unused memory.
                    365:                 */
                    366: 
                    367: #if    MACH_OLD_VM_COPY
                    368:                kr = vm_map_pageable(ipc_kernel_map,
                    369:                                     addr1, addr1 + vm_size_used,
                    370:                                     TRUE);
                    371:                assert(kr == KERN_SUCCESS);
                    372: 
                    373:                kr = vm_map_pageable(ipc_kernel_map,
                    374:                                     addr2, addr2 + vm_size_used,
                    375:                                     TRUE);
                    376:                assert(kr == KERN_SUCCESS);
                    377: 
                    378:                kr = vm_move(
                    379:                        ipc_kernel_map, addr1,
                    380:                        ipc_soft_map, size_used,
                    381:                        TRUE, &memory1);
                    382:                assert(kr == KERN_SUCCESS);
                    383: 
                    384:                kr = vm_move(
                    385:                        ipc_kernel_map, addr2,
                    386:                        ipc_soft_map, size_used,
                    387:                        TRUE, &memory2);
                    388:                assert(kr == KERN_SUCCESS);
                    389: #else  /* MACH_OLD_VM_COPY */
                    390:                kr = vm_map_unwire(ipc_kernel_map,
                    391:                                     addr1, addr1 + vm_size_used, FALSE);
                    392:                assert(kr == KERN_SUCCESS);
                    393: 
                    394:                kr = vm_map_unwire(ipc_kernel_map,
                    395:                                     addr2, addr2 + vm_size_used, FALSE);
                    396:                assert(kr == KERN_SUCCESS);
                    397: 
                    398:                kr = vm_map_copyin(ipc_kernel_map, addr1, size_used,
                    399:                                   TRUE, &memory1);
                    400:                assert(kr == KERN_SUCCESS);
                    401: 
                    402:                kr = vm_map_copyin(ipc_kernel_map, addr2, size_used,
                    403:                                   TRUE, &memory2);
                    404:                assert(kr == KERN_SUCCESS);
                    405: #endif /* MACH_OLD_VM_COPY */
                    406: 
                    407:                if (vm_size_used != size) {
                    408:                        kmem_free(ipc_kernel_map,
                    409:                                  addr1 + vm_size_used, size - vm_size_used);
                    410:                        kmem_free(ipc_kernel_map,
                    411:                                  addr2 + vm_size_used, size - vm_size_used);
                    412:                }
                    413:        }
                    414: 
                    415:        *namesp = (mach_port_t *) memory1;
                    416:        *namesCnt = actual;
                    417:        *typesp = (mach_port_type_t *) memory2;
                    418:        *typesCnt = actual;
                    419:        return KERN_SUCCESS;
                    420: }
                    421: 
                    422: /*
                    423:  *     Routine:        mach_port_type [kernel call]
                    424:  *     Purpose:
                    425:  *             Retrieves the type of a right in the space.
                    426:  *             The type is a bitwise combination of one or more
                    427:  *             of the following type bits:
                    428:  *                     MACH_PORT_TYPE_SEND
                    429:  *                     MACH_PORT_TYPE_RECEIVE
                    430:  *                     MACH_PORT_TYPE_SEND_ONCE
                    431:  *                     MACH_PORT_TYPE_PORT_SET
                    432:  *                     MACH_PORT_TYPE_DEAD_NAME
                    433:  *             In addition, the following pseudo-type bits may be present:
                    434:  *                     MACH_PORT_TYPE_DNREQUEST
                    435:  *                             A dead-name notification is requested.
                    436:  *                     MACH_PORT_TYPE_MAREQUEST
                    437:  *                             The send/receive right is blocked;
                    438:  *                             a msg-accepted notification is outstanding.
                    439:  *                     MACH_PORT_TYPE_COMPAT
                    440:  *                             This is a compatibility-mode right;
                    441:  *                             when the port dies, it will disappear
                    442:  *                             instead of turning into a dead-name.
                    443:  *     Conditions:
                    444:  *             Nothing locked.
                    445:  *     Returns:
                    446:  *             KERN_SUCCESS            Type is returned.
                    447:  *             KERN_INVALID_TASK       The space is null.
                    448:  *             KERN_INVALID_TASK       The space is dead.
                    449:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    450:  */
                    451: 
                    452: kern_return_t
                    453: mach_port_type(
                    454:        ipc_space_t             space,
                    455:        mach_port_t             name,
                    456:        mach_port_type_t        *typep)
                    457: {
                    458:        mach_port_urefs_t urefs;
                    459:        ipc_entry_t entry;
                    460:        kern_return_t kr;
                    461: 
                    462:        if (space == IS_NULL)
                    463:                return KERN_INVALID_TASK;
                    464: 
                    465:        kr = ipc_right_lookup_write(space, name, &entry);
                    466:        if (kr != KERN_SUCCESS)
                    467:                return kr;
                    468:        /* space is write-locked and active */
                    469: 
                    470:        kr = ipc_right_info(space, name, entry, typep, &urefs);
                    471:        if (kr == KERN_SUCCESS)
                    472:                is_write_unlock(space);
                    473:        /* space is unlocked */
                    474:        return kr;
                    475: }
                    476: 
                    477: /*
                    478:  *     Routine:        mach_port_rename [kernel call]
                    479:  *     Purpose:
                    480:  *             Changes the name denoting a right,
                    481:  *             from oname to nname.
                    482:  *     Conditions:
                    483:  *             Nothing locked.
                    484:  *     Returns:
                    485:  *             KERN_SUCCESS            The right is renamed.
                    486:  *             KERN_INVALID_TASK       The space is null.
                    487:  *             KERN_INVALID_TASK       The space is dead.
                    488:  *             KERN_INVALID_NAME       The oname doesn't denote a right.
                    489:  *             KERN_INVALID_VALUE      The nname isn't a legal name.
                    490:  *             KERN_NAME_EXISTS        The nname already denotes a right.
                    491:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    492:  */
                    493: 
                    494: kern_return_t
                    495: mach_port_rename(
                    496:        ipc_space_t     space,
                    497:        mach_port_t     oname,
                    498:        mach_port_t     nname)
                    499: {
                    500:        if (space == IS_NULL)
                    501:                return KERN_INVALID_TASK;
                    502: 
                    503:        if (!MACH_PORT_VALID(nname))
                    504:                return KERN_INVALID_VALUE;
                    505: 
                    506:        return ipc_object_rename(space, oname, nname);
                    507: }
                    508: 
                    509: /*
                    510:  *     Routine:        mach_port_allocate_name [kernel call]
                    511:  *     Purpose:
                    512:  *             Allocates a right in a space, using a specific name
                    513:  *             for the new right.  Possible rights:
                    514:  *                     MACH_PORT_RIGHT_RECEIVE
                    515:  *                     MACH_PORT_RIGHT_PORT_SET
                    516:  *                     MACH_PORT_RIGHT_DEAD_NAME
                    517:  *
                    518:  *             A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
                    519:  *             has no extant send or send-once rights and no queued
                    520:  *             messages.  Its queue limit is MACH_PORT_QLIMIT_DEFAULT
                    521:  *             and its make-send count is 0.  It is not a member of
                    522:  *             a port set.  It has no registered no-senders or
                    523:  *             port-destroyed notification requests.
                    524:  *
                    525:  *             A new port set has no members.
                    526:  *
                    527:  *             A new dead name has one user reference.
                    528:  *     Conditions:
                    529:  *             Nothing locked.
                    530:  *     Returns:
                    531:  *             KERN_SUCCESS            The right is allocated.
                    532:  *             KERN_INVALID_TASK       The space is null.
                    533:  *             KERN_INVALID_TASK       The space is dead.
                    534:  *             KERN_INVALID_VALUE      The name isn't a legal name.
                    535:  *             KERN_INVALID_VALUE      "right" isn't a legal kind of right.
                    536:  *             KERN_NAME_EXISTS        The name already denotes a right.
                    537:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    538:  */
                    539: 
                    540: kern_return_t
                    541: mach_port_allocate_name(
                    542:        ipc_space_t             space,
                    543:        mach_port_right_t       right,
                    544:        mach_port_t             name)
                    545: {
                    546:        kern_return_t kr;
                    547: 
                    548:        if (space == IS_NULL)
                    549:                return KERN_INVALID_TASK;
                    550: 
                    551:        if (!MACH_PORT_VALID(name))
                    552:                return KERN_INVALID_VALUE;
                    553: 
                    554:        switch (right) {
                    555:            case MACH_PORT_RIGHT_RECEIVE: {
                    556:                ipc_port_t port;
                    557: 
                    558:                kr = ipc_port_alloc_name(space, name, &port);
                    559:                if (kr == KERN_SUCCESS)
                    560:                        ip_unlock(port);
                    561:                break;
                    562:            }
                    563: 
                    564:            case MACH_PORT_RIGHT_PORT_SET: {
                    565:                ipc_pset_t pset;
                    566: 
                    567:                kr = ipc_pset_alloc_name(space, name, &pset);
                    568:                if (kr == KERN_SUCCESS)
                    569:                        ips_unlock(pset);
                    570:                break;
                    571:            }
                    572: 
                    573:            case MACH_PORT_RIGHT_DEAD_NAME:
                    574:                kr = ipc_object_alloc_dead_name(space, name);
                    575:                break;
                    576: 
                    577:            default:
                    578:                kr = KERN_INVALID_VALUE;
                    579:                break;
                    580:        }
                    581: 
                    582:        return kr;
                    583: }
                    584: 
                    585: /*
                    586:  *     Routine:        mach_port_allocate [kernel call]
                    587:  *     Purpose:
                    588:  *             Allocates a right in a space.  Like mach_port_allocate_name,
                    589:  *             except that the implementation picks a name for the right.
                    590:  *             The name may be any legal name in the space that doesn't
                    591:  *             currently denote a right.
                    592:  *     Conditions:
                    593:  *             Nothing locked.
                    594:  *     Returns:
                    595:  *             KERN_SUCCESS            The right is allocated.
                    596:  *             KERN_INVALID_TASK       The space is null.
                    597:  *             KERN_INVALID_TASK       The space is dead.
                    598:  *             KERN_INVALID_VALUE      "right" isn't a legal kind of right.
                    599:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    600:  *             KERN_NO_SPACE           No room in space for another right.
                    601:  */
                    602: 
                    603: kern_return_t
                    604: mach_port_allocate(
                    605:        ipc_space_t             space,
                    606:        mach_port_right_t       right,
                    607:        mach_port_t             *namep)
                    608: {
                    609:        kern_return_t kr;
                    610: 
                    611:        if (space == IS_NULL)
                    612:                return KERN_INVALID_TASK;
                    613: 
                    614:        switch (right) {
                    615:            case MACH_PORT_RIGHT_RECEIVE: {
                    616:                ipc_port_t port;
                    617: 
                    618:                kr = ipc_port_alloc(space, namep, &port);
                    619:                if (kr == KERN_SUCCESS)
                    620:                        ip_unlock(port);
                    621:                break;
                    622:            }
                    623: 
                    624:            case MACH_PORT_RIGHT_PORT_SET: {
                    625:                ipc_pset_t pset;
                    626: 
                    627:                kr = ipc_pset_alloc(space, namep, &pset);
                    628:                if (kr == KERN_SUCCESS)
                    629:                        ips_unlock(pset);
                    630:                break;
                    631:            }
                    632: 
                    633:            case MACH_PORT_RIGHT_DEAD_NAME:
                    634:                kr = ipc_object_alloc_dead(space, namep);
                    635:                break;
                    636: 
                    637:            default:
                    638:                kr = KERN_INVALID_VALUE;
                    639:                break;
                    640:        }
                    641: 
                    642:        return kr;
                    643: }
                    644: 
                    645: /*
                    646:  *     Routine:        mach_port_destroy [kernel call]
                    647:  *     Purpose:
                    648:  *             Cleans up and destroys all rights denoted by a name
                    649:  *             in a space.  The destruction of a receive right
                    650:  *             destroys the port, unless a port-destroyed request
                    651:  *             has been made for it; the destruction of a port-set right
                    652:  *             destroys the port set.
                    653:  *     Conditions:
                    654:  *             Nothing locked.
                    655:  *     Returns:
                    656:  *             KERN_SUCCESS            The name is destroyed.
                    657:  *             KERN_INVALID_TASK       The space is null.
                    658:  *             KERN_INVALID_TASK       The space is dead.
                    659:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    660:  */
                    661: 
                    662: kern_return_t
                    663: mach_port_destroy(
                    664:        ipc_space_t     space,
                    665:        mach_port_t     name)
                    666: {
                    667:        ipc_entry_t entry;
                    668:        kern_return_t kr;
                    669: 
                    670:        if (space == IS_NULL)
                    671:                return KERN_INVALID_TASK;
                    672: 
                    673:        kr = ipc_right_lookup_write(space, name, &entry);
                    674:        if (kr != KERN_SUCCESS)
                    675:                return kr;
                    676:        /* space is write-locked and active */
                    677: 
                    678:        kr = ipc_right_destroy(space, name, entry); /* unlocks space */
                    679:        return kr;
                    680: }
                    681: 
                    682: /*
                    683:  *     Routine:        mach_port_deallocate [kernel call]
                    684:  *     Purpose:
                    685:  *             Deallocates a user reference from a send right,
                    686:  *             send-once right, or a dead-name right.  May
                    687:  *             deallocate the right, if this is the last uref,
                    688:  *             and destroy the name, if it doesn't denote
                    689:  *             other rights.
                    690:  *     Conditions:
                    691:  *             Nothing locked.
                    692:  *     Returns:
                    693:  *             KERN_SUCCESS            The uref is deallocated.
                    694:  *             KERN_INVALID_TASK       The space is null.
                    695:  *             KERN_INVALID_TASK       The space is dead.
                    696:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    697:  *             KERN_INVALID_RIGHT      The right isn't correct.
                    698:  */
                    699: 
                    700: kern_return_t
                    701: mach_port_deallocate(
                    702:        ipc_space_t     space,
                    703:        mach_port_t     name)
                    704: {
                    705:        ipc_entry_t entry;
                    706:        kern_return_t kr;
                    707: 
                    708:        if (space == IS_NULL)
                    709:                return KERN_INVALID_TASK;
                    710: 
                    711:        kr = ipc_right_lookup_write(space, name, &entry);
                    712:        if (kr != KERN_SUCCESS)
                    713:                return kr;
                    714:        /* space is write-locked */
                    715: 
                    716:        kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
                    717:        return kr;
                    718: }
                    719: 
                    720: /*
                    721:  *     Routine:        mach_port_get_refs [kernel call]
                    722:  *     Purpose:
                    723:  *             Retrieves the number of user references held by a right.
                    724:  *             Receive rights, port-set rights, and send-once rights
                    725:  *             always have one user reference.  Returns zero if the
                    726:  *             name denotes a right, but not the queried right.
                    727:  *     Conditions:
                    728:  *             Nothing locked.
                    729:  *     Returns:
                    730:  *             KERN_SUCCESS            Number of urefs returned.
                    731:  *             KERN_INVALID_TASK       The space is null.
                    732:  *             KERN_INVALID_TASK       The space is dead.
                    733:  *             KERN_INVALID_VALUE      "right" isn't a legal value.
                    734:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    735:  */
                    736: 
                    737: kern_return_t
                    738: mach_port_get_refs(
                    739:        ipc_space_t             space,
                    740:        mach_port_t             name,
                    741:        mach_port_right_t       right,
                    742:        mach_port_urefs_t       *urefsp)
                    743: {
                    744:        mach_port_type_t type;
                    745:        mach_port_urefs_t urefs;
                    746:        ipc_entry_t entry;
                    747:        kern_return_t kr;
                    748: 
                    749:        if (space == IS_NULL)
                    750:                return KERN_INVALID_TASK;
                    751: 
                    752:        if (right >= MACH_PORT_RIGHT_NUMBER)
                    753:                return KERN_INVALID_VALUE;
                    754: 
                    755:        kr = ipc_right_lookup_write(space, name, &entry);
                    756:        if (kr != KERN_SUCCESS)
                    757:                return kr;
                    758:        /* space is write-locked and active */
                    759: 
                    760:        kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */
                    761:        if (kr != KERN_SUCCESS)
                    762:                return kr;      /* space is unlocked */
                    763:        is_write_unlock(space);
                    764: 
                    765:        if (type & MACH_PORT_TYPE(right))
                    766:                switch (right) {
                    767:                    case MACH_PORT_RIGHT_SEND_ONCE:
                    768:                        assert(urefs == 1);
                    769:                        /* fall-through */
                    770: 
                    771:                    case MACH_PORT_RIGHT_PORT_SET:
                    772:                    case MACH_PORT_RIGHT_RECEIVE:
                    773:                        *urefsp = 1;
                    774:                        break;
                    775: 
                    776:                    case MACH_PORT_RIGHT_DEAD_NAME:
                    777:                    case MACH_PORT_RIGHT_SEND:
                    778:                        assert(urefs > 0);
                    779:                        *urefsp = urefs;
                    780:                        break;
                    781: 
                    782:                    default:
                    783:                        panic("mach_port_get_refs: strange rights");
                    784:                }
                    785:        else
                    786:                *urefsp = 0;
                    787: 
                    788:        return kr;
                    789: }
                    790: 
                    791: /*
                    792:  *     Routine:        mach_port_mod_refs
                    793:  *     Purpose:
                    794:  *             Modifies the number of user references held by a right.
                    795:  *             The resulting number of user references must be non-negative.
                    796:  *             If it is zero, the right is deallocated.  If the name
                    797:  *             doesn't denote other rights, it is destroyed.
                    798:  *     Conditions:
                    799:  *             Nothing locked.
                    800:  *     Returns:
                    801:  *             KERN_SUCCESS            Modified number of urefs.
                    802:  *             KERN_INVALID_TASK       The space is null.
                    803:  *             KERN_INVALID_TASK       The space is dead.
                    804:  *             KERN_INVALID_VALUE      "right" isn't a legal value.
                    805:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    806:  *             KERN_INVALID_RIGHT      Name doesn't denote specified right.
                    807:  *             KERN_INVALID_VALUE      Impossible modification to urefs.
                    808:  *             KERN_UREFS_OVERFLOW     Urefs would overflow.
                    809:  */
                    810: 
                    811: kern_return_t
                    812: mach_port_mod_refs(
                    813:        ipc_space_t             space,
                    814:        mach_port_t             name,
                    815:        mach_port_right_t       right,
                    816:        mach_port_delta_t       delta)
                    817: {
                    818:        ipc_entry_t entry;
                    819:        kern_return_t kr;
                    820: 
                    821:        if (space == IS_NULL)
                    822:                return KERN_INVALID_TASK;
                    823: 
                    824:        if (right >= MACH_PORT_RIGHT_NUMBER)
                    825:                return KERN_INVALID_VALUE;
                    826: 
                    827:        kr = ipc_right_lookup_write(space, name, &entry);
                    828:        if (kr != KERN_SUCCESS)
                    829:                return kr;
                    830:        /* space is write-locked and active */
                    831: 
                    832:        kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
                    833:        return kr;
                    834: }
                    835: 
                    836: /*
                    837:  *     Routine:        mach_port_set_qlimit [kernel call]
                    838:  *     Purpose:
                    839:  *             Changes a receive right's queue limit.
                    840:  *             The new queue limit must be between 0 and
                    841:  *             MACH_PORT_QLIMIT_MAX, inclusive.
                    842:  *     Conditions:
                    843:  *             Nothing locked.
                    844:  *     Returns:
                    845:  *             KERN_SUCCESS            Set queue limit.
                    846:  *             KERN_INVALID_TASK       The space is null.
                    847:  *             KERN_INVALID_TASK       The space is dead.
                    848:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    849:  *             KERN_INVALID_RIGHT      Name doesn't denote receive rights.
                    850:  *             KERN_INVALID_VALUE      Illegal queue limit.
                    851:  */
                    852: 
                    853: kern_return_t
                    854: mach_port_set_qlimit(
                    855:        ipc_space_t             space,
                    856:        mach_port_t             name,
                    857:        mach_port_msgcount_t    qlimit)
                    858: {
                    859:        ipc_port_t port;
                    860:        kern_return_t kr;
                    861: 
                    862:        if (space == IS_NULL)
                    863:                return KERN_INVALID_TASK;
                    864: 
                    865:        if (qlimit > MACH_PORT_QLIMIT_MAX)
                    866:                return KERN_INVALID_VALUE;
                    867: 
                    868:        kr = ipc_port_translate_receive(space, name, &port);
                    869:        if (kr != KERN_SUCCESS)
                    870:                return kr;
                    871:        /* port is locked and active */
                    872: 
                    873:        ipc_port_set_qlimit(port, qlimit);
                    874: 
                    875:        ip_unlock(port);
                    876:        return KERN_SUCCESS;
                    877: }
                    878: 
                    879: /*
                    880:  *     Routine:        mach_port_set_mscount [kernel call]
                    881:  *     Purpose:
                    882:  *             Changes a receive right's make-send count.
                    883:  *     Conditions:
                    884:  *             Nothing locked.
                    885:  *     Returns:
                    886:  *             KERN_SUCCESS            Set make-send count.
                    887:  *             KERN_INVALID_TASK       The space is null.
                    888:  *             KERN_INVALID_TASK       The space is dead.
                    889:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    890:  *             KERN_INVALID_RIGHT      Name doesn't denote receive rights.
                    891:  */
                    892: 
                    893: kern_return_t
                    894: mach_port_set_mscount(
                    895:        ipc_space_t             space,
                    896:        mach_port_t             name,
                    897:        mach_port_mscount_t     mscount)
                    898: {
                    899:        ipc_port_t port;
                    900:        kern_return_t kr;
                    901: 
                    902:        if (space == IS_NULL)
                    903:                return KERN_INVALID_TASK;
                    904: 
                    905:        kr = ipc_port_translate_receive(space, name, &port);
                    906:        if (kr != KERN_SUCCESS)
                    907:                return kr;
                    908:        /* port is locked and active */
                    909: 
                    910:        ipc_port_set_mscount(port, mscount);
                    911: 
                    912:        ip_unlock(port);
                    913:        return KERN_SUCCESS;
                    914: }
                    915: 
                    916: /*
                    917:  *     Routine:        mach_port_set_seqno [kernel call]
                    918:  *     Purpose:
                    919:  *             Changes a receive right's sequence number.
                    920:  *     Conditions:
                    921:  *             Nothing locked.
                    922:  *     Returns:
                    923:  *             KERN_SUCCESS            Set sequence number.
                    924:  *             KERN_INVALID_TASK       The space is null.
                    925:  *             KERN_INVALID_TASK       The space is dead.
                    926:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    927:  *             KERN_INVALID_RIGHT      Name doesn't denote receive rights.
                    928:  */
                    929: 
                    930: kern_return_t
                    931: mach_port_set_seqno(
                    932:        ipc_space_t             space,
                    933:        mach_port_t             name,
                    934:        mach_port_seqno_t       seqno)
                    935: {
                    936:        ipc_port_t port;
                    937:        kern_return_t kr;
                    938: 
                    939:        if (space == IS_NULL)
                    940:                return KERN_INVALID_TASK;
                    941: 
                    942:        kr = ipc_port_translate_receive(space, name, &port);
                    943:        if (kr != KERN_SUCCESS)
                    944:                return kr;
                    945:        /* port is locked and active */
                    946: 
                    947:        ipc_port_set_seqno(port, seqno);
                    948: 
                    949:        ip_unlock(port);
                    950:        return KERN_SUCCESS;
                    951: }
                    952: 
                    953: /*
                    954:  *     Routine:        mach_port_gst_helper
                    955:  *     Purpose:
                    956:  *             A helper function for mach_port_get_set_status.
                    957:  */
                    958: 
                    959: void
                    960: mach_port_gst_helper(
                    961:        ipc_pset_t              pset,
                    962:        ipc_port_t              port,
                    963:        ipc_entry_num_t         maxnames,
                    964:        mach_port_t             *names,
                    965:        ipc_entry_num_t         *actualp)
                    966: {
                    967:        ipc_pset_t ip_pset;
                    968:        mach_port_t name;
                    969: 
                    970:        assert(port != IP_NULL);
                    971: 
                    972:        ip_lock(port);
                    973:        assert(ip_active(port));
                    974: 
                    975:        name = port->ip_receiver_name;
                    976:        assert(name != MACH_PORT_NULL);
                    977:        ip_pset = port->ip_pset;
                    978: 
                    979:        ip_unlock(port);
                    980: 
                    981:        if (pset == ip_pset) {
                    982:                ipc_entry_num_t actual = *actualp;
                    983: 
                    984:                if (actual < maxnames)
                    985:                        names[actual] = name;
                    986: 
                    987:                *actualp = actual+1;
                    988:        }
                    989: }
                    990: 
                    991: /*
                    992:  *     Routine:        mach_port_get_set_status [kernel call]
                    993:  *     Purpose:
                    994:  *             Retrieves a list of members in a port set.
                    995:  *             Returns the space's name for each receive right member.
                    996:  *     Conditions:
                    997:  *             Nothing locked.
                    998:  *     Returns:
                    999:  *             KERN_SUCCESS            Retrieved list of members.
                   1000:  *             KERN_INVALID_TASK       The space is null.
                   1001:  *             KERN_INVALID_TASK       The space is dead.
                   1002:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                   1003:  *             KERN_INVALID_RIGHT      Name doesn't denote a port set.
                   1004:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1005:  */
                   1006: 
                   1007: kern_return_t
                   1008: mach_port_get_set_status(
                   1009:        ipc_space_t                     space,
                   1010:        mach_port_t                     name,
                   1011:        mach_port_t                     **members,
                   1012:        mach_msg_type_number_t          *membersCnt)
                   1013: {
                   1014:        ipc_entry_num_t actual;         /* this many members */
                   1015:        ipc_entry_num_t maxnames;       /* space for this many members */
                   1016:        kern_return_t kr;
                   1017: 
                   1018:        vm_size_t size;         /* size of allocated memory */
                   1019:        vm_offset_t addr;       /* allocated memory */
                   1020: #if    MACH_OLD_VM_COPY
                   1021:        vm_offset_t memory;     /* copied-in memory */
                   1022: #else  /* MACH_OLD_VM_COPY */
                   1023:        vm_map_copy_t memory;   /* copied-in memory */
                   1024: #endif /* MACH_OLD_VM_COPY */
                   1025: 
                   1026:        if (space == IS_NULL)
                   1027:                return KERN_INVALID_TASK;
                   1028: 
                   1029:        size = PAGE_SIZE;       /* initial guess */
                   1030: 
                   1031:        for (;;) {
                   1032:                ipc_tree_entry_t tentry;
                   1033:                ipc_entry_t entry, table;
                   1034:                ipc_entry_num_t tsize;
                   1035:                mach_port_index_t index;
                   1036:                mach_port_t *names;
                   1037:                ipc_pset_t pset;
                   1038: 
                   1039:                kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE);
                   1040:                if (kr != KERN_SUCCESS)
                   1041:                        return KERN_RESOURCE_SHORTAGE;
                   1042: 
                   1043:                /* can't fault while we hold locks */
                   1044: 
                   1045: #if    MACH_OLD_VM_COPY
                   1046:                kr = vm_map_pageable(ipc_kernel_map, addr, addr + size,
                   1047:                                     FALSE);
                   1048:                assert(kr == KERN_SUCCESS);
                   1049: #else  /* MACH_OLD_VM_COPY */
                   1050:                kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
                   1051:                                     VM_PROT_READ|VM_PROT_WRITE, FALSE);
                   1052:                assert(kr == KERN_SUCCESS);
                   1053: #endif /* MACH_OLD_VM_COPY */
                   1054: 
                   1055:                kr = ipc_right_lookup_read(space, name, &entry);
                   1056:                if (kr != KERN_SUCCESS) {
                   1057:                        kmem_free(ipc_kernel_map, addr, size);
                   1058:                        return kr;
                   1059:                }
                   1060:                /* space is read-locked and active */
                   1061: 
                   1062:                if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
                   1063:                        is_read_unlock(space);
                   1064:                        kmem_free(ipc_kernel_map, addr, size);
                   1065:                        return KERN_INVALID_RIGHT;
                   1066:                }
                   1067: 
                   1068:                pset = (ipc_pset_t) entry->ie_object;
                   1069:                assert(pset != IPS_NULL);
                   1070:                /* the port set must be active */
                   1071: 
                   1072:                names = (mach_port_t *) addr;
                   1073:                maxnames = size / sizeof(mach_port_t);
                   1074:                actual = 0;
                   1075: 
                   1076:                table = space->is_table;
                   1077:                tsize = space->is_table_size;
                   1078: 
                   1079:                for (index = 0; index < tsize; index++) {
                   1080:                        ipc_entry_t ientry = &table[index];
                   1081:                        ipc_entry_bits_t bits = ientry->ie_bits;
                   1082: 
                   1083:                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1084:                                ipc_port_t port =
                   1085:                                        (ipc_port_t) ientry->ie_object;
                   1086: 
                   1087:                                mach_port_gst_helper(pset, port,
                   1088:                                                     maxnames,
                   1089:                                                     names, &actual);
                   1090:                        }
                   1091:                }
                   1092: 
                   1093:                for (tentry = ipc_splay_traverse_start(&space->is_tree);
                   1094:                     tentry != ITE_NULL;
                   1095:                     tentry = ipc_splay_traverse_next(&space->is_tree,
                   1096:                        FALSE)) {
                   1097:                        ipc_entry_bits_t bits = tentry->ite_bits;
                   1098: 
                   1099:                        assert(IE_BITS_TYPE(bits) !=
                   1100:                                MACH_PORT_TYPE_NONE);
                   1101: 
                   1102:                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1103:                                ipc_port_t port =
                   1104:                                        (ipc_port_t) tentry->ite_object;
                   1105: 
                   1106:                                mach_port_gst_helper(pset, port,
                   1107:                                                     maxnames,
                   1108:                                                     names, &actual);
                   1109:                        }
                   1110:                }
                   1111:                ipc_splay_traverse_finish(&space->is_tree);
                   1112:                is_read_unlock(space);
                   1113: 
                   1114:                if (actual <= maxnames)
                   1115:                        break;
                   1116: 
                   1117:                /* didn't have enough memory; allocate more */
                   1118: 
                   1119:                kmem_free(ipc_kernel_map, addr, size);
                   1120:                size = round_page(actual * sizeof(mach_port_t)) + PAGE_SIZE;
                   1121:        }
                   1122: 
                   1123:        if (actual == 0) {
                   1124: #if    MACH_OLD_VM_COPY
                   1125:                memory = 0;
                   1126: #else  /* MACH_OLD_VM_COPY */
                   1127:                memory = VM_MAP_COPY_NULL;
                   1128: #endif /* MACH_OLD_VM_COPY */
                   1129: 
                   1130:                kmem_free(ipc_kernel_map, addr, size);
                   1131:        } else {
                   1132:                vm_size_t size_used;
                   1133:                vm_size_t vm_size_used;
                   1134: 
                   1135:                size_used = actual * sizeof(mach_port_t);
                   1136:                vm_size_used = round_page(size_used);
                   1137: 
                   1138:                /*
                   1139:                 *      Make used memory pageable and get it into
                   1140:                 *      copied-in form.  Free any unused memory.
                   1141:                 */
                   1142: 
                   1143: #if    MACH_OLD_VM_COPY
                   1144:                kr = vm_map_pageable(ipc_kernel_map,
                   1145:                                     addr, addr + vm_size_used,
                   1146:                                     TRUE);
                   1147:                assert(kr == KERN_SUCCESS);
                   1148: 
                   1149:                kr = vm_move(
                   1150:                        ipc_kernel_map, addr,
                   1151:                        ipc_soft_map, size_used,
                   1152:                        TRUE, &memory);
                   1153:                assert(kr == KERN_SUCCESS);
                   1154: #else  /* MACH_OLD_VM_COPY */
                   1155:                kr = vm_map_unwire(ipc_kernel_map,
                   1156:                                     addr, addr + vm_size_used, FALSE);
                   1157:                assert(kr == KERN_SUCCESS);
                   1158: 
                   1159:                kr = vm_map_copyin(ipc_kernel_map, addr, size_used,
                   1160:                                   TRUE, &memory);
                   1161:                assert(kr == KERN_SUCCESS);
                   1162: #endif /* MACH_OLD_VM_COPY */
                   1163: 
                   1164:                if (vm_size_used != size)
                   1165:                        kmem_free(ipc_kernel_map,
                   1166:                                  addr + vm_size_used, size - vm_size_used);
                   1167:        }
                   1168: 
                   1169:        *members = (mach_port_t *) memory;
                   1170:        *membersCnt = actual;
                   1171:        return KERN_SUCCESS;
                   1172: }
                   1173: 
                   1174: /*
                   1175:  *     Routine:        mach_port_move_member [kernel call]
                   1176:  *     Purpose:
                   1177:  *             If after is MACH_PORT_NULL, removes member
                   1178:  *             from the port set it is in.  Otherwise, adds
                   1179:  *             member to after, removing it from any set
                   1180:  *             it might already be in.
                   1181:  *     Conditions:
                   1182:  *             Nothing locked.
                   1183:  *     Returns:
                   1184:  *             KERN_SUCCESS            Moved the port.
                   1185:  *             KERN_INVALID_TASK       The space is null.
                   1186:  *             KERN_INVALID_TASK       The space is dead.
                   1187:  *             KERN_INVALID_NAME       Member didn't denote a right.
                   1188:  *             KERN_INVALID_RIGHT      Member didn't denote a receive right.
                   1189:  *             KERN_INVALID_NAME       After didn't denote a right.
                   1190:  *             KERN_INVALID_RIGHT      After didn't denote a port set right.
                   1191:  *             KERN_NOT_IN_SET
                   1192:  *                     After is MACH_PORT_NULL and Member isn't in a port set.
                   1193:  */
                   1194: 
                   1195: kern_return_t
                   1196: mach_port_move_member(
                   1197:        ipc_space_t     space,
                   1198:        mach_port_t     member,
                   1199:        mach_port_t     after)
                   1200: {
                   1201:        ipc_entry_t entry;
                   1202:        ipc_port_t port;
                   1203:        ipc_pset_t nset;
                   1204:        kern_return_t kr;
                   1205: 
                   1206:        if (space == IS_NULL)
                   1207:                return KERN_INVALID_TASK;
                   1208: 
                   1209:        kr = ipc_right_lookup_read(space, member, &entry);
                   1210:        if (kr != KERN_SUCCESS)
                   1211:                return kr;
                   1212:        /* space is read-locked and active */
                   1213: 
                   1214:        if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
                   1215:                is_read_unlock(space);
                   1216:                return KERN_INVALID_RIGHT;
                   1217:        }
                   1218: 
                   1219:        port = (ipc_port_t) entry->ie_object;
                   1220:        assert(port != IP_NULL);
                   1221: 
                   1222:        if (after == MACH_PORT_NULL)
                   1223:                nset = IPS_NULL;
                   1224:        else {
                   1225:                entry = ipc_entry_lookup(space, after);
                   1226:                if (entry == IE_NULL) {
                   1227:                        is_read_unlock(space);
                   1228:                        return KERN_INVALID_NAME;
                   1229:                }
                   1230: 
                   1231:                if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
                   1232:                        is_read_unlock(space);
                   1233:                        return KERN_INVALID_RIGHT;
                   1234:                }
                   1235: 
                   1236:                nset = (ipc_pset_t) entry->ie_object;
                   1237:                assert(nset != IPS_NULL);
                   1238:        }
                   1239: 
                   1240:        kr = ipc_pset_move(space, port, nset);
                   1241:        /* space is unlocked */
                   1242:        return kr;
                   1243: }
                   1244: 
                   1245: /*
                   1246:  *     Routine:        mach_port_request_notification [kernel call]
                   1247:  *     Purpose:
                   1248:  *             Requests a notification.  The caller supplies
                   1249:  *             a send-once right for the notification to use,
                   1250:  *             and the call returns the previously registered
                   1251:  *             send-once right, if any.  Possible types:
                   1252:  *
                   1253:  *             MACH_NOTIFY_PORT_DESTROYED
                   1254:  *                     Requests a port-destroyed notification
                   1255:  *                     for a receive right.  Sync should be zero.
                   1256:  *             MACH_NOTIFY_NO_SENDERS
                   1257:  *                     Requests a no-senders notification for a
                   1258:  *                     receive right.  If there are currently no
                   1259:  *                     senders, sync is less than or equal to the
                   1260:  *                     current make-send count, and a send-once right
                   1261:  *                     is supplied, then an immediate no-senders
                   1262:  *                     notification is generated.
                   1263:  *             MACH_NOTIFY_DEAD_NAME
                   1264:  *                     Requests a dead-name notification for a send
                   1265:  *                     or receive right.  If the name is already a
                   1266:  *                     dead name, sync is non-zero, and a send-once
                   1267:  *                     right is supplied, then an immediate dead-name
                   1268:  *                     notification is generated.
                   1269:  *     Conditions:
                   1270:  *             Nothing locked.
                   1271:  *     Returns:
                   1272:  *             KERN_SUCCESS            Requested a notification.
                   1273:  *             KERN_INVALID_TASK       The space is null.
                   1274:  *             KERN_INVALID_TASK       The space is dead.
                   1275:  *             KERN_INVALID_VALUE      Bad id value.
                   1276:  *             KERN_INVALID_NAME       Name doesn't denote a right.
                   1277:  *             KERN_INVALID_RIGHT      Name doesn't denote appropriate right.
                   1278:  *             KERN_INVALID_CAPABILITY The notify port is dead.
                   1279:  *     MACH_NOTIFY_PORT_DESTROYED:
                   1280:  *             KERN_INVALID_VALUE      Sync isn't zero.
                   1281:  *     MACH_NOTIFY_DEAD_NAME:
                   1282:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1283:  *             KERN_INVALID_ARGUMENT   Name denotes dead name, but
                   1284:  *                     sync is zero or notify is IP_NULL.
                   1285:  *             KERN_UREFS_OVERFLOW     Name denotes dead name, but
                   1286:  *                     generating immediate notif. would overflow urefs.
                   1287:  */
                   1288: 
                   1289: kern_return_t
                   1290: mach_port_request_notification(
                   1291:        ipc_space_t             space,
                   1292:        mach_port_t             name,
                   1293:        mach_msg_id_t           id,
                   1294:        mach_port_mscount_t     sync,
                   1295:        ipc_port_t              notify,
                   1296:        ipc_port_t              *previousp)
                   1297: {
                   1298:        kern_return_t kr;
                   1299: 
                   1300:        if (space == IS_NULL)
                   1301:                return KERN_INVALID_TASK;
                   1302: 
                   1303:        if (notify == IP_DEAD)
                   1304:                return KERN_INVALID_CAPABILITY;
                   1305: 
                   1306:        switch (id) {
                   1307:            case MACH_NOTIFY_PORT_DESTROYED: {
                   1308:                ipc_port_t port, previous;
                   1309: 
                   1310:                if (sync != 0)
                   1311:                        return KERN_INVALID_VALUE;
                   1312: 
                   1313:                kr = ipc_port_translate_receive(space, name, &port);
                   1314:                if (kr != KERN_SUCCESS)
                   1315:                        return kr;
                   1316:                /* port is locked and active */
                   1317: 
                   1318:                ipc_port_pdrequest(port, notify, &previous);
                   1319:                /* port is unlocked */
                   1320: 
                   1321: #if    MACH_IPC_COMPAT
                   1322:                /*
                   1323:                 *      If previous was a send right instead of a send-once
                   1324:                 *      right, we can't return it in the reply message.
                   1325:                 *      So destroy it instead.
                   1326:                 */
                   1327: 
                   1328:                if ((previous != IP_NULL) && ip_pdsendp(previous)) {
                   1329:                        ipc_port_release_send(ip_pdsend(previous));
                   1330:                        previous = IP_NULL;
                   1331:                }
                   1332: #endif /* MACH_IPC_COMPAT */
                   1333: 
                   1334:                *previousp = previous;
                   1335:                break;
                   1336:            }
                   1337: 
                   1338:            case MACH_NOTIFY_NO_SENDERS: {
                   1339:                ipc_port_t port;
                   1340: 
                   1341:                kr = ipc_port_translate_receive(space, name, &port);
                   1342:                if (kr != KERN_SUCCESS)
                   1343:                        return kr;
                   1344:                /* port is locked and active */
                   1345: 
                   1346:                ipc_port_nsrequest(port, sync, notify, previousp);
                   1347:                /* port is unlocked */
                   1348:                break;
                   1349:            }
                   1350: 
                   1351:            case MACH_NOTIFY_DEAD_NAME:
                   1352:                kr = ipc_right_dnrequest(space, name, sync != 0,
                   1353:                                         notify, previousp);
                   1354:                if (kr != KERN_SUCCESS)
                   1355:                        return kr;
                   1356:                break;
                   1357: 
                   1358:            default:
                   1359:                return KERN_INVALID_VALUE;
                   1360:        }
                   1361: 
                   1362:        return KERN_SUCCESS;
                   1363: }
                   1364: 
                   1365: /*
                   1366:  *     Routine:        mach_port_insert_right [kernel call]
                   1367:  *     Purpose:
                   1368:  *             Inserts a right into a space, as if the space
                   1369:  *             voluntarily received the right in a message,
                   1370:  *             except that the right gets the specified name.
                   1371:  *     Conditions:
                   1372:  *             Nothing locked.
                   1373:  *     Returns:
                   1374:  *             KERN_SUCCESS            Inserted the right.
                   1375:  *             KERN_INVALID_TASK       The space is null.
                   1376:  *             KERN_INVALID_TASK       The space is dead.
                   1377:  *             KERN_INVALID_VALUE      The name isn't a legal name.
                   1378:  *             KERN_NAME_EXISTS        The name already denotes a right.
                   1379:  *             KERN_INVALID_VALUE      Message doesn't carry a port right.
                   1380:  *             KERN_INVALID_CAPABILITY Port is null or dead.
                   1381:  *             KERN_UREFS_OVERFLOW     Urefs limit would be exceeded.
                   1382:  *             KERN_RIGHT_EXISTS       Space has rights under another name.
                   1383:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1384:  */
                   1385: 
                   1386: kern_return_t
                   1387: mach_port_insert_right(
                   1388:        ipc_space_t             space,
                   1389:        mach_port_t             name,
                   1390:        ipc_port_t              poly,
                   1391:        mach_msg_type_name_t    polyPoly)
                   1392: {
                   1393:        if (space == IS_NULL)
                   1394:                return KERN_INVALID_TASK;
                   1395: 
                   1396:        if (!MACH_PORT_VALID(name) ||
                   1397:            !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
                   1398:                return KERN_INVALID_VALUE;
                   1399: 
                   1400:        if (!IO_VALID((ipc_object_t) poly))
                   1401:                return KERN_INVALID_CAPABILITY;
                   1402: 
                   1403:        return ipc_object_copyout_name(space, (ipc_object_t) poly, 
                   1404:                                       polyPoly, FALSE, name);
                   1405: }
                   1406: 
                   1407: /*
                   1408:  *     Routine:        mach_port_extract_right [kernel call]
                   1409:  *     Purpose:
                   1410:  *             Extracts a right from a space, as if the space
                   1411:  *             voluntarily sent the right to the caller.
                   1412:  *     Conditions:
                   1413:  *             Nothing locked.
                   1414:  *     Returns:
                   1415:  *             KERN_SUCCESS            Extracted the right.
                   1416:  *             KERN_INVALID_TASK       The space is null.
                   1417:  *             KERN_INVALID_TASK       The space is dead.
                   1418:  *             KERN_INVALID_VALUE      Requested type isn't a port right.
                   1419:  *             KERN_INVALID_NAME       Name doesn't denote a right.
                   1420:  *             KERN_INVALID_RIGHT      Name doesn't denote appropriate right.
                   1421:  */
                   1422: 
                   1423: kern_return_t
                   1424: mach_port_extract_right(
                   1425:        ipc_space_t             space,
                   1426:        mach_port_t             name,
                   1427:        mach_msg_type_name_t    msgt_name,
                   1428:        ipc_port_t              *poly,
                   1429:        mach_msg_type_name_t    *polyPoly)
                   1430: {
                   1431:        kern_return_t kr;
                   1432: 
                   1433:        if (space == IS_NULL)
                   1434:                return KERN_INVALID_TASK;
                   1435: 
                   1436:        if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
                   1437:                return KERN_INVALID_VALUE;
                   1438: 
                   1439:        kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
                   1440: 
                   1441:        if (kr == KERN_SUCCESS)
                   1442:                *polyPoly = ipc_object_copyin_type(msgt_name);
                   1443:        return kr;
                   1444: }
                   1445: 
                   1446: /*
                   1447:  *     Routine:        mach_port_get_receive_status [kernel call]
                   1448:  *     Purpose:
                   1449:  *             Retrieves mucho info about a receive right.
                   1450:  *     Conditions:
                   1451:  *             Nothing locked.
                   1452:  *     Returns:
                   1453:  *             KERN_SUCCESS            Retrieved status.
                   1454:  *             KERN_INVALID_TASK       The space is null.
                   1455:  *             KERN_INVALID_TASK       The space is dead.
                   1456:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                   1457:  *             KERN_INVALID_RIGHT      Name doesn't denote receive rights.
                   1458:  */
                   1459: 
                   1460: kern_return_t
                   1461: mach_port_get_receive_status(space, name, statusp)
                   1462:        ipc_space_t space;
                   1463:        mach_port_t name;
                   1464:        mach_port_status_t *statusp;
                   1465: {
                   1466:        ipc_port_t port;
                   1467:        kern_return_t kr;
                   1468: 
                   1469:        if (space == IS_NULL)
                   1470:                return KERN_INVALID_TASK;
                   1471: 
                   1472:        kr = ipc_port_translate_receive(space, name, &port);
                   1473:        if (kr != KERN_SUCCESS)
                   1474:                return kr;
                   1475:        /* port is locked and active */
                   1476: 
                   1477:        if (port->ip_pset != IPS_NULL) {
                   1478:                ipc_pset_t pset = port->ip_pset;
                   1479: 
                   1480:                ips_lock(pset);
                   1481:                if (!ips_active(pset)) {
                   1482:                        ipc_pset_remove(pset, port);
                   1483:                        ips_check_unlock(pset);
                   1484:                        goto no_port_set;
                   1485:                } else {
                   1486:                        statusp->mps_pset = pset->ips_local_name;
                   1487:                        imq_lock(&pset->ips_messages);
                   1488:                        statusp->mps_seqno = port->ip_seqno;
                   1489:                        imq_unlock(&pset->ips_messages);
                   1490:                        ips_unlock(pset);
                   1491:                        assert(MACH_PORT_VALID(statusp->mps_pset));
                   1492:                }
                   1493:        } else {
                   1494:            no_port_set:
                   1495:                statusp->mps_pset = MACH_PORT_NULL;
                   1496:                imq_lock(&port->ip_messages);
                   1497:                statusp->mps_seqno = port->ip_seqno;
                   1498:                imq_unlock(&port->ip_messages);
                   1499:        }
                   1500: 
                   1501:        statusp->mps_mscount = port->ip_mscount;
                   1502:        statusp->mps_qlimit = port->ip_qlimit;
                   1503:        statusp->mps_msgcount = port->ip_msgcount;
                   1504:        statusp->mps_sorights = port->ip_sorights;
                   1505:        statusp->mps_srights = port->ip_srights > 0;
                   1506:        statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
                   1507:        statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
                   1508:        ip_unlock(port);
                   1509: 
                   1510:        return KERN_SUCCESS;
                   1511: }
                   1512: 
                   1513: #if    MACH_IPC_COMPAT
                   1514: 
                   1515: /*
                   1516:  *     Routine:        port_translate_compat
                   1517:  *     Purpose:
                   1518:  *             Converts a name to a receive right.
                   1519:  *     Conditions:
                   1520:  *             Nothing locked.  If successful, the port
                   1521:  *             is returned locked and active.
                   1522:  *     Returns:
                   1523:  *             KERN_SUCCESS            Port is returned.
                   1524:  *             KERN_INVALID_ARGUMENT   The space is dead.
                   1525:  *             KERN_INVALID_ARGUMENT   Name doesn't denote port rights.
                   1526:  *             KERN_NOT_RECEIVER       Name denotes send, not receive, rights.
                   1527:  *             KERN_NOT_RECEIVER       Name denotes a send-once right.
                   1528:  *             KERN_NOT_RECEIVER       Name denotes a dead name.
                   1529:  */
                   1530: 
                   1531: kern_return_t
                   1532: port_translate_compat(space, name, portp)
                   1533:        ipc_space_t space;
                   1534:        mach_port_t name;
                   1535:        ipc_port_t *portp;
                   1536: {
                   1537:        ipc_entry_t entry;
                   1538:        mach_port_type_t type;
                   1539:        mach_port_urefs_t urefs;
                   1540:        ipc_port_t port;
                   1541:        kern_return_t kr;
                   1542: 
                   1543:        kr = ipc_right_lookup_write(space, name, &entry);
                   1544:        if (kr != KERN_SUCCESS)
                   1545:                return KERN_INVALID_ARGUMENT;
                   1546:        /* space is write-locked and active */
                   1547: 
                   1548:        kr = ipc_right_info(space, name, entry, &type, &urefs);
                   1549:        if (kr != KERN_SUCCESS)
                   1550:                return KERN_INVALID_ARGUMENT; /* space is unlocked */
                   1551: 
                   1552:        if ((type & (MACH_PORT_TYPE_RECEIVE)) == 0) {
                   1553:                is_write_unlock(space);
                   1554:                if (type & MACH_PORT_TYPE_PORT_OR_DEAD)
                   1555:                        return KERN_NOT_RECEIVER;
                   1556:                else
                   1557:                        return KERN_INVALID_ARGUMENT;
                   1558:        }
                   1559: 
                   1560:        port = (ipc_port_t) entry->ie_object;
                   1561:        assert(port != IP_NULL);
                   1562: 
                   1563:        ip_lock(port);
                   1564:        is_write_unlock(space);
                   1565:        assert(ip_active(port));
                   1566: 
                   1567:        *portp = port;
                   1568:        return KERN_SUCCESS;
                   1569: }
                   1570: 
                   1571: /*
                   1572:  *     Routine:        convert_port_type
                   1573:  *     Purpose:
                   1574:  *             Convert a new mach_port_type_t to an old value.
                   1575:  *             Note send-once rights and dead names get
                   1576:  *             represented as send rights.  The extra info
                   1577:  *             bits get dropped.
                   1578:  */
                   1579: 
                   1580: mach_port_type_t
                   1581: convert_port_type(type)
                   1582:        mach_port_type_t type;
                   1583: {
                   1584:        switch (type & MACH_PORT_TYPE_ALL_RIGHTS) {
                   1585:            case MACH_PORT_TYPE_SEND:
                   1586:            case MACH_PORT_TYPE_SEND_ONCE:
                   1587:            case MACH_PORT_TYPE_DEAD_NAME:
                   1588:                return PORT_TYPE_SEND;
                   1589: 
                   1590:            case MACH_PORT_TYPE_RECEIVE:
                   1591:            case MACH_PORT_TYPE_SEND_RECEIVE:
                   1592:                return PORT_TYPE_RECEIVE_OWN;
                   1593: 
                   1594:            case MACH_PORT_TYPE_PORT_SET:
                   1595:                return PORT_TYPE_SET;
                   1596: 
                   1597:            default:
                   1598: #if MACH_ASSERT
                   1599:                assert(!"convert_port_type: strange port type");
                   1600: #else
                   1601:                panic("convert_port_type: strange port type");
                   1602: #endif
                   1603:        }
                   1604: }
                   1605: 
                   1606: /*
                   1607:  *     Routine:        port_names [kernel call]
                   1608:  *     Purpose:
                   1609:  *             Retrieve all the names in the task's port name space.
                   1610:  *             As a (major) convenience, return port type information.
                   1611:  *             The port name space includes port sets.
                   1612:  *     Conditions:
                   1613:  *             Nothing locked.
                   1614:  *     Returns:
                   1615:  *             KERN_SUCCESS            Retrieved names.
                   1616:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1617:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1618:  *     Additions:
                   1619:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1620:  */
                   1621: 
                   1622: kern_return_t
                   1623: port_names(space, namesp, namesCnt, typesp, typesCnt)
                   1624:        ipc_space_t space;
                   1625:        mach_port_t **namesp;
                   1626:        mach_msg_type_number_t *namesCnt;
                   1627:        mach_port_type_t **typesp;
                   1628:        mach_msg_type_number_t *typesCnt;
                   1629: {
                   1630:        kern_return_t kr;
                   1631: 
                   1632:        kr = mach_port_names(space, namesp, namesCnt, typesp, typesCnt);
                   1633:        if (kr == KERN_SUCCESS) {
                   1634:                ipc_entry_num_t actual = (ipc_entry_num_t) *typesCnt;
                   1635:                mach_port_type_t *types;
                   1636:                ipc_entry_num_t i;
                   1637: 
                   1638: #if    MACH_OLD_VM_COPY
                   1639:                vm_offset_t copy = (vm_offset_t) *typesp;
                   1640: #else  /* MACH_OLD_VM_COPY */
                   1641:                vm_map_copy_t copy = (vm_map_copy_t) *typesp;
                   1642: #endif /* MACH_OLD_VM_COPY */
                   1643:                vm_offset_t addr;
                   1644:                vm_size_t size = round_page(actual * sizeof(mach_port_type_t));
                   1645: 
                   1646:                /* convert copy object back to something we can use */
                   1647: 
                   1648: #if    MACH_OLD_VM_COPY
                   1649:                kr = vm_move(
                   1650:                        ipc_soft_map, copy,
                   1651:                        ipc_kernel_map, size,
                   1652:                        FALSE, &addr);
                   1653: #else  /* MACH_OLD_VM_COPY */
                   1654:                kr = vm_map_copyout(ipc_kernel_map, &addr, copy);
                   1655: #endif /* MACH_OLD_VM_COPY */
                   1656:                if (kr != KERN_SUCCESS) {
                   1657: #if    MACH_OLD_VM_COPY
                   1658:                        kmem_free(
                   1659:                                ipc_soft_map,
                   1660:                                (vm_offset_t) *typesp,
                   1661:                                (vm_size_t)
                   1662:                                round_page((ipc_entry_num_t) *typesCnt *
                   1663:                                                sizeof(mach_port_type_t)));
                   1664:                        kmem_free(
                   1665:                                ipc_soft_map,
                   1666:                                (vm_offset_t) *namesp,
                   1667:                                (vm_size_t)
                   1668:                                round_page((ipc_entry_num_t) *namesCnt *
                   1669:                                                sizeof(mach_port_t)));
                   1670: #else  /* MACH_OLD_VM_COPY */
                   1671:                        vm_map_copy_discard((vm_map_copy_t) *typesp);
                   1672:                        vm_map_copy_discard((vm_map_copy_t) *namesp);
                   1673: #endif /* MACH_OLD_VM_COPY */
                   1674:                        return KERN_RESOURCE_SHORTAGE;
                   1675:                }
                   1676: #if    MACH_OLD_VM_COPY
                   1677:                else
                   1678:                        (void) vm_deallocate(ipc_soft_map, copy, size);
                   1679: #endif /* MACH_OLD_VM_COPY */
                   1680: 
                   1681:                types = (mach_port_type_t *) addr;
                   1682: 
                   1683:                for (i = 0; i < actual; i++)
                   1684:                        types[i] = convert_port_type(types[i]);
                   1685: 
                   1686:                /* convert memory back into a copy object */
                   1687: 
                   1688: #if    MACH_OLD_VM_COPY
                   1689:                kr = vm_move(
                   1690:                        ipc_kernel_map, addr,
                   1691:                        ipc_soft_map, size,
                   1692:                        TRUE, &copy);
                   1693:                assert(kr == KERN_SUCCESS);
                   1694: #else  /* MACH_OLD_VM_COPY */
                   1695:                kr = vm_map_copyin(ipc_kernel_map, addr, size,
                   1696:                                   TRUE, &copy);
                   1697:                assert(kr == KERN_SUCCESS);
                   1698: #endif /* MACH_OLD_VM_COPY */
                   1699: 
                   1700:                *typesp = (mach_port_type_t *) copy;
                   1701:        } else if (kr != KERN_RESOURCE_SHORTAGE)
                   1702:                kr = KERN_INVALID_ARGUMENT;
                   1703: 
                   1704:        return kr;
                   1705: }
                   1706: 
                   1707: /*
                   1708:  *     Routine:        port_type [kernel call]
                   1709:  *     Purpose:
                   1710:  *             Return type of the capability named.
                   1711:  *     Conditions:
                   1712:  *             Nothing locked.
                   1713:  *     Returns:
                   1714:  *             KERN_SUCCESS            Retrieved type.
                   1715:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1716:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1717:  *             KERN_INVALID_ARGUMENT   The name doesn't denote a right.
                   1718:  */
                   1719: 
                   1720: kern_return_t
                   1721: port_type(space, name, typep)
                   1722:        ipc_space_t space;
                   1723:        mach_port_t name;
                   1724:        mach_port_type_t *typep;
                   1725: {
                   1726:        mach_port_type_t type;
                   1727:        kern_return_t kr;
                   1728: 
                   1729:        kr = mach_port_type(space, name, &type);
                   1730:        if (kr != KERN_SUCCESS)
                   1731:                return KERN_INVALID_ARGUMENT;
                   1732: 
                   1733:        *typep = convert_port_type(type);
                   1734:        return KERN_SUCCESS;
                   1735: }
                   1736: 
                   1737: /*
                   1738:  *     Routine:        port_rename [kernel call]
                   1739:  *     Purpose:
                   1740:  *             Change the name of a capability.
                   1741:  *             The new name can't be in use.
                   1742:  *     Conditions:
                   1743:  *             Nothing locked.
                   1744:  *     Returns:
                   1745:  *             KERN_SUCCESS            Retrieved type.
                   1746:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1747:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1748:  *             KERN_INVALID_ARGUMENT   The new name is reserved.
                   1749:  *             KERN_NAME_EXISTS        The new name already denotes a right.
                   1750:  *             KERN_INVALID_ARGUMENT   The old name doesn't denote a right.
                   1751:  */
                   1752: 
                   1753: kern_return_t
                   1754: port_rename(space, old_name, new_name)
                   1755:        ipc_space_t space;
                   1756:        mach_port_t old_name;
                   1757:        mach_port_t new_name;
                   1758: {
                   1759:        kern_return_t kr;
                   1760: 
                   1761:        kr = mach_port_rename(space, old_name, new_name);
                   1762:        if ((kr != KERN_SUCCESS) && (kr != KERN_NAME_EXISTS))
                   1763:                kr = KERN_INVALID_ARGUMENT;
                   1764: 
                   1765:        return kr;
                   1766: }
                   1767: 
                   1768: /*
                   1769:  *     Routine:        port_allocate [kernel call]
                   1770:  *     Purpose:
                   1771:  *             Allocate a new port, giving all rights to "task".
                   1772:  *
                   1773:  *             Returns in "port_name" the task's local name for the port.
                   1774:  *             Doesn't return a reference to the port.
                   1775:  *     Conditions:
                   1776:  *             Nothing locked.
                   1777:  *     Returns:
                   1778:  *             KERN_SUCCESS            Allocated a port.
                   1779:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1780:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1781:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1782:  */
                   1783: 
                   1784: kern_return_t
                   1785: port_allocate(space, namep)
                   1786:        ipc_space_t space;
                   1787:        mach_port_t *namep;
                   1788: {
                   1789:        ipc_port_t port;
                   1790:        kern_return_t kr;
                   1791: 
                   1792:        if (space == IS_NULL)
                   1793:                return KERN_INVALID_ARGUMENT;
                   1794: 
                   1795:        kr = ipc_port_alloc_compat(space, namep, &port);
                   1796:        if (kr == KERN_SUCCESS)
                   1797:                ip_unlock(port);
                   1798:        else if (kr != KERN_RESOURCE_SHORTAGE)
                   1799:                kr = KERN_INVALID_ARGUMENT;
                   1800: 
                   1801:        return kr;
                   1802: }
                   1803: 
                   1804: /*
                   1805:  *     Routine:        port_deallocate [kernel call]
                   1806:  *     Purpose:
                   1807:  *             Delete port rights (send and receive) from a task.
                   1808:  *     Conditions:
                   1809:  *             Nothing locked.
                   1810:  *     Returns:
                   1811:  *             KERN_SUCCESS            Deallocated the port right.
                   1812:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1813:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1814:  *             KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
                   1815:  *     Additions:
                   1816:  *             KERN_SUCCESS            Deallocated a send-once right.
                   1817:  *             KERN_SUCCESS            Destroyed a dead name.
                   1818:  */
                   1819: 
                   1820: kern_return_t
                   1821: port_deallocate(space, name)
                   1822:        ipc_space_t space;
                   1823:        mach_port_t name;
                   1824: {
                   1825:        ipc_entry_t entry;
                   1826:        mach_port_type_t type;
                   1827:        mach_port_urefs_t urefs;
                   1828:        kern_return_t kr;
                   1829: 
                   1830:        if (space == IS_NULL)
                   1831:                return KERN_INVALID_ARGUMENT;
                   1832: 
                   1833:        kr = ipc_right_lookup_write(space, name, &entry);
                   1834:        if (kr != KERN_SUCCESS)
                   1835:                return KERN_INVALID_ARGUMENT;
                   1836:        /* space is write-locked and active */
                   1837: 
                   1838:        /*
                   1839:         *      We serialize with port destruction with the
                   1840:         *      ipc_right_info call, not ipc_right_destroy.
                   1841:         *      After ipc_right_info, we pretend that the
                   1842:         *      port doesn't get destroyed.
                   1843:         */
                   1844: 
                   1845:        kr = ipc_right_info(space, name, entry, &type, &urefs);
                   1846:        if (kr != KERN_SUCCESS)
                   1847:                return KERN_INVALID_ARGUMENT; /* space is unlocked */
                   1848: 
                   1849:        if ((type & (MACH_PORT_TYPE_PORT_OR_DEAD)) == 0) {
                   1850:                is_write_unlock(space);
                   1851:                return KERN_INVALID_ARGUMENT;
                   1852:        }
                   1853: 
                   1854:        (void) ipc_right_destroy(space, name, entry);
                   1855:        /* space is unlocked */
                   1856: 
                   1857:        return KERN_SUCCESS;
                   1858: }
                   1859: 
                   1860: /*
                   1861:  *     Routine:        port_set_backlog [kernel call]
                   1862:  *     Purpose:
                   1863:  *             Change the queueing backlog on "port_name" to "backlog";
                   1864:  *             the specified "task" must be the current receiver.
                   1865:  *
                   1866:  *             Valid backlog values are 0 < backlog <= PORT_BACKLOG_MAX.
                   1867:  *     Conditions:
                   1868:  *             Nothing locked.
                   1869:  *     Returns:
                   1870:  *             KERN_SUCCESS            Set the backlog.
                   1871:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1872:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1873:  *             KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
                   1874:  *             KERN_NOT_RECEIVER       Name denotes send rights, not receive.
                   1875:  *             KERN_INVALID_ARGUMENT   Backlog value is invalid.
                   1876:  *     Additions:
                   1877:  *             KERN_NOT_RECEIVER       Name denotes a send-once right.
                   1878:  *             KERN_NOT_RECEIVER       Name denotes a dead name.
                   1879:  */
                   1880: 
                   1881: kern_return_t
                   1882: port_set_backlog(space, name, backlog)
                   1883:        ipc_space_t space;
                   1884:        mach_port_t name;
                   1885:        int backlog;
                   1886: {
                   1887:        ipc_port_t port;
                   1888:        kern_return_t kr;
                   1889: 
                   1890:        if ((space == IS_NULL) ||
                   1891:            (backlog <= 0) ||
                   1892:            (backlog > PORT_BACKLOG_MAX))
                   1893:                return KERN_INVALID_ARGUMENT;
                   1894: 
                   1895:        kr = port_translate_compat(space, name, &port);
                   1896:        if (kr != KERN_SUCCESS)
                   1897:                return kr;
                   1898:        /* port is locked and active */
                   1899: 
                   1900:        ipc_port_set_qlimit(port, (mach_port_msgcount_t) backlog);
                   1901: 
                   1902:        ip_unlock(port);
                   1903:        return KERN_SUCCESS;
                   1904: }
                   1905: 
                   1906: /*
                   1907:  *     Routine:        port_set_backup [kernel call]
                   1908:  *     Purpose:
                   1909:  *             Changes the backup port for the the named port.
                   1910:  *             The specified "task" must be the current receiver.
                   1911:  *             Returns the old backup port, if any.
                   1912:  *     Conditions:
                   1913:  *             Nothing locked.
                   1914:  *     Returns:
                   1915:  *             KERN_SUCCESS            Set the backup.
                   1916:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1917:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1918:  *             KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
                   1919:  *             KERN_NOT_RECEIVER       Name denotes send rights, not receive.
                   1920:  *     Additions:
                   1921:  *             KERN_NOT_RECEIVER       Name denotes a send-once right.
                   1922:  *             KERN_NOT_RECEIVER       Name denotes a dead name.
                   1923:  */
                   1924: 
                   1925: kern_return_t
                   1926: port_set_backup(space, name, backup, previousp)
                   1927:        ipc_space_t space;
                   1928:        mach_port_t name;
                   1929:        ipc_port_t backup;
                   1930:        ipc_port_t *previousp;
                   1931: {
                   1932:        ipc_port_t port, previous;
                   1933:        kern_return_t kr;
                   1934: 
                   1935:        if (space == IS_NULL)
                   1936:                return KERN_INVALID_ARGUMENT;
                   1937: 
                   1938:        if (backup == IP_DEAD)
                   1939:                backup = IP_NULL;
                   1940:        else if (backup != IP_NULL)
                   1941:                backup = ip_pdsendm(backup);
                   1942: 
                   1943:        kr = port_translate_compat(space, name, &port);
                   1944:        if (kr != KERN_SUCCESS)
                   1945:                return kr;
                   1946:        /* port is locked and active */
                   1947: 
                   1948:        ipc_port_pdrequest(port, backup, &previous);
                   1949:        /* port is unlocked */
                   1950: 
                   1951:        /*
                   1952:         *      If previous was a send-once right instead of a send
                   1953:         *      right, we can't return it in the reply message.
                   1954:         *      So get rid of it in a notification instead.
                   1955:         */
                   1956: 
                   1957:        if (previous != IP_NULL) {
                   1958:                if (ip_pdsendp(previous))
                   1959:                        previous = ip_pdsend(previous);
                   1960:                else {
                   1961:                        ipc_notify_send_once(previous);
                   1962:                        previous = IP_NULL;
                   1963:                }
                   1964:        }
                   1965: 
                   1966:        *previousp = previous;
                   1967:        return KERN_SUCCESS;
                   1968: }
                   1969: 
                   1970: /*
                   1971:  *     Routine:        port_status [kernel call]
                   1972:  *     Purpose:
                   1973:  *             Returns statistics related to "port_name", as seen by "task".
                   1974:  *             Only the receiver for a given port will see true message
                   1975:  *             counts.
                   1976:  *     Conditions:
                   1977:  *             Nothing locked.
                   1978:  *     Returns:
                   1979:  *             KERN_SUCCESS            Retrieved status.
                   1980:  *             KERN_INVALID_ARGUMENT   Task is null.
                   1981:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   1982:  *             KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
                   1983:  *     Additions:
                   1984:  *             KERN_SUCCESS            Send-once right.
                   1985:  *             KERN_SUCCESS            Dead name.
                   1986:  */
                   1987: 
                   1988: kern_return_t
                   1989: port_status(space, name, enabledp, num_msgs, backlog,
                   1990:            ownership, receive_rights)
                   1991:        ipc_space_t space;
                   1992:        mach_port_t name;
                   1993:        mach_port_t *enabledp;
                   1994:        int *num_msgs;
                   1995:        int *backlog;
                   1996:        boolean_t *ownership;
                   1997:        boolean_t *receive_rights;
                   1998: {
                   1999:        ipc_entry_t entry;
                   2000:        mach_port_type_t type;
                   2001:        mach_port_urefs_t urefs;
                   2002:        kern_return_t kr;
                   2003: 
                   2004:        if (space == IS_NULL)
                   2005:                return KERN_INVALID_ARGUMENT;
                   2006: 
                   2007:        kr = ipc_right_lookup_write(space, name, &entry);
                   2008:        if (kr != KERN_SUCCESS)
                   2009:                return KERN_INVALID_ARGUMENT;
                   2010:        /* space is write-locked and active */
                   2011: 
                   2012:        kr = ipc_right_info(space, name, entry, &type, &urefs);
                   2013:        if (kr != KERN_SUCCESS)
                   2014:                return KERN_INVALID_ARGUMENT; /* space is unlocked */
                   2015: 
                   2016:        if ((type & MACH_PORT_TYPE_PORT_OR_DEAD) == 0) {
                   2017:                is_write_unlock(space);
                   2018:                return KERN_INVALID_ARGUMENT;
                   2019:        }
                   2020: 
                   2021:        if (type & MACH_PORT_TYPE_RECEIVE) {
                   2022:                mach_port_t enabled;
                   2023:                mach_port_msgcount_t qlimit;
                   2024:                mach_port_msgcount_t msgcount;
                   2025:                ipc_port_t port;
                   2026: 
                   2027:                port = (ipc_port_t) entry->ie_object;
                   2028:                assert(port != IP_NULL);
                   2029: 
                   2030:                ip_lock(port);
                   2031:                is_write_unlock(space);
                   2032:                assert(ip_active(port));
                   2033: 
                   2034:                if (port->ip_pset != IPS_NULL) {
                   2035:                        ipc_pset_t pset = port->ip_pset;
                   2036: 
                   2037:                        ips_lock(pset);
                   2038:                        if (!ips_active(pset)) {
                   2039:                                ipc_pset_remove(pset, port);
                   2040:                                ips_check_unlock(pset);
                   2041:                                enabled = MACH_PORT_NULL;
                   2042:                        } else {
                   2043:                                enabled = pset->ips_local_name;
                   2044:                                ips_unlock(pset);
                   2045:                                assert(MACH_PORT_VALID(enabled));
                   2046:                        }
                   2047:                } else
                   2048:                        enabled = MACH_PORT_NULL;
                   2049: 
                   2050:                qlimit = port->ip_qlimit;
                   2051:                msgcount = port->ip_msgcount;
                   2052:                ip_unlock(port);
                   2053: 
                   2054:                *ownership = TRUE;
                   2055:                *receive_rights = TRUE;
                   2056:                *enabledp = enabled;
                   2057:                *num_msgs = (int) msgcount;
                   2058:                *backlog = (int) qlimit;
                   2059:        } else {
                   2060:                is_write_unlock(space);
                   2061: 
                   2062:                *ownership = FALSE;
                   2063:                *receive_rights = FALSE;
                   2064:                *enabledp = MACH_PORT_NULL;
                   2065:                *num_msgs = -1;
                   2066:                *backlog = 0;
                   2067:        }
                   2068: 
                   2069:        return KERN_SUCCESS;
                   2070: }
                   2071: 
                   2072: /*
                   2073:  *     Routine:        port_set_allocate [kernel call]
                   2074:  *     Purpose:
                   2075:  *             Create a new port set, give rights to task, and
                   2076:  *             return task's local name for the set.
                   2077:  *     Conditions:
                   2078:  *             Nothing locked.
                   2079:  *     Returns:
                   2080:  *             KERN_SUCCESS            Allocated a port set.
                   2081:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2082:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2083:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   2084:  */
                   2085: 
                   2086: kern_return_t
                   2087: port_set_allocate(space, namep)
                   2088:        ipc_space_t space;
                   2089:        mach_port_t *namep;
                   2090: {
                   2091:        ipc_pset_t pset;
                   2092:        kern_return_t kr;
                   2093: 
                   2094:        if (space == IS_NULL)
                   2095:                return KERN_INVALID_ARGUMENT;
                   2096: 
                   2097:        kr = ipc_pset_alloc(space, namep, &pset);
                   2098:        if (kr == KERN_SUCCESS)
                   2099:                ips_unlock(pset);
                   2100:        else if (kr != KERN_RESOURCE_SHORTAGE)
                   2101:                kr = KERN_INVALID_ARGUMENT;
                   2102: 
                   2103:        return kr;
                   2104: }
                   2105: 
                   2106: /*
                   2107:  *     Routine:        port_set_deallocate [kernel call]
                   2108:  *     Purpose:
                   2109:  *             Destroys the task's port set.  If there are any
                   2110:  *             receive rights in the set, they are removed.
                   2111:  *     Conditions:
                   2112:  *             Nothing locked.
                   2113:  *     Returns:
                   2114:  *             KERN_SUCCESS            Deallocated the port set.
                   2115:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2116:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2117:  *             KERN_INVALID_ARGUMENT   Name doesn't denote a port set.
                   2118:  */
                   2119: 
                   2120: kern_return_t
                   2121: port_set_deallocate(space, name)
                   2122:        ipc_space_t space;
                   2123:        mach_port_t name;
                   2124: {
                   2125:        ipc_entry_t entry;
                   2126:        kern_return_t kr;
                   2127: 
                   2128:        if (space == IS_NULL)
                   2129:                return KERN_INVALID_ARGUMENT;
                   2130: 
                   2131:        kr = ipc_right_lookup_write(space, name, &entry);
                   2132:        if (kr != KERN_SUCCESS)
                   2133:                return kr;
                   2134:        /* space is write-locked and active */
                   2135: 
                   2136:        if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
                   2137:                is_write_unlock(space);
                   2138:                return KERN_INVALID_ARGUMENT;
                   2139:        }
                   2140: 
                   2141:        kr = ipc_right_destroy(space, name, entry);
                   2142:        /* space is unlocked */
                   2143:        assert(kr == KERN_SUCCESS);
                   2144:        return kr;
                   2145: }
                   2146: 
                   2147: /*
                   2148:  *     Routine:        port_set_add [kernel call]
                   2149:  *     Purpose:
                   2150:  *             Moves receive rights into the port set.
                   2151:  *     Conditions:
                   2152:  *             Nothing locked.
                   2153:  *     Returns:
                   2154:  *             KERN_SUCCESS            Moved the receive right.
                   2155:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2156:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2157:  *             KERN_INVALID_ARGUMENT   port_name doesn't denote port rights.
                   2158:  *             KERN_NOT_RECEIVER       port_name doesn't denote receive right.
                   2159:  *             KERN_INVALID_ARGUMENT   set_name doesn't denote a port set.
                   2160:  *     Additions:
                   2161:  *             KERN_NOT_RECEIVER       port_name denotes a send-once right.
                   2162:  *             KERN_NOT_RECEIVER       port_name denotes a dead name.
                   2163:  */
                   2164: 
                   2165: kern_return_t
                   2166: port_set_add(space, set_name, port_name)
                   2167:        ipc_space_t space;
                   2168:        mach_port_t set_name;
                   2169:        mach_port_t port_name;
                   2170: {
                   2171:        ipc_entry_t entry;
                   2172:        mach_port_type_t type;
                   2173:        mach_port_urefs_t urefs;
                   2174:        ipc_port_t port;
                   2175:        ipc_pset_t pset;
                   2176:        kern_return_t kr;
                   2177: 
                   2178:        if (space == IS_NULL)
                   2179:                return KERN_INVALID_ARGUMENT;
                   2180: 
                   2181:        kr = ipc_right_lookup_write(space, port_name, &entry);
                   2182:        if (kr != KERN_SUCCESS)
                   2183:                return KERN_INVALID_ARGUMENT;
                   2184:        /* space is write-locked and active */
                   2185: 
                   2186:        /* use ipc_right_info to check for dead compat entries */
                   2187: 
                   2188:        kr = ipc_right_info(space, port_name, entry, &type, &urefs);
                   2189:        if (kr != KERN_SUCCESS)
                   2190:                return KERN_INVALID_ARGUMENT; /* space is unlocked */
                   2191: 
                   2192:        if ((type & MACH_PORT_TYPE_RECEIVE) == 0) {
                   2193:                is_write_unlock(space);
                   2194:                if (type & MACH_PORT_TYPE_PORT_OR_DEAD)
                   2195:                        return KERN_NOT_RECEIVER;
                   2196:                else
                   2197:                        return KERN_INVALID_ARGUMENT;
                   2198:        }
                   2199: 
                   2200:        is_write_to_read_lock(space);
                   2201:        port = (ipc_port_t) entry->ie_object;
                   2202:        assert(port != IP_NULL);
                   2203: 
                   2204:        entry = ipc_entry_lookup(space, set_name);
                   2205:        if ((entry == IE_NULL) ||
                   2206:            ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0)) {
                   2207:                is_read_unlock(space);
                   2208:                return KERN_INVALID_ARGUMENT;
                   2209:        }
                   2210: 
                   2211:        pset = (ipc_pset_t) entry->ie_object;
                   2212:        assert(pset != IPS_NULL);
                   2213: 
                   2214:        kr = ipc_pset_move(space, port, pset);
                   2215:        /* space is unlocked */
                   2216:        assert(kr == KERN_SUCCESS);
                   2217:        return kr;
                   2218: }
                   2219: 
                   2220: /*
                   2221:  *     Routine:        port_set_remove [kernel call]
                   2222:  *     Purpose:
                   2223:  *             Removes the receive rights from the set they are in.
                   2224:  *     Conditions:
                   2225:  *             Nothing locked.
                   2226:  *     Returns:
                   2227:  *             KERN_SUCCESS            Removed the receive right.
                   2228:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2229:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2230:  *             KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
                   2231:  *             KERN_NOT_RECEIVER       Name denotes send rights, not receive.
                   2232:  *             KERN_NOT_IN_SET         Port isn't in a port set.
                   2233:  *     Additions:
                   2234:  *             KERN_NOT_RECEIVER       Name denotes a send-once right.
                   2235:  *             KERN_NOT_RECEIVER       Name denotes a dead name.
                   2236:  */
                   2237: 
                   2238: kern_return_t
                   2239: port_set_remove(space, name)
                   2240:        ipc_space_t space;
                   2241:        mach_port_t name;
                   2242: {
                   2243:        ipc_entry_t entry;
                   2244:        mach_port_type_t type;
                   2245:        mach_port_urefs_t urefs;
                   2246:        ipc_port_t port;
                   2247:        kern_return_t kr;
                   2248: 
                   2249:        if (space == IS_NULL)
                   2250:                return KERN_INVALID_ARGUMENT;
                   2251: 
                   2252:        kr = ipc_right_lookup_write(space, name, &entry);
                   2253:        if (kr != KERN_SUCCESS)
                   2254:                return KERN_INVALID_ARGUMENT;
                   2255:        /* space is write-locked and active */
                   2256: 
                   2257:        /* use ipc_right_info to check for dead compat entries */
                   2258: 
                   2259:        kr = ipc_right_info(space, name, entry, &type, &urefs);
                   2260:        if (kr != KERN_SUCCESS)
                   2261:                return KERN_INVALID_ARGUMENT; /* space is unlocked */
                   2262: 
                   2263:        if ((type & (MACH_PORT_TYPE_RECEIVE)) == 0) {
                   2264:                is_write_unlock(space);
                   2265:                if (type & MACH_PORT_TYPE_PORT_OR_DEAD)
                   2266:                        return KERN_NOT_RECEIVER;
                   2267:                else
                   2268:                        return KERN_INVALID_ARGUMENT;
                   2269:        }
                   2270: 
                   2271:        is_write_to_read_lock(space);
                   2272:        port = (ipc_port_t) entry->ie_object;
                   2273:        assert(port != IP_NULL);
                   2274: 
                   2275:        kr = ipc_pset_move(space, port, IPS_NULL);
                   2276:        /* space is unlocked */
                   2277:        return kr;
                   2278: }
                   2279: 
                   2280: /*
                   2281:  *     Routine:        port_set_status [kernel call]
                   2282:  *     Purpose:
                   2283:  *             Retrieve list of members of a port set.
                   2284:  *     Conditions:
                   2285:  *             Nothing locked.
                   2286:  *     Returns:
                   2287:  *             KERN_SUCCESS            Retrieved port set status.
                   2288:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2289:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2290:  *             KERN_INVALID_ARGUMENT   Name doesn't denote a port set.
                   2291:  *     Additions:
                   2292:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   2293:  */
                   2294: 
                   2295: kern_return_t
                   2296: port_set_status(space, name, members, membersCnt)
                   2297:        ipc_space_t space;
                   2298:        mach_port_t name;
                   2299:        mach_port_t **members;
                   2300:        mach_msg_type_number_t *membersCnt;
                   2301: {
                   2302:        kern_return_t kr;
                   2303: 
                   2304:        kr = mach_port_get_set_status(space, name, members, membersCnt);
                   2305:        if ((kr != KERN_SUCCESS) && (kr != KERN_RESOURCE_SHORTAGE))
                   2306:                kr = KERN_INVALID_ARGUMENT;
                   2307: 
                   2308:        return kr;
                   2309: }
                   2310: 
                   2311: /*
                   2312:  *     Routine:        port_insert_send [kernel call]
                   2313:  *     Purpose:
                   2314:  *             Inserts send rights to a port into a task,
                   2315:  *             at a given name.  The name must not be in use.
                   2316:  *     Conditions:
                   2317:  *             Nothing locked.
                   2318:  *     Returns:
                   2319:  *             KERN_SUCCESS            Inserted send right.
                   2320:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2321:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2322:  *             KERN_INVALID_ARGUMENT   Port is null or dead.
                   2323:  *             KERN_INVALID_ARGUMENT   Name is reserved.
                   2324:  *             KERN_NAME_EXISTS        Name already denotes a right.
                   2325:  *             KERN_FAILURE            Task already has rights for the port.
                   2326:  *     Additions:
                   2327:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   2328:  */
                   2329: 
                   2330: kern_return_t
                   2331: port_insert_send(space, port, name)
                   2332:        ipc_space_t space;
                   2333:        ipc_port_t port;
                   2334:        mach_port_t name;
                   2335: {
                   2336:        kern_return_t kr;
                   2337: 
                   2338:        if ((space == IS_NULL) ||
                   2339:            !MACH_PORT_VALID(name) ||
                   2340:            !IP_VALID(port))
                   2341:                return KERN_INVALID_ARGUMENT;
                   2342: 
                   2343:        kr = ipc_object_copyout_name_compat(space, (ipc_object_t) port,
                   2344:                                            MACH_MSG_TYPE_PORT_SEND, name);
                   2345:        switch (kr) {
                   2346:            case KERN_SUCCESS:
                   2347:            case KERN_NAME_EXISTS:
                   2348:            case KERN_RESOURCE_SHORTAGE:
                   2349:                break;
                   2350: 
                   2351:            case KERN_RIGHT_EXISTS:
                   2352:                kr = KERN_FAILURE;
                   2353:                break;
                   2354: 
                   2355:            default:
                   2356:                kr = KERN_INVALID_ARGUMENT;
                   2357:                break;
                   2358:        }
                   2359: 
                   2360:        return kr;
                   2361: }
                   2362: 
                   2363: /*
                   2364:  *     Routine:        port_extract_send [kernel call]
                   2365:  *     Purpose:
                   2366:  *             Extracts send rights from "task"'s "his_name" port.
                   2367:  *             The task is left with no rights for the port.
                   2368:  *     Conditions:
                   2369:  *             Nothing locked.
                   2370:  *     Returns:
                   2371:  *             KERN_SUCCESS            Extracted send right.
                   2372:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2373:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2374:  *             KERN_INVALID_ARGUMENT   Name doesn't denote pure send rights.
                   2375:  */
                   2376: 
                   2377: kern_return_t
                   2378: port_extract_send(space, name, portp)
                   2379:        ipc_space_t space;
                   2380:        mach_port_t name;
                   2381:        ipc_port_t *portp;
                   2382: {
                   2383:        kern_return_t kr;
                   2384: 
                   2385:        if (space == IS_NULL)
                   2386:                return KERN_INVALID_ARGUMENT;
                   2387: 
                   2388:        kr = ipc_object_copyin_compat(space, name,
                   2389:                                      MSG_TYPE_PORT, TRUE,
                   2390:                                      (ipc_object_t *) portp);
                   2391:        if (kr != KERN_SUCCESS)
                   2392:                kr = KERN_INVALID_ARGUMENT;
                   2393: 
                   2394:        return kr;
                   2395: }
                   2396: 
                   2397: /*
                   2398:  *     Routine:        port_insert_receive [kernel call]
                   2399:  *     Purpose:
                   2400:  *             Inserts receive/ownership rights to a port into a task,
                   2401:  *             at a given name.
                   2402:  *     Conditions:
                   2403:  *             Nothing locked.
                   2404:  *     Returns:
                   2405:  *             KERN_SUCCESS            Inserted receive right.
                   2406:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2407:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2408:  *             KERN_INVALID_ARGUMENT   Port is null.  (Can't be dead.)
                   2409:  *             KERN_INVALID_ARGUMENT   Name is reserved.
                   2410:  *             KERN_NAME_EXISTS        Name already denotes a right.
                   2411:  *             KERN_FAILURE            Task already has rights for the port.
                   2412:  *     Additions:
                   2413:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   2414:  */
                   2415: 
                   2416: kern_return_t
                   2417: port_insert_receive(space, port, name)
                   2418:        ipc_space_t space;
                   2419:        ipc_port_t port;
                   2420:        mach_port_t name;
                   2421: {
                   2422:        kern_return_t kr;
                   2423: 
                   2424:        if ((space == IS_NULL) ||
                   2425:            !MACH_PORT_VALID(name) ||
                   2426:            !IP_VALID(port))
                   2427:                return KERN_INVALID_ARGUMENT;
                   2428: 
                   2429:        kr = ipc_object_copyout_name_compat(space, (ipc_object_t) port,
                   2430:                                            MACH_MSG_TYPE_PORT_RECEIVE, name);
                   2431:        switch (kr) {
                   2432:            case KERN_SUCCESS:
                   2433:            case KERN_NAME_EXISTS:
                   2434:            case KERN_RESOURCE_SHORTAGE:
                   2435:                break;
                   2436: 
                   2437:            case KERN_RIGHT_EXISTS:
                   2438:                kr = KERN_FAILURE;
                   2439:                break;
                   2440: 
                   2441:            default:
                   2442:                kr = KERN_INVALID_ARGUMENT;
                   2443:                break;
                   2444:        }
                   2445: 
                   2446:        return kr;
                   2447: }
                   2448: 
                   2449: /*
                   2450:  *     Routine:        port_extract_receive [kernel call]
                   2451:  *     Purpose:
                   2452:  *             Extracts receive/ownership rights
                   2453:  *             from "task"'s "his_name" port.
                   2454:  *
                   2455:  *             The task is left with no rights for the port.
                   2456:  *     Conditions:
                   2457:  *             Nothing locked.
                   2458:  *     Returns:
                   2459:  *             KERN_SUCCESS            Extracted receive right.
                   2460:  *             KERN_INVALID_ARGUMENT   Task is null.
                   2461:  *             KERN_INVALID_ARGUMENT   Task is not active.
                   2462:  *             KERN_INVALID_ARGUMENT   Name doesn't denote receive rights.
                   2463:  */
                   2464: 
                   2465: kern_return_t
                   2466: port_extract_receive(space, name, portp)
                   2467:        ipc_space_t space;
                   2468:        mach_port_t name;
                   2469:        ipc_port_t *portp;
                   2470: {
                   2471:        kern_return_t kr;
                   2472: 
                   2473:        if (space == IS_NULL)
                   2474:                return KERN_INVALID_ARGUMENT;
                   2475: 
                   2476:        kr = ipc_object_copyin_compat(space, name,
                   2477:                                      MSG_TYPE_PORT_ALL, TRUE,
                   2478:                                      (ipc_object_t *) portp);
                   2479:        if (kr != KERN_SUCCESS)
                   2480:                kr = KERN_INVALID_ARGUMENT;
                   2481: 
                   2482:        return kr;
                   2483: }
                   2484: 
                   2485: #endif /* MACH_IPC_COMPAT */

unix.superglobalmegacorp.com

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