Annotation of XNU/osfmk/ipc/ipc_right.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_FREE_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  */
                     52: /*
                     53:  *     File:   ipc/ipc_right.c
                     54:  *     Author: Rich Draves
                     55:  *     Date:   1989
                     56:  *
                     57:  *     Functions to manipulate IPC capabilities.
                     58:  */
                     59: 
                     60: #include <dipc.h>
                     61: 
                     62: #include <mach/boolean.h>
                     63: #include <mach/kern_return.h>
                     64: #include <mach/port.h>
                     65: #include <mach/message.h>
                     66: #include <kern/assert.h>
                     67: #include <kern/misc_protos.h>
                     68: #include <kern/ipc_subsystem.h>
                     69: #include <ipc/port.h>
                     70: #include <ipc/ipc_entry.h>
                     71: #include <ipc/ipc_space.h>
                     72: #include <ipc/ipc_object.h>
                     73: #include <ipc/ipc_hash.h>
                     74: #include <ipc/ipc_port.h>
                     75: #include <ipc/ipc_pset.h>
                     76: #include <ipc/ipc_right.h>
                     77: #include <ipc/ipc_notify.h>
                     78: #include <ipc/ipc_table.h>
                     79: 
                     80: /*
                     81:  *     Routine:        ipc_right_lookup_write
                     82:  *     Purpose:
                     83:  *             Finds an entry in a space, given the name.
                     84:  *     Conditions:
                     85:  *             Nothing locked.  If successful, the space is write-locked.
                     86:  *     Returns:
                     87:  *             KERN_SUCCESS            Found an entry.
                     88:  *             KERN_INVALID_TASK       The space is dead.
                     89:  *             KERN_INVALID_NAME       Name doesn't exist in space.
                     90:  */
                     91: 
                     92: kern_return_t
                     93: ipc_right_lookup_write(
                     94:        ipc_space_t             space,
                     95:        mach_port_name_t        name,
                     96:        ipc_entry_t             *entryp)
                     97: {
                     98:        ipc_entry_t entry;
                     99: 
                    100:        assert(space != IS_NULL);
                    101: 
                    102:        is_write_lock(space);
                    103: 
                    104:        if (!space->is_active) {
                    105:                is_write_unlock(space);
                    106:                return KERN_INVALID_TASK;
                    107:        }
                    108: 
                    109:        if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) {
                    110:                is_write_unlock(space);
                    111:                return KERN_INVALID_NAME;
                    112:        }
                    113: 
                    114:        *entryp = entry;
                    115:        return KERN_SUCCESS;
                    116: }
                    117: 
                    118: /*
                    119:  *     Routine:        ipc_right_reverse
                    120:  *     Purpose:
                    121:  *             Translate (space, object) -> (name, entry).
                    122:  *             Only finds send/receive rights.
                    123:  *             Returns TRUE if an entry is found; if so,
                    124:  *             the object is locked and active.
                    125:  *     Conditions:
                    126:  *             The space must be locked (read or write) and active.
                    127:  *             Nothing else locked.
                    128:  */
                    129: 
                    130: boolean_t
                    131: ipc_right_reverse(
                    132:        ipc_space_t             space,
                    133:        ipc_object_t            object,
                    134:        mach_port_name_t        *namep,
                    135:        ipc_entry_t             *entryp)
                    136: {
                    137:        ipc_port_t port;
                    138:        mach_port_name_t name;
                    139:        ipc_entry_t entry;
                    140: 
                    141:        /* would switch on io_otype to handle multiple types of object */
                    142: 
                    143:        assert(space->is_active);
                    144:        assert(io_otype(object) == IOT_PORT);
                    145: 
                    146:        port = (ipc_port_t) object;
                    147: 
                    148:        ip_lock(port);
                    149:        if (!ip_active(port)) {
                    150:                ip_unlock(port);
                    151: 
                    152:                return FALSE;
                    153:        }
                    154: 
                    155:        if (port->ip_receiver == space) {
                    156:                name = port->ip_receiver_name;
                    157:                assert(name != MACH_PORT_NULL);
                    158: 
                    159:                entry = ipc_entry_lookup(space, name);
                    160: 
                    161:                assert(entry != IE_NULL);
                    162:                assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                    163:                assert(port == (ipc_port_t) entry->ie_object);
                    164: 
                    165:                *namep = name;
                    166:                *entryp = entry;
                    167:                return TRUE;
                    168:        }
                    169: 
                    170:        if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) {
                    171:                assert((entry = *entryp) != IE_NULL);
                    172:                assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND);
                    173:                assert(port == (ipc_port_t) entry->ie_object);
                    174: 
                    175:                return TRUE;
                    176:        }
                    177: 
                    178:        ip_unlock(port);
                    179:        return FALSE;
                    180: }
                    181: 
                    182: /*
                    183:  *     Routine:        ipc_right_dnrequest
                    184:  *     Purpose:
                    185:  *             Make a dead-name request, returning the previously
                    186:  *             registered send-once right.  If notify is IP_NULL,
                    187:  *             just cancels the previously registered request.
                    188:  *
                    189:  *             This interacts with the IE_BITS_COMPAT, because they
                    190:  *             both use ie_request.  If this is a compat entry, then
                    191:  *             previous always gets IP_NULL.  If notify is IP_NULL,
                    192:  *             then the entry remains a compat entry.  Otherwise
                    193:  *             the real dead-name request is registered and the entry
                    194:  *             is no longer a compat entry.
                    195:  *     Conditions:
                    196:  *             Nothing locked.  May allocate memory.
                    197:  *             Only consumes/returns refs if successful.
                    198:  *     Returns:
                    199:  *             KERN_SUCCESS            Made/canceled dead-name request.
                    200:  *             KERN_INVALID_TASK       The space is dead.
                    201:  *             KERN_INVALID_NAME       Name doesn't exist in space.
                    202:  *             KERN_INVALID_RIGHT      Name doesn't denote port/dead rights.
                    203:  *             KERN_INVALID_ARGUMENT   Name denotes dead name, but
                    204:  *                     immediate is FALSE or notify is IP_NULL.
                    205:  *             KERN_UREFS_OVERFLOW     Name denotes dead name, but
                    206:  *                     generating immediate notif. would overflow urefs.
                    207:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    208:  */
                    209: 
                    210: kern_return_t
                    211: ipc_right_dnrequest(
                    212:        ipc_space_t             space,
                    213:        mach_port_name_t        name,
                    214:        boolean_t               immediate,
                    215:        ipc_port_t              notify,
                    216:        ipc_port_t              *previousp)
                    217: {
                    218:        ipc_port_t previous;
                    219: 
                    220:        for (;;) {
                    221:                ipc_entry_t entry;
                    222:                ipc_entry_bits_t bits;
                    223:                kern_return_t kr;
                    224: 
                    225:                kr = ipc_right_lookup_write(space, name, &entry);
                    226:                if (kr != KERN_SUCCESS)
                    227:                        return kr;
                    228:                /* space is write-locked and active */
                    229:                bits = entry->ie_bits;
                    230:                if (bits & MACH_PORT_TYPE_PORT_RIGHTS) {
                    231:                        ipc_port_t port;
                    232:                        ipc_port_request_index_t request;
                    233: 
                    234:                        port = (ipc_port_t) entry->ie_object;
                    235:                        assert(port != IP_NULL);
                    236: 
                    237:                        if (!ipc_right_check(space, port, name, entry)) {
                    238:                                /* port is locked and active */
                    239: 
                    240:                                if (notify == IP_NULL) {
                    241:                                        previous = ipc_right_dncancel_macro(
                    242:                                                   space, port, name, entry);
                    243: 
                    244:                                        ip_unlock(port);
                    245:                                        is_write_unlock(space);
                    246:                                        break;
                    247:                                }
                    248: 
                    249:                                /*
                    250:                                 *      If a registered soright exists,
                    251:                                 *      want to atomically switch with it.
                    252:                                 *      If ipc_port_dncancel finds us a
                    253:                                 *      soright, then the following
                    254:                                 *      ipc_port_dnrequest will reuse
                    255:                                 *      that slot, so we are guaranteed
                    256:                                 *      not to unlock and retry.
                    257:                                 */
                    258: 
                    259:                                previous = ipc_right_dncancel_macro(space,
                    260:                                                port, name, entry);
                    261: 
                    262:                                kr = ipc_port_dnrequest(port, name, notify,
                    263:                                                        &request);
                    264:                                if (kr != KERN_SUCCESS) {
                    265:                                        assert(previous == IP_NULL);
                    266:                                        is_write_unlock(space);
                    267: 
                    268:                                        kr = ipc_port_dngrow(port,
                    269:                                                             ITS_SIZE_NONE);
                    270:                                        /* port is unlocked */
                    271:                                        if (kr != KERN_SUCCESS)
                    272:                                                return kr;
                    273: 
                    274:                                        continue;
                    275:                                }
                    276: 
                    277:                                assert(request != 0);
                    278:                                ip_unlock(port);
                    279: 
                    280:                                entry->ie_request = request;
                    281:                                is_write_unlock(space);
                    282:                                break;
                    283:                        } else {
                    284: 
                    285:                          /*
                    286:                           * Our capability bits were changed by ipc_right_check
                    287:                           * because it found an inactive port and removed our
                    288:                           * references to it (converting our entry into a dead
                    289:                           * one).  Reload the bits (and obviously we can't use
                    290:                           * the port name anymore).
                    291:                           */
                    292:                          bits = entry->ie_bits;
                    293: 
                    294:                        }
                    295: 
                    296:                        assert(bits & MACH_PORT_TYPE_DEAD_NAME);
                    297:                }
                    298: 
                    299:                if ((bits & MACH_PORT_TYPE_DEAD_NAME) &&
                    300:                    immediate && (notify != IP_NULL)) {
                    301:                        mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
                    302: 
                    303:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                    304:                        assert(urefs > 0);
                    305: 
                    306:                        if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) {
                    307:                                is_write_unlock(space);
                    308:                                return KERN_UREFS_OVERFLOW;
                    309:                        }
                    310: 
                    311:                        (entry->ie_bits)++; /* increment urefs */
                    312:                        is_write_unlock(space);
                    313: 
                    314:                        ipc_notify_dead_name(notify, name);
                    315:                        previous = IP_NULL;
                    316:                        break;
                    317:                }
                    318: 
                    319:                is_write_unlock(space);
                    320:                if (bits & MACH_PORT_TYPE_PORT_OR_DEAD)
                    321:                        return KERN_INVALID_ARGUMENT;
                    322:                else
                    323:                        return KERN_INVALID_RIGHT;
                    324:        }
                    325: 
                    326:        *previousp = previous;
                    327:        return KERN_SUCCESS;
                    328: }
                    329: 
                    330: /*
                    331:  *     Routine:        ipc_right_dncancel
                    332:  *     Purpose:
                    333:  *             Cancel a dead-name request and return the send-once right.
                    334:  *             Afterwards, entry->ie_request == 0.
                    335:  *     Conditions:
                    336:  *             The space must be write-locked; the port must be locked.
                    337:  *             The port must be active; the space doesn't have to be.
                    338:  */
                    339: 
                    340: ipc_port_t
                    341: ipc_right_dncancel(
                    342:        ipc_space_t             space,
                    343:        ipc_port_t              port,
                    344:        mach_port_name_t        name,
                    345:        ipc_entry_t             entry)
                    346: {
                    347:        ipc_port_t dnrequest;
                    348: 
                    349:        assert(ip_active(port));
                    350:        assert(port == (ipc_port_t) entry->ie_object);
                    351: 
                    352:        dnrequest = ipc_port_dncancel(port, name, entry->ie_request);
                    353:        entry->ie_request = 0;
                    354: 
                    355:        return dnrequest;
                    356: }
                    357: 
                    358: /*
                    359:  *     Routine:        ipc_right_inuse
                    360:  *     Purpose:
                    361:  *             Check if an entry is being used.
                    362:  *             Returns TRUE if it is.
                    363:  *     Conditions:
                    364:  *             The space is write-locked and active.
                    365:  *             It is unlocked if the entry is inuse.
                    366:  */
                    367: 
                    368: boolean_t
                    369: ipc_right_inuse(
                    370:        ipc_space_t             space,
                    371:        mach_port_name_t        name,
                    372:        ipc_entry_t             entry)
                    373: {
                    374:        if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) {
                    375:                is_write_unlock(space);
                    376:                return TRUE;
                    377:        }
                    378:        return FALSE;
                    379: }
                    380: 
                    381: /*
                    382:  *     Routine:        ipc_right_check
                    383:  *     Purpose:
                    384:  *             Check if the port has died.  If it has,
                    385:  *             clean up the entry and return TRUE.
                    386:  *     Conditions:
                    387:  *             The space is write-locked; the port is not locked.
                    388:  *             If returns FALSE, the port is also locked and active.
                    389:  *             Otherwise, entry is converted to a dead name, freeing
                    390:  *             a reference to port.
                    391:  */
                    392: 
                    393: boolean_t
                    394: ipc_right_check(
                    395:        ipc_space_t             space,
                    396:        ipc_port_t              port,
                    397:        mach_port_name_t        name,
                    398:        ipc_entry_t             entry)
                    399: {
                    400:        ipc_entry_bits_t bits;
                    401: 
                    402:        assert(space->is_active);
                    403:        assert(port == (ipc_port_t) entry->ie_object);
                    404: 
                    405:        ip_lock(port);
                    406:        if (ip_active(port))
                    407:                return FALSE;
                    408:        ip_unlock(port);
                    409: 
                    410:        /* this was either a pure send right or a send-once right */
                    411: 
                    412:        bits = entry->ie_bits;
                    413:        assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
                    414:        assert(IE_BITS_UREFS(bits) > 0);
                    415: 
                    416:        if (bits & MACH_PORT_TYPE_SEND) {   
                    417:                 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                    418:         } else {
                    419:                 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                    420:                 assert(IE_BITS_UREFS(bits) == 1);
                    421:         }
                    422: 
                    423: 
                    424:        ipc_port_release(port);
                    425: 
                    426:        /* convert entry to dead name */
                    427: 
                    428:        if ((bits & MACH_PORT_TYPE_SEND) && !(bits & MACH_PORT_TYPE_RECEIVE))
                    429:                ipc_hash_delete(space, (ipc_object_t)port, name, entry);
                    430: 
                    431:        bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME;
                    432:        
                    433:        /*
                    434:         * If there was a notification request outstanding on this
                    435:         * name, and since the port went dead, that notification
                    436:         * must already be on its way up from the port layer. We
                    437:         * don't need the index of the notification port anymore.
                    438:         *
                    439:         * JMM - We also add a reference to the entry since the
                    440:         * notification only carries the name and NOT a reference
                    441:         * (or right). This makes for pretty loose reference
                    442:         * counting, since it is only happenstance that we
                    443:         * detected the notification in progress like this.
                    444:         * But most (all?) calls that try to deal with this entry
                    445:         * will also come through here, so the reference gets added
                    446:         * before the entry gets used eventually (I would rather it
                    447:         * be explicit in the notification generation, though)
                    448:         */
                    449:        if (entry->ie_request != 0) {
                    450:                assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
                    451:                entry->ie_request = 0; 
                    452:                bits++; 
                    453:        }
                    454:        entry->ie_bits = bits;
                    455:        entry->ie_object = IO_NULL;
                    456:        return TRUE;
                    457: }
                    458: 
                    459: /*
                    460:  *     Routine:        ipc_right_clean
                    461:  *     Purpose:
                    462:  *             Cleans up an entry in a dead space.
                    463:  *             The entry isn't deallocated or removed
                    464:  *             from reverse hash tables.
                    465:  *     Conditions:
                    466:  *             The space is dead and unlocked.
                    467:  */
                    468: 
                    469: void
                    470: ipc_right_clean(
                    471:        ipc_space_t             space,
                    472:        mach_port_name_t        name,
                    473:        ipc_entry_t             entry)
                    474: {
                    475:        ipc_entry_bits_t bits;
                    476:        mach_port_type_t type;
                    477: 
                    478:        bits = entry->ie_bits;
                    479:        type = IE_BITS_TYPE(bits);
                    480: 
                    481:        assert(!space->is_active);
                    482: 
                    483:        /*
                    484:         *      IE_BITS_COMPAT/ipc_right_dncancel doesn't have this
                    485:         *      problem, because we check that the port is active.  If
                    486:         *      we didn't cancel IE_BITS_COMPAT, ipc_port_destroy
                    487:         *      would still work, but dead space refs would accumulate
                    488:         *      in ip_dnrequests.  They would use up slots in
                    489:         *      ip_dnrequests and keep the spaces from being freed.
                    490:         */
                    491: 
                    492:        switch (type) {
                    493:            case MACH_PORT_TYPE_DEAD_NAME:
                    494:                assert(entry->ie_request == 0);
                    495:                assert(entry->ie_object == IO_NULL);
                    496:                break;
                    497: 
                    498:            case MACH_PORT_TYPE_PORT_SET: {
                    499:                ipc_pset_t pset = (ipc_pset_t) entry->ie_object;
                    500: 
                    501:                assert(entry->ie_request == 0);
                    502:                assert(pset != IPS_NULL);
                    503: 
                    504:                ips_lock(pset);
                    505:                assert(ips_active(pset));
                    506: 
                    507:                ipc_pset_destroy(pset); /* consumes ref, unlocks */
                    508:                break;
                    509:            }
                    510: 
                    511:            case MACH_PORT_TYPE_SEND:
                    512:            case MACH_PORT_TYPE_RECEIVE:
                    513:            case MACH_PORT_TYPE_SEND_RECEIVE:
                    514:            case MACH_PORT_TYPE_SEND_ONCE: {
                    515:                ipc_port_t port = (ipc_port_t) entry->ie_object;
                    516:                ipc_port_t dnrequest;
                    517:                ipc_port_t nsrequest = IP_NULL;
                    518:                mach_port_mscount_t mscount;
                    519: 
                    520:                assert(port != IP_NULL);
                    521:                ip_lock(port);
                    522: 
                    523:                if (!ip_active(port)) {
                    524:                        ip_release(port);
                    525:                        ip_check_unlock(port);
                    526:                        break;
                    527:                }
                    528: 
                    529:                dnrequest = ipc_right_dncancel_macro(space, port, 
                    530:                                        name, entry);
                    531: 
                    532:                if (type & MACH_PORT_TYPE_SEND) {
                    533:                        assert(port->ip_srights > 0);
                    534:                        if (--port->ip_srights == 0
                    535:                            ) {
                    536:                                nsrequest = port->ip_nsrequest;
                    537:                                if (nsrequest != IP_NULL) {
                    538:                                        port->ip_nsrequest = IP_NULL;
                    539:                                        mscount = port->ip_mscount;
                    540:                                }
                    541:                        }
                    542:                }
                    543: 
                    544:                if (type & MACH_PORT_TYPE_RECEIVE) {
                    545:                        assert(port->ip_receiver_name == name);
                    546:                        assert(port->ip_receiver == space);
                    547: 
                    548:                        ipc_port_clear_receiver(port);
                    549:                        ipc_port_destroy(port); /* consumes our ref, unlocks */
                    550:                } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
                    551:                        assert(port->ip_sorights > 0);
                    552:                        ip_unlock(port);
                    553: 
                    554:                        ipc_notify_send_once(port); /* consumes our ref */
                    555:                } else {
                    556:                        assert(port->ip_receiver != space);
                    557: 
                    558:                        ip_release(port);
                    559:                        ip_unlock(port); /* port is active */
                    560:                }
                    561: 
                    562:                if (nsrequest != IP_NULL)
                    563:                        ipc_notify_no_senders(nsrequest, mscount);
                    564: 
                    565:                if (dnrequest != IP_NULL)
                    566:                        ipc_notify_port_deleted(dnrequest, name);
                    567:                break;
                    568:            }
                    569: 
                    570:            default:
                    571:                panic("ipc_right_clean: strange type");
                    572:        }
                    573: }
                    574: 
                    575: /*
                    576:  *     Routine:        ipc_right_destroy
                    577:  *     Purpose:
                    578:  *             Destroys an entry in a space.
                    579:  *     Conditions:
                    580:  *             The space is write-locked.
                    581:  *             The space must be active.
                    582:  *     Returns:
                    583:  *             KERN_SUCCESS            The entry was destroyed.
                    584:  */
                    585: 
                    586: kern_return_t
                    587: ipc_right_destroy(
                    588:        ipc_space_t             space,
                    589:        mach_port_name_t        name,
                    590:        ipc_entry_t             entry)
                    591: {
                    592:        ipc_entry_bits_t bits;
                    593:        mach_port_type_t type;
                    594: 
                    595:        bits = entry->ie_bits;
                    596:        entry->ie_bits &= ~IE_BITS_TYPE_MASK;
                    597:        type = IE_BITS_TYPE(bits);
                    598: 
                    599:        assert(space->is_active);
                    600: 
                    601:        switch (type) {
                    602:            case MACH_PORT_TYPE_DEAD_NAME:
                    603:                assert(entry->ie_request == 0);
                    604:                assert(entry->ie_object == IO_NULL);
                    605: 
                    606:                ipc_entry_dealloc(space, name, entry);
                    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(pset != IPS_NULL);
                    614: 
                    615:                entry->ie_object = IO_NULL;
                    616:                /* port sets are not sharable entries on a subspace basis */
                    617:                /* so there is no need to check the subspace array here   */
                    618:                ipc_entry_dealloc(space, name, entry);
                    619: 
                    620:                ips_lock(pset);
                    621:                assert(ips_active(pset));
                    622: 
                    623:                ipc_pset_destroy(pset); /* consumes ref, unlocks */
                    624:                break;
                    625:            }
                    626: 
                    627:            case MACH_PORT_TYPE_SEND:
                    628:            case MACH_PORT_TYPE_RECEIVE:
                    629:            case MACH_PORT_TYPE_SEND_RECEIVE:
                    630:            case MACH_PORT_TYPE_SEND_ONCE: {
                    631:                ipc_port_t port = (ipc_port_t) entry->ie_object;
                    632:                ipc_port_t nsrequest = IP_NULL;
                    633:                mach_port_mscount_t mscount;
                    634:                ipc_port_t dnrequest;
                    635: 
                    636:                assert(port != IP_NULL);
                    637: 
                    638:                if (type == MACH_PORT_TYPE_SEND)
                    639:                        ipc_hash_delete(space, (ipc_object_t) port,
                    640:                                        name, entry);
                    641: 
                    642:                ip_lock(port);
                    643: 
                    644:                if (!ip_active(port)) {
                    645:                        assert((type & MACH_PORT_TYPE_RECEIVE) == 0);
                    646:                        ip_release(port);
                    647:                        ip_check_unlock(port);
                    648: 
                    649:                        entry->ie_request = 0;
                    650:                        entry->ie_object = IO_NULL;
                    651:                        ipc_entry_dealloc(space, name, entry);
                    652: 
                    653:                        break;
                    654:                }
                    655: 
                    656:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                    657: 
                    658:                entry->ie_object = IO_NULL;
                    659:                ipc_entry_dealloc(space, name, entry);
                    660: 
                    661:                if (type & MACH_PORT_TYPE_SEND) {
                    662:                        assert(port->ip_srights > 0);
                    663:                        if (--port->ip_srights == 0) {
                    664:                                nsrequest = port->ip_nsrequest;
                    665:                                if (nsrequest != IP_NULL) {
                    666:                                        port->ip_nsrequest = IP_NULL;
                    667:                                        mscount = port->ip_mscount;
                    668:                                }
                    669:                        }
                    670:                }
                    671: 
                    672:                if (type & MACH_PORT_TYPE_RECEIVE) {
                    673:                        assert(ip_active(port));
                    674:                        assert(port->ip_receiver == space);
                    675: 
                    676:                        if (port->ip_subsystem)
                    677:                                subsystem_deallocate(
                    678:                                        port->ip_subsystem->subsystem);
                    679:                        ipc_port_clear_receiver(port);
                    680:                        ipc_port_destroy(port); /* consumes our ref, unlocks */
                    681:                } else if (type & MACH_PORT_TYPE_SEND_ONCE) {
                    682:                        assert(port->ip_sorights > 0);
                    683:                        ip_unlock(port);
                    684: 
                    685:                        ipc_notify_send_once(port); /* consumes our ref */
                    686:                } else {
                    687:                        assert(port->ip_receiver != space);
                    688: 
                    689:                        ip_release(port);
                    690:                        ip_unlock(port);
                    691:                }
                    692: 
                    693:                if (nsrequest != IP_NULL)
                    694:                        ipc_notify_no_senders(nsrequest, mscount);
                    695: 
                    696:                if (dnrequest != IP_NULL)
                    697:                        ipc_notify_port_deleted(dnrequest, name);
                    698:                break;
                    699:            }
                    700: 
                    701:            default:
                    702:                panic("ipc_right_destroy: strange type");
                    703:        }
                    704: 
                    705:        return KERN_SUCCESS;
                    706: }
                    707: 
                    708: /*
                    709:  *     Routine:        ipc_right_dealloc
                    710:  *     Purpose:
                    711:  *             Releases a send/send-once/dead-name user ref.
                    712:  *             Like ipc_right_delta with a delta of -1,
                    713:  *             but looks at the entry to determine the right.
                    714:  *     Conditions:
                    715:  *             The space is write-locked, and is unlocked upon return.
                    716:  *             The space must be active.
                    717:  *     Returns:
                    718:  *             KERN_SUCCESS            A user ref was released.
                    719:  *             KERN_INVALID_RIGHT      Entry has wrong type.
                    720:  */
                    721: 
                    722: kern_return_t
                    723: ipc_right_dealloc(
                    724:        ipc_space_t             space,
                    725:        mach_port_name_t        name,
                    726:        ipc_entry_t             entry)
                    727: {
                    728: 
                    729:        ipc_entry_bits_t bits;
                    730:        mach_port_type_t type;
                    731: 
                    732:        bits = entry->ie_bits;
                    733:        type = IE_BITS_TYPE(bits);
                    734: 
                    735: 
                    736:        assert(space->is_active);
                    737: 
                    738:        switch (type) {
                    739:            case MACH_PORT_TYPE_DEAD_NAME: {
                    740:            dead_name:
                    741: 
                    742:                assert(IE_BITS_UREFS(bits) > 0);
                    743:                assert(entry->ie_request == 0);
                    744:                assert(entry->ie_object == IO_NULL);
                    745: 
                    746:                if (IE_BITS_UREFS(bits) == 1) {
                    747:                        ipc_entry_dealloc(space, name, entry);
                    748:                }
                    749:                else
                    750:                        entry->ie_bits = bits-1; /* decrement urefs */
                    751: 
                    752:                is_write_unlock(space);
                    753:                break;
                    754:            }
                    755: 
                    756:            case MACH_PORT_TYPE_SEND_ONCE: {
                    757:                ipc_port_t port, dnrequest;
                    758: 
                    759:                assert(IE_BITS_UREFS(bits) == 1);
                    760: 
                    761:                port = (ipc_port_t) entry->ie_object;
                    762:                assert(port != IP_NULL);
                    763: 
                    764:                if (ipc_right_check(space, port, name, entry)) {
                    765: 
                    766:                        bits = entry->ie_bits;
                    767:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                    768:                        goto dead_name;
                    769:                }
                    770:                /* port is locked and active */
                    771: 
                    772:                assert(port->ip_sorights > 0);
                    773: 
                    774:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                    775:                ip_unlock(port);
                    776: 
                    777:                entry->ie_object = IO_NULL;
                    778:                ipc_entry_dealloc(space, name, entry);
                    779: 
                    780:                is_write_unlock(space);
                    781: 
                    782:                ipc_notify_send_once(port);
                    783: 
                    784:                if (dnrequest != IP_NULL)
                    785:                        ipc_notify_port_deleted(dnrequest, name);
                    786:                break;
                    787:            }
                    788: 
                    789:            case MACH_PORT_TYPE_SEND: {
                    790:                ipc_port_t port;
                    791:                ipc_port_t dnrequest = IP_NULL;
                    792:                ipc_port_t nsrequest = IP_NULL;
                    793:                mach_port_mscount_t mscount;
                    794: 
                    795: 
                    796:                assert(IE_BITS_UREFS(bits) > 0);
                    797: 
                    798:                port = (ipc_port_t) entry->ie_object;
                    799:                assert(port != IP_NULL);
                    800: 
                    801:                if (ipc_right_check(space, port, name, entry)) {
                    802:                        bits = entry->ie_bits;
                    803:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                    804:                        goto dead_name;
                    805:                }
                    806:                /* port is locked and active */
                    807: 
                    808:                assert(port->ip_srights > 0);
                    809: 
                    810:                if (IE_BITS_UREFS(bits) == 1) {
                    811:                        if (--port->ip_srights == 0) {
                    812:                                nsrequest = port->ip_nsrequest;
                    813:                                if (nsrequest != IP_NULL) {
                    814:                                        port->ip_nsrequest = IP_NULL;
                    815:                                        mscount = port->ip_mscount;
                    816:                                }
                    817:                        }
                    818: 
                    819:                        dnrequest = ipc_right_dncancel_macro(space, port,
                    820:                                                             name, entry);
                    821:                        ipc_hash_delete(space, (ipc_object_t) port,
                    822:                                        name, entry);
                    823: 
                    824:                        ip_release(port);
                    825:                        entry->ie_object = IO_NULL;
                    826:                        ipc_entry_dealloc(space, name, entry);
                    827: 
                    828:                } else
                    829:                        entry->ie_bits = bits-1; /* decrement urefs */
                    830: 
                    831:                /* even if dropped a ref, port is active */
                    832:                ip_unlock(port);
                    833:                is_write_unlock(space);
                    834: 
                    835:                if (nsrequest != IP_NULL)
                    836:                        ipc_notify_no_senders(nsrequest, mscount);
                    837: 
                    838:                if (dnrequest != IP_NULL)
                    839:                        ipc_notify_port_deleted(dnrequest, name);
                    840:                break;
                    841:            }
                    842: 
                    843:            case MACH_PORT_TYPE_SEND_RECEIVE: {
                    844:                ipc_port_t port;
                    845:                ipc_port_t nsrequest = IP_NULL;
                    846:                mach_port_mscount_t mscount;
                    847: 
                    848:                assert(IE_BITS_UREFS(bits) > 0);
                    849: 
                    850:                port = (ipc_port_t) entry->ie_object;
                    851:                assert(port != IP_NULL);
                    852: 
                    853:                ip_lock(port);
                    854:                assert(ip_active(port));
                    855:                assert(port->ip_receiver_name == name);
                    856:                assert(port->ip_receiver == space);
                    857:                assert(port->ip_srights > 0);
                    858: 
                    859:                if (IE_BITS_UREFS(bits) == 1) {
                    860:                        if (--port->ip_srights == 0) {
                    861:                                nsrequest = port->ip_nsrequest;
                    862:                                if (nsrequest != IP_NULL) {
                    863:                                        port->ip_nsrequest = IP_NULL;
                    864:                                        mscount = port->ip_mscount;
                    865:                                }
                    866:                        }
                    867: 
                    868:                        entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK |
                    869:                                                  MACH_PORT_TYPE_SEND);
                    870:                } else
                    871:                        entry->ie_bits = bits-1; /* decrement urefs */
                    872: 
                    873:                ip_unlock(port);
                    874:                is_write_unlock(space);
                    875: 
                    876:                if (nsrequest != IP_NULL)
                    877:                        ipc_notify_no_senders(nsrequest, mscount);
                    878:                break;
                    879:            }
                    880: 
                    881:            default:
                    882:                is_write_unlock(space);
                    883:                return KERN_INVALID_RIGHT;
                    884:        }
                    885: 
                    886:        return KERN_SUCCESS;
                    887: }
                    888: 
                    889: /*
                    890:  *     Routine:        ipc_right_delta
                    891:  *     Purpose:
                    892:  *             Modifies the user-reference count for a right.
                    893:  *             May deallocate the right, if the count goes to zero.
                    894:  *     Conditions:
                    895:  *             The space is write-locked, and is unlocked upon return.
                    896:  *             The space must be active.
                    897:  *     Returns:
                    898:  *             KERN_SUCCESS            Count was modified.
                    899:  *             KERN_INVALID_RIGHT      Entry has wrong type.
                    900:  *             KERN_INVALID_VALUE      Bad delta for the right.
                    901:  *             KERN_UREFS_OVERFLOW     OK delta, except would overflow.
                    902:  */
                    903: 
                    904: kern_return_t
                    905: ipc_right_delta(
                    906:        ipc_space_t             space,
                    907:        mach_port_name_t        name,
                    908:        ipc_entry_t             entry,
                    909:        mach_port_right_t       right,
                    910:        mach_port_delta_t       delta)
                    911: {
                    912:        ipc_entry_bits_t bits;
                    913:        
                    914:        bits = entry->ie_bits;
                    915: 
                    916: 
                    917: /*
                    918:  *     The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the
                    919:  *     switch below. It is used to keep track of those cases (in DIPC)
                    920:  *     where we have postponed the dropping of a port reference. Since
                    921:  *     the dropping of the reference could cause the port to disappear
                    922:  *     we postpone doing so when we are holding the space lock.
                    923:  */
                    924: 
                    925:        assert(space->is_active);
                    926:        assert(right < MACH_PORT_RIGHT_NUMBER);
                    927: 
                    928:        /* Rights-specific restrictions and operations. */
                    929: 
                    930:        switch (right) {
                    931:            case MACH_PORT_RIGHT_PORT_SET: {
                    932:                ipc_pset_t pset;
                    933: 
                    934:                if ((bits & MACH_PORT_TYPE_PORT_SET) == 0)
                    935:                        goto invalid_right;
                    936: 
                    937:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET);
                    938:                assert(IE_BITS_UREFS(bits) == 0);
                    939:                assert(entry->ie_request == 0);
                    940: 
                    941:                if (delta == 0)
                    942:                        goto success;
                    943: 
                    944:                if (delta != -1)
                    945:                        goto invalid_value;
                    946: 
                    947:                pset = (ipc_pset_t) entry->ie_object;
                    948:                assert(pset != IPS_NULL);
                    949: 
                    950: 
                    951: 
                    952:                entry->ie_object = IO_NULL;
                    953:                ipc_entry_dealloc(space, name, entry);
                    954: 
                    955: 
                    956:                ips_lock(pset);
                    957:                assert(ips_active(pset));
                    958:                is_write_unlock(space);
                    959: 
                    960:                ipc_pset_destroy(pset); /* consumes ref, unlocks */
                    961:                break;
                    962:            }
                    963: 
                    964:            case MACH_PORT_RIGHT_RECEIVE: {
                    965:                ipc_port_t port;
                    966:                ipc_port_t dnrequest = IP_NULL;
                    967: 
                    968:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                    969:                        goto invalid_right;
                    970: 
                    971:                if (delta == 0)
                    972:                        goto success;
                    973: 
                    974:                if (delta != -1)
                    975:                        goto invalid_value;
                    976: 
                    977:                port = (ipc_port_t) entry->ie_object;
                    978:                assert(port != IP_NULL);
                    979: 
                    980:                /*
                    981:                 *      The port lock is needed for ipc_right_dncancel;
                    982:                 *      otherwise, we wouldn't have to take the lock
                    983:                 *      until just before dropping the space lock.
                    984:                 */
                    985: 
                    986:                ip_lock(port);
                    987:                assert(ip_active(port));
                    988:                assert(port->ip_receiver_name == name);
                    989:                assert(port->ip_receiver == space);
                    990: 
                    991:                if (bits & MACH_PORT_TYPE_SEND) {
                    992:                        assert(IE_BITS_TYPE(bits) ==
                    993:                                        MACH_PORT_TYPE_SEND_RECEIVE);
                    994:                        assert(IE_BITS_UREFS(bits) > 0);
                    995:                        assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
                    996:                        assert(port->ip_srights > 0);
                    997: 
                    998:                        /*
                    999:                         *      The remaining send right turns into a
                   1000:                         *      dead name.  Notice we don't decrement
                   1001:                         *      ip_srights, generate a no-senders notif,
                   1002:                         *      or use ipc_right_dncancel, because the
                   1003:                         *      port is destroyed "first".
                   1004:                         */
                   1005:                        bits &= ~IE_BITS_TYPE_MASK;
                   1006:                        bits |= MACH_PORT_TYPE_DEAD_NAME;
                   1007:                        if (entry->ie_request) {
                   1008:                                entry->ie_request = 0;
                   1009:                                bits++;
                   1010:                        }
                   1011:                        entry->ie_bits = bits;
                   1012:                        entry->ie_object = IO_NULL;
                   1013:                } else {
                   1014:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                   1015:                        assert(IE_BITS_UREFS(bits) == 0);
                   1016: 
                   1017:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   1018:                                                             name, entry);
                   1019:                        entry->ie_object = IO_NULL;
                   1020:                        ipc_entry_dealloc(space, name, entry);
                   1021:                }
                   1022:                is_write_unlock(space);
                   1023: 
                   1024:                ipc_port_clear_receiver(port);
                   1025:                ipc_port_destroy(port); /* consumes ref, unlocks */
                   1026: 
                   1027:                if (dnrequest != IP_NULL)
                   1028:                        ipc_notify_port_deleted(dnrequest, name);
                   1029:                break;
                   1030:            }
                   1031: 
                   1032:            case MACH_PORT_RIGHT_SEND_ONCE: {
                   1033:                ipc_port_t port, dnrequest;
                   1034: 
                   1035:                if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
                   1036:                        goto invalid_right;
                   1037: 
                   1038:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1039:                assert(IE_BITS_UREFS(bits) == 1);
                   1040: 
                   1041:                port = (ipc_port_t) entry->ie_object;
                   1042:                assert(port != IP_NULL);
                   1043: 
                   1044:                if (ipc_right_check(space, port, name, entry)) {
                   1045:                        assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE));
                   1046:                        goto invalid_right;
                   1047:                }
                   1048:                /* port is locked and active */
                   1049: 
                   1050:                assert(port->ip_sorights > 0);
                   1051: 
                   1052:                if ((delta > 0) || (delta < -1)) {
                   1053:                        ip_unlock(port);
                   1054:                        goto invalid_value;
                   1055:                }
                   1056: 
                   1057:                if (delta == 0) {
                   1058:                        ip_unlock(port);
                   1059:                        goto success;
                   1060:                }
                   1061: 
                   1062:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                   1063:                ip_unlock(port);
                   1064: 
                   1065:                entry->ie_object = IO_NULL;
                   1066:                ipc_entry_dealloc(space, name, entry);
                   1067: 
                   1068:                is_write_unlock(space);
                   1069: 
                   1070:                ipc_notify_send_once(port);
                   1071: 
                   1072:                if (dnrequest != IP_NULL)
                   1073:                        ipc_notify_port_deleted(dnrequest, name);
                   1074:                break;
                   1075:            }
                   1076: 
                   1077:            case MACH_PORT_RIGHT_DEAD_NAME: {
                   1078:                mach_port_urefs_t urefs;
                   1079: 
                   1080:                if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
                   1081:                        ipc_port_t port;
                   1082: 
                   1083:                        port = (ipc_port_t) entry->ie_object;
                   1084:                        assert(port != IP_NULL);
                   1085: 
                   1086:                        if (!ipc_right_check(space, port, name, entry)) {
                   1087:                                /* port is locked and active */
                   1088:                                ip_unlock(port);
                   1089:                                goto invalid_right;
                   1090:                        }
                   1091:                        bits = entry->ie_bits;
                   1092:                } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0)
                   1093:                        goto invalid_right;
                   1094: 
                   1095:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1096:                assert(IE_BITS_UREFS(bits) > 0);
                   1097:                assert(entry->ie_object == IO_NULL);
                   1098:                assert(entry->ie_request == 0);
                   1099: 
                   1100:                urefs = IE_BITS_UREFS(bits);
                   1101:                if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta))
                   1102:                        goto invalid_value;
                   1103:                if (MACH_PORT_UREFS_OVERFLOW(urefs, delta))
                   1104:                        goto urefs_overflow;
                   1105: 
                   1106:                if ((urefs + delta) == 0) {
                   1107:                        ipc_entry_dealloc(space, name, entry);
                   1108:                }
                   1109:                else
                   1110:                        entry->ie_bits = bits + delta;
                   1111: 
                   1112:                is_write_unlock(space);
                   1113: 
                   1114:                break;
                   1115:            }
                   1116: 
                   1117:            case MACH_PORT_RIGHT_SEND: {
                   1118:                mach_port_urefs_t urefs;
                   1119:                ipc_port_t port;
                   1120:                ipc_port_t dnrequest = IP_NULL;
                   1121:                ipc_port_t nsrequest = IP_NULL;
                   1122:                mach_port_mscount_t mscount;
                   1123: 
                   1124:                if ((bits & MACH_PORT_TYPE_SEND) == 0)
                   1125:                        goto invalid_right;
                   1126: 
                   1127:                /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */
                   1128: 
                   1129:                port = (ipc_port_t) entry->ie_object;
                   1130:                assert(port != IP_NULL);
                   1131: 
                   1132:                if (ipc_right_check(space, port, name, entry)) {
                   1133:                        assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0);
                   1134:                        goto invalid_right;
                   1135:                }
                   1136:                /* port is locked and active */
                   1137: 
                   1138:                assert(port->ip_srights > 0);
                   1139: 
                   1140:                urefs = IE_BITS_UREFS(bits);
                   1141:                if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) {
                   1142:                        ip_unlock(port);
                   1143:                        goto invalid_value;
                   1144:                }
                   1145:                if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) {
                   1146:                        ip_unlock(port);
                   1147:                        goto urefs_overflow;
                   1148:                }
                   1149: 
                   1150:                if ((urefs + delta) == 0) {
                   1151:                        if (--port->ip_srights == 0) {
                   1152:                                nsrequest = port->ip_nsrequest;
                   1153:                                if (nsrequest != IP_NULL) {
                   1154:                                        port->ip_nsrequest = IP_NULL;
                   1155:                                        mscount = port->ip_mscount;
                   1156:                                }
                   1157:                        }
                   1158: 
                   1159:                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1160:                                assert(port->ip_receiver_name == name);
                   1161:                                assert(port->ip_receiver == space);
                   1162:                                assert(IE_BITS_TYPE(bits) ==
                   1163:                                                MACH_PORT_TYPE_SEND_RECEIVE);
                   1164: 
                   1165:                                entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|
                   1166:                                                       MACH_PORT_TYPE_SEND);
                   1167:                        } else {
                   1168:                                assert(IE_BITS_TYPE(bits) ==
                   1169:                                                MACH_PORT_TYPE_SEND);
                   1170: 
                   1171:                                dnrequest = ipc_right_dncancel_macro(space, port,
                   1172:                                                                     name, entry);
                   1173:                                ipc_hash_delete(space, (ipc_object_t) port,
                   1174:                                                name, entry);
                   1175: 
                   1176:                                ip_release(port);
                   1177: 
                   1178:                                entry->ie_object = IO_NULL;
                   1179:                                ipc_entry_dealloc(space, name, entry);
                   1180:                        }
                   1181:                } else
                   1182:                        entry->ie_bits = bits + delta;
                   1183: 
                   1184:                /* even if dropped a ref, port is active */
                   1185:                ip_unlock(port);
                   1186:                is_write_unlock(space);
                   1187: 
                   1188:                if (nsrequest != IP_NULL)
                   1189:                        ipc_notify_no_senders(nsrequest, mscount);
                   1190: 
                   1191:                if (dnrequest != IP_NULL)
                   1192:                        ipc_notify_port_deleted(dnrequest, name);
                   1193:                break;
                   1194:            }
                   1195: 
                   1196:            default:
                   1197:                panic("ipc_right_delta: strange right");
                   1198:        }
                   1199: 
                   1200:        return KERN_SUCCESS;
                   1201: 
                   1202:     success:
                   1203:        is_write_unlock(space);
                   1204:        return KERN_SUCCESS;
                   1205: 
                   1206:     invalid_right:
                   1207:        is_write_unlock(space);
                   1208:        return KERN_INVALID_RIGHT;
                   1209: 
                   1210:     invalid_value:
                   1211:        is_write_unlock(space);
                   1212:        return KERN_INVALID_VALUE;
                   1213: 
                   1214:     urefs_overflow:
                   1215:        is_write_unlock(space);
                   1216:        return KERN_UREFS_OVERFLOW;
                   1217: }
                   1218: 
                   1219: /*
                   1220:  *     Routine:        ipc_right_info
                   1221:  *     Purpose:
                   1222:  *             Retrieves information about the right.
                   1223:  *     Conditions:
                   1224:  *             The space is write-locked, and is unlocked upon return
                   1225:  *             if the call is unsuccessful.  The space must be active.
                   1226:  *     Returns:
                   1227:  *             KERN_SUCCESS            Retrieved info; space still locked.
                   1228:  */
                   1229: 
                   1230: kern_return_t
                   1231: ipc_right_info(
                   1232:        ipc_space_t             space,
                   1233:        mach_port_name_t        name,
                   1234:        ipc_entry_t             entry,
                   1235:        mach_port_type_t        *typep,
                   1236:        mach_port_urefs_t       *urefsp)
                   1237: {
                   1238:        ipc_entry_bits_t bits;
                   1239:        mach_port_type_t type;
                   1240:        ipc_port_request_index_t request;
                   1241: 
                   1242:        bits = entry->ie_bits;
                   1243: 
                   1244:        if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
                   1245:                ipc_port_t port = (ipc_port_t) entry->ie_object;
                   1246: 
                   1247:                if (ipc_right_check(space, port, name, entry)) {
                   1248:                        bits = entry->ie_bits;
                   1249:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1250:                } else
                   1251:                        ip_unlock(port);
                   1252:        }
                   1253: 
                   1254:        type = IE_BITS_TYPE(bits);
                   1255:        request = entry->ie_request;
                   1256: 
                   1257:        if (request != 0)
                   1258:                type |= MACH_PORT_TYPE_DNREQUEST;
                   1259: 
                   1260:        *typep = type;
                   1261:        *urefsp = IE_BITS_UREFS(bits);
                   1262:        return KERN_SUCCESS;
                   1263: }
                   1264: 
                   1265: /*
                   1266:  *     Routine:        ipc_right_copyin_check
                   1267:  *     Purpose:
                   1268:  *             Check if a subsequent ipc_right_copyin would succeed.
                   1269:  *     Conditions:
                   1270:  *             The space is locked (read or write) and active.
                   1271:  */
                   1272: 
                   1273: boolean_t
                   1274: ipc_right_copyin_check(
                   1275:        ipc_space_t             space,
                   1276:        mach_port_name_t        name,
                   1277:        ipc_entry_t             entry,
                   1278:        mach_msg_type_name_t    msgt_name)
                   1279: {
                   1280:        ipc_entry_bits_t bits;
                   1281: 
                   1282:        bits= entry->ie_bits;
                   1283:        assert(space->is_active);
                   1284: 
                   1285:        switch (msgt_name) {
                   1286:            case MACH_MSG_TYPE_MAKE_SEND:
                   1287:            case MACH_MSG_TYPE_MAKE_SEND_ONCE:
                   1288:            case MACH_MSG_TYPE_MOVE_RECEIVE:
                   1289:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1290:                        return FALSE;
                   1291: 
                   1292:                break;
                   1293: 
                   1294:            case MACH_MSG_TYPE_COPY_SEND:
                   1295:            case MACH_MSG_TYPE_MOVE_SEND:
                   1296:            case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
                   1297:                ipc_port_t port;
                   1298:                boolean_t active;
                   1299: 
                   1300:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1301:                        break;
                   1302: 
                   1303:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1304:                        return FALSE;
                   1305: 
                   1306:                port = (ipc_port_t) entry->ie_object;
                   1307:                assert(port != IP_NULL);
                   1308: 
                   1309:                ip_lock(port);
                   1310:                active = ip_active(port);
                   1311:                ip_unlock(port);
                   1312: 
                   1313:                if (!active) {
                   1314:                        break;
                   1315:                }
                   1316: 
                   1317:                if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
                   1318:                        if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0)
                   1319:                                return FALSE;
                   1320:                } else {
                   1321:                        if ((bits & MACH_PORT_TYPE_SEND) == 0)
                   1322:                                return FALSE;
                   1323:                }
                   1324: 
                   1325:                break;
                   1326:            }
                   1327: 
                   1328:            default:
                   1329:                panic("ipc_right_copyin_check: strange rights");
                   1330:        }
                   1331: 
                   1332:        return TRUE;
                   1333: }
                   1334: 
                   1335: /*
                   1336:  *     Routine:        ipc_right_copyin
                   1337:  *     Purpose:
                   1338:  *             Copyin a capability from a space.
                   1339:  *             If successful, the caller gets a ref
                   1340:  *             for the resulting object, unless it is IO_DEAD,
                   1341:  *             and possibly a send-once right which should
                   1342:  *             be used in a port-deleted notification.
                   1343:  *
                   1344:  *             If deadok is not TRUE, the copyin operation
                   1345:  *             will fail instead of producing IO_DEAD.
                   1346:  *
                   1347:  *             The entry is never deallocated (except
                   1348:  *             when KERN_INVALID_NAME), so the caller
                   1349:  *             should deallocate the entry if its type
                   1350:  *             is MACH_PORT_TYPE_NONE.
                   1351:  *     Conditions:
                   1352:  *             The space is write-locked and active.
                   1353:  *     Returns:
                   1354:  *             KERN_SUCCESS            Acquired an object, possibly IO_DEAD.
                   1355:  *             KERN_INVALID_RIGHT      Name doesn't denote correct right.
                   1356:  */
                   1357: 
                   1358: kern_return_t
                   1359: ipc_right_copyin(
                   1360:        ipc_space_t             space,
                   1361:        mach_port_name_t        name,
                   1362:        ipc_entry_t             entry,
                   1363:        mach_msg_type_name_t    msgt_name,
                   1364:        boolean_t               deadok,
                   1365:        ipc_object_t            *objectp,
                   1366:        ipc_port_t              *sorightp)
                   1367: {
                   1368:        ipc_entry_bits_t bits;
                   1369:        
                   1370:        bits = entry->ie_bits;
                   1371: 
                   1372:        assert(space->is_active);
                   1373: 
                   1374:        switch (msgt_name) {
                   1375:            case MACH_MSG_TYPE_MAKE_SEND: {
                   1376:                ipc_port_t port;
                   1377: 
                   1378:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1379:                        goto invalid_right;
                   1380: 
                   1381:                port = (ipc_port_t) entry->ie_object;
                   1382:                assert(port != IP_NULL);
                   1383: 
                   1384:                ip_lock(port);
                   1385:                assert(ip_active(port));
                   1386:                assert(port->ip_receiver_name == name);
                   1387:                assert(port->ip_receiver == space);
                   1388: 
                   1389:                port->ip_mscount++;
                   1390:                port->ip_srights++;
                   1391:                ip_reference(port);
                   1392:                ip_unlock(port);
                   1393: 
                   1394:                *objectp = (ipc_object_t) port;
                   1395:                *sorightp = IP_NULL;
                   1396:                break;
                   1397:            }
                   1398: 
                   1399:            case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
                   1400:                ipc_port_t port;
                   1401: 
                   1402:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1403:                        goto invalid_right;
                   1404: 
                   1405:                port = (ipc_port_t) entry->ie_object;
                   1406:                assert(port != IP_NULL);
                   1407: 
                   1408:                ip_lock(port);
                   1409:                assert(ip_active(port));
                   1410:                assert(port->ip_receiver_name == name);
                   1411:                assert(port->ip_receiver == space);
                   1412: 
                   1413:                port->ip_sorights++;
                   1414:                ip_reference(port);
                   1415:                ip_unlock(port);
                   1416: 
                   1417:                *objectp = (ipc_object_t) port;
                   1418:                *sorightp = IP_NULL;
                   1419:                break;
                   1420:            }
                   1421: 
                   1422:            case MACH_MSG_TYPE_MOVE_RECEIVE: {
                   1423:                ipc_port_t port;
                   1424:                ipc_port_t dnrequest = IP_NULL;
                   1425: 
                   1426:                if ((bits & MACH_PORT_TYPE_RECEIVE) == 0)
                   1427:                        goto invalid_right;
                   1428: 
                   1429:                port = (ipc_port_t) entry->ie_object;
                   1430:                assert(port != IP_NULL);
                   1431: 
                   1432:                ip_lock(port);
                   1433:                assert(ip_active(port));
                   1434:                assert(port->ip_receiver_name == name);
                   1435:                assert(port->ip_receiver == space);
                   1436: 
                   1437:                if (bits & MACH_PORT_TYPE_SEND) {
                   1438:                        assert(IE_BITS_TYPE(bits) ==
                   1439:                                        MACH_PORT_TYPE_SEND_RECEIVE);
                   1440:                        assert(IE_BITS_UREFS(bits) > 0);
                   1441:                        assert(port->ip_srights > 0);
                   1442: 
                   1443:                        ipc_hash_insert(space, (ipc_object_t) port,
                   1444:                                        name, entry);
                   1445:                        ip_reference(port);
                   1446:                } else {
                   1447:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                   1448:                        assert(IE_BITS_UREFS(bits) == 0);
                   1449: 
                   1450:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   1451:                                                             name, entry);
                   1452:                        entry->ie_object = IO_NULL;
                   1453:                }
                   1454:                entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE;
                   1455: 
                   1456:                ipc_port_clear_receiver(port);
                   1457: 
                   1458:                port->ip_receiver_name = MACH_PORT_NULL;
                   1459:                port->ip_destination = IP_NULL;
                   1460:                ip_unlock(port);
                   1461: 
                   1462:                *objectp = (ipc_object_t) port;
                   1463:                *sorightp = dnrequest;
                   1464:                break;
                   1465:            }
                   1466: 
                   1467:            case MACH_MSG_TYPE_COPY_SEND: {
                   1468:                ipc_port_t port;
                   1469: 
                   1470:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1471:                        goto copy_dead;
                   1472: 
                   1473:                /* allow for dead send-once rights */
                   1474: 
                   1475:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1476:                        goto invalid_right;
                   1477: 
                   1478:                assert(IE_BITS_UREFS(bits) > 0);
                   1479: 
                   1480:                port = (ipc_port_t) entry->ie_object;
                   1481:                assert(port != IP_NULL);
                   1482: 
                   1483:                if (ipc_right_check(space, port, name, entry)) {
                   1484:                        bits = entry->ie_bits;
                   1485:                        goto copy_dead;
                   1486:                }
                   1487:                /* port is locked and active */
                   1488: 
                   1489:                if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                   1490:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1491:                        assert(port->ip_sorights > 0);
                   1492: 
                   1493:                        ip_unlock(port);
                   1494:                        goto invalid_right;
                   1495:                }
                   1496: 
                   1497:                assert(port->ip_srights > 0);
                   1498: 
                   1499:                port->ip_srights++;
                   1500:                ip_reference(port);
                   1501:                ip_unlock(port);
                   1502: 
                   1503:                *objectp = (ipc_object_t) port;
                   1504:                *sorightp = IP_NULL;
                   1505:                break;
                   1506:            }
                   1507: 
                   1508:            case MACH_MSG_TYPE_MOVE_SEND: {
                   1509:                ipc_port_t port;
                   1510:                ipc_port_t dnrequest = IP_NULL;
                   1511: 
                   1512:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1513:                        goto move_dead;
                   1514: 
                   1515:                /* allow for dead send-once rights */
                   1516: 
                   1517:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1518:                        goto invalid_right;
                   1519: 
                   1520:                assert(IE_BITS_UREFS(bits) > 0);
                   1521: 
                   1522:                port = (ipc_port_t) entry->ie_object;
                   1523:                assert(port != IP_NULL);
                   1524: 
                   1525:                if (ipc_right_check(space, port, name, entry)) {
                   1526:                        bits = entry->ie_bits;
                   1527:                        goto move_dead;
                   1528:                }
                   1529:                /* port is locked and active */
                   1530: 
                   1531:                if ((bits & MACH_PORT_TYPE_SEND) == 0) {
                   1532:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1533:                        assert(port->ip_sorights > 0);
                   1534: 
                   1535:                        ip_unlock(port);
                   1536:                        goto invalid_right;
                   1537:                }
                   1538: 
                   1539:                assert(port->ip_srights > 0);
                   1540: 
                   1541:                if (IE_BITS_UREFS(bits) == 1) {
                   1542:                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1543:                                assert(port->ip_receiver_name == name);
                   1544:                                assert(port->ip_receiver == space);
                   1545:                                assert(IE_BITS_TYPE(bits) ==
                   1546:                                                MACH_PORT_TYPE_SEND_RECEIVE);
                   1547: 
                   1548:                                ip_reference(port);
                   1549:                        } else {
                   1550:                                assert(IE_BITS_TYPE(bits) ==
                   1551:                                                MACH_PORT_TYPE_SEND);
                   1552: 
                   1553:                                dnrequest = ipc_right_dncancel_macro(space, port,
                   1554:                                                                     name, entry);
                   1555:                                ipc_hash_delete(space, (ipc_object_t) port,
                   1556:                                                name, entry);
                   1557:                                entry->ie_object = IO_NULL;
                   1558:                        }
                   1559:                        entry->ie_bits = bits &~
                   1560:                                (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
                   1561:                } else {
                   1562:                        port->ip_srights++;
                   1563:                        ip_reference(port);
                   1564:                        entry->ie_bits = bits-1; /* decrement urefs */
                   1565:                }
                   1566: 
                   1567:                ip_unlock(port);
                   1568: 
                   1569:                *objectp = (ipc_object_t) port;
                   1570:                *sorightp = dnrequest;
                   1571:                break;
                   1572:            }
                   1573: 
                   1574:            case MACH_MSG_TYPE_MOVE_SEND_ONCE: {
                   1575:                ipc_port_t port;
                   1576:                ipc_port_t dnrequest;
                   1577: 
                   1578:                if (bits & MACH_PORT_TYPE_DEAD_NAME)
                   1579:                        goto move_dead;
                   1580: 
                   1581:                /* allow for dead send rights */
                   1582: 
                   1583:                if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0)
                   1584:                        goto invalid_right;
                   1585: 
                   1586:                assert(IE_BITS_UREFS(bits) > 0);
                   1587: 
                   1588:                port = (ipc_port_t) entry->ie_object;
                   1589:                assert(port != IP_NULL);
                   1590: 
                   1591:                if (ipc_right_check(space, port, name, entry)) {
                   1592:                        bits = entry->ie_bits;
                   1593:                        goto move_dead;
                   1594:                }
                   1595:                /* port is locked and active */
                   1596: 
                   1597:                if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) {
                   1598:                        assert(bits & MACH_PORT_TYPE_SEND);
                   1599:                        assert(port->ip_srights > 0);
                   1600: 
                   1601:                        ip_unlock(port);
                   1602:                        goto invalid_right;
                   1603:                }
                   1604: 
                   1605:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
                   1606:                assert(IE_BITS_UREFS(bits) == 1);
                   1607:                assert(port->ip_sorights > 0);
                   1608: 
                   1609:                dnrequest = ipc_right_dncancel_macro(space, port, name, entry);
                   1610:                ip_unlock(port);
                   1611: 
                   1612:                entry->ie_object = IO_NULL;
                   1613:                entry->ie_bits = bits &~
                   1614:                        (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE);
                   1615: 
                   1616:                *objectp = (ipc_object_t) port;
                   1617:                *sorightp = dnrequest;
                   1618:                break;
                   1619:            }
                   1620: 
                   1621:            default:
                   1622:                panic("ipc_right_copyin: strange rights");
                   1623:        }
                   1624: 
                   1625:        return KERN_SUCCESS;
                   1626: 
                   1627:     copy_dead:
                   1628:        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1629:        assert(IE_BITS_UREFS(bits) > 0);
                   1630:        assert(entry->ie_request == 0);
                   1631:        assert(entry->ie_object == 0);
                   1632: 
                   1633:        if (!deadok)
                   1634:                goto invalid_right;
                   1635: 
                   1636:        *objectp = IO_DEAD;
                   1637:        *sorightp = IP_NULL;
                   1638:        return KERN_SUCCESS;
                   1639: 
                   1640:     move_dead:
                   1641:        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   1642:        assert(IE_BITS_UREFS(bits) > 0);
                   1643:        assert(entry->ie_request == 0);
                   1644:        assert(entry->ie_object == 0);
                   1645: 
                   1646:        if (!deadok)
                   1647:                goto invalid_right;
                   1648: 
                   1649:        if (IE_BITS_UREFS(bits) == 1) {
                   1650:                bits &= ~MACH_PORT_TYPE_DEAD_NAME;
                   1651:        }
                   1652:        entry->ie_bits = bits-1; /* decrement urefs */
                   1653: 
                   1654:        *objectp = IO_DEAD;
                   1655:        *sorightp = IP_NULL;
                   1656:        return KERN_SUCCESS;
                   1657: 
                   1658:     invalid_right:
                   1659:        return KERN_INVALID_RIGHT;
                   1660: }
                   1661: 
                   1662: /*
                   1663:  *     Routine:        ipc_right_copyin_undo
                   1664:  *     Purpose:
                   1665:  *             Undoes the effects of an ipc_right_copyin
                   1666:  *             of a send/send-once right that is dead.
                   1667:  *             (Object is either IO_DEAD or a dead port.)
                   1668:  *     Conditions:
                   1669:  *             The space is write-locked and active.
                   1670:  */
                   1671: 
                   1672: void
                   1673: ipc_right_copyin_undo(
                   1674:        ipc_space_t             space,
                   1675:        mach_port_name_t        name,
                   1676:        ipc_entry_t             entry,
                   1677:        mach_msg_type_name_t    msgt_name,
                   1678:        ipc_object_t            object,
                   1679:        ipc_port_t              soright)
                   1680: {
                   1681:        ipc_entry_bits_t bits;
                   1682: 
                   1683:        bits = entry->ie_bits;
                   1684: 
                   1685:        assert(space->is_active);
                   1686: 
                   1687:        assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1688:               (msgt_name == MACH_MSG_TYPE_COPY_SEND) ||
                   1689:               (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
                   1690: 
                   1691:        if (soright != IP_NULL) {
                   1692:                assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1693:                       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
                   1694:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   1695:                assert(object != IO_DEAD);
                   1696: 
                   1697:                entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
                   1698:                                  MACH_PORT_TYPE_DEAD_NAME | 2);
                   1699: 
                   1700:        } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) {
                   1701:                assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1702:                       (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE));
                   1703: 
                   1704:                entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) |
                   1705:                                  MACH_PORT_TYPE_DEAD_NAME | 1);
                   1706:        } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) {
                   1707:                assert(object == IO_DEAD);
                   1708:                assert(IE_BITS_UREFS(bits) > 0);
                   1709: 
                   1710:                if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
                   1711:                        assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX);
                   1712:                        entry->ie_bits = bits+1; /* increment urefs */
                   1713:                }
                   1714:        } else {
                   1715:                assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) ||
                   1716:                       (msgt_name == MACH_MSG_TYPE_COPY_SEND));
                   1717:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                   1718:                assert(object != IO_DEAD);
                   1719:                assert(entry->ie_object == object);
                   1720:                assert(IE_BITS_UREFS(bits) > 0);
                   1721: 
                   1722:                if (msgt_name != MACH_MSG_TYPE_COPY_SEND) {
                   1723:                        assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1);
                   1724:                        entry->ie_bits = bits+1; /* increment urefs */
                   1725:                }
                   1726: 
                   1727:                /*
                   1728:                 *      May as well convert the entry to a dead name.
                   1729:                 *      (Or if it is a compat entry, destroy it.)
                   1730:                 */
                   1731: 
                   1732:                (void) ipc_right_check(space, (ipc_port_t) object,
                   1733:                                       name, entry);
                   1734:                /* object is dead so it is not locked */
                   1735:        }
                   1736: 
                   1737:        /* release the reference acquired by copyin */
                   1738: 
                   1739:        if (object != IO_DEAD)
                   1740:                ipc_object_release(object);
                   1741: }
                   1742: 
                   1743: /*
                   1744:  *     Routine:        ipc_right_copyin_two
                   1745:  *     Purpose:
                   1746:  *             Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND
                   1747:  *             and deadok == FALSE, except that this moves two
                   1748:  *             send rights at once.
                   1749:  *     Conditions:
                   1750:  *             The space is write-locked and active.
                   1751:  *             The object is returned with two refs/send rights.
                   1752:  *     Returns:
                   1753:  *             KERN_SUCCESS            Acquired an object.
                   1754:  *             KERN_INVALID_RIGHT      Name doesn't denote correct right.
                   1755:  */
                   1756: 
                   1757: kern_return_t
                   1758: ipc_right_copyin_two(
                   1759:        ipc_space_t             space,
                   1760:        mach_port_name_t        name,
                   1761:        ipc_entry_t             entry,
                   1762:        ipc_object_t            *objectp,
                   1763:        ipc_port_t              *sorightp)
                   1764: {
                   1765:        ipc_entry_bits_t bits;
                   1766:        mach_port_urefs_t urefs;
                   1767:        ipc_port_t port;
                   1768:        ipc_port_t dnrequest = IP_NULL;
                   1769: 
                   1770:        assert(space->is_active);
                   1771: 
                   1772:        bits = entry->ie_bits;
                   1773: 
                   1774:        if ((bits & MACH_PORT_TYPE_SEND) == 0)
                   1775:                goto invalid_right;
                   1776: 
                   1777:        urefs = IE_BITS_UREFS(bits);
                   1778:        if (urefs < 2)
                   1779:                goto invalid_right;
                   1780: 
                   1781:        port = (ipc_port_t) entry->ie_object;
                   1782:        assert(port != IP_NULL);
                   1783: 
                   1784:        if (ipc_right_check(space, port, name, entry)) {
                   1785:                goto invalid_right;
                   1786:        }
                   1787:        /* port is locked and active */
                   1788: 
                   1789:        assert(port->ip_srights > 0);
                   1790: 
                   1791:        if (urefs == 2) {
                   1792:                if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1793:                        assert(port->ip_receiver_name == name);
                   1794:                        assert(port->ip_receiver == space);
                   1795:                        assert(IE_BITS_TYPE(bits) ==
                   1796:                                        MACH_PORT_TYPE_SEND_RECEIVE);
                   1797: 
                   1798:                        port->ip_srights++;
                   1799:                        ip_reference(port);
                   1800:                        ip_reference(port);
                   1801:                } else {
                   1802:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                   1803: 
                   1804:                        dnrequest = ipc_right_dncancel_macro(space, port,
                   1805:                                                             name, entry);
                   1806: 
                   1807:                        port->ip_srights++;
                   1808:                        ip_reference(port);
                   1809:                        ipc_hash_delete(space, (ipc_object_t) port,
                   1810:                                        name, entry);
                   1811:                        entry->ie_object = IO_NULL;
                   1812:                }
                   1813:                entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND);
                   1814:        } else {
                   1815:                port->ip_srights += 2;
                   1816:                ip_reference(port);
                   1817:                ip_reference(port);
                   1818:                entry->ie_bits = bits-2; /* decrement urefs */
                   1819:        }
                   1820:        ip_unlock(port);
                   1821: 
                   1822:        *objectp = (ipc_object_t) port;
                   1823:        *sorightp = dnrequest;
                   1824:        return KERN_SUCCESS;
                   1825: 
                   1826:     invalid_right:
                   1827:        return KERN_INVALID_RIGHT;
                   1828: }
                   1829: 
                   1830: /*
                   1831:  *     Routine:        ipc_right_copyout
                   1832:  *     Purpose:
                   1833:  *             Copyout a capability to a space.
                   1834:  *             If successful, consumes a ref for the object.
                   1835:  *
                   1836:  *             Always succeeds when given a newly-allocated entry,
                   1837:  *             because user-reference overflow isn't a possibility.
                   1838:  *
                   1839:  *             If copying out the object would cause the user-reference
                   1840:  *             count in the entry to overflow, and overflow is TRUE,
                   1841:  *             then instead the user-reference count is left pegged
                   1842:  *             to its maximum value and the copyout succeeds anyway.
                   1843:  *     Conditions:
                   1844:  *             The space is write-locked and active.
                   1845:  *             The object is locked and active.
                   1846:  *             The object is unlocked; the space isn't.
                   1847:  *     Returns:
                   1848:  *             KERN_SUCCESS            Copied out capability.
                   1849:  *             KERN_UREFS_OVERFLOW     User-refs would overflow;
                   1850:  *                     guaranteed not to happen with a fresh entry
                   1851:  *                     or if overflow=TRUE was specified.
                   1852:  */
                   1853: 
                   1854: kern_return_t
                   1855: ipc_right_copyout(
                   1856:        ipc_space_t             space,
                   1857:        mach_port_name_t        name,
                   1858:        ipc_entry_t             entry,
                   1859:        mach_msg_type_name_t    msgt_name,
                   1860:        boolean_t               overflow,
                   1861:        ipc_object_t            object)
                   1862: {
                   1863:        ipc_entry_bits_t bits;
                   1864:        ipc_port_t port;
                   1865: 
                   1866:        bits = entry->ie_bits;
                   1867: 
                   1868:        assert(IO_VALID(object));
                   1869:        assert(io_otype(object) == IOT_PORT);
                   1870:        assert(io_active(object));
                   1871:        assert(entry->ie_object == object);
                   1872: 
                   1873:        port = (ipc_port_t) object;
                   1874: 
                   1875:        switch (msgt_name) {
                   1876:            case MACH_MSG_TYPE_PORT_SEND_ONCE:
                   1877:                
                   1878:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   1879:                assert(port->ip_sorights > 0);
                   1880: 
                   1881:                /* transfer send-once right and ref to entry */
                   1882:                ip_unlock(port);
                   1883: 
                   1884:                entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1);
                   1885:                break;
                   1886: 
                   1887:            case MACH_MSG_TYPE_PORT_SEND:
                   1888:                assert(port->ip_srights > 0);
                   1889: 
                   1890:                if (bits & MACH_PORT_TYPE_SEND) {
                   1891:                        mach_port_urefs_t urefs = IE_BITS_UREFS(bits);
                   1892: 
                   1893:                        assert(port->ip_srights > 1);
                   1894:                        assert(urefs > 0);
                   1895:                        assert(urefs < MACH_PORT_UREFS_MAX);
                   1896: 
                   1897:                        if (urefs+1 == MACH_PORT_UREFS_MAX) {
                   1898:                                if (overflow) {
                   1899:                                        /* leave urefs pegged to maximum */
                   1900: 
                   1901:                                        port->ip_srights--;
                   1902:                                        ip_release(port);
                   1903:                                        ip_unlock(port);
                   1904:                                        return KERN_SUCCESS;
                   1905:                                }
                   1906: 
                   1907:                                ip_unlock(port);
                   1908:                                return KERN_UREFS_OVERFLOW;
                   1909:                        }
                   1910: 
                   1911:                        port->ip_srights--;
                   1912:                        ip_release(port);
                   1913:                        ip_unlock(port);
                   1914:                } else if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1915:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE);
                   1916:                        assert(IE_BITS_UREFS(bits) == 0);
                   1917: 
                   1918:                        /* transfer send right to entry */
                   1919:                        ip_release(port);
                   1920:                        ip_unlock(port);
                   1921:                } else {
                   1922:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   1923:                        assert(IE_BITS_UREFS(bits) == 0);
                   1924: 
                   1925:                        /* transfer send right and ref to entry */
                   1926:                        ip_unlock(port);
                   1927: 
                   1928:                        /* entry is locked holding ref, so can use port */
                   1929: 
                   1930:                        ipc_hash_insert(space, (ipc_object_t) port,
                   1931:                                        name, entry);
                   1932:                }
                   1933: 
                   1934:                entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1;
                   1935:                break;
                   1936: 
                   1937:            case MACH_MSG_TYPE_PORT_RECEIVE: {
                   1938:                ipc_port_t dest;
                   1939: 
                   1940:                assert(port->ip_mscount == 0);
                   1941:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                   1942:                dest = port->ip_destination;
                   1943: 
                   1944:                port->ip_receiver_name = name;
                   1945:                port->ip_receiver = space;
                   1946: 
                   1947:                assert((bits & MACH_PORT_TYPE_RECEIVE) == 0);
                   1948: 
                   1949:                if (bits & MACH_PORT_TYPE_SEND) {
                   1950:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND);
                   1951:                        assert(IE_BITS_UREFS(bits) > 0);
                   1952:                        assert(port->ip_srights > 0);
                   1953: 
                   1954:                        ip_release(port);
                   1955:                        ip_unlock(port);
                   1956: 
                   1957:                        /* entry is locked holding ref, so can use port */
                   1958: 
                   1959:                        ipc_hash_delete(space, (ipc_object_t) port,
                   1960:                                        name, entry);
                   1961:                } else {
                   1962:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE);
                   1963:                        assert(IE_BITS_UREFS(bits) == 0);
                   1964: 
                   1965:                        /* transfer ref to entry */
                   1966:                        ip_unlock(port);
                   1967:                }
                   1968:                entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE;
                   1969: 
                   1970:                if (dest != IP_NULL)
                   1971:                        ipc_port_release(dest);
                   1972:                break;
                   1973:            }
                   1974: 
                   1975:            default:
                   1976:                panic("ipc_right_copyout: strange rights");
                   1977:        }
                   1978: 
                   1979:        return KERN_SUCCESS;
                   1980: }
                   1981: 
                   1982: /*
                   1983:  *     Routine:        ipc_right_rename
                   1984:  *     Purpose:
                   1985:  *             Transfer an entry from one name to another.
                   1986:  *             The old entry is deallocated.
                   1987:  *     Conditions:
                   1988:  *             The space is write-locked and active.
                   1989:  *             The new entry is unused.  Upon return,
                   1990:  *             the space is unlocked.
                   1991:  *     Returns:
                   1992:  *             KERN_SUCCESS            Moved entry to new name.
                   1993:  */
                   1994: 
                   1995: kern_return_t
                   1996: ipc_right_rename(
                   1997:        ipc_space_t             space,
                   1998:        mach_port_name_t        oname,
                   1999:        ipc_entry_t             oentry,
                   2000:        mach_port_name_t        nname,
                   2001:        ipc_entry_t             nentry)
                   2002: {
                   2003:        ipc_port_request_index_t request = oentry->ie_request;
                   2004:        ipc_entry_bits_t bits = oentry->ie_bits;
                   2005:        ipc_object_t object = oentry->ie_object;
                   2006: 
                   2007:        assert(space->is_active);
                   2008:        assert(oname != nname);
                   2009: 
                   2010:        /*
                   2011:         *      If IE_BITS_COMPAT, we can't allow the entry to be renamed
                   2012:         *      if the port is dead.  (This would foil ipc_port_destroy.)
                   2013:         *      Instead we should fail because oentry shouldn't exist.
                   2014:         *      Note IE_BITS_COMPAT implies ie_request != 0.
                   2015:         */
                   2016: 
                   2017:        if (request != 0) {
                   2018:                ipc_port_t port;
                   2019: 
                   2020:                assert(bits & MACH_PORT_TYPE_PORT_RIGHTS);
                   2021:                port = (ipc_port_t) object;
                   2022:                assert(port != IP_NULL);
                   2023: 
                   2024:                if (ipc_right_check(space, port, oname, oentry)) {
                   2025:                        request = 0;
                   2026:                        object = IO_NULL;
                   2027:                        bits = oentry->ie_bits;
                   2028:                        assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME);
                   2029:                        assert(oentry->ie_request == 0);
                   2030:                } else {
                   2031:                        /* port is locked and active */
                   2032: 
                   2033:                        ipc_port_dnrename(port, request, oname, nname);
                   2034:                        ip_unlock(port);
                   2035:                        oentry->ie_request = 0;
                   2036:                }
                   2037:        }
                   2038: 
                   2039:        /* initialize nentry before letting ipc_hash_insert see it */
                   2040: 
                   2041:        assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0);
                   2042:        nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK;
                   2043:        nentry->ie_request = request;
                   2044:        nentry->ie_object = object;
                   2045: 
                   2046:        switch (IE_BITS_TYPE(bits)) {
                   2047:            case MACH_PORT_TYPE_SEND: {
                   2048:                ipc_port_t port;
                   2049: 
                   2050:                port = (ipc_port_t) object;
                   2051:                assert(port != IP_NULL);
                   2052: 
                   2053:                /* remember, there are no other share entries possible */
                   2054:                /* or we can't do the rename.  Therefore we do not need */
                   2055:                /* to check the other subspaces */
                   2056:                ipc_hash_delete(space, (ipc_object_t) port, oname, oentry);
                   2057:                ipc_hash_insert(space, (ipc_object_t) port, nname, nentry);
                   2058:                break;
                   2059:            }
                   2060: 
                   2061:            case MACH_PORT_TYPE_RECEIVE:
                   2062:            case MACH_PORT_TYPE_SEND_RECEIVE: {
                   2063:                ipc_port_t port;
                   2064: 
                   2065:                port = (ipc_port_t) object;
                   2066:                assert(port != IP_NULL);
                   2067: 
                   2068:                ip_lock(port);
                   2069:                assert(ip_active(port));
                   2070:                assert(port->ip_receiver_name == oname);
                   2071:                assert(port->ip_receiver == space);
                   2072: 
                   2073:                port->ip_receiver_name = nname;
                   2074:                ip_unlock(port);
                   2075:                break;
                   2076:            }
                   2077: 
                   2078:            case MACH_PORT_TYPE_PORT_SET: {
                   2079:                ipc_pset_t pset;
                   2080: 
                   2081:                pset = (ipc_pset_t) object;
                   2082:                assert(pset != IPS_NULL);
                   2083: 
                   2084:                ips_lock(pset);
                   2085:                assert(ips_active(pset));
                   2086:                assert(pset->ips_local_name == oname);
                   2087: 
                   2088:                pset->ips_local_name = nname;
                   2089:                ips_unlock(pset);
                   2090:                break;
                   2091:            }
                   2092: 
                   2093:            case MACH_PORT_TYPE_SEND_ONCE:
                   2094:            case MACH_PORT_TYPE_DEAD_NAME:
                   2095:                break;
                   2096: 
                   2097:            default:
                   2098:                panic("ipc_right_rename: strange rights");
                   2099:        }
                   2100: 
                   2101:        assert(oentry->ie_request == 0);
                   2102:        oentry->ie_object = IO_NULL;
                   2103:        ipc_entry_dealloc(space, oname, oentry);
                   2104:        is_write_unlock(space);
                   2105: 
                   2106:        return KERN_SUCCESS;
                   2107: }

unix.superglobalmegacorp.com

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