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

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990  
                     27:  * Open Software Foundation, Inc. 
                     28:  *  
                     29:  * Permission to use, copy, modify, and distribute this software and 
                     30:  * its documentation for any purpose and without fee is hereby granted, 
                     31:  * provided that the above copyright notice appears in all copies and 
                     32:  * that both the copyright notice and this permission notice appear in 
                     33:  * supporting documentation, and that the name of ("OSF") or Open Software 
                     34:  * Foundation not be used in advertising or publicity pertaining to 
                     35:  * distribution of the software without specific, written prior permission. 
                     36:  *  
                     37:  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
                     38:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
                     39:  * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY 
                     40:  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
                     41:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
                     42:  * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING 
                     43:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE 
                     44:  */
                     45: /*
                     46:  * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
                     47:  */
                     48: /* 
                     49:  * Mach Operating System
                     50:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
                     51:  * All Rights Reserved.
                     52:  * 
                     53:  * Permission to use, copy, modify and distribute this software and its
                     54:  * documentation is hereby granted, provided that both the copyright
                     55:  * notice and this permission notice appear in all copies of the
                     56:  * software, derivative works or modified versions, and any portions
                     57:  * thereof, and that both notices appear in supporting documentation.
                     58:  * 
                     59:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     60:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     61:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     62:  * 
                     63:  * Carnegie Mellon requests users of this software to return to
                     64:  * 
                     65:  *  Software Distribution Coordinator  or  [email protected]
                     66:  *  School of Computer Science
                     67:  *  Carnegie Mellon University
                     68:  *  Pittsburgh PA 15213-3890
                     69:  * 
                     70:  * any improvements or extensions that they make and grant Carnegie Mellon
                     71:  * the rights to redistribute these changes.
                     72:  */
                     73: /*
                     74:  *     File:   ipc/ipc_right.c
                     75:  *     Author: Rich Draves
                     76:  *     Date:   1989
                     77:  *
                     78:  *     Functions to manipulate IPC capabilities.
                     79:  */
                     80: 
                     81: #import <mach/features.h>
                     82: 
                     83: #include <mach/boolean.h>
                     84: #include <mach/kern_return.h>
                     85: #include <mach/port.h>
                     86: #include <mach/message.h>
                     87: #include <kern/assert.h>
                     88: #include <ipc/port.h>
                     89: #include <ipc/ipc_entry.h>
                     90: #include <ipc/ipc_space.h>
                     91: #include <ipc/ipc_object.h>
                     92: #include <ipc/ipc_hash.h>
                     93: #include <ipc/ipc_port.h>
                     94: #include <ipc/ipc_pset.h>
                     95: #include <ipc/ipc_marequest.h>
                     96: #include <ipc/ipc_right.h>
                     97: #include <ipc/ipc_notify.h>
                     98: 
                     99: 
                    100: 
                    101: /*
                    102:  *     Routine:        ipc_right_lookup_write
                    103:  *     Purpose:
                    104:  *             Finds an entry in a space, given the name.
                    105:  *     Conditions:
                    106:  *             Nothing locked.  If successful, the space is write-locked.
                    107:  *     Returns:
                    108:  *             KERN_SUCCESS            Found an entry.
                    109:  *             KERN_INVALID_TASK       The space is dead.
                    110:  *             KERN_INVALID_NAME       Name doesn't exist in space.
                    111:  */
                    112: 
                    113: kern_return_t
                    114: ipc_right_lookup_write(
                    115:        ipc_space_t     space,
                    116:        mach_port_t     name,
                    117:        ipc_entry_t     *entryp)
                    118: {
                    119:        ipc_entry_t entry;
                    120: 
                    121:        assert(space != IS_NULL);
                    122: 
                    123:        is_write_lock(space);
                    124: 
                    125:        if (!space->is_active) {
                    126:                is_write_unlock(space);
                    127:                return KERN_INVALID_TASK;
                    128:        }
                    129: 
                    130:        if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
                    131:                is_write_unlock(space);
                    132:                return KERN_INVALID_NAME;
                    133:        }
                    134: 
                    135:        *entryp = entry;
                    136:        return KERN_SUCCESS;
                    137: }
                    138: 
                    139: /*
                    140:  *     Routine:        ipc_right_reverse
                    141:  *     Purpose:
                    142:  *             Translate (space, object) -> (name, entry).
                    143:  *             Only finds send/receive rights.
                    144:  *             Returns TRUE if an entry is found; if so,
                    145:  *             the object is locked and active.
                    146:  *     Conditions:
                    147:  *             The space must be locked (read or write) and active.
                    148:  *             Nothing else locked.
                    149:  */
                    150: 
                    151: boolean_t
                    152: ipc_right_reverse(
                    153:        ipc_space_t     space,
                    154:        ipc_object_t    object,
                    155:        mach_port_t     *namep,
                    156:        ipc_entry_t     *entryp)
                    157: {
                    158:        ipc_port_t port;
                    159:        mach_port_t name;
                    160:        ipc_entry_t entry;
                    161: 
                    162:        /* would switch on io_otype to handle multiple types of object */
                    163: 
                    164:        assert(space->is_active);
                    165:        assert(io_otype(object) == IOT_PORT);
                    166: 
                    167:        port = (ipc_port_t) object;
                    168: 
                    169:        ip_lock(port);
                    170:        if (!ip_active(port)) {
                    171:                ip_unlock(port);
                    172: 
                    173:                return FALSE;
                    174:        }
                    175: 
                    176:        if (port->ip_receiver == space) {
                    177:                name = port->ip_receiver_name;
                    178:                assert(name != MACH_PORT_NULL);
                    179: 
                    180:                entry = ipc_entry_lookup(space, name);
                    181: 
                    182:                assert(entry != IE_NULL);
                    183:                assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                    184:                assert(port == (ipc_port_t) entry->ie_object);
                    185: 
                    186:                *namep = name;
                    187:                *entryp = entry;
                    188:                return TRUE;
                    189:        }
                    190: 
                    191:        if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
                    192:                assert((entry = *entryp) != IE_NULL);
                    193:                assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
                    194:                assert(port == (ipc_port_t) entry->ie_object);
                    195: 
                    196:                return TRUE;
                    197:        }
                    198: 
                    199:        ip_unlock(port);
                    200:        return FALSE;
                    201: }
                    202: 
                    203: /*
                    204:  *     Routine:        ipc_right_dnrequest
                    205:  *     Purpose:
                    206:  *             Make a dead-name request, returning the previously
                    207:  *             registered send-once right.  If notify is IP_NULL,
                    208:  *             just cancels the previously registered request.
                    209:  *
                    210:  *             This interacts with the IE_BITS_COMPAT, because they
                    211:  *             both use ie_request.  If this is a compat entry, then
                    212:  *             previous always gets IP_NULL.  If notify is IP_NULL,
                    213:  *             then the entry remains a compat entry.  Otherwise
                    214:  *             the real dead-name request is registered and the entry
                    215:  *             is no longer a compat entry.
                    216:  *     Conditions:
                    217:  *             Nothing locked.  May allocate memory.
                    218:  *             Only consumes/returns refs if successful.
                    219:  *     Returns:
                    220:  *             KERN_SUCCESS            Made/canceled dead-name request.
                    221:  *             KERN_INVALID_TASK       The space is dead.
                    222:  *             KERN_INVALID_NAME       Name doesn't exist in space.
                    223:  *             KERN_INVALID_RIGHT      Name doesn't denote port/dead rights.
                    224:  *             KERN_INVALID_ARGUMENT   Name denotes dead name, but
                    225:  *                     immediate is FALSE or notify is IP_NULL.
                    226:  *             KERN_UREFS_OVERFLOW     Name denotes dead name, but
                    227:  *                     generating immediate notif. would overflow urefs.
                    228:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    229:  */
                    230: 
                    231: kern_return_t
                    232: ipc_right_dnrequest(
                    233:        ipc_space_t     space,
                    234:        mach_port_t     name,
                    235:        boolean_t       immediate,
                    236:        ipc_port_t      notify,
                    237:        ipc_port_t      *previousp)
                    238: {
                    239:        ipc_port_t previous;
                    240: 
                    241:        for (;;) {
                    242:                ipc_entry_t entry;
                    243:                ipc_entry_bits_t bits;
                    244:                kern_return_t kr;
                    245: 
                    246:                kr = ipc_right_lookup_write(space, name, &entry);
                    247:                if (kr != KERN_SUCCESS)
                    248:                        return kr;
                    249:                /* space is write-locked and active */
                    250: 
                    251:                bits = entry->ie_bits;
                    252:                if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
                    253:                        ipc_port_t port;
                    254:                        ipc_port_request_index_t request;
                    255: 
                    256:                        port = (ipc_port_t) entry->ie_object;
                    257:                        assert(port != IP_NULL);
                    258: 
                    259:                        if (!ipc_right_check(space, port, name, entry)) {
                    260:                                /* port is locked and active */
                    261: 
                    262:                                if (notify == IP_NULL) {
                    263: #if    MACH_IPC_COMPAT
                    264:                                        if (bits & IE_BITS_COMPAT) {
                    265:                                                assert(entry->ie_request != 0);
                    266: 
                    267:                                                previous = IP_NULL;
                    268:                                        } else
                    269: #endif /* MACH_IPC_COMPAT */
                    270:                                        previous = ipc_right_dncancel_macro(
                    271:                                                space, port, name, entry);
                    272: 
                    273:                                        ip_unlock(port);
                    274:                                        is_write_unlock(space);
                    275:                                        break;
                    276:                                }
                    277: 
                    278:                                /*
                    279:                                 *      If a registered soright exists,
                    280:                                 *      want to atomically switch with it.
                    281:                                 *      If ipc_port_dncancel finds us a
                    282:                                 *      soright, then the following
                    283:                                 *      ipc_port_dnrequest will reuse
                    284:                                 *      that slot, so we are guaranteed
                    285:                                 *      not to unlock and retry.
                    286:                                 */
                    287: 
                    288:                                previous = ipc_right_dncancel_macro(space,
                    289:                                                        port, name, entry);
                    290: 
                    291:                                kr = ipc_port_dnrequest(port, name, notify,
                    292:                                                        &request);
                    293:                                if (kr != KERN_SUCCESS) {
                    294:                                        assert(previous == IP_NULL);
                    295:                                        is_write_unlock(space);
                    296: 
                    297:                                        kr = ipc_port_dngrow(port,
                    298:                                                             ITS_SIZE_NONE);
                    299:                                        /* port is unlocked */
                    300:                                        if (kr != KERN_SUCCESS)
                    301:                                                return kr;
                    302: 
                    303:                                        continue;
                    304:                                }
                    305: 
                    306:                                assert(request != 0);
                    307:                                ip_unlock(port);
                    308: 
                    309:                                entry->ie_request = request;
                    310: #if    MACH_IPC_COMPAT
                    311:                                entry->ie_bits = bits &~ IE_BITS_COMPAT;
                    312: #endif /* MACH_IPC_COMPAT */
                    313:                                is_write_unlock(space);
                    314:                                break;
                    315:                        }
                    316: 
                    317: #if    MACH_IPC_COMPAT
                    318:                        if (bits & IE_BITS_COMPAT) {
                    319:                                is_write_unlock(space);
                    320:                                return KERN_INVALID_NAME;
                    321:                        }
                    322: #endif /* MACH_IPC_COMPAT */
                    323: 
                    324:                        bits = entry->ie_bits;
                    325:                        assert(bits & MACH_PORT_TYPE_DEAD_NAME);
                    326:                }
                    327: 
                    328:                if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
                    329:                    immediate && (notify != IP_NULL)) {
                    330:                        mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
                    331: 
                    332:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                    333:                        assert(urefs > 0);
                    334: 
                    335:                        if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
                    336:                                is_write_unlock(space);
                    337:                                return KERN_UREFS_OVERFLOW;
                    338:                        }
                    339: 
                    340:                        entry->ie_bits = bits + 1; /* increment urefs */
                    341:                        is_write_unlock(space);
                    342: 
                    343:                        ipc_notify_dead_name(notify, name);
                    344:                        previous = IP_NULL;
                    345:                        break;
                    346:                }
                    347: 
                    348:                is_write_unlock(space);
                    349:                if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
                    350:                        return KERN_INVALID_ARGUMENT;
                    351:                else
                    352:                        return KERN_INVALID_RIGHT;
                    353:        }
                    354: 
                    355:        *previousp = previous;
                    356:        return KERN_SUCCESS;
                    357: }
                    358: 
                    359: /*
                    360:  *     Routine:        ipc_right_dncancel
                    361:  *     Purpose:
                    362:  *             Cancel a dead-name request and return the send-once right.
                    363:  *             Afterwards, entry->ie_request == 0.
                    364:  *     Conditions:
                    365:  *             The space must be write-locked; the port must be locked.
                    366:  *             The port must be active; the space doesn't have to be.
                    367:  */
                    368: 
                    369: ipc_port_t
                    370: ipc_right_dncancel(
                    371:        ipc_space_t     space,
                    372:        ipc_port_t      port,
                    373:        mach_port_t     name,
                    374:        ipc_entry_t     entry)
                    375: {
                    376:        ipc_port_t dnrequest;
                    377: 
                    378:        assert(ip_active(port));
                    379:        assert(port == (ipc_port_t) entry->ie_object);
                    380: 
                    381:        dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
                    382:        entry->ie_request = 0;
                    383: 
                    384: #if    MACH_IPC_COMPAT
                    385:        assert(!ipr_spacep(dnrequest) == !(entry->ie_bits & IE_BITS_COMPAT));
                    386: 
                    387:        /* if this is actually a space ptr, just release the ref */
                    388: 
                    389:        if (entry->ie_bits & IE_BITS_COMPAT) {
                    390:                assert(space == ipr_space(dnrequest));
                    391: 
                    392:                is_release(space);
                    393:                dnrequest = IP_NULL;
                    394:        }
                    395: #endif /* MACH_IPC_COMPAT */
                    396: 
                    397:        return dnrequest;
                    398: }
                    399: 
                    400: /*
                    401:  *     Routine:        ipc_right_inuse
                    402:  *     Purpose:
                    403:  *             Check if an entry is being used.
                    404:  *             Returns TRUE if it is.
                    405:  *     Conditions:
                    406:  *             The space is write-locked and active.
                    407:  *             It is unlocked if the entry is inuse.
                    408:  */
                    409: 
                    410: boolean_t
                    411: ipc_right_inuse(
                    412:        ipc_space_t     space,
                    413:        mach_port_t     name,
                    414:        ipc_entry_t     entry)
                    415: {
                    416:        ipc_entry_bits_t bits = entry->ie_bits;
                    417: 
                    418:        if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
                    419: #if    MACH_IPC_COMPAT
                    420:                mach_port_type_t type = IE_BITS_TYPE(bits);
                    421: 
                    422:                /*
                    423:                 *      There is yet hope.  If the port has died, we
                    424:                 *      must clean up the entry so it's as good as new.
                    425:                 */
                    426: 
                    427:                if ((bits & IE_BITS_COMPAT) &&
                    428:                    ((type == MACH_PORT_TYPE_SEND) ||
                    429:                     (type == MACH_PORT_TYPE_SEND_ONCE))) {
                    430:                        ipc_port_t port;
                    431:                        boolean_t active;
                    432: 
                    433:                        assert(IE_BITS_UREFS(bits) > 0);
                    434:                        assert(entry->ie_request != 0);
                    435: 
                    436:                        port = (ipc_port_t) entry->ie_object;
                    437:                        assert(port != IP_NULL);
                    438: 
                    439:                        ip_lock(port);
                    440:                        active = ip_active(port);
                    441:                        ip_unlock(port);
                    442: 
                    443:                        if (!active) {
                    444:                                if (type == MACH_PORT_TYPE_SEND) {
                    445:                                        /* clean up msg-accepted request */
                    446: 
                    447:                                        if (bits & IE_BITS_MAREQUEST)
                    448:                                                ipc_marequest_cancel(
                    449:                                                                space, name);
                    450: 
                    451:                                        ipc_hash_delete(
                    452:                                                space, (ipc_object_t) port,
                    453:                                                name, entry);
                    454:                                } else {
                    455:                                        assert(IE_BITS_UREFS(bits) == 1);
                    456:                                        assert(!(bits & IE_BITS_MAREQUEST));
                    457:                                }
                    458: 
                    459:                                ipc_port_release(port);
                    460: 
                    461:                                entry->ie_request = 0;
                    462:                                entry->ie_object = IO_NULL;
                    463:                                entry->ie_bits &= ~IE_BITS_RIGHT_MASK;
                    464: 
                    465:                                return FALSE;
                    466:                        }
                    467:                }
                    468: #endif /* MACH_IPC_COMPAT */
                    469: 
                    470:                is_write_unlock(space);
                    471:                return TRUE;
                    472:        }
                    473: 
                    474:        return FALSE;
                    475: }
                    476: 
                    477: /*
                    478:  *     Routine:        ipc_right_check
                    479:  *     Purpose:
                    480:  *             Check if the port has died.  If it has,
                    481:  *             clean up the entry and return TRUE.
                    482:  *     Conditions:
                    483:  *             The space is write-locked; the port is not locked.
                    484:  *             If returns FALSE, the port is also locked and active.
                    485:  *             Otherwise, entry is converted to a dead name, freeing
                    486:  *             a reference to port.
                    487:  *
                    488:  *             [MACH_IPC_COMPAT] If the port is dead, and this is a
                    489:  *             compat mode entry, then the port reference is released
                    490:  *             and the entry is destroyed.  The call returns TRUE,
                    491:  *             and the space is left locked.
                    492:  */
                    493: 
                    494: boolean_t
                    495: ipc_right_check(
                    496:        ipc_space_t     space,
                    497:        ipc_port_t      port,
                    498:        mach_port_t     name,
                    499:        ipc_entry_t     entry)
                    500: {
                    501:        ipc_entry_bits_t bits;
                    502: 
                    503:        assert(space->is_active);
                    504:        assert(port == (ipc_port_t) entry->ie_object);
                    505: 
                    506:        ip_lock(port);
                    507:        if (ip_active(port))
                    508:                return FALSE;
                    509:        ip_unlock(port);
                    510: 
                    511:        /* this was either a pure send right or a send-once right */
                    512: 
                    513:        bits = entry->ie_bits;
                    514:        assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
                    515:        assert(IE_BITS_UREFS(bits) > 0);
                    516: 
                    517:        if (bits & MACH_PORT_TYPE_SEND) {
                    518:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                    519: 
                    520:                /* clean up msg-accepted request */
                    521: 
                    522:                if (bits & IE_BITS_MAREQUEST) {
                    523:                        bits &= ~IE_BITS_MAREQUEST;
                    524: 
                    525:                        ipc_marequest_cancel(space, name);
                    526:                }
                    527: 
                    528:                ipc_hash_delete(space, (ipc_object_t) port, name, entry);
                    529:        } else {
                    530:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                    531:                assert(IE_BITS_UREFS(bits) == 1);
                    532:                assert((bits & IE_BITS_MAREQUEST) == 0);
                    533:        }
                    534: 
                    535:        ipc_port_release(port);
                    536: 
                    537: #if    MACH_IPC_COMPAT
                    538:        if (bits & IE_BITS_COMPAT) {
                    539:                assert(entry->ie_request != 0);
                    540:                entry->ie_request = 0;
                    541: 
                    542:                entry->ie_object = IO_NULL;
                    543:                ipc_entry_dealloc(space, name, entry);
                    544: 
                    545:                return TRUE;
                    546:        }
                    547: #endif /* MACH_IPC_COMPAT */
                    548: 
                    549:        /* convert entry to dead name */
                    550: 
                    551:        bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
                    552: 
                    553:        if (entry->ie_request != 0) {
                    554:                assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
                    555: 
                    556:                entry->ie_request = 0;
                    557:                bits++;         /* increment urefs */
                    558:        }
                    559: 
                    560:        entry->ie_bits = bits;
                    561:        entry->ie_object = IO_NULL;
                    562:        return TRUE;
                    563: }
                    564: 
                    565: /*
                    566:  *     Routine:        ipc_right_clean
                    567:  *     Purpose:
                    568:  *             Cleans up an entry in a dead space.
                    569:  *             The entry isn't deallocated or removed
                    570:  *             from reverse hash tables.
                    571:  *     Conditions:
                    572:  *             The space is dead and unlocked.
                    573:  */
                    574: 
                    575: void
                    576: ipc_right_clean(
                    577:        ipc_space_t     space,
                    578:        mach_port_t     name,
                    579:        ipc_entry_t     entry)
                    580: {
                    581:        ipc_entry_bits_t bits = entry->ie_bits;
                    582:        mach_port_type_t type = IE_BITS_TYPE(bits);
                    583: 
                    584:        assert(!space->is_active);
                    585: 
                    586:        /*
                    587:         *      We can't clean up IE_BITS_MAREQUEST when the space is dead.
                    588:         *      This is because ipc_marequest_destroy can't turn off
                    589:         *      the bit if the space is dead.  Hence, it might be on
                    590:         *      even though the marequest has been destroyed.  It's OK
                    591:         *      not to cancel the marequest, because ipc_marequest_destroy
                    592:         *      cancels for us if the space is dead.
                    593:         *
                    594:         *      IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
                    595:         *      problem, because we check that the port is active.  If
                    596:         *      we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
                    597:         *      would still work, but dead space refs would accumulate
                    598:         *      in ip_dnrequests.  They would use up slots in
                    599:         *      ip_dnrequests and keep the spaces from being freed.
                    600:         */
                    601: 
                    602:        switch (type) {
                    603:            case MACH_PORT_TYPE_DEAD_NAME:
                    604:                assert(entry->ie_request == 0);
                    605:                assert(entry->ie_object == IO_NULL);
                    606:                assert((bits & IE_BITS_MAREQUEST) == 0);
                    607:                break;
                    608: 
                    609:            case MACH_PORT_TYPE_PORT_SET: {
                    610:                ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
                    611: 
                    612:                assert(entry->ie_request == 0);
                    613:                assert((bits & IE_BITS_MAREQUEST) == 0);
                    614:                assert(pset != IPS_NULL);
                    615: 
                    616:                ips_lock(pset);
                    617:                assert(ips_active(pset));
                    618: 
                    619:                ipc_pset_destroy(pset); /* consumes ref, unlocks */
                    620:                break;
                    621:            }
                    622: 
                    623:            case MACH_PORT_TYPE_SEND:
                    624:            case MACH_PORT_TYPE_RECEIVE:
                    625:            case MACH_PORT_TYPE_SEND_RECEIVE:
                    626:            case MACH_PORT_TYPE_SEND_ONCE: {
                    627:                ipc_port_t port = (ipc_port_t) entry->ie_object;
                    628:                ipc_port_t dnrequest;
                    629:                ipc_port_t nsrequest = IP_NULL;
                    630:                mach_port_mscount_t mscount;
                    631: 
                    632:                assert(port != IP_NULL);
                    633:                ip_lock(port);
                    634: 
                    635:                if (!ip_active(port)) {
                    636:                        ip_release(port);
                    637:                        ip_check_unlock(port);
                    638:                        break;
                    639:                }
                    640: 
                    641:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                    642: 
                    643:                if (type & MACH_PORT_TYPE_SEND) {
                    644:                        assert(port->ip_srights > 0);
                    645:                        if (--port->ip_srights == 0) {
                    646:                                nsrequest = port->ip_nsrequest;
                    647:                                if (nsrequest != IP_NULL) {
                    648:                                        port->ip_nsrequest = IP_NULL;
                    649:                                        mscount = port->ip_mscount;
                    650:                                }
                    651:                        }
                    652:                }
                    653: 
                    654:                if (type & MACH_PORT_TYPE_RECEIVE) {
                    655:                        assert(port->ip_receiver_name == name);
                    656:                        assert(port->ip_receiver == space);
                    657: 
                    658:                        ipc_port_clear_receiver(port);
                    659:                        ipc_port_destroy(port); /* consumes our ref, unlocks */
                    660:                } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
                    661:                        assert(port->ip_sorights > 0);
                    662:                        ip_unlock(port);
                    663: 
                    664:                        ipc_notify_send_once(port); /* consumes our ref */
                    665:                } else {
                    666:                        assert(port->ip_receiver != space);
                    667: 
                    668:                        ip_release(port);
                    669:                        ip_unlock(port); /* port is active */
                    670:                }
                    671: 
                    672:                if (nsrequest != IP_NULL)
                    673:                        ipc_notify_no_senders(nsrequest, mscount);
                    674: 
                    675:                if (dnrequest != IP_NULL)
                    676:                        ipc_notify_port_deleted(dnrequest, name);
                    677:                break;
                    678:            }
                    679: 
                    680:            default:
                    681:                panic("ipc_right_clean: strange type");
                    682:        }
                    683: }
                    684: 
                    685: /*
                    686:  *     Routine:        ipc_right_destroy
                    687:  *     Purpose:
                    688:  *             Destroys an entry in a space.
                    689:  *     Conditions:
                    690:  *             The space is write-locked, and is unlocked upon return.
                    691:  *             The space must be active.
                    692:  *     Returns:
                    693:  *             KERN_SUCCESS            The entry was destroyed.
                    694:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                    695:  *                     Caller should pretend lookup of entry failed.
                    696:  */
                    697: 
                    698: kern_return_t
                    699: ipc_right_destroy(
                    700:        ipc_space_t     space,
                    701:        mach_port_t     name,
                    702:        ipc_entry_t     entry)
                    703: {
                    704:        ipc_entry_bits_t bits = entry->ie_bits;
                    705:        mach_port_type_t type = IE_BITS_TYPE(bits);
                    706: 
                    707:        assert(space->is_active);
                    708: 
                    709:        switch (type) {
                    710:            case MACH_PORT_TYPE_DEAD_NAME:
                    711:                assert(entry->ie_request == 0);
                    712:                assert(entry->ie_object == IO_NULL);
                    713:                assert((bits & IE_BITS_MAREQUEST) == 0);
                    714: 
                    715:                ipc_entry_dealloc(space, name, entry);
                    716:                is_write_unlock(space);
                    717:                break;
                    718: 
                    719:            case MACH_PORT_TYPE_PORT_SET: {
                    720:                ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
                    721: 
                    722:                assert(entry->ie_request == 0);
                    723:                assert(pset != IPS_NULL);
                    724: 
                    725:                entry->ie_object = IO_NULL;
                    726:                ipc_entry_dealloc(space, name, entry);
                    727: 
                    728:                ips_lock(pset);
                    729:                assert(ips_active(pset));
                    730:                is_write_unlock(space);
                    731: 
                    732:                ipc_pset_destroy(pset); /* consumes ref, unlocks */
                    733:                break;
                    734:            }
                    735: 
                    736:            case MACH_PORT_TYPE_SEND:
                    737:            case MACH_PORT_TYPE_RECEIVE:
                    738:            case MACH_PORT_TYPE_SEND_RECEIVE:
                    739:            case MACH_PORT_TYPE_SEND_ONCE: {
                    740:                ipc_port_t port = (ipc_port_t) entry->ie_object;
                    741:                ipc_port_t nsrequest = IP_NULL;
                    742:                mach_port_mscount_t mscount;
                    743:                ipc_port_t dnrequest;
                    744: 
                    745:                assert(port != IP_NULL);
                    746: 
                    747:                if (bits & IE_BITS_MAREQUEST) {
                    748:                        assert(type & MACH_PORT_TYPE_SEND_RECEIVE);
                    749: 
                    750:                        ipc_marequest_cancel(space, name);
                    751:                }
                    752: 
                    753:                if (type == MACH_PORT_TYPE_SEND)
                    754:                        ipc_hash_delete(space, (ipc_object_t) port,
                    755:                                        name, entry);
                    756: 
                    757:                ip_lock(port);
                    758: 
                    759:                if (!ip_active(port)) {
                    760:                        assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
                    761: 
                    762:                        ip_release(port);
                    763:                        ip_check_unlock(port);
                    764: 
                    765:                        entry->ie_request = 0;
                    766:                        entry->ie_object = IO_NULL;
                    767:                        ipc_entry_dealloc(space, name, entry);
                    768:                        is_write_unlock(space);
                    769: 
                    770: #if    MACH_IPC_COMPAT
                    771:                        if (bits & IE_BITS_COMPAT)
                    772:                                return KERN_INVALID_NAME;
                    773: #endif /* MACH_IPC_COMPAT */
                    774:                        break;
                    775:                }
                    776: 
                    777:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                    778: 
                    779:                entry->ie_object = IO_NULL;
                    780:                ipc_entry_dealloc(space, name, entry);
                    781:                is_write_unlock(space);
                    782: 
                    783:                if (type & MACH_PORT_TYPE_SEND) {
                    784:                        assert(port->ip_srights > 0);
                    785:                        if (--port->ip_srights == 0) {
                    786:                                nsrequest = port->ip_nsrequest;
                    787:                                if (nsrequest != IP_NULL) {
                    788:                                        port->ip_nsrequest = IP_NULL;
                    789:                                        mscount = port->ip_mscount;
                    790:                                }
                    791:                        }
                    792:                }
                    793: 
                    794:                if (type & MACH_PORT_TYPE_RECEIVE) {
                    795:                        assert(ip_active(port));
                    796:                        assert(port->ip_receiver == space);
                    797: 
                    798:                        ipc_port_clear_receiver(port);
                    799:                        ipc_port_destroy(port); /* consumes our ref, unlocks */
                    800:                } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
                    801:                        assert(port->ip_sorights > 0);
                    802:                        ip_unlock(port);
                    803: 
                    804:                        ipc_notify_send_once(port); /* consumes our ref */
                    805:                } else {
                    806:                        assert(port->ip_receiver != space);
                    807: 
                    808:                        ip_release(port);
                    809:                        ip_unlock(port);
                    810:                }
                    811: 
                    812:                if (nsrequest != IP_NULL)
                    813:                        ipc_notify_no_senders(nsrequest, mscount);
                    814: 
                    815:                if (dnrequest != IP_NULL)
                    816:                        ipc_notify_port_deleted(dnrequest, name);
                    817:                break;
                    818:            }
                    819: 
                    820:            default:
                    821:                panic("ipc_right_destroy: strange type");
                    822:        }
                    823: 
                    824:        return KERN_SUCCESS;
                    825: }
                    826: 
                    827: /*
                    828:  *     Routine:        ipc_right_dealloc
                    829:  *     Purpose:
                    830:  *             Releases a send/send-once/dead-name user ref.
                    831:  *             Like ipc_right_delta with a delta of -1,
                    832:  *             but looks at the entry to determine the right.
                    833:  *     Conditions:
                    834:  *             The space is write-locked, and is unlocked upon return.
                    835:  *             The space must be active.
                    836:  *     Returns:
                    837:  *             KERN_SUCCESS            A user ref was released.
                    838:  *             KERN_INVALID_RIGHT      Entry has wrong type.
                    839:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                    840:  *                     Caller should pretend lookup of entry failed.
                    841:  */
                    842: 
                    843: kern_return_t
                    844: ipc_right_dealloc(
                    845:        ipc_space_t     space,
                    846:        mach_port_t     name,
                    847:        ipc_entry_t     entry)
                    848: {
                    849:        ipc_entry_bits_t bits = entry->ie_bits;
                    850:        mach_port_type_t type = IE_BITS_TYPE(bits);
                    851: 
                    852:        assert(space->is_active);
                    853: 
                    854:        switch (type) {
                    855:            case MACH_PORT_TYPE_DEAD_NAME: {
                    856:            dead_name:
                    857: 
                    858:                assert(IE_BITS_UREFS(bits) > 0);
                    859:                assert(entry->ie_request == 0);
                    860:                assert(entry->ie_object == IO_NULL);
                    861:                assert((bits & IE_BITS_MAREQUEST) == 0);
                    862: 
                    863:                if (IE_BITS_UREFS(bits) == 1)
                    864:                        ipc_entry_dealloc(space, name, entry);
                    865:                else
                    866:                        entry->ie_bits = bits-1; /* decrement urefs */
                    867: 
                    868:                is_write_unlock(space);
                    869:                break;
                    870:            }
                    871: 
                    872:            case MACH_PORT_TYPE_SEND_ONCE: {
                    873:                ipc_port_t port, dnrequest;
                    874: 
                    875:                assert(IE_BITS_UREFS(bits) == 1);
                    876:                assert((bits & IE_BITS_MAREQUEST) == 0);
                    877: 
                    878:                port = (ipc_port_t) entry->ie_object;
                    879:                assert(port != IP_NULL);
                    880: 
                    881:                if (ipc_right_check(space, port, name, entry)) {
                    882: #if    MACH_IPC_COMPAT
                    883:                        if (bits & IE_BITS_COMPAT)
                    884:                                goto invalid_name;
                    885: #endif /* MACH_IPC_COMPAT */
                    886: 
                    887:                        bits = entry->ie_bits;
                    888:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                    889:                        goto dead_name;
                    890:                }
                    891:                /* port is locked and active */
                    892: 
                    893:                assert(port->ip_sorights > 0);
                    894: 
                    895:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                    896:                ip_unlock(port);
                    897: 
                    898:                entry->ie_object = IO_NULL;
                    899:                ipc_entry_dealloc(space, name, entry);
                    900:                is_write_unlock(space);
                    901: 
                    902:                ipc_notify_send_once(port);
                    903: 
                    904:                if (dnrequest != IP_NULL)
                    905:                        ipc_notify_port_deleted(dnrequest, name);
                    906:                break;
                    907:            }
                    908: 
                    909:            case MACH_PORT_TYPE_SEND: {
                    910:                ipc_port_t port;
                    911:                ipc_port_t dnrequest = IP_NULL;
                    912:                ipc_port_t nsrequest = IP_NULL;
                    913:                mach_port_mscount_t mscount;
                    914: 
                    915:                assert(IE_BITS_UREFS(bits) > 0);
                    916: 
                    917:                port = (ipc_port_t) entry->ie_object;
                    918:                assert(port != IP_NULL);
                    919: 
                    920:                if (ipc_right_check(space, port, name, entry)) {
                    921: #if    MACH_IPC_COMPAT
                    922:                        if (bits & IE_BITS_COMPAT)
                    923:                                goto invalid_name;
                    924: #endif /* MACH_IPC_COMPAT */
                    925: 
                    926:                        bits = entry->ie_bits;
                    927:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                    928:                        goto dead_name;
                    929:                }
                    930:                /* port is locked and active */
                    931: 
                    932:                assert(port->ip_srights > 0);
                    933: 
                    934:                if (IE_BITS_UREFS(bits) == 1) {
                    935:                        if (--port->ip_srights == 0) {
                    936:                                nsrequest = port->ip_nsrequest;
                    937:                                if (nsrequest != IP_NULL) {
                    938:                                        port->ip_nsrequest = IP_NULL;
                    939:                                        mscount = port->ip_mscount;
                    940:                                }
                    941:                        }
                    942: 
                    943:                        dnrequest = ipc_right_dncancel_macro(space, port,
                    944:                                                             name, entry);
                    945: 
                    946:                        ipc_hash_delete(space, (ipc_object_t) port,
                    947:                                        name, entry);
                    948: 
                    949:                        if (bits & IE_BITS_MAREQUEST)
                    950:                                ipc_marequest_cancel(space, name);
                    951: 
                    952:                        ip_release(port);
                    953:                        entry->ie_object = IO_NULL;
                    954:                        ipc_entry_dealloc(space, name, entry);
                    955:                } else
                    956:                        entry->ie_bits = bits-1; /* decrement urefs */
                    957: 
                    958:                ip_unlock(port); /* even if dropped a ref, port is active */
                    959:                is_write_unlock(space);
                    960: 
                    961:                if (nsrequest != IP_NULL)
                    962:                        ipc_notify_no_senders(nsrequest, mscount);
                    963: 
                    964:                if (dnrequest != IP_NULL)
                    965:                        ipc_notify_port_deleted(dnrequest, name);
                    966:                break;
                    967:            }
                    968: 
                    969:            case MACH_PORT_TYPE_SEND_RECEIVE: {
                    970:                ipc_port_t port;
                    971:                ipc_port_t nsrequest = IP_NULL;
                    972:                mach_port_mscount_t mscount;
                    973: 
                    974:                assert(IE_BITS_UREFS(bits) > 0);
                    975: 
                    976:                port = (ipc_port_t) entry->ie_object;
                    977:                assert(port != IP_NULL);
                    978: 
                    979:                ip_lock(port);
                    980:                assert(ip_active(port));
                    981:                assert(port->ip_receiver_name == name);
                    982:                assert(port->ip_receiver == space);
                    983:                assert(port->ip_srights > 0);
                    984: 
                    985:                if (IE_BITS_UREFS(bits) == 1) {
                    986:                        if (--port->ip_srights == 0) {
                    987:                                nsrequest = port->ip_nsrequest;
                    988:                                if (nsrequest != IP_NULL) {
                    989:                                        port->ip_nsrequest = IP_NULL;
                    990:                                        mscount = port->ip_mscount;
                    991:                                }
                    992:                        }
                    993: 
                    994:                        entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
                    995:                                                  MACH_PORT_TYPE_SEND);
                    996:                } else
                    997:                        entry->ie_bits = bits-1; /* decrement urefs */
                    998: 
                    999:                ip_unlock(port);
                   1000:                is_write_unlock(space);
                   1001: 
                   1002:                if (nsrequest != IP_NULL)
                   1003:                        ipc_notify_no_senders(nsrequest, mscount);
                   1004:                break;
                   1005:            }
                   1006: 
                   1007:            default:
                   1008:                is_write_unlock(space);
                   1009:                return KERN_INVALID_RIGHT;
                   1010:        }
                   1011: 
                   1012:        return KERN_SUCCESS;
                   1013: 
                   1014: #if    MACH_IPC_COMPAT
                   1015:     invalid_name:
                   1016:        is_write_unlock(space);
                   1017:        return KERN_INVALID_NAME;
                   1018: #endif /* MACH_IPC_COMPAT */
                   1019: }
                   1020: 
                   1021: /*
                   1022:  *     Routine:        ipc_right_delta
                   1023:  *     Purpose:
                   1024:  *             Modifies the user-reference count for a right.
                   1025:  *             May deallocate the right, if the count goes to zero.
                   1026:  *     Conditions:
                   1027:  *             The space is write-locked, and is unlocked upon return.
                   1028:  *             The space must be active.
                   1029:  *     Returns:
                   1030:  *             KERN_SUCCESS            Count was modified.
                   1031:  *             KERN_INVALID_RIGHT      Entry has wrong type.
                   1032:  *             KERN_INVALID_VALUE      Bad delta for the right.
                   1033:  *             KERN_UREFS_OVERFLOW     OK delta, except would overflow.
                   1034:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                   1035:  *                     Caller should pretend lookup of entry failed.
                   1036:  */
                   1037: 
                   1038: kern_return_t
                   1039: ipc_right_delta(
                   1040:        ipc_space_t             space,
                   1041:        mach_port_t             name,
                   1042:        ipc_entry_t             entry,
                   1043:        mach_port_right_t       right,
                   1044:        mach_port_delta_t       delta)
                   1045: {
                   1046:        ipc_entry_bits_t bits = entry->ie_bits;
                   1047: 
                   1048:        assert(space->is_active);
                   1049:        assert(right < MACH_PORT_RIGHT_NUMBER);
                   1050: 
                   1051:        /* Rights-specific restrictions and operations. */
                   1052: 
                   1053:        switch (right) {
                   1054:            case MACH_PORT_RIGHT_PORT_SET: {
                   1055:                ipc_pset_t pset;
                   1056: 
                   1057:                if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
                   1058:                        goto invalid_right;
                   1059: 
                   1060:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
                   1061:                assert(IE_BITS_UREFS(bits) == 0);
                   1062:                assert((bits & IE_BITS_MAREQUEST) == 0);
                   1063:                assert(entry->ie_request == 0);
                   1064: 
                   1065:                if (delta == 0)
                   1066:                        goto success;
                   1067: 
                   1068:                if (delta != -1)
                   1069:                        goto invalid_value;
                   1070: 
                   1071:                pset = (ipc_pset_t) entry->ie_object;
                   1072:                assert(pset != IPS_NULL);
                   1073: 
                   1074:                entry->ie_object = IO_NULL;
                   1075:                ipc_entry_dealloc(space, name, entry);
                   1076: 
                   1077:                ips_lock(pset);
                   1078:                assert(ips_active(pset));
                   1079:                is_write_unlock(space);
                   1080: 
                   1081:                ipc_pset_destroy(pset); /* consumes ref, unlocks */
                   1082:                break;
                   1083:            }
                   1084: 
                   1085:            case MACH_PORT_RIGHT_RECEIVE: {
                   1086:                ipc_port_t port;
                   1087:                ipc_port_t dnrequest = IP_NULL;
                   1088: 
                   1089:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1090:                        goto invalid_right;
                   1091: 
                   1092:                if (delta == 0)
                   1093:                        goto success;
                   1094: 
                   1095:                if (delta != -1)
                   1096:                        goto invalid_value;
                   1097: 
                   1098:                if (bits & IE_BITS_MAREQUEST) {
                   1099:                        bits &= ~IE_BITS_MAREQUEST;
                   1100: 
                   1101:                        ipc_marequest_cancel(space, name);
                   1102:                }
                   1103: 
                   1104:                port = (ipc_port_t) entry->ie_object;
                   1105:                assert(port != IP_NULL);
                   1106: 
                   1107:                /*
                   1108:                 *      The port lock is needed for ipc_right_dncancel;
                   1109:                 *      otherwise, we wouldn't have to take the lock
                   1110:                 *      until just before dropping the space lock.
                   1111:                 */
                   1112: 
                   1113:                ip_lock(port);
                   1114:                assert(ip_active(port));
                   1115:                assert(port->ip_receiver_name == name);
                   1116:                assert(port->ip_receiver == space);
                   1117: 
                   1118: #if    MACH_IPC_COMPAT
                   1119:                if (bits & IE_BITS_COMPAT) {
                   1120:                        assert(entry->ie_request != 0);
                   1121:                        dnrequest = ipc_right_dncancel(space, port,
                   1122:                                                       name, entry);
                   1123:                        assert(dnrequest == IP_NULL);
                   1124: 
                   1125:                        entry->ie_object = IO_NULL;
                   1126:                        ipc_entry_dealloc(space, name, entry);
                   1127:                } else
                   1128: #endif /* MACH_IPC_COMPAT */
                   1129:                if (bits & MACH_PORT_TYPE_SEND) {
                   1130:                        assert(IE_BITS_TYPE(bits) ==
                   1131:                                        MACH_PORT_TYPE_SEND_RECEIVE);
                   1132:                        assert(IE_BITS_UREFS(bits) > 0);
                   1133:                        assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
                   1134:                        assert(port->ip_srights > 0);
                   1135: 
                   1136:                        /*
                   1137:                         *      The remaining send right turns into a
                   1138:                         *      dead name.  Notice we don't decrement
                   1139:                         *      ip_srights, generate a no-senders notif,
                   1140:                         *      or use ipc_right_dncancel, because the
                   1141:                         *      port is destroyed "first".
                   1142:                         */
                   1143: 
                   1144:                        bits &= ~IE_BITS_TYPE_MASK;
                   1145:                        bits |= MACH_PORT_TYPE_DEAD_NAME;
                   1146: 
                   1147:                        if (entry->ie_request != 0) {
                   1148:                                entry->ie_request = 0;
                   1149:                                bits++; /* increment urefs */
                   1150:                        }
                   1151: 
                   1152:                        entry->ie_bits = bits;
                   1153:                        entry->ie_object = IO_NULL;
                   1154:                } else {
                   1155:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                   1156:                        assert(IE_BITS_UREFS(bits) == 0);
                   1157: 
                   1158:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   1159:                                                             name, entry);
                   1160: 
                   1161:                        entry->ie_object = IO_NULL;
                   1162:                        ipc_entry_dealloc(space, name, entry);
                   1163:                }
                   1164:                is_write_unlock(space);
                   1165: 
                   1166:                ipc_port_clear_receiver(port);
                   1167:                ipc_port_destroy(port); /* consumes ref, unlocks */
                   1168: 
                   1169:                if (dnrequest != IP_NULL)
                   1170:                        ipc_notify_port_deleted(dnrequest, name);
                   1171:                break;
                   1172:            }
                   1173: 
                   1174:            case MACH_PORT_RIGHT_SEND_ONCE: {
                   1175:                ipc_port_t port, dnrequest;
                   1176: 
                   1177:                if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
                   1178:                        goto invalid_right;
                   1179: 
                   1180:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1181:                assert(IE_BITS_UREFS(bits) == 1);
                   1182:                assert((bits & IE_BITS_MAREQUEST) == 0);
                   1183: 
                   1184:                port = (ipc_port_t) entry->ie_object;
                   1185:                assert(port != IP_NULL);
                   1186: 
                   1187:                if (ipc_right_check(space, port, name, entry)) {
                   1188: #if    MACH_IPC_COMPAT
                   1189:                        if (bits & IE_BITS_COMPAT)
                   1190:                                goto invalid_name;
                   1191: #endif /* MACH_IPC_COMPAT */
                   1192: 
                   1193:                        assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
                   1194:                        goto invalid_right;
                   1195:                }
                   1196:                /* port is locked and active */
                   1197: 
                   1198:                assert(port->ip_sorights > 0);
                   1199: 
                   1200:                if ((delta > 0) || (delta < -1)) {
                   1201:                        ip_unlock(port);
                   1202:                        goto invalid_value;
                   1203:                }
                   1204: 
                   1205:                if (delta == 0) {
                   1206:                        ip_unlock(port);
                   1207:                        goto success;
                   1208:                }
                   1209: 
                   1210:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                   1211:                ip_unlock(port);
                   1212: 
                   1213:                entry->ie_object = IO_NULL;
                   1214:                ipc_entry_dealloc(space, name, entry);
                   1215:                is_write_unlock(space);
                   1216: 
                   1217:                ipc_notify_send_once(port);
                   1218: 
                   1219:                if (dnrequest != IP_NULL)
                   1220:                        ipc_notify_port_deleted(dnrequest, name);
                   1221:                break;
                   1222:            }
                   1223: 
                   1224:            case MACH_PORT_RIGHT_DEAD_NAME: {
                   1225:                mach_port_urefs_t urefs;
                   1226: 
                   1227:                if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
                   1228:                        ipc_port_t port;
                   1229: 
                   1230:                        port = (ipc_port_t) entry->ie_object;
                   1231:                        assert(port != IP_NULL);
                   1232: 
                   1233:                        if (!ipc_right_check(space, port, name, entry)) {
                   1234:                                /* port is locked and active */
                   1235:                                ip_unlock(port);
                   1236:                                goto invalid_right;
                   1237:                        }
                   1238: 
                   1239: #if    MACH_IPC_COMPAT
                   1240:                        if (bits & IE_BITS_COMPAT)
                   1241:                                goto invalid_name;
                   1242: #endif /* MACH_IPC_COMPAT */
                   1243: 
                   1244:                        bits = entry->ie_bits;
                   1245:                } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
                   1246:                        goto invalid_right;
                   1247: 
                   1248:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1249:                assert(IE_BITS_UREFS(bits) > 0);
                   1250:                assert((bits & IE_BITS_MAREQUEST) == 0);
                   1251:                assert(entry->ie_object == IO_NULL);
                   1252:                assert(entry->ie_request == 0);
                   1253: 
                   1254:                urefs = IE_BITS_UREFS(bits);
                   1255:                if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
                   1256:                        goto invalid_value;
                   1257:                if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
                   1258:                        goto urefs_overflow;
                   1259: 
                   1260:                if ((urefs + delta) == 0)
                   1261:                        ipc_entry_dealloc(space, name, entry);
                   1262:                else
                   1263:                        entry->ie_bits = bits + delta;
                   1264: 
                   1265:                is_write_unlock(space);
                   1266:                break;
                   1267:            }
                   1268: 
                   1269:            case MACH_PORT_RIGHT_SEND: {
                   1270:                mach_port_urefs_t urefs;
                   1271:                ipc_port_t port;
                   1272:                ipc_port_t dnrequest = IP_NULL;
                   1273:                ipc_port_t nsrequest = IP_NULL;
                   1274:                mach_port_mscount_t mscount;
                   1275: 
                   1276:                if ((bits & MACH_PORT_TYPE_SEND) == 0)
                   1277:                        goto invalid_right;
                   1278: 
                   1279:                /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
                   1280: 
                   1281:                port = (ipc_port_t) entry->ie_object;
                   1282:                assert(port != IP_NULL);
                   1283: 
                   1284:                if (ipc_right_check(space, port, name, entry)) {
                   1285: #if    MACH_IPC_COMPAT
                   1286:                        if (bits & IE_BITS_COMPAT)
                   1287:                                goto invalid_name;
                   1288: #endif /* MACH_IPC_COMPAT */
                   1289: 
                   1290:                        assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
                   1291:                        goto invalid_right;
                   1292:                }
                   1293:                /* port is locked and active */
                   1294: 
                   1295:                assert(port->ip_srights > 0);
                   1296: 
                   1297:                urefs = IE_BITS_UREFS(bits);
                   1298:                if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
                   1299:                        ip_unlock(port);
                   1300:                        goto invalid_value;
                   1301:                }
                   1302:                if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) {
                   1303:                        ip_unlock(port);
                   1304:                        goto urefs_overflow;
                   1305:                }
                   1306: 
                   1307:                if ((urefs + delta) == 0) {
                   1308:                        if (--port->ip_srights == 0) {
                   1309:                                nsrequest = port->ip_nsrequest;
                   1310:                                if (nsrequest != IP_NULL) {
                   1311:                                        port->ip_nsrequest = IP_NULL;
                   1312:                                        mscount = port->ip_mscount;
                   1313:                                }
                   1314:                        }
                   1315: 
                   1316:                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1317:                                assert(port->ip_receiver_name == name);
                   1318:                                assert(port->ip_receiver == space);
                   1319:                                assert(IE_BITS_TYPE(bits) ==
                   1320:                                                MACH_PORT_TYPE_SEND_RECEIVE);
                   1321: 
                   1322:                                entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
                   1323:                                                          MACH_PORT_TYPE_SEND);
                   1324:                        } else {
                   1325:                                assert(IE_BITS_TYPE(bits) ==
                   1326:                                                MACH_PORT_TYPE_SEND);
                   1327: 
                   1328:                                dnrequest = ipc_right_dncancel_macro(
                   1329:                                                space, port, name, entry);
                   1330: 
                   1331:                                ipc_hash_delete(space, (ipc_object_t) port,
                   1332:                                                name, entry);
                   1333: 
                   1334:                                if (bits & IE_BITS_MAREQUEST)
                   1335:                                        ipc_marequest_cancel(space, name);
                   1336: 
                   1337:                                ip_release(port);
                   1338:                                entry->ie_object = IO_NULL;
                   1339:                                ipc_entry_dealloc(space, name, entry);
                   1340:                        }
                   1341:                } else
                   1342:                        entry->ie_bits = bits + delta;
                   1343: 
                   1344:                ip_unlock(port); /* even if dropped a ref, port is active */
                   1345:                is_write_unlock(space);
                   1346: 
                   1347:                if (nsrequest != IP_NULL)
                   1348:                        ipc_notify_no_senders(nsrequest, mscount);
                   1349: 
                   1350:                if (dnrequest != IP_NULL)
                   1351:                        ipc_notify_port_deleted(dnrequest, name);
                   1352:                break;
                   1353:            }
                   1354: 
                   1355:            default:
                   1356:                panic("ipc_right_delta: strange right");
                   1357:        }
                   1358: 
                   1359:        return KERN_SUCCESS;
                   1360: 
                   1361:     success:
                   1362:        is_write_unlock(space);
                   1363:        return KERN_SUCCESS;
                   1364: 
                   1365:     invalid_right:
                   1366:        is_write_unlock(space);
                   1367:        return KERN_INVALID_RIGHT;
                   1368: 
                   1369:     invalid_value:
                   1370:        is_write_unlock(space);
                   1371:        return KERN_INVALID_VALUE;
                   1372: 
                   1373:     urefs_overflow:
                   1374:        is_write_unlock(space);
                   1375:        return KERN_UREFS_OVERFLOW;
                   1376: 
                   1377: #if    MACH_IPC_COMPAT
                   1378:     invalid_name:
                   1379:        is_write_unlock(space);
                   1380:        return KERN_INVALID_NAME;
                   1381: #endif /* MACH_IPC_COMPAT */
                   1382: }
                   1383: 
                   1384: /*
                   1385:  *     Routine:        ipc_right_info
                   1386:  *     Purpose:
                   1387:  *             Retrieves information about the right.
                   1388:  *     Conditions:
                   1389:  *             The space is write-locked, and is unlocked upon return
                   1390:  *             if the call is unsuccessful.  The space must be active.
                   1391:  *     Returns:
                   1392:  *             KERN_SUCCESS            Retrieved info; space still locked.
                   1393:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                   1394:  *                     Caller should pretend lookup of entry failed.
                   1395:  */
                   1396: 
                   1397: kern_return_t
                   1398: ipc_right_info(
                   1399:        ipc_space_t             space,
                   1400:        mach_port_t             name,
                   1401:        ipc_entry_t             entry,
                   1402:        mach_port_type_t        *typep,
                   1403:        mach_port_urefs_t       *urefsp)
                   1404: {
                   1405:        ipc_entry_bits_t bits = entry->ie_bits;
                   1406:        ipc_port_request_index_t request;
                   1407:        mach_port_type_t type;
                   1408: 
                   1409:        if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
                   1410:                ipc_port_t port = (ipc_port_t) entry->ie_object;
                   1411: 
                   1412:                if (ipc_right_check(space, port, name, entry)) {
                   1413: #if    MACH_IPC_COMPAT
                   1414:                        if (bits & IE_BITS_COMPAT) {
                   1415:                                is_write_unlock(space);
                   1416:                                return KERN_INVALID_NAME;
                   1417:                        }
                   1418: #endif /* MACH_IPC_COMPAT */
                   1419: 
                   1420:                        bits = entry->ie_bits;
                   1421:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1422:                } else
                   1423:                        ip_unlock(port);
                   1424:        }
                   1425: 
                   1426:        type = IE_BITS_TYPE(bits);
                   1427:        request = entry->ie_request;
                   1428: 
                   1429: #if    MACH_IPC_COMPAT
                   1430:        if (bits & IE_BITS_COMPAT)
                   1431:                type |= MACH_PORT_TYPE_COMPAT;
                   1432:        else
                   1433: #endif /* MACH_IPC_COMPAT */
                   1434:        if (request != 0)
                   1435:                type |= MACH_PORT_TYPE_DNREQUEST;
                   1436:        if (bits & IE_BITS_MAREQUEST)
                   1437:                type |= MACH_PORT_TYPE_MAREQUEST;
                   1438: 
                   1439:        *typep = type;
                   1440:        *urefsp = IE_BITS_UREFS(bits);
                   1441:        return KERN_SUCCESS;
                   1442: }
                   1443: 
                   1444: /*
                   1445:  *     Routine:        ipc_right_copyin_check
                   1446:  *     Purpose:
                   1447:  *             Check if a subsequent ipc_right_copyin would succeed.
                   1448:  *     Conditions:
                   1449:  *             The space is locked (read or write) and active.
                   1450:  */
                   1451: 
                   1452: boolean_t
                   1453: ipc_right_copyin_check(
                   1454:        ipc_space_t             space,
                   1455:        mach_port_t             name,
                   1456:        ipc_entry_t             entry,
                   1457:        mach_msg_type_name_t    msgt_name)
                   1458: {
                   1459:        ipc_entry_bits_t bits = entry->ie_bits;
                   1460: 
                   1461:        assert(space->is_active);
                   1462: 
                   1463:        switch (msgt_name) {
                   1464:            case MACH_MSG_TYPE_MAKE_SEND:
                   1465:            case MACH_MSG_TYPE_MAKE_SEND_ONCE:
                   1466:            case MACH_MSG_TYPE_MOVE_RECEIVE:
                   1467:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1468:                        return FALSE;
                   1469: 
                   1470:                break;
                   1471: 
                   1472:            case MACH_MSG_TYPE_COPY_SEND:
                   1473:            case MACH_MSG_TYPE_MOVE_SEND:
                   1474:            case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
                   1475:                ipc_port_t port;
                   1476:                boolean_t active;
                   1477: 
                   1478:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1479:                        break;
                   1480: 
                   1481:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1482:                        return FALSE;
                   1483: 
                   1484:                port = (ipc_port_t) entry->ie_object;
                   1485:                assert(port != IP_NULL);
                   1486: 
                   1487:                ip_lock(port);
                   1488:                active = ip_active(port);
                   1489:                ip_unlock(port);
                   1490: 
                   1491:                if (!active) {
                   1492: #if    MACH_IPC_COMPAT
                   1493:                        if (bits & IE_BITS_COMPAT)
                   1494:                                return FALSE;
                   1495: #endif /* MACH_IPC_COMPAT */
                   1496: 
                   1497:                        break;
                   1498:                }
                   1499: 
                   1500:                if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
                   1501:                        if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
                   1502:                                return FALSE;
                   1503:                } else {
                   1504:                        if ((bits & MACH_PORT_TYPE_SEND) == 0)
                   1505:                                return FALSE;
                   1506:                }
                   1507: 
                   1508:                break;
                   1509:            }
                   1510: 
                   1511:            default:
                   1512:                panic("ipc_right_copyin_check: strange rights");
                   1513:        }
                   1514: 
                   1515:        return TRUE;
                   1516: }
                   1517: 
                   1518: /*
                   1519:  *     Routine:        ipc_right_copyin
                   1520:  *     Purpose:
                   1521:  *             Copyin a capability from a space.
                   1522:  *             If successful, the caller gets a ref
                   1523:  *             for the resulting object, unless it is IO_DEAD,
                   1524:  *             and possibly a send-once right which should
                   1525:  *             be used in a port-deleted notification.
                   1526:  *
                   1527:  *             If deadok is not TRUE, the copyin operation
                   1528:  *             will fail instead of producing IO_DEAD.
                   1529:  *
                   1530:  *             The entry is never deallocated (except
                   1531:  *             when KERN_INVALID_NAME), so the caller
                   1532:  *             should deallocate the entry if its type
                   1533:  *             is MACH_PORT_TYPE_NONE.
                   1534:  *     Conditions:
                   1535:  *             The space is write-locked and active.
                   1536:  *     Returns:
                   1537:  *             KERN_SUCCESS            Acquired an object, possibly IO_DEAD.
                   1538:  *             KERN_INVALID_RIGHT      Name doesn't denote correct right.
                   1539:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                   1540:  *                     Caller should pretend lookup of entry failed.
                   1541:  */
                   1542: 
                   1543: kern_return_t
                   1544: ipc_right_copyin(
                   1545:        ipc_space_t             space,
                   1546:        mach_port_t             name,
                   1547:        ipc_entry_t             entry,
                   1548:        mach_msg_type_name_t    msgt_name,
                   1549:        boolean_t               deadok,
                   1550:        ipc_object_t            *objectp,
                   1551:        ipc_port_t              *sorightp)
                   1552: {
                   1553:        ipc_entry_bits_t bits = entry->ie_bits;
                   1554: 
                   1555:        assert(space->is_active);
                   1556: 
                   1557:        switch (msgt_name) {
                   1558:            case MACH_MSG_TYPE_MAKE_SEND: {
                   1559:                ipc_port_t port;
                   1560: 
                   1561:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1562:                        goto invalid_right;
                   1563: 
                   1564:                port = (ipc_port_t) entry->ie_object;
                   1565:                assert(port != IP_NULL);
                   1566: 
                   1567:                ip_lock(port);
                   1568:                assert(ip_active(port));
                   1569:                assert(port->ip_receiver_name == name);
                   1570:                assert(port->ip_receiver == space);
                   1571: 
                   1572:                port->ip_mscount++;
                   1573:                port->ip_srights++;
                   1574:                ip_reference(port);
                   1575:                ip_unlock(port);
                   1576: 
                   1577:                *objectp = (ipc_object_t) port;
                   1578:                *sorightp = IP_NULL;
                   1579:                break;
                   1580:            }
                   1581: 
                   1582:            case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
                   1583:                ipc_port_t port;
                   1584: 
                   1585:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1586:                        goto invalid_right;
                   1587: 
                   1588:                port = (ipc_port_t) entry->ie_object;
                   1589:                assert(port != IP_NULL);
                   1590: 
                   1591:                ip_lock(port);
                   1592:                assert(ip_active(port));
                   1593:                assert(port->ip_receiver_name == name);
                   1594:                assert(port->ip_receiver == space);
                   1595: 
                   1596:                port->ip_sorights++;
                   1597:                ip_reference(port);
                   1598:                ip_unlock(port);
                   1599: 
                   1600:                *objectp = (ipc_object_t) port;
                   1601:                *sorightp = IP_NULL;
                   1602:                break;
                   1603:            }
                   1604: 
                   1605:            case MACH_MSG_TYPE_MOVE_RECEIVE: {
                   1606:                ipc_port_t port;
                   1607:                ipc_port_t dnrequest = IP_NULL;
                   1608: 
                   1609:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1610:                        goto invalid_right;
                   1611: 
                   1612:                port = (ipc_port_t) entry->ie_object;
                   1613:                assert(port != IP_NULL);
                   1614: 
                   1615:                ip_lock(port);
                   1616:                assert(ip_active(port));
                   1617:                assert(port->ip_receiver_name == name);
                   1618:                assert(port->ip_receiver == space);
                   1619: 
                   1620:                if (bits & MACH_PORT_TYPE_SEND) {
                   1621:                        assert(IE_BITS_TYPE(bits) ==
                   1622:                                        MACH_PORT_TYPE_SEND_RECEIVE);
                   1623:                        assert(IE_BITS_UREFS(bits) > 0);
                   1624:                        assert(port->ip_srights > 0);
                   1625: 
                   1626:                        ipc_hash_insert(space, (ipc_object_t) port,
                   1627:                                        name, entry);
                   1628: 
                   1629:                        ip_reference(port);
                   1630:                } else {
                   1631:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                   1632:                        assert(IE_BITS_UREFS(bits) == 0);
                   1633: 
                   1634:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   1635:                                                             name, entry);
                   1636: 
                   1637:                        if (bits & IE_BITS_MAREQUEST)
                   1638:                                ipc_marequest_cancel(space, name);
                   1639: 
                   1640:                        entry->ie_object = IO_NULL;
                   1641:                }
                   1642:                entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
                   1643: 
                   1644:                ipc_port_clear_receiver(port);
                   1645: 
                   1646:                port->ip_receiver_name = MACH_PORT_NULL;
                   1647:                port->ip_destination = IP_NULL;
                   1648:                ip_unlock(port);
                   1649: 
                   1650:                *objectp = (ipc_object_t) port;
                   1651:                *sorightp = dnrequest;
                   1652:                break;
                   1653:            }
                   1654: 
                   1655:            case MACH_MSG_TYPE_COPY_SEND: {
                   1656:                ipc_port_t port;
                   1657: 
                   1658:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1659:                        goto copy_dead;
                   1660: 
                   1661:                /* allow for dead send-once rights */
                   1662: 
                   1663:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1664:                        goto invalid_right;
                   1665: 
                   1666:                assert(IE_BITS_UREFS(bits) > 0);
                   1667: 
                   1668:                port = (ipc_port_t) entry->ie_object;
                   1669:                assert(port != IP_NULL);
                   1670: 
                   1671:                if (ipc_right_check(space, port, name, entry)) {
                   1672: #if    MACH_IPC_COMPAT
                   1673:                        if (bits & IE_BITS_COMPAT)
                   1674:                                goto invalid_name;
                   1675: #endif /* MACH_IPC_COMPAT */
                   1676: 
                   1677:                        bits = entry->ie_bits;
                   1678:                        goto copy_dead;
                   1679:                }
                   1680:                /* port is locked and active */
                   1681: 
                   1682:                if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                   1683:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1684:                        assert(port->ip_sorights > 0);
                   1685: 
                   1686:                        ip_unlock(port);
                   1687:                        goto invalid_right;
                   1688:                }
                   1689: 
                   1690:                assert(port->ip_srights > 0);
                   1691: 
                   1692:                port->ip_srights++;
                   1693:                ip_reference(port);
                   1694:                ip_unlock(port);
                   1695: 
                   1696:                *objectp = (ipc_object_t) port;
                   1697:                *sorightp = IP_NULL;
                   1698:                break;
                   1699:            }
                   1700: 
                   1701:            case MACH_MSG_TYPE_MOVE_SEND: {
                   1702:                ipc_port_t port;
                   1703:                ipc_port_t dnrequest = IP_NULL;
                   1704: 
                   1705:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1706:                        goto move_dead;
                   1707: 
                   1708:                /* allow for dead send-once rights */
                   1709: 
                   1710:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1711:                        goto invalid_right;
                   1712: 
                   1713:                assert(IE_BITS_UREFS(bits) > 0);
                   1714: 
                   1715:                port = (ipc_port_t) entry->ie_object;
                   1716:                assert(port != IP_NULL);
                   1717: 
                   1718:                if (ipc_right_check(space, port, name, entry)) {
                   1719: #if    MACH_IPC_COMPAT
                   1720:                        if (bits & IE_BITS_COMPAT)
                   1721:                                goto invalid_name;
                   1722: #endif /* MACH_IPC_COMPAT */
                   1723: 
                   1724:                        bits = entry->ie_bits;
                   1725:                        goto move_dead;
                   1726:                }
                   1727:                /* port is locked and active */
                   1728: 
                   1729:                if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                   1730:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1731:                        assert(port->ip_sorights > 0);
                   1732: 
                   1733:                        ip_unlock(port);
                   1734:                        goto invalid_right;
                   1735:                }
                   1736: 
                   1737:                assert(port->ip_srights > 0);
                   1738: 
                   1739:                if (IE_BITS_UREFS(bits) == 1) {
                   1740:                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1741:                                assert(port->ip_receiver_name == name);
                   1742:                                assert(port->ip_receiver == space);
                   1743:                                assert(IE_BITS_TYPE(bits) ==
                   1744:                                                MACH_PORT_TYPE_SEND_RECEIVE);
                   1745: 
                   1746:                                ip_reference(port);
                   1747:                        } else {
                   1748:                                assert(IE_BITS_TYPE(bits) ==
                   1749:                                                MACH_PORT_TYPE_SEND);
                   1750: 
                   1751:                                dnrequest = ipc_right_dncancel_macro(
                   1752:                                                space, port, name, entry);
                   1753: 
                   1754:                                ipc_hash_delete(space, (ipc_object_t) port,
                   1755:                                                name, entry);
                   1756: 
                   1757:                                if (bits & IE_BITS_MAREQUEST)
                   1758:                                        ipc_marequest_cancel(space, name);
                   1759: 
                   1760:                                entry->ie_object = IO_NULL;
                   1761:                        }
                   1762:                        entry->ie_bits = bits &~
                   1763:                                (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
                   1764:                } else {
                   1765:                        port->ip_srights++;
                   1766:                        ip_reference(port);
                   1767:                        entry->ie_bits = bits-1; /* decrement urefs */
                   1768:                }
                   1769: 
                   1770:                ip_unlock(port);
                   1771: 
                   1772:                *objectp = (ipc_object_t) port;
                   1773:                *sorightp = dnrequest;
                   1774:                break;
                   1775:            }
                   1776: 
                   1777:            case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
                   1778:                ipc_port_t port;
                   1779:                ipc_port_t dnrequest;
                   1780: 
                   1781:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1782:                        goto move_dead;
                   1783: 
                   1784:                /* allow for dead send rights */
                   1785: 
                   1786:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1787:                        goto invalid_right;
                   1788: 
                   1789:                assert(IE_BITS_UREFS(bits) > 0);
                   1790: 
                   1791:                port = (ipc_port_t) entry->ie_object;
                   1792:                assert(port != IP_NULL);
                   1793: 
                   1794:                if (ipc_right_check(space, port, name, entry)) {
                   1795: #if    MACH_IPC_COMPAT
                   1796:                        if (bits & IE_BITS_COMPAT)
                   1797:                                goto invalid_name;
                   1798: #endif /* MACH_IPC_COMPAT */
                   1799: 
                   1800:                        bits = entry->ie_bits;
                   1801:                        goto move_dead;
                   1802:                }
                   1803:                /* port is locked and active */
                   1804: 
                   1805:                if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
                   1806:                        assert(bits & MACH_PORT_TYPE_SEND);
                   1807:                        assert(port->ip_srights > 0);
                   1808: 
                   1809:                        ip_unlock(port);
                   1810:                        goto invalid_right;
                   1811:                }
                   1812: 
                   1813:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1814:                assert(IE_BITS_UREFS(bits) == 1);
                   1815:                assert((bits & IE_BITS_MAREQUEST) == 0);
                   1816:                assert(port->ip_sorights > 0);
                   1817: 
                   1818:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                   1819:                ip_unlock(port);
                   1820: 
                   1821:                entry->ie_object = IO_NULL;
                   1822:                entry->ie_bits = bits &~ MACH_PORT_TYPE_SEND_ONCE;
                   1823: 
                   1824:                *objectp = (ipc_object_t) port;
                   1825:                *sorightp = dnrequest;
                   1826:                break;
                   1827:            }
                   1828: 
                   1829:            default:
                   1830:                panic("ipc_right_copyin: strange rights");
                   1831:        }
                   1832: 
                   1833:        return KERN_SUCCESS;
                   1834: 
                   1835:     copy_dead:
                   1836:        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1837:        assert(IE_BITS_UREFS(bits) > 0);
                   1838:        assert((bits & IE_BITS_MAREQUEST) == 0);
                   1839:        assert(entry->ie_request == 0);
                   1840:        assert(entry->ie_object == 0);
                   1841: 
                   1842:        if (!deadok)
                   1843:                goto invalid_right;
                   1844: 
                   1845:        *objectp = IO_DEAD;
                   1846:        *sorightp = IP_NULL;
                   1847:        return KERN_SUCCESS;
                   1848: 
                   1849:     move_dead:
                   1850:        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1851:        assert(IE_BITS_UREFS(bits) > 0);
                   1852:        assert((bits & IE_BITS_MAREQUEST) == 0);
                   1853:        assert(entry->ie_request == 0);
                   1854:        assert(entry->ie_object == 0);
                   1855: 
                   1856:        if (!deadok)
                   1857:                goto invalid_right;
                   1858: 
                   1859:        if (IE_BITS_UREFS(bits) == 1)
                   1860:                entry->ie_bits = bits &~ MACH_PORT_TYPE_DEAD_NAME;
                   1861:        else
                   1862:                entry->ie_bits = bits-1; /* decrement urefs */
                   1863: 
                   1864:        *objectp = IO_DEAD;
                   1865:        *sorightp = IP_NULL;
                   1866:        return KERN_SUCCESS;
                   1867: 
                   1868:     invalid_right:
                   1869:        return KERN_INVALID_RIGHT;
                   1870: 
                   1871: #if    MACH_IPC_COMPAT
                   1872:     invalid_name:
                   1873:        return KERN_INVALID_NAME;
                   1874: #endif /* MACH_IPC_COMPAT */
                   1875: }
                   1876: 
                   1877: /*
                   1878:  *     Routine:        ipc_right_copyin_undo
                   1879:  *     Purpose:
                   1880:  *             Undoes the effects of an ipc_right_copyin
                   1881:  *             of a send/send-once right that is dead.
                   1882:  *             (Object is either IO_DEAD or a dead port.)
                   1883:  *     Conditions:
                   1884:  *             The space is write-locked and active.
                   1885:  */
                   1886: 
                   1887: void
                   1888: ipc_right_copyin_undo(
                   1889:        ipc_space_t             space,
                   1890:        mach_port_t             name,
                   1891:        ipc_entry_t             entry,
                   1892:        mach_msg_type_name_t    msgt_name,
                   1893:        ipc_object_t            object,
                   1894:        ipc_port_t              soright)
                   1895: {
                   1896:        ipc_entry_bits_t bits = entry->ie_bits;
                   1897: 
                   1898:        assert(space->is_active);
                   1899: 
                   1900:        assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1901:               (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
                   1902:               (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
                   1903: 
                   1904:        if (soright != IP_NULL) {
                   1905:                assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1906:                       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
                   1907:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   1908:                assert(entry->ie_object == IO_NULL);
                   1909:                assert(object != IO_DEAD);
                   1910: 
                   1911:                entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
                   1912:                                  MACH_PORT_TYPE_DEAD_NAME | 2);
                   1913:        } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
                   1914:                assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1915:                       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
                   1916:                assert(entry->ie_object == IO_NULL);
                   1917: 
                   1918:                entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
                   1919:                                  MACH_PORT_TYPE_DEAD_NAME | 1);
                   1920:        } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
                   1921:                assert(entry->ie_object == IO_NULL);
                   1922:                assert(object == IO_DEAD);
                   1923:                assert(IE_BITS_UREFS(bits) > 0);
                   1924: 
                   1925:                if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
                   1926:                        assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
                   1927: 
                   1928:                        entry->ie_bits = bits+1; /* increment urefs */
                   1929:                }
                   1930:        } else {
                   1931:                assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1932:                       (msgt_name == MACH_MSG_TYPE_COPY_SEND));
                   1933:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                   1934:                assert(object != IO_DEAD);
                   1935:                assert(entry->ie_object == object);
                   1936:                assert(IE_BITS_UREFS(bits) > 0);
                   1937: 
                   1938:                if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
                   1939:                        assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
                   1940: 
                   1941:                        entry->ie_bits = bits+1; /* increment urefs */
                   1942:                }
                   1943: 
                   1944:                /*
                   1945:                 *      May as well convert the entry to a dead name.
                   1946:                 *      (Or if it is a compat entry, destroy it.)
                   1947:                 */
                   1948: 
                   1949:                (void) ipc_right_check(space, (ipc_port_t) object,
                   1950:                                       name, entry);
                   1951:                /* object is dead so it is not locked */
                   1952:        }
                   1953: 
                   1954:        /* release the reference acquired by copyin */
                   1955: 
                   1956:        if (object != IO_DEAD)
                   1957:                ipc_object_release(object);
                   1958: }
                   1959: 
                   1960: /*
                   1961:  *     Routine:        ipc_right_copyin_two
                   1962:  *     Purpose:
                   1963:  *             Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
                   1964:  *             and deadok == FALSE, except that this moves two
                   1965:  *             send rights at once.
                   1966:  *     Conditions:
                   1967:  *             The space is write-locked and active.
                   1968:  *             The object is returned with two refs/send rights.
                   1969:  *     Returns:
                   1970:  *             KERN_SUCCESS            Acquired an object.
                   1971:  *             KERN_INVALID_RIGHT      Name doesn't denote correct right.
                   1972:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                   1973:  *                     Caller should pretend lookup of entry failed.
                   1974:  */
                   1975: 
                   1976: kern_return_t
                   1977: ipc_right_copyin_two(
                   1978:        ipc_space_t     space,
                   1979:        mach_port_t     name,
                   1980:        ipc_entry_t     entry,
                   1981:        ipc_object_t    *objectp,
                   1982:        ipc_port_t      *sorightp)
                   1983: {
                   1984:        ipc_entry_bits_t bits = entry->ie_bits;
                   1985:        mach_port_urefs_t urefs;
                   1986:        ipc_port_t port;
                   1987:        ipc_port_t dnrequest = IP_NULL;
                   1988: 
                   1989:        assert(space->is_active);
                   1990: 
                   1991:        if ((bits & MACH_PORT_TYPE_SEND) == 0)
                   1992:                goto invalid_right;
                   1993: 
                   1994:        urefs = IE_BITS_UREFS(bits);
                   1995:        if (urefs < 2)
                   1996:                goto invalid_right;
                   1997: 
                   1998:        port = (ipc_port_t) entry->ie_object;
                   1999:        assert(port != IP_NULL);
                   2000: 
                   2001:        if (ipc_right_check(space, port, name, entry)) {
                   2002: #if    MACH_IPC_COMPAT
                   2003:                if (bits & IE_BITS_COMPAT)
                   2004:                        goto invalid_name;
                   2005: #endif /* MACH_IPC_COMPAT */
                   2006: 
                   2007:                goto invalid_right;
                   2008:        }
                   2009:        /* port is locked and active */
                   2010: 
                   2011:        assert(port->ip_srights > 0);
                   2012: 
                   2013:        if (urefs == 2) {
                   2014:                if (bits & MACH_PORT_TYPE_RECEIVE) {
                   2015:                        assert(port->ip_receiver_name == name);
                   2016:                        assert(port->ip_receiver == space);
                   2017:                        assert(IE_BITS_TYPE(bits) ==
                   2018:                                        MACH_PORT_TYPE_SEND_RECEIVE);
                   2019: 
                   2020:                        port->ip_srights++;
                   2021:                        ip_reference(port);
                   2022:                        ip_reference(port);
                   2023:                } else {
                   2024:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                   2025: 
                   2026:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   2027:                                                             name, entry);
                   2028: 
                   2029:                        ipc_hash_delete(space, (ipc_object_t) port,
                   2030:                                        name, entry);
                   2031: 
                   2032:                        if (bits & IE_BITS_MAREQUEST)
                   2033:                                ipc_marequest_cancel(space, name);
                   2034: 
                   2035:                        port->ip_srights++;
                   2036:                        ip_reference(port);
                   2037:                        entry->ie_object = IO_NULL;
                   2038:                }
                   2039:                entry->ie_bits = bits &~
                   2040:                        (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
                   2041:        } else {
                   2042:                port->ip_srights += 2;
                   2043:                ip_reference(port);
                   2044:                ip_reference(port);
                   2045:                entry->ie_bits = bits-2; /* decrement urefs */
                   2046:        }
                   2047:        ip_unlock(port);
                   2048: 
                   2049:        *objectp = (ipc_object_t) port;
                   2050:        *sorightp = dnrequest;
                   2051:        return KERN_SUCCESS;
                   2052: 
                   2053:     invalid_right:
                   2054:        return KERN_INVALID_RIGHT;
                   2055: 
                   2056: #if    MACH_IPC_COMPAT
                   2057:     invalid_name:
                   2058:        return KERN_INVALID_NAME;
                   2059: #endif /* MACH_IPC_COMPAT */
                   2060: }
                   2061: 
                   2062: /*
                   2063:  *     Routine:        ipc_right_copyout
                   2064:  *     Purpose:
                   2065:  *             Copyout a capability to a space.
                   2066:  *             If successful, consumes a ref for the object.
                   2067:  *
                   2068:  *             Always succeeds when given a newly-allocated entry,
                   2069:  *             because user-reference overflow isn't a possibility.
                   2070:  *
                   2071:  *             If copying out the object would cause the user-reference
                   2072:  *             count in the entry to overflow, and overflow is TRUE,
                   2073:  *             then instead the user-reference count is left pegged
                   2074:  *             to its maximum value and the copyout succeeds anyway.
                   2075:  *     Conditions:
                   2076:  *             The space is write-locked and active.
                   2077:  *             The object is locked and active.
                   2078:  *             The object is unlocked; the space isn't.
                   2079:  *     Returns:
                   2080:  *             KERN_SUCCESS            Copied out capability.
                   2081:  *             KERN_UREFS_OVERFLOW     User-refs would overflow;
                   2082:  *                     guaranteed not to happen with a fresh entry
                   2083:  *                     or if overflow=TRUE was specified.
                   2084:  */
                   2085: 
                   2086: kern_return_t
                   2087: ipc_right_copyout(
                   2088:        ipc_space_t             space,
                   2089:        mach_port_t             name,
                   2090:        ipc_entry_t             entry,
                   2091:        mach_msg_type_name_t    msgt_name,
                   2092:        boolean_t               overflow,
                   2093:        ipc_object_t            object)
                   2094: {
                   2095:        ipc_entry_bits_t bits = entry->ie_bits;
                   2096:        ipc_port_t port;
                   2097: 
                   2098:        assert(IO_VALID(object));
                   2099:        assert(io_otype(object) == IOT_PORT);
                   2100:        assert(io_active(object));
                   2101:        assert(entry->ie_object == object);
                   2102: 
                   2103:        port = (ipc_port_t) object;
                   2104: 
                   2105:        switch (msgt_name) {
                   2106:            case MACH_MSG_TYPE_PORT_SEND_ONCE:
                   2107:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   2108:                assert(port->ip_sorights > 0);
                   2109: 
                   2110:                /* transfer send-once right and ref to entry */
                   2111:                ip_unlock(port);
                   2112: 
                   2113:                entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
                   2114:                break;
                   2115: 
                   2116:            case MACH_MSG_TYPE_PORT_SEND:
                   2117:                assert(port->ip_srights > 0);
                   2118: 
                   2119:                if (bits & MACH_PORT_TYPE_SEND) {
                   2120:                        mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
                   2121: 
                   2122:                        assert(port->ip_srights > 1);
                   2123:                        assert(urefs > 0);
                   2124:                        assert(urefs < MACH_PORT_UREFS_MAX);
                   2125: 
                   2126:                        if (urefs+1 == MACH_PORT_UREFS_MAX) {
                   2127:                                if (overflow) {
                   2128:                                        /* leave urefs pegged to maximum */
                   2129: 
                   2130:                                        port->ip_srights--;
                   2131:                                        ip_release(port);
                   2132:                                        ip_unlock(port);
                   2133:                                        return KERN_SUCCESS;
                   2134:                                }
                   2135: 
                   2136:                                ip_unlock(port);
                   2137:                                return KERN_UREFS_OVERFLOW;
                   2138:                        }
                   2139: 
                   2140:                        port->ip_srights--;
                   2141:                        ip_release(port);
                   2142:                        ip_unlock(port);
                   2143:                } else if (bits & MACH_PORT_TYPE_RECEIVE) {
                   2144:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                   2145:                        assert(IE_BITS_UREFS(bits) == 0);
                   2146: 
                   2147:                        /* transfer send right to entry */
                   2148:                        ip_release(port);
                   2149:                        ip_unlock(port);
                   2150:                } else {
                   2151:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   2152:                        assert(IE_BITS_UREFS(bits) == 0);
                   2153: 
                   2154:                        /* transfer send right and ref to entry */
                   2155:                        ip_unlock(port);
                   2156: 
                   2157:                        /* entry is locked holding ref, so can use port */
                   2158: 
                   2159:                        ipc_hash_insert(space, (ipc_object_t) port,
                   2160:                                        name, entry);
                   2161:                }
                   2162: 
                   2163:                entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
                   2164:                break;
                   2165: 
                   2166:            case MACH_MSG_TYPE_PORT_RECEIVE: {
                   2167:                ipc_port_t dest;
                   2168: 
                   2169:                assert(port->ip_mscount == 0);
                   2170:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                   2171:                dest = port->ip_destination;
                   2172: 
                   2173:                port->ip_receiver_name = name;
                   2174:                port->ip_receiver = space;
                   2175: 
                   2176:                assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
                   2177: 
                   2178:                if (bits & MACH_PORT_TYPE_SEND) {
                   2179:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                   2180:                        assert(IE_BITS_UREFS(bits) > 0);
                   2181:                        assert(port->ip_srights > 0);
                   2182: 
                   2183:                        ip_release(port);
                   2184:                        ip_unlock(port);
                   2185: 
                   2186:                        /* entry is locked holding ref, so can use port */
                   2187: 
                   2188:                        ipc_hash_delete(space, (ipc_object_t) port,
                   2189:                                        name, entry);
                   2190:                } else {
                   2191:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   2192:                        assert(IE_BITS_UREFS(bits) == 0);
                   2193: 
                   2194:                        /* transfer ref to entry */
                   2195:                        ip_unlock(port);
                   2196:                }
                   2197: 
                   2198:                entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
                   2199: 
                   2200:                if (dest != IP_NULL)
                   2201:                        ipc_port_release(dest);
                   2202:                break;
                   2203:            }
                   2204: 
                   2205:            default:
                   2206:                panic("ipc_right_copyout: strange rights");
                   2207:        }
                   2208: 
                   2209:        return KERN_SUCCESS;
                   2210: }
                   2211: 
                   2212: /*
                   2213:  *     Routine:        ipc_right_rename
                   2214:  *     Purpose:
                   2215:  *             Transfer an entry from one name to another.
                   2216:  *             The old entry is deallocated.
                   2217:  *     Conditions:
                   2218:  *             The space is write-locked and active.
                   2219:  *             The new entry is unused.  Upon return,
                   2220:  *             the space is unlocked.
                   2221:  *     Returns:
                   2222:  *             KERN_SUCCESS            Moved entry to new name.
                   2223:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                   2224:  *                     Caller should pretend old entry wasn't found.
                   2225:  *                     New entry was deallocated.
                   2226:  */
                   2227: 
                   2228: kern_return_t
                   2229: ipc_right_rename(
                   2230:        ipc_space_t     space,
                   2231:        mach_port_t     oname,
                   2232:        ipc_entry_t     oentry,
                   2233:        mach_port_t     nname,
                   2234:        ipc_entry_t     nentry)
                   2235: {
                   2236:        ipc_entry_bits_t bits = oentry->ie_bits;
                   2237:        ipc_port_request_index_t request = oentry->ie_request;
                   2238:        ipc_object_t object = oentry->ie_object;
                   2239: 
                   2240:        assert(space->is_active);
                   2241:        assert(oname != nname);
                   2242: 
                   2243:        /*
                   2244:         *      If IE_BITS_COMPAT, we can't allow the entry to be renamed
                   2245:         *      if the port is dead.  (This would foil ipc_port_destroy.)
                   2246:         *      Instead we should fail because oentry shouldn't exist.
                   2247:         *      Note IE_BITS_COMPAT implies ie_request != 0.
                   2248:         */
                   2249: 
                   2250:        if (request != 0) {
                   2251:                ipc_port_t port;
                   2252: 
                   2253:                assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
                   2254:                port = (ipc_port_t) object;
                   2255:                assert(port != IP_NULL);
                   2256: 
                   2257:                if (ipc_right_check(space, port, oname, oentry)) {
                   2258: #if    MACH_IPC_COMPAT
                   2259:                        if (bits & IE_BITS_COMPAT) {
                   2260:                                ipc_entry_dealloc(space, nname, nentry);
                   2261:                                is_write_unlock(space);
                   2262:                                return KERN_INVALID_NAME;
                   2263:                        }
                   2264: #endif /* MACH_IPC_COMPAT */
                   2265: 
                   2266:                        bits = oentry->ie_bits;
                   2267:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   2268:                        assert(oentry->ie_request == 0);
                   2269:                        request = 0;
                   2270:                        assert(oentry->ie_object == IO_NULL);
                   2271:                        object = IO_NULL;
                   2272:                } else {
                   2273:                        /* port is locked and active */
                   2274: 
                   2275:                        ipc_port_dnrename(port, request, oname, nname);
                   2276:                        ip_unlock(port);
                   2277:                        oentry->ie_request = 0;
                   2278:                }
                   2279:        }
                   2280: 
                   2281:        if (bits & IE_BITS_MAREQUEST) {
                   2282:                assert(bits & MACH_PORT_TYPE_SEND_RECEIVE);
                   2283: 
                   2284:                ipc_marequest_rename(space, oname, nname);
                   2285:        }
                   2286: 
                   2287:        /* initialize nentry before letting ipc_hash_insert see it */
                   2288: 
                   2289:        assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
                   2290:        nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
                   2291:        nentry->ie_request = request;
                   2292:        nentry->ie_object = object;
                   2293: 
                   2294:        switch (IE_BITS_TYPE(bits)) {
                   2295:            case MACH_PORT_TYPE_SEND: {
                   2296:                ipc_port_t port;
                   2297: 
                   2298:                port = (ipc_port_t) object;
                   2299:                assert(port != IP_NULL);
                   2300: 
                   2301:                ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
                   2302:                ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
                   2303:                break;
                   2304:            }
                   2305: 
                   2306:            case MACH_PORT_TYPE_RECEIVE:
                   2307:            case MACH_PORT_TYPE_SEND_RECEIVE: {
                   2308:                ipc_port_t port;
                   2309: 
                   2310:                port = (ipc_port_t) object;
                   2311:                assert(port != IP_NULL);
                   2312: 
                   2313:                ip_lock(port);
                   2314:                assert(ip_active(port));
                   2315:                assert(port->ip_receiver_name == oname);
                   2316:                assert(port->ip_receiver == space);
                   2317: 
                   2318:                port->ip_receiver_name = nname;
                   2319:                ip_unlock(port);
                   2320:                break;
                   2321:            }
                   2322: 
                   2323:            case MACH_PORT_TYPE_PORT_SET: {
                   2324:                ipc_pset_t pset;
                   2325: 
                   2326:                pset = (ipc_pset_t) object;
                   2327:                assert(pset != IPS_NULL);
                   2328: 
                   2329:                ips_lock(pset);
                   2330:                assert(ips_active(pset));
                   2331:                assert(pset->ips_local_name == oname);
                   2332: 
                   2333:                pset->ips_local_name = nname;
                   2334:                ips_unlock(pset);
                   2335:                break;
                   2336:            }
                   2337: 
                   2338:            case MACH_PORT_TYPE_SEND_ONCE:
                   2339:            case MACH_PORT_TYPE_DEAD_NAME:
                   2340:                break;
                   2341: 
                   2342:            default:
                   2343:                panic("ipc_right_rename: strange rights");
                   2344:        }
                   2345: 
                   2346:        assert(oentry->ie_request == 0);
                   2347:        oentry->ie_object = IO_NULL;
                   2348:        ipc_entry_dealloc(space, oname, oentry);
                   2349:        is_write_unlock(space);
                   2350: 
                   2351:        return KERN_SUCCESS;
                   2352: }
                   2353: 
                   2354: #if    MACH_IPC_COMPAT
                   2355: 
                   2356: /*
                   2357:  *     Routine:        ipc_right_copyin_compat
                   2358:  *     Purpose:
                   2359:  *             Copyin a capability from a space.
                   2360:  *             If successful, the caller gets a ref
                   2361:  *             for the resulting object, which is always valid.
                   2362:  *     Conditions:
                   2363:  *             The space is write-locked, and is unlocked upon return.
                   2364:  *             The space must be active.
                   2365:  *     Returns:
                   2366:  *             KERN_SUCCESS            Acquired a valid object.
                   2367:  *             KERN_INVALID_RIGHT      Name doesn't denote correct right.
                   2368:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                   2369:  *                     Caller should pretend lookup of entry failed.
                   2370:  */
                   2371: 
                   2372: kern_return_t
                   2373: ipc_right_copyin_compat(space, name, entry, msgt_name, dealloc, objectp)
                   2374:        ipc_space_t space;
                   2375:        mach_port_t name;
                   2376:        ipc_entry_t entry;
                   2377:        mach_msg_type_name_t msgt_name;
                   2378:        boolean_t dealloc;
                   2379:        ipc_object_t *objectp;
                   2380: {
                   2381:        ipc_entry_bits_t bits = entry->ie_bits;
                   2382: 
                   2383:        assert(space->is_active);
                   2384: 
                   2385:        switch (msgt_name) {
                   2386:            case MSG_TYPE_PORT:
                   2387:                if (dealloc) {
                   2388:                        ipc_port_t port;
                   2389:                        ipc_port_t dnrequest;
                   2390: 
                   2391:                        /*
                   2392:                         *      Pulls a send right out of the space,
                   2393:                         *      leaving the space with no rights.
                   2394:                         *      Not allowed to destroy the port,
                   2395:                         *      so the space can't have receive rights.
                   2396:                         *      Doesn't operate on dead names.
                   2397:                         */
                   2398: 
                   2399:                        if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_SEND)
                   2400:                                goto invalid_right;
                   2401: 
                   2402:                        port = (ipc_port_t) entry->ie_object;
                   2403:                        assert(port != IP_NULL);
                   2404: 
                   2405:                        if (ipc_right_check(space, port, name, entry)) {
                   2406:                                if (bits & IE_BITS_COMPAT)
                   2407:                                        goto invalid_name;
                   2408: 
                   2409:                                goto invalid_right;
                   2410:                        }
                   2411:                        /* port is locked and active */
                   2412: 
                   2413:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   2414:                                                             name, entry);
                   2415: 
                   2416:                        assert(port->ip_srights > 0);
                   2417:                        ip_unlock(port);
                   2418: 
                   2419:                        if (bits & IE_BITS_MAREQUEST)
                   2420:                                ipc_marequest_cancel(space, name);
                   2421: 
                   2422:                        ipc_hash_delete(
                   2423:                                space, (ipc_object_t) port,
                   2424:                                name, entry);
                   2425: 
                   2426:                        entry->ie_object = IO_NULL;
                   2427:                        ipc_entry_dealloc(space, name, entry);
                   2428:                        is_write_unlock(space);
                   2429: 
                   2430:                        if (dnrequest != IP_NULL)
                   2431:                                ipc_notify_port_deleted(dnrequest, name);
                   2432: 
                   2433:                        *objectp = (ipc_object_t) port;
                   2434:                        break;
                   2435:                } else {
                   2436:                        ipc_port_t port;
                   2437: 
                   2438:                        /*
                   2439:                         *      Pulls a send right out of the space,
                   2440:                         *      making a send right if necessary.
                   2441:                         *      Doesn't operate on dead names.
                   2442:                         */
                   2443: 
                   2444:                        if ((bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0)
                   2445:                                goto invalid_right;
                   2446: 
                   2447:                        port = (ipc_port_t) entry->ie_object;
                   2448:                        assert(port != IP_NULL);
                   2449: 
                   2450:                        if (ipc_right_check(space, port, name, entry)) {
                   2451:                                if (bits & IE_BITS_COMPAT)
                   2452:                                        goto invalid_name;
                   2453: 
                   2454:                                goto invalid_right;
                   2455:                        }
                   2456:                        /* port is locked and active */
                   2457: 
                   2458:                        is_write_unlock(space);
                   2459: 
                   2460:                        if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                   2461:                                assert(IE_BITS_TYPE(bits) ==
                   2462:                                                MACH_PORT_TYPE_RECEIVE);
                   2463:                                assert(IE_BITS_UREFS(bits) == 0);
                   2464: 
                   2465:                                port->ip_mscount++;
                   2466:                        }
                   2467: 
                   2468:                        port->ip_srights++;
                   2469:                        ip_reference(port);
                   2470:                        ip_unlock(port);
                   2471: 
                   2472:                        *objectp = (ipc_object_t) port;
                   2473:                        break;
                   2474:                }
                   2475: 
                   2476:            case MSG_TYPE_PORT_ALL:
                   2477:                if (dealloc) {
                   2478:                        ipc_port_t port;
                   2479:                        ipc_port_t dnrequest = IP_NULL;
                   2480:                        ipc_port_t nsrequest = IP_NULL;
                   2481:                        mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
                   2482: 
                   2483:                        /*
                   2484:                         *      Like MACH_MSG_TYPE_MOVE_RECEIVE, except that
                   2485:                         *      the space is always left without rights,
                   2486:                         *      so we kill send rights if necessary.
                   2487:                         */
                   2488: 
                   2489:                        if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   2490:                                goto invalid_right;
                   2491: 
                   2492:                        port = (ipc_port_t) entry->ie_object;
                   2493:                        assert(port != IP_NULL);
                   2494: 
                   2495:                        ip_lock(port);
                   2496:                        assert(ip_active(port));
                   2497:                        assert(port->ip_receiver_name == name);
                   2498:                        assert(port->ip_receiver == space);
                   2499: 
                   2500:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   2501:                                                             name, entry);
                   2502: 
                   2503:                        if (bits & IE_BITS_MAREQUEST)
                   2504:                                ipc_marequest_cancel(space, name);
                   2505: 
                   2506:                        entry->ie_object = IO_NULL;
                   2507:                        ipc_entry_dealloc(space, name, entry);
                   2508:                        is_write_unlock(space);
                   2509: 
                   2510:                        if (bits & MACH_PORT_TYPE_SEND) {
                   2511:                                assert(IE_BITS_TYPE(bits) ==
                   2512:                                                MACH_PORT_TYPE_SEND_RECEIVE);
                   2513:                                assert(IE_BITS_UREFS(bits) > 0);
                   2514:                                assert(port->ip_srights > 0);
                   2515: 
                   2516:                                if (--port->ip_srights == 0) {
                   2517:                                        nsrequest = port->ip_nsrequest;
                   2518:                                        if (nsrequest != IP_NULL) {
                   2519:                                                port->ip_nsrequest = IP_NULL;
                   2520:                                                mscount = port->ip_mscount;
                   2521:                                        }
                   2522:                                }
                   2523:                        }
                   2524: 
                   2525:                        ipc_port_clear_receiver(port);
                   2526: 
                   2527:                        port->ip_receiver_name = MACH_PORT_NULL;
                   2528:                        port->ip_destination = IP_NULL;
                   2529:                        ip_unlock(port);
                   2530: 
                   2531:                        if (nsrequest != IP_NULL)
                   2532:                                ipc_notify_no_senders(nsrequest, mscount);
                   2533: 
                   2534:                        if (dnrequest != IP_NULL)
                   2535:                                ipc_notify_port_deleted(dnrequest, name);
                   2536: 
                   2537:                        *objectp = (ipc_object_t) port;
                   2538:                        break;
                   2539:                } else {
                   2540:                        ipc_port_t port;
                   2541: 
                   2542:                        /*
                   2543:                         *      Like MACH_MSG_TYPE_MOVE_RECEIVE, except that
                   2544:                         *      the space is always left with send rights,
                   2545:                         *      so we make a send right if necessary.
                   2546:                         */
                   2547: 
                   2548:                        if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   2549:                                goto invalid_right;
                   2550: 
                   2551:                        port = (ipc_port_t) entry->ie_object;
                   2552:                        assert(port != IP_NULL);
                   2553: 
                   2554:                        ip_lock(port);
                   2555:                        assert(ip_active(port));
                   2556:                        assert(port->ip_receiver_name == name);
                   2557:                        assert(port->ip_receiver == space);
                   2558: 
                   2559:                        if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                   2560:                                assert(IE_BITS_TYPE(bits) ==
                   2561:                                                MACH_PORT_TYPE_RECEIVE);
                   2562:                                assert(IE_BITS_UREFS(bits) == 0);
                   2563: 
                   2564:                                /* ip_mscount will be cleared below */
                   2565:                                port->ip_srights++;
                   2566:                                bits |= MACH_PORT_TYPE_SEND | 1;
                   2567:                        }
                   2568: 
                   2569:                        ipc_hash_insert(space, (ipc_object_t) port,
                   2570:                                        name, entry);
                   2571: 
                   2572:                        entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
                   2573:                        is_write_unlock(space);
                   2574: 
                   2575:                        ipc_port_clear_receiver(port); /* clears ip_mscount */
                   2576: 
                   2577:                        port->ip_receiver_name = MACH_PORT_NULL;
                   2578:                        port->ip_destination = IP_NULL;
                   2579:                        ip_reference(port);
                   2580:                        ip_unlock(port);
                   2581: 
                   2582:                        *objectp = (ipc_object_t) port;
                   2583:                        break;
                   2584:                }
                   2585: 
                   2586:            default:
                   2587: #if MACH_ASSERT
                   2588:                assert(!"ipc_right_copyin_compat: strange rights");
                   2589: #else
                   2590:                panic("ipc_right_copyin_compat: strange rights");
                   2591: #endif
                   2592:        }
                   2593: 
                   2594:        return KERN_SUCCESS;
                   2595: 
                   2596:     invalid_right:
                   2597:        is_write_unlock(space);
                   2598:        return KERN_INVALID_RIGHT;
                   2599: 
                   2600:     invalid_name:
                   2601:        is_write_unlock(space);
                   2602:        return KERN_INVALID_NAME;
                   2603: }
                   2604: 
                   2605: /*
                   2606:  *     Routine:        ipc_right_copyin_header
                   2607:  *     Purpose:
                   2608:  *             Copyin a capability from a space.
                   2609:  *             If successful, the caller gets a ref
                   2610:  *             for the resulting object, which is always valid.
                   2611:  *             The type of the acquired capability is returned.
                   2612:  *     Conditions:
                   2613:  *             The space is write-locked, and is unlocked upon return.
                   2614:  *             The space must be active.
                   2615:  *     Returns:
                   2616:  *             KERN_SUCCESS            Acquired a valid object.
                   2617:  *             KERN_INVALID_RIGHT      Name doesn't denote correct right.
                   2618:  *             KERN_INVALID_NAME       [MACH_IPC_COMPAT]
                   2619:  *                     Caller should pretend lookup of entry failed.
                   2620:  */
                   2621: 
                   2622: kern_return_t
                   2623: ipc_right_copyin_header(
                   2624:        ipc_space_t             space,
                   2625:        mach_port_t             name,
                   2626:        ipc_entry_t             entry,
                   2627:        ipc_object_t            *objectp,
                   2628:        mach_msg_type_name_t    *msgt_namep)
                   2629: {
                   2630:        ipc_entry_bits_t bits = entry->ie_bits;
                   2631:        mach_port_type_t type = IE_BITS_TYPE(bits);
                   2632: 
                   2633:        assert(space->is_active);
                   2634: 
                   2635:        switch (type) {
                   2636:            case MACH_PORT_TYPE_PORT_SET:
                   2637:            case MACH_PORT_TYPE_DEAD_NAME:
                   2638:                goto invalid_right;
                   2639: 
                   2640:            case MACH_PORT_TYPE_RECEIVE: {
                   2641:                ipc_port_t port;
                   2642: 
                   2643:                /*
                   2644:                 *      Like MACH_MSG_TYPE_MAKE_SEND.
                   2645:                 */
                   2646: 
                   2647:                port = (ipc_port_t) entry->ie_object;
                   2648:                assert(port != IP_NULL);
                   2649: 
                   2650:                ip_lock(port);
                   2651:                assert(ip_active(port));
                   2652:                assert(port->ip_receiver_name == name);
                   2653:                assert(port->ip_receiver == space);
                   2654:                is_write_unlock(space);
                   2655: 
                   2656:                port->ip_mscount++;
                   2657:                port->ip_srights++;
                   2658:                ip_reference(port);
                   2659:                ip_unlock(port);
                   2660: 
                   2661:                *objectp = (ipc_object_t) port;
                   2662:                *msgt_namep = MACH_MSG_TYPE_PORT_SEND;
                   2663:                break;
                   2664:            }
                   2665: 
                   2666:            case MACH_PORT_TYPE_SEND:
                   2667:            case MACH_PORT_TYPE_SEND_RECEIVE: {
                   2668:                ipc_port_t port;
                   2669: 
                   2670:                /*
                   2671:                 *      Like MACH_MSG_TYPE_COPY_SEND,
                   2672:                 *      except that the port must be alive.
                   2673:                 */
                   2674: 
                   2675:                assert(IE_BITS_UREFS(bits) > 0);
                   2676: 
                   2677:                port = (ipc_port_t) entry->ie_object;
                   2678:                assert(port != IP_NULL);
                   2679: 
                   2680:                if (ipc_right_check(space, port, name, entry)) {
                   2681:                        if (bits & IE_BITS_COMPAT)
                   2682:                                goto invalid_name;
                   2683: 
                   2684:                        goto invalid_right;
                   2685:                }
                   2686:                /* port is locked and active */
                   2687: 
                   2688:                assert(port->ip_srights > 0);
                   2689:                is_write_unlock(space);
                   2690: 
                   2691:                port->ip_srights++;
                   2692:                ip_reference(port);
                   2693:                ip_unlock(port);
                   2694: 
                   2695:                *objectp = (ipc_object_t) port;
                   2696:                *msgt_namep = MACH_MSG_TYPE_PORT_SEND;
                   2697:                break;
                   2698:            }
                   2699: 
                   2700:            case MACH_PORT_TYPE_SEND_ONCE: {
                   2701:                ipc_port_t port;
                   2702:                ipc_port_t dnrequest, notify;
                   2703: 
                   2704:                /*
                   2705:                 *      Like MACH_MSG_TYPE_MOVE_SEND_ONCE,
                   2706:                 *      except that the port must be alive
                   2707:                 *      and a port-deleted notification is generated.
                   2708:                 */
                   2709: 
                   2710:                assert(IE_BITS_UREFS(bits) == 1);
                   2711:                assert((bits & IE_BITS_MAREQUEST) == 0);
                   2712: 
                   2713:                port = (ipc_port_t) entry->ie_object;
                   2714:                assert(port != IP_NULL);
                   2715: 
                   2716:                if (ipc_right_check(space, port, name, entry)) {
                   2717:                        if (bits & IE_BITS_COMPAT)
                   2718:                                goto invalid_name;
                   2719: 
                   2720:                        goto invalid_right;
                   2721:                }
                   2722:                /* port is locked and active */
                   2723: 
                   2724:                assert(port->ip_sorights > 0);
                   2725: 
                   2726:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                   2727:                ip_unlock(port);
                   2728: 
                   2729:                entry->ie_object = IO_NULL;
                   2730:                ipc_entry_dealloc(space, name, entry);
                   2731: 
                   2732:                notify = ipc_space_make_notify(space);
                   2733:                is_write_unlock(space);
                   2734: 
                   2735:                if (dnrequest != IP_NULL)
                   2736:                        ipc_notify_port_deleted(dnrequest, name);
                   2737: 
                   2738:                if (IP_VALID(notify))
                   2739:                        ipc_notify_port_deleted_compat(notify, name);
                   2740: 
                   2741:                *objectp = (ipc_object_t) port;
                   2742:                *msgt_namep = MACH_MSG_TYPE_PORT_SEND_ONCE;
                   2743:                break;
                   2744:            }
                   2745: 
                   2746:            default:
                   2747:                panic("ipc_right_copyin_header: strange rights");
                   2748:        }
                   2749: 
                   2750:        return KERN_SUCCESS;
                   2751: 
                   2752:     invalid_right:
                   2753:        is_write_unlock(space);
                   2754:        return KERN_INVALID_RIGHT;
                   2755: 
                   2756:     invalid_name:
                   2757:        is_write_unlock(space);
                   2758:        return KERN_INVALID_NAME;
                   2759: }
                   2760: 
                   2761: #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.