Annotation of Gnu-Mach/ipc/mach_port.c, revision 1.1

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