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

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

unix.superglobalmegacorp.com

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