Annotation of XNU/osfmk/ipc/ipc_right.c, revision 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.