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

Cache object: f678518163920d4e0fbfc94e38cb2500


[ 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.