Annotation of Gnu-Mach/ipc/mach_port.c, revision 1.1.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.