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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /*
        !            26:  * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990  
        !            27:  * Open Software Foundation, Inc. 
        !            28:  *  
        !            29:  * Permission to use, copy, modify, and distribute this software and 
        !            30:  * its documentation for any purpose and without fee is hereby granted, 
        !            31:  * provided that the above copyright notice appears in all copies and 
        !            32:  * that both the copyright notice and this permission notice appear in 
        !            33:  * supporting documentation, and that the name of ("OSF") or Open Software 
        !            34:  * Foundation not be used in advertising or publicity pertaining to 
        !            35:  * distribution of the software without specific, written prior permission. 
        !            36:  *  
        !            37:  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
        !            38:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
        !            39:  * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY 
        !            40:  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
        !            41:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
        !            42:  * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING 
        !            43:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE 
        !            44:  */
        !            45: /*
        !            46:  * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
        !            47:  */
        !            48: /* 
        !            49:  * Mach Operating System
        !            50:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
        !            51:  * All Rights Reserved.
        !            52:  * 
        !            53:  * Permission to use, copy, modify and distribute this software and its
        !            54:  * documentation is hereby granted, provided that both the copyright
        !            55:  * notice and this permission notice appear in all copies of the
        !            56:  * software, derivative works or modified versions, and any portions
        !            57:  * thereof, and that both notices appear in supporting documentation.
        !            58:  * 
        !            59:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            60:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            61:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            62:  * 
        !            63:  * Carnegie Mellon requests users of this software to return to
        !            64:  * 
        !            65:  *  Software Distribution Coordinator  or  [email protected]
        !            66:  *  School of Computer Science
        !            67:  *  Carnegie Mellon University
        !            68:  *  Pittsburgh PA 15213-3890
        !            69:  * 
        !            70:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            71:  * the rights to redistribute these changes.
        !            72:  */
        !            73: /*
        !            74:  *     File:   ipc/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.