The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_right.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 25c48d80634ae45feb1e9ce674c4d441


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.