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/mach_port.c

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

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        mach_port.c,v $
   29  * Revision 2.10  93/11/17  17:04:59  dbg
   30  *      Added ANSI function prototypes.
   31  *      [93/09/24            dbg]
   32  * 
   33  * Revision 2.9  92/08/03  17:36:24  jfriedl
   34  *      removed silly prototypes
   35  *      [92/08/02            jfriedl]
   36  * 
   37  * Revision 2.8  92/05/21  17:12:31  jfriedl
   38  *      Added some things to quiet gcc warnings.
   39  *      Also made correct for when assert is off.
   40  *      [92/05/16            jfriedl]
   41  * 
   42  * Revision 2.7  92/02/23  19:52:46  elf
   43  *      Eliminate keep_wired argument from vm_map_copyin().
   44  *      [92/02/21  10:13:34  dlb]
   45  * 
   46  * Revision 2.6  91/10/09  16:11:42  af
   47  *      Added <ipc/ipc_notify.h>.
   48  *      [91/09/02            rpd]
   49  * 
   50  * Revision 2.5  91/08/28  11:14:04  jsb
   51  *      Added mach_port_set_seqno and updated mach_port_get_receive_status
   52  *      for mps_seqno.  Added old_mach_port_get_receive_status.
   53  *      [91/08/09            rpd]
   54  *      Changed port_names for new vm_map_copyout failure behavior.
   55  *      [91/08/03            rpd]
   56  * 
   57  * Revision 2.4  91/05/14  16:39:20  mrt
   58  *      Correcting copyright
   59  * 
   60  * Revision 2.3  91/02/05  17:25:06  mrt
   61  *      Changed to new Mach copyright
   62  *      [91/02/01  15:53:35  mrt]
   63  * 
   64  * Revision 2.2  90/06/02  14:52:28  rpd
   65  *      Modified mach_port_get_receive_status to return a mach_port_status_t.
   66  *      [90/05/13            rpd]
   67  *      Created for new IPC.
   68  *      [90/03/26  21:06:13  rpd]
   69  * 
   70  */
   71 /*
   72  *      File:   ipc/mach_port.c
   73  *      Author: Rich Draves
   74  *      Date:   1989
   75  *
   76  *      Exported kernel calls.  See mach/mach_port.defs.
   77  */
   78 
   79 #include <mach_ipc_compat.h>
   80 
   81 #include <mach/port.h>
   82 #include <mach/kern_return.h>
   83 #include <mach/notify.h>
   84 #include <mach/vm_param.h>
   85 #include <mach/vm_prot.h>
   86 #include <vm/vm_map.h>
   87 #include <vm/vm_kern.h>
   88 #include <vm/vm_user.h>
   89 #include <ipc/ipc_entry.h>
   90 #include <ipc/ipc_space.h>
   91 #include <ipc/ipc_object.h>
   92 #include <ipc/ipc_notify.h>
   93 #include <ipc/ipc_port.h>
   94 #include <ipc/ipc_pset.h>
   95 #include <ipc/ipc_right.h>
   96 
   97 
   98 
   99 /*
  100  *      Routine:        mach_port_names_helper
  101  *      Purpose:
  102  *              A helper function for mach_port_names.
  103  */
  104 
  105 void
  106 mach_port_names_helper(
  107         ipc_port_timestamp_t timestamp,
  108         ipc_entry_t entry,
  109         mach_port_t name,
  110         mach_port_t *names,
  111         mach_port_type_t *types,
  112         ipc_entry_num_t *actualp)
  113 {
  114         ipc_entry_bits_t bits = entry->ie_bits;
  115         ipc_port_request_index_t request = entry->ie_request;
  116         mach_port_type_t type;
  117         ipc_entry_num_t actual;
  118 
  119         if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
  120                 ipc_port_t port;
  121                 boolean_t died;
  122 
  123                 port = (ipc_port_t) entry->ie_object;
  124                 assert(port != IP_NULL);
  125 
  126                 /*
  127                  *      The timestamp serializes mach_port_names
  128                  *      with ipc_port_destroy.  If the port died,
  129                  *      but after mach_port_names started, pretend
  130                  *      that it isn't dead.
  131                  */
  132 
  133                 ip_lock(port);
  134                 died = (!ip_active(port) &&
  135                         IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
  136                 ip_unlock(port);
  137 
  138                 if (died) {
  139 #if     MACH_IPC_COMPAT
  140                         if (bits & IE_BITS_COMPAT)
  141                                 return;
  142 #endif  /* MACH_IPC_COMPAT */
  143 
  144                         /* pretend this is a dead-name entry */
  145 
  146                         bits &= ~(IE_BITS_TYPE_MASK|IE_BITS_MAREQUEST);
  147                         bits |= MACH_PORT_TYPE_DEAD_NAME;
  148                         if (request != 0)
  149                                 bits++;
  150                         request = 0;
  151                 }
  152         }
  153 
  154         type = IE_BITS_TYPE(bits);
  155 #if     MACH_IPC_COMPAT
  156         if (bits & IE_BITS_COMPAT)
  157                 type |= MACH_PORT_TYPE_COMPAT;
  158         else
  159 #endif  /* MACH_IPC_COMPAT */
  160         if (request != 0)
  161                 type |= MACH_PORT_TYPE_DNREQUEST;
  162         if (bits & IE_BITS_MAREQUEST)
  163                 type |= MACH_PORT_TYPE_MAREQUEST;
  164 
  165         actual = *actualp;
  166         names[actual] = name;
  167         types[actual] = type;
  168         *actualp = actual+1;
  169 }
  170 
  171 /*
  172  *      Routine:        mach_port_names [kernel call]
  173  *      Purpose:
  174  *              Retrieves a list of the rights present in the space,
  175  *              along with type information.  (Same as returned
  176  *              by mach_port_type.)  The names are returned in
  177  *              no particular order, but they (and the type info)
  178  *              are an accurate snapshot of the space.
  179  *      Conditions:
  180  *              Nothing locked.
  181  *      Returns:
  182  *              KERN_SUCCESS            Arrays of names and types returned.
  183  *              KERN_INVALID_TASK       The space is null.
  184  *              KERN_INVALID_TASK       The space is dead.
  185  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  186  */
  187 
  188 kern_return_t
  189 mach_port_names(
  190         ipc_space_t space,
  191         mach_port_t **namesp,
  192         mach_msg_type_number_t *namesCnt,
  193         mach_port_type_t **typesp,
  194         mach_msg_type_number_t *typesCnt)
  195 {
  196         ipc_tree_entry_t tentry;
  197         ipc_entry_t table;
  198         ipc_entry_num_t tsize;
  199         mach_port_index_t index;
  200         ipc_entry_num_t actual; /* this many names */
  201         ipc_port_timestamp_t timestamp; /* logical time of this operation */
  202         mach_port_t *names;
  203         mach_port_type_t *types;
  204         kern_return_t kr;
  205 
  206         vm_size_t size;         /* size of allocated memory */
  207         vm_offset_t addr1;      /* allocated memory, for names */
  208         vm_offset_t addr2;      /* allocated memory, for types */
  209         vm_map_copy_t memory1;  /* copied-in memory, for names */
  210         vm_map_copy_t memory2;  /* copied-in memory, for types */
  211 
  212         /* safe simplifying assumption */
  213         assert_static(sizeof(mach_port_t) == sizeof(mach_port_type_t));
  214 
  215         if (space == IS_NULL)
  216                 return KERN_INVALID_TASK;
  217 
  218         size = 0;
  219 
  220         for (;;) {
  221                 ipc_entry_num_t bound;
  222                 vm_size_t size_needed;
  223 
  224                 is_read_lock(space);
  225                 if (!space->is_active) {
  226                         is_read_unlock(space);
  227                         if (size != 0) {
  228                                 kmem_free(ipc_kernel_map, addr1, size);
  229                                 kmem_free(ipc_kernel_map, addr2, size);
  230                         }
  231                         return KERN_INVALID_TASK;
  232                 }
  233 
  234                 /* upper bound on number of names in the space */
  235 
  236                 bound = space->is_table_size + space->is_tree_total;
  237                 size_needed = round_page(bound * sizeof(mach_port_t));
  238 
  239                 if (size_needed <= size)
  240                         break;
  241 
  242                 is_read_unlock(space);
  243 
  244                 if (size != 0) {
  245                         kmem_free(ipc_kernel_map, addr1, size);
  246                         kmem_free(ipc_kernel_map, addr2, size);
  247                 }
  248                 size = size_needed;
  249 
  250                 kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE);
  251                 if (kr != KERN_SUCCESS)
  252                         return KERN_RESOURCE_SHORTAGE;
  253 
  254                 kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE);
  255                 if (kr != KERN_SUCCESS) {
  256                         kmem_free(ipc_kernel_map, addr1, size);
  257                         return KERN_RESOURCE_SHORTAGE;
  258                 }
  259 
  260                 /* can't fault while we hold locks */
  261 
  262                 kr = vm_map_pageable(ipc_kernel_map, addr1, addr1 + size,
  263                                      VM_PROT_READ|VM_PROT_WRITE);
  264                 assert(kr == KERN_SUCCESS);
  265 
  266                 kr = vm_map_pageable(ipc_kernel_map, addr2, addr2 + size,
  267                                      VM_PROT_READ|VM_PROT_WRITE);
  268                 assert(kr == KERN_SUCCESS);
  269         }
  270         /* space is read-locked and active */
  271 
  272         names = (mach_port_t *) addr1;
  273         types = (mach_port_type_t *) addr2;
  274         actual = 0;
  275 
  276         timestamp = ipc_port_timestamp();
  277 
  278         table = space->is_table;
  279         tsize = space->is_table_size;
  280 
  281         for (index = 0; index < tsize; index++) {
  282                 ipc_entry_t entry = &table[index];
  283                 ipc_entry_bits_t bits = entry->ie_bits;
  284 
  285                 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
  286                         mach_port_t name = MACH_PORT_MAKEB(index, bits);
  287 
  288                         mach_port_names_helper(timestamp, entry, name,
  289                                                names, types, &actual);
  290                 }
  291         }
  292 
  293         for (tentry = ipc_splay_traverse_start(&space->is_tree);
  294              tentry != ITE_NULL;
  295              tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
  296                 ipc_entry_t entry = &tentry->ite_entry;
  297                 mach_port_t name = tentry->ite_name;
  298 
  299                 assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE);
  300 
  301                 mach_port_names_helper(timestamp, entry, name,
  302                                        names, types, &actual);
  303         }
  304         ipc_splay_traverse_finish(&space->is_tree);
  305         is_read_unlock(space);
  306 
  307         if (actual == 0) {
  308                 memory1 = VM_MAP_COPY_NULL;
  309                 memory2 = VM_MAP_COPY_NULL;
  310 
  311                 if (size != 0) {
  312                         kmem_free(ipc_kernel_map, addr1, size);
  313                         kmem_free(ipc_kernel_map, addr2, size);
  314                 }
  315         } else {
  316                 vm_size_t size_used;
  317 
  318                 size_used = round_page(actual * sizeof(mach_port_t));
  319 
  320                 /*
  321                  *      Make used memory pageable and get it into
  322                  *      copied-in form.  Free any unused memory.
  323                  */
  324 
  325                 kr = vm_map_pageable(ipc_kernel_map,
  326                                      addr1, addr1 + size_used,
  327                                      VM_PROT_NONE);
  328                 assert(kr == KERN_SUCCESS);
  329 
  330                 kr = vm_map_pageable(ipc_kernel_map,
  331                                      addr2, addr2 + size_used,
  332                                      VM_PROT_NONE);
  333                 assert(kr == KERN_SUCCESS);
  334 
  335                 kr = vm_map_copyin(ipc_kernel_map, addr1, size_used,
  336                                    TRUE, &memory1);
  337                 assert(kr == KERN_SUCCESS);
  338 
  339                 kr = vm_map_copyin(ipc_kernel_map, addr2, size_used,
  340                                    TRUE, &memory2);
  341                 assert(kr == KERN_SUCCESS);
  342 
  343                 if (size_used != size) {
  344                         kmem_free(ipc_kernel_map,
  345                                   addr1 + size_used, size - size_used);
  346                         kmem_free(ipc_kernel_map,
  347                                   addr2 + size_used, size - size_used);
  348                 }
  349         }
  350 
  351         *namesp = (mach_port_t *) memory1;
  352         *namesCnt = actual;
  353         *typesp = (mach_port_type_t *) memory2;
  354         *typesCnt = actual;
  355         return KERN_SUCCESS;
  356 }
  357 
  358 /*
  359  *      Routine:        mach_port_type [kernel call]
  360  *      Purpose:
  361  *              Retrieves the type of a right in the space.
  362  *              The type is a bitwise combination of one or more
  363  *              of the following type bits:
  364  *                      MACH_PORT_TYPE_SEND
  365  *                      MACH_PORT_TYPE_RECEIVE
  366  *                      MACH_PORT_TYPE_SEND_ONCE
  367  *                      MACH_PORT_TYPE_PORT_SET
  368  *                      MACH_PORT_TYPE_DEAD_NAME
  369  *              In addition, the following pseudo-type bits may be present:
  370  *                      MACH_PORT_TYPE_DNREQUEST
  371  *                              A dead-name notification is requested.
  372  *                      MACH_PORT_TYPE_MAREQUEST
  373  *                              The send/receive right is blocked;
  374  *                              a msg-accepted notification is outstanding.
  375  *                      MACH_PORT_TYPE_COMPAT
  376  *                              This is a compatibility-mode right;
  377  *                              when the port dies, it will disappear
  378  *                              instead of turning into a dead-name.
  379  *      Conditions:
  380  *              Nothing locked.
  381  *      Returns:
  382  *              KERN_SUCCESS            Type is returned.
  383  *              KERN_INVALID_TASK       The space is null.
  384  *              KERN_INVALID_TASK       The space is dead.
  385  *              KERN_INVALID_NAME       The name doesn't denote a right.
  386  */
  387 
  388 kern_return_t
  389 mach_port_type(
  390         ipc_space_t space,
  391         mach_port_t name,
  392         mach_port_type_t *typep)
  393 {
  394         mach_port_urefs_t urefs;
  395         ipc_entry_t entry;
  396         kern_return_t kr;
  397 
  398         if (space == IS_NULL)
  399                 return KERN_INVALID_TASK;
  400 
  401         kr = ipc_right_lookup_write(space, name, &entry);
  402         if (kr != KERN_SUCCESS)
  403                 return kr;
  404         /* space is write-locked and active */
  405 
  406         kr = ipc_right_info(space, name, entry, typep, &urefs);
  407         if (kr == KERN_SUCCESS)
  408                 is_write_unlock(space);
  409         /* space is unlocked */
  410         return kr;
  411 }
  412 
  413 /*
  414  *      Routine:        mach_port_rename [kernel call]
  415  *      Purpose:
  416  *              Changes the name denoting a right,
  417  *              from oname to nname.
  418  *      Conditions:
  419  *              Nothing locked.
  420  *      Returns:
  421  *              KERN_SUCCESS            The right is renamed.
  422  *              KERN_INVALID_TASK       The space is null.
  423  *              KERN_INVALID_TASK       The space is dead.
  424  *              KERN_INVALID_NAME       The oname doesn't denote a right.
  425  *              KERN_INVALID_VALUE      The nname isn't a legal name.
  426  *              KERN_NAME_EXISTS        The nname already denotes a right.
  427  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  428  */
  429 
  430 kern_return_t
  431 mach_port_rename(
  432         ipc_space_t space,
  433         mach_port_t oname,
  434         mach_port_t nname)
  435 {
  436         if (space == IS_NULL)
  437                 return KERN_INVALID_TASK;
  438 
  439         if (!MACH_PORT_VALID(nname))
  440                 return KERN_INVALID_VALUE;
  441 
  442         return ipc_object_rename(space, oname, nname);
  443 }
  444 
  445 /*
  446  *      Routine:        mach_port_allocate_name [kernel call]
  447  *      Purpose:
  448  *              Allocates a right in a space, using a specific name
  449  *              for the new right.  Possible rights:
  450  *                      MACH_PORT_RIGHT_RECEIVE
  451  *                      MACH_PORT_RIGHT_PORT_SET
  452  *                      MACH_PORT_RIGHT_DEAD_NAME
  453  *
  454  *              A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
  455  *              has no extant send or send-once rights and no queued
  456  *              messages.  Its queue limit is MACH_PORT_QLIMIT_DEFAULT
  457  *              and its make-send count is 0.  It is not a member of
  458  *              a port set.  It has no registered no-senders or
  459  *              port-destroyed notification requests.
  460  *
  461  *              A new port set has no members.
  462  *
  463  *              A new dead name has one user reference.
  464  *      Conditions:
  465  *              Nothing locked.
  466  *      Returns:
  467  *              KERN_SUCCESS            The right is allocated.
  468  *              KERN_INVALID_TASK       The space is null.
  469  *              KERN_INVALID_TASK       The space is dead.
  470  *              KERN_INVALID_VALUE      The name isn't a legal name.
  471  *              KERN_INVALID_VALUE      "right" isn't a legal kind of right.
  472  *              KERN_NAME_EXISTS        The name already denotes a right.
  473  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  474  */
  475 
  476 kern_return_t
  477 mach_port_allocate_name(
  478         ipc_space_t space,
  479         mach_port_right_t right,
  480         mach_port_t name)
  481 {
  482         kern_return_t kr;
  483 
  484         if (space == IS_NULL)
  485                 return KERN_INVALID_TASK;
  486 
  487         if (!MACH_PORT_VALID(name))
  488                 return KERN_INVALID_VALUE;
  489 
  490         switch (right) {
  491             case MACH_PORT_RIGHT_RECEIVE: {
  492                 ipc_port_t port;
  493 
  494                 kr = ipc_port_alloc_name(space, name, &port);
  495                 if (kr == KERN_SUCCESS)
  496                         ip_unlock(port);
  497                 break;
  498             }
  499 
  500             case MACH_PORT_RIGHT_PORT_SET: {
  501                 ipc_pset_t pset;
  502 
  503                 kr = ipc_pset_alloc_name(space, name, &pset);
  504                 if (kr == KERN_SUCCESS)
  505                         ips_unlock(pset);
  506                 break;
  507             }
  508 
  509             case MACH_PORT_RIGHT_DEAD_NAME:
  510                 kr = ipc_object_alloc_dead_name(space, name);
  511                 break;
  512 
  513             default:
  514                 kr = KERN_INVALID_VALUE;
  515                 break;
  516         }
  517 
  518         return kr;
  519 }
  520 
  521 /*
  522  *      Routine:        mach_port_allocate [kernel call]
  523  *      Purpose:
  524  *              Allocates a right in a space.  Like mach_port_allocate_name,
  525  *              except that the implementation picks a name for the right.
  526  *              The name may be any legal name in the space that doesn't
  527  *              currently denote a right.
  528  *      Conditions:
  529  *              Nothing locked.
  530  *      Returns:
  531  *              KERN_SUCCESS            The right is allocated.
  532  *              KERN_INVALID_TASK       The space is null.
  533  *              KERN_INVALID_TASK       The space is dead.
  534  *              KERN_INVALID_VALUE      "right" isn't a legal kind of right.
  535  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  536  *              KERN_NO_SPACE           No room in space for another right.
  537  */
  538 
  539 kern_return_t
  540 mach_port_allocate(
  541         ipc_space_t space,
  542         mach_port_right_t right,
  543         mach_port_t *namep)
  544 {
  545         kern_return_t kr;
  546 
  547         if (space == IS_NULL)
  548                 return KERN_INVALID_TASK;
  549 
  550         switch (right) {
  551             case MACH_PORT_RIGHT_RECEIVE: {
  552                 ipc_port_t port;
  553 
  554                 kr = ipc_port_alloc(space, namep, &port);
  555                 if (kr == KERN_SUCCESS)
  556                         ip_unlock(port);
  557                 break;
  558             }
  559 
  560             case MACH_PORT_RIGHT_PORT_SET: {
  561                 ipc_pset_t pset;
  562 
  563                 kr = ipc_pset_alloc(space, namep, &pset);
  564                 if (kr == KERN_SUCCESS)
  565                         ips_unlock(pset);
  566                 break;
  567             }
  568 
  569             case MACH_PORT_RIGHT_DEAD_NAME:
  570                 kr = ipc_object_alloc_dead(space, namep);
  571                 break;
  572 
  573             default:
  574                 kr = KERN_INVALID_VALUE;
  575                 break;
  576         }
  577 
  578         return kr;
  579 }
  580 
  581 /*
  582  *      Routine:        mach_port_destroy [kernel call]
  583  *      Purpose:
  584  *              Cleans up and destroys all rights denoted by a name
  585  *              in a space.  The destruction of a receive right
  586  *              destroys the port, unless a port-destroyed request
  587  *              has been made for it; the destruction of a port-set right
  588  *              destroys the port set.
  589  *      Conditions:
  590  *              Nothing locked.
  591  *      Returns:
  592  *              KERN_SUCCESS            The name is destroyed.
  593  *              KERN_INVALID_TASK       The space is null.
  594  *              KERN_INVALID_TASK       The space is dead.
  595  *              KERN_INVALID_NAME       The name doesn't denote a right.
  596  */
  597 
  598 kern_return_t
  599 mach_port_destroy(
  600         ipc_space_t space,
  601         mach_port_t name)
  602 {
  603         ipc_entry_t entry;
  604         kern_return_t kr;
  605 
  606         if (space == IS_NULL)
  607                 return KERN_INVALID_TASK;
  608 
  609         kr = ipc_right_lookup_write(space, name, &entry);
  610         if (kr != KERN_SUCCESS)
  611                 return kr;
  612         /* space is write-locked and active */
  613 
  614         kr = ipc_right_destroy(space, name, entry); /* unlocks space */
  615         return kr;
  616 }
  617 
  618 /*
  619  *      Routine:        mach_port_deallocate [kernel call]
  620  *      Purpose:
  621  *              Deallocates a user reference from a send right,
  622  *              send-once right, or a dead-name right.  May
  623  *              deallocate the right, if this is the last uref,
  624  *              and destroy the name, if it doesn't denote
  625  *              other rights.
  626  *      Conditions:
  627  *              Nothing locked.
  628  *      Returns:
  629  *              KERN_SUCCESS            The uref is deallocated.
  630  *              KERN_INVALID_TASK       The space is null.
  631  *              KERN_INVALID_TASK       The space is dead.
  632  *              KERN_INVALID_NAME       The name doesn't denote a right.
  633  *              KERN_INVALID_RIGHT      The right isn't correct.
  634  */
  635 
  636 kern_return_t
  637 mach_port_deallocate(
  638         ipc_space_t space,
  639         mach_port_t name)
  640 {
  641         ipc_entry_t entry;
  642         kern_return_t kr;
  643 
  644         if (space == IS_NULL)
  645                 return KERN_INVALID_TASK;
  646 
  647         kr = ipc_right_lookup_write(space, name, &entry);
  648         if (kr != KERN_SUCCESS)
  649                 return kr;
  650         /* space is write-locked */
  651 
  652         kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
  653         return kr;
  654 }
  655 
  656 /*
  657  *      Routine:        mach_port_get_refs [kernel call]
  658  *      Purpose:
  659  *              Retrieves the number of user references held by a right.
  660  *              Receive rights, port-set rights, and send-once rights
  661  *              always have one user reference.  Returns zero if the
  662  *              name denotes a right, but not the queried right.
  663  *      Conditions:
  664  *              Nothing locked.
  665  *      Returns:
  666  *              KERN_SUCCESS            Number of urefs returned.
  667  *              KERN_INVALID_TASK       The space is null.
  668  *              KERN_INVALID_TASK       The space is dead.
  669  *              KERN_INVALID_VALUE      "right" isn't a legal value.
  670  *              KERN_INVALID_NAME       The name doesn't denote a right.
  671  */
  672 
  673 kern_return_t
  674 mach_port_get_refs(
  675         ipc_space_t space,
  676         mach_port_t name,
  677         mach_port_right_t right,
  678         mach_port_urefs_t *urefsp)
  679 {
  680         mach_port_type_t type;
  681         mach_port_urefs_t urefs;
  682         ipc_entry_t entry;
  683         kern_return_t kr;
  684 
  685         if (space == IS_NULL)
  686                 return KERN_INVALID_TASK;
  687 
  688         if (right >= MACH_PORT_RIGHT_NUMBER)
  689                 return KERN_INVALID_VALUE;
  690 
  691         kr = ipc_right_lookup_write(space, name, &entry);
  692         if (kr != KERN_SUCCESS)
  693                 return kr;
  694         /* space is write-locked and active */
  695 
  696         kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */
  697         if (kr != KERN_SUCCESS)
  698                 return kr;      /* space is unlocked */
  699         is_write_unlock(space);
  700 
  701         if (type & MACH_PORT_TYPE(right))
  702                 switch (right) {
  703                     case MACH_PORT_RIGHT_SEND_ONCE:
  704                         assert(urefs == 1);
  705                         /* fall-through */
  706 
  707                     case MACH_PORT_RIGHT_PORT_SET:
  708                     case MACH_PORT_RIGHT_RECEIVE:
  709                         *urefsp = 1;
  710                         break;
  711 
  712                     case MACH_PORT_RIGHT_DEAD_NAME:
  713                     case MACH_PORT_RIGHT_SEND:
  714                         assert(urefs > 0);
  715                         *urefsp = urefs;
  716                         break;
  717 
  718                     default:
  719 #if MACH_ASSERT
  720                         assert(!"mach_port_get_refs: strange rights");
  721 #else
  722                         panic("mach_port_get_refs: strange rights");
  723 #endif
  724                 }
  725         else
  726                 *urefsp = 0;
  727 
  728         return kr;
  729 }
  730 
  731 /*
  732  *      Routine:        mach_port_mod_refs
  733  *      Purpose:
  734  *              Modifies the number of user references held by a right.
  735  *              The resulting number of user references must be non-negative.
  736  *              If it is zero, the right is deallocated.  If the name
  737  *              doesn't denote other rights, it is destroyed.
  738  *      Conditions:
  739  *              Nothing locked.
  740  *      Returns:
  741  *              KERN_SUCCESS            Modified number of urefs.
  742  *              KERN_INVALID_TASK       The space is null.
  743  *              KERN_INVALID_TASK       The space is dead.
  744  *              KERN_INVALID_VALUE      "right" isn't a legal value.
  745  *              KERN_INVALID_NAME       The name doesn't denote a right.
  746  *              KERN_INVALID_RIGHT      Name doesn't denote specified right.
  747  *              KERN_INVALID_VALUE      Impossible modification to urefs.
  748  *              KERN_UREFS_OVERFLOW     Urefs would overflow.
  749  */
  750 
  751 kern_return_t
  752 mach_port_mod_refs(
  753         ipc_space_t space,
  754         mach_port_t name,
  755         mach_port_right_t right,
  756         mach_port_delta_t delta)
  757 {
  758         ipc_entry_t entry;
  759         kern_return_t kr;
  760 
  761         if (space == IS_NULL)
  762                 return KERN_INVALID_TASK;
  763 
  764         if (right >= MACH_PORT_RIGHT_NUMBER)
  765                 return KERN_INVALID_VALUE;
  766 
  767         kr = ipc_right_lookup_write(space, name, &entry);
  768         if (kr != KERN_SUCCESS)
  769                 return kr;
  770         /* space is write-locked and active */
  771 
  772         kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
  773         return kr;
  774 }
  775 
  776 /*
  777  *      Routine:        old_mach_port_get_receive_status [kernel call]
  778  *      Purpose:
  779  *              Compatibility for code written before sequence numbers.
  780  *              Retrieves mucho info about a receive right.
  781  *      Conditions:
  782  *              Nothing locked.
  783  *      Returns:
  784  *              KERN_SUCCESS            Retrieved status.
  785  *              KERN_INVALID_TASK       The space is null.
  786  *              KERN_INVALID_TASK       The space is dead.
  787  *              KERN_INVALID_NAME       The name doesn't denote a right.
  788  *              KERN_INVALID_RIGHT      Name doesn't denote receive rights.
  789  */
  790 
  791 kern_return_t
  792 mach_port_get_receive_status(
  793         ipc_space_t space,
  794         mach_port_t name,
  795         mach_port_status_t *statusp);   /* forward */
  796 
  797 kern_return_t
  798 old_mach_port_get_receive_status(
  799         ipc_space_t space,
  800         mach_port_t name,
  801         old_mach_port_status_t *statusp)
  802 {
  803         mach_port_status_t status;
  804         kern_return_t kr;
  805 
  806         kr = mach_port_get_receive_status(space, name, &status);
  807         if (kr != KERN_SUCCESS)
  808                 return kr;
  809 
  810         statusp->mps_pset = status.mps_pset;
  811         statusp->mps_mscount = status.mps_mscount;
  812         statusp->mps_qlimit = status.mps_qlimit;
  813         statusp->mps_msgcount = status.mps_msgcount;
  814         statusp->mps_sorights = status.mps_sorights;
  815         statusp->mps_srights = status.mps_srights;
  816         statusp->mps_pdrequest = status.mps_pdrequest;
  817         statusp->mps_nsrequest = status.mps_nsrequest;
  818 
  819         return KERN_SUCCESS;
  820 }
  821 
  822 /*
  823  *      Routine:        mach_port_set_qlimit [kernel call]
  824  *      Purpose:
  825  *              Changes a receive right's queue limit.
  826  *              The new queue limit must be between 0 and
  827  *              MACH_PORT_QLIMIT_MAX, inclusive.
  828  *      Conditions:
  829  *              Nothing locked.
  830  *      Returns:
  831  *              KERN_SUCCESS            Set queue limit.
  832  *              KERN_INVALID_TASK       The space is null.
  833  *              KERN_INVALID_TASK       The space is dead.
  834  *              KERN_INVALID_NAME       The name doesn't denote a right.
  835  *              KERN_INVALID_RIGHT      Name doesn't denote receive rights.
  836  *              KERN_INVALID_VALUE      Illegal queue limit.
  837  */
  838 
  839 kern_return_t
  840 mach_port_set_qlimit(
  841         ipc_space_t space,
  842         mach_port_t name,
  843         mach_port_msgcount_t qlimit)
  844 {
  845         ipc_port_t port;
  846         kern_return_t kr;
  847 
  848         if (space == IS_NULL)
  849                 return KERN_INVALID_TASK;
  850 
  851         if (qlimit > MACH_PORT_QLIMIT_MAX)
  852                 return KERN_INVALID_VALUE;
  853 
  854         kr = ipc_port_translate_receive(space, name, &port);
  855         if (kr != KERN_SUCCESS)
  856                 return kr;
  857         /* port is locked and active */
  858 
  859         ipc_port_set_qlimit(port, qlimit);
  860 
  861         ip_unlock(port);
  862         return KERN_SUCCESS;
  863 }
  864 
  865 /*
  866  *      Routine:        mach_port_set_mscount [kernel call]
  867  *      Purpose:
  868  *              Changes a receive right's make-send count.
  869  *      Conditions:
  870  *              Nothing locked.
  871  *      Returns:
  872  *              KERN_SUCCESS            Set make-send count.
  873  *              KERN_INVALID_TASK       The space is null.
  874  *              KERN_INVALID_TASK       The space is dead.
  875  *              KERN_INVALID_NAME       The name doesn't denote a right.
  876  *              KERN_INVALID_RIGHT      Name doesn't denote receive rights.
  877  */
  878 
  879 kern_return_t
  880 mach_port_set_mscount(
  881         ipc_space_t space,
  882         mach_port_t name,
  883         mach_port_mscount_t mscount)
  884 {
  885         ipc_port_t port;
  886         kern_return_t kr;
  887 
  888         if (space == IS_NULL)
  889                 return KERN_INVALID_TASK;
  890 
  891         kr = ipc_port_translate_receive(space, name, &port);
  892         if (kr != KERN_SUCCESS)
  893                 return kr;
  894         /* port is locked and active */
  895 
  896         ipc_port_set_mscount(port, mscount);
  897 
  898         ip_unlock(port);
  899         return KERN_SUCCESS;
  900 }
  901 
  902 /*
  903  *      Routine:        mach_port_set_seqno [kernel call]
  904  *      Purpose:
  905  *              Changes a receive right's sequence number.
  906  *      Conditions:
  907  *              Nothing locked.
  908  *      Returns:
  909  *              KERN_SUCCESS            Set sequence number.
  910  *              KERN_INVALID_TASK       The space is null.
  911  *              KERN_INVALID_TASK       The space is dead.
  912  *              KERN_INVALID_NAME       The name doesn't denote a right.
  913  *              KERN_INVALID_RIGHT      Name doesn't denote receive rights.
  914  */
  915 
  916 kern_return_t
  917 mach_port_set_seqno(
  918         ipc_space_t space,
  919         mach_port_t name,
  920         mach_port_seqno_t seqno)
  921 {
  922         ipc_port_t port;
  923         kern_return_t kr;
  924 
  925         if (space == IS_NULL)
  926                 return KERN_INVALID_TASK;
  927 
  928         kr = ipc_port_translate_receive(space, name, &port);
  929         if (kr != KERN_SUCCESS)
  930                 return kr;
  931         /* port is locked and active */
  932 
  933         ipc_port_set_seqno(port, seqno);
  934 
  935         ip_unlock(port);
  936         return KERN_SUCCESS;
  937 }
  938 
  939 /*
  940  *      Routine:        mach_port_gst_helper
  941  *      Purpose:
  942  *              A helper function for mach_port_get_set_status.
  943  */
  944 
  945 void
  946 mach_port_gst_helper(
  947         ipc_pset_t pset,
  948         ipc_port_t port,
  949         ipc_entry_num_t maxnames,
  950         mach_port_t *names,
  951         ipc_entry_num_t *actualp)
  952 {
  953         ipc_pset_t ip_pset;
  954         mach_port_t name;
  955 
  956         assert(port != IP_NULL);
  957 
  958         ip_lock(port);
  959         assert(ip_active(port));
  960 
  961         name = port->ip_receiver_name;
  962         assert(name != MACH_PORT_NULL);
  963         ip_pset = port->ip_pset;
  964 
  965         ip_unlock(port);
  966 
  967         if (pset == ip_pset) {
  968                 ipc_entry_num_t actual = *actualp;
  969 
  970                 if (actual < maxnames)
  971                         names[actual] = name;
  972 
  973                 *actualp = actual+1;
  974         }
  975 }
  976 
  977 /*
  978  *      Routine:        mach_port_get_set_status [kernel call]
  979  *      Purpose:
  980  *              Retrieves a list of members in a port set.
  981  *              Returns the space's name for each receive right member.
  982  *      Conditions:
  983  *              Nothing locked.
  984  *      Returns:
  985  *              KERN_SUCCESS            Retrieved list of members.
  986  *              KERN_INVALID_TASK       The space is null.
  987  *              KERN_INVALID_TASK       The space is dead.
  988  *              KERN_INVALID_NAME       The name doesn't denote a right.
  989  *              KERN_INVALID_RIGHT      Name doesn't denote a port set.
  990  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
  991  */
  992 
  993 kern_return_t
  994 mach_port_get_set_status(
  995         ipc_space_t space,
  996         mach_port_t name,
  997         mach_port_t **members,
  998         mach_msg_type_number_t *membersCnt)
  999 {
 1000         ipc_entry_num_t actual;         /* this many members */
 1001         ipc_entry_num_t maxnames;       /* space for this many members */
 1002         kern_return_t kr;
 1003 
 1004         vm_size_t size;         /* size of allocated memory */
 1005         vm_offset_t addr;       /* allocated memory */
 1006         vm_map_copy_t memory;   /* copied-in memory */
 1007 
 1008         if (space == IS_NULL)
 1009                 return KERN_INVALID_TASK;
 1010 
 1011         size = PAGE_SIZE;       /* initial guess */
 1012 
 1013         for (;;) {
 1014                 ipc_tree_entry_t tentry;
 1015                 ipc_entry_t entry, table;
 1016                 ipc_entry_num_t tsize;
 1017                 mach_port_index_t index;
 1018                 mach_port_t *names;
 1019                 ipc_pset_t pset;
 1020 
 1021                 kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE);
 1022                 if (kr != KERN_SUCCESS)
 1023                         return KERN_RESOURCE_SHORTAGE;
 1024 
 1025                 /* can't fault while we hold locks */
 1026 
 1027                 kr = vm_map_pageable(ipc_kernel_map, addr, addr + size,
 1028                                      VM_PROT_READ|VM_PROT_WRITE);
 1029                 assert(kr == KERN_SUCCESS);
 1030 
 1031                 kr = ipc_right_lookup_read(space, name, &entry);
 1032                 if (kr != KERN_SUCCESS) {
 1033                         kmem_free(ipc_kernel_map, addr, size);
 1034                         return kr;
 1035                 }
 1036                 /* space is read-locked and active */
 1037 
 1038                 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
 1039                         is_read_unlock(space);
 1040                         kmem_free(ipc_kernel_map, addr, size);
 1041                         return KERN_INVALID_RIGHT;
 1042                 }
 1043 
 1044                 pset = (ipc_pset_t) entry->ie_object;
 1045                 assert(pset != IPS_NULL);
 1046                 /* the port set must be active */
 1047 
 1048                 names = (mach_port_t *) addr;
 1049                 maxnames = size / sizeof(mach_port_t);
 1050                 actual = 0;
 1051 
 1052                 table = space->is_table;
 1053                 tsize = space->is_table_size;
 1054 
 1055                 for (index = 0; index < tsize; index++) {
 1056                         ipc_entry_t ientry = &table[index];
 1057                         ipc_entry_bits_t bits = ientry->ie_bits;
 1058 
 1059                         if (bits & MACH_PORT_TYPE_RECEIVE) {
 1060                                 ipc_port_t port =
 1061                                         (ipc_port_t) ientry->ie_object;
 1062 
 1063                                 mach_port_gst_helper(pset, port, maxnames,
 1064                                                      names, &actual);
 1065                         }
 1066                 }
 1067 
 1068                 for (tentry = ipc_splay_traverse_start(&space->is_tree);
 1069                      tentry != ITE_NULL;
 1070                      tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) {
 1071                         ipc_entry_bits_t bits = tentry->ite_bits;
 1072 
 1073                         assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
 1074 
 1075                         if (bits & MACH_PORT_TYPE_RECEIVE) {
 1076                                 ipc_port_t port =
 1077                                         (ipc_port_t) tentry->ite_object;
 1078 
 1079                                 mach_port_gst_helper(pset, port, maxnames,
 1080                                                      names, &actual);
 1081                         }
 1082                 }
 1083                 ipc_splay_traverse_finish(&space->is_tree);
 1084                 is_read_unlock(space);
 1085 
 1086                 if (actual <= maxnames)
 1087                         break;
 1088 
 1089                 /* didn't have enough memory; allocate more */
 1090 
 1091                 kmem_free(ipc_kernel_map, addr, size);
 1092                 size = round_page(actual * sizeof(mach_port_t)) + PAGE_SIZE;
 1093         }
 1094 
 1095         if (actual == 0) {
 1096                 memory = VM_MAP_COPY_NULL;
 1097 
 1098                 kmem_free(ipc_kernel_map, addr, size);
 1099         } else {
 1100                 vm_size_t size_used;
 1101 
 1102                 size_used = round_page(actual * sizeof(mach_port_t));
 1103 
 1104                 /*
 1105                  *      Make used memory pageable and get it into
 1106                  *      copied-in form.  Free any unused memory.
 1107                  */
 1108 
 1109                 kr = vm_map_pageable(ipc_kernel_map,
 1110                                      addr, addr + size_used,
 1111                                      VM_PROT_NONE);
 1112                 assert(kr == KERN_SUCCESS);
 1113 
 1114                 kr = vm_map_copyin(ipc_kernel_map, addr, size_used,
 1115                                    TRUE, &memory);
 1116                 assert(kr == KERN_SUCCESS);
 1117 
 1118                 if (size_used != size)
 1119                         kmem_free(ipc_kernel_map,
 1120                                   addr + size_used, size - size_used);
 1121         }
 1122 
 1123         *members = (mach_port_t *) memory;
 1124         *membersCnt = actual;
 1125         return KERN_SUCCESS;
 1126 }
 1127 
 1128 /*
 1129  *      Routine:        mach_port_move_member [kernel call]
 1130  *      Purpose:
 1131  *              If after is MACH_PORT_NULL, removes member
 1132  *              from the port set it is in.  Otherwise, adds
 1133  *              member to after, removing it from any set
 1134  *              it might already be in.
 1135  *      Conditions:
 1136  *              Nothing locked.
 1137  *      Returns:
 1138  *              KERN_SUCCESS            Moved the port.
 1139  *              KERN_INVALID_TASK       The space is null.
 1140  *              KERN_INVALID_TASK       The space is dead.
 1141  *              KERN_INVALID_NAME       Member didn't denote a right.
 1142  *              KERN_INVALID_RIGHT      Member didn't denote a receive right.
 1143  *              KERN_INVALID_NAME       After didn't denote a right.
 1144  *              KERN_INVALID_RIGHT      After didn't denote a port set right.
 1145  *              KERN_NOT_IN_SET
 1146  *                      After is MACH_PORT_NULL and Member isn't in a port set.
 1147  */
 1148 
 1149 kern_return_t
 1150 mach_port_move_member(
 1151         ipc_space_t space,
 1152         mach_port_t member,
 1153         mach_port_t after)
 1154 {
 1155         ipc_entry_t entry;
 1156         ipc_port_t port;
 1157         ipc_pset_t nset;
 1158         kern_return_t kr;
 1159 
 1160         if (space == IS_NULL)
 1161                 return KERN_INVALID_TASK;
 1162 
 1163         kr = ipc_right_lookup_read(space, member, &entry);
 1164         if (kr != KERN_SUCCESS)
 1165                 return kr;
 1166         /* space is read-locked and active */
 1167 
 1168         if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
 1169                 is_read_unlock(space);
 1170                 return KERN_INVALID_RIGHT;
 1171         }
 1172 
 1173         port = (ipc_port_t) entry->ie_object;
 1174         assert(port != IP_NULL);
 1175 
 1176         if (after == MACH_PORT_NULL)
 1177                 nset = IPS_NULL;
 1178         else {
 1179                 entry = ipc_entry_lookup(space, after);
 1180                 if (entry == IE_NULL) {
 1181                         is_read_unlock(space);
 1182                         return KERN_INVALID_NAME;
 1183                 }
 1184 
 1185                 if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
 1186                         is_read_unlock(space);
 1187                         return KERN_INVALID_RIGHT;
 1188                 }
 1189 
 1190                 nset = (ipc_pset_t) entry->ie_object;
 1191                 assert(nset != IPS_NULL);
 1192         }
 1193 
 1194         kr = ipc_pset_move(space, port, nset);
 1195         /* space is unlocked */
 1196         return kr;
 1197 }
 1198 
 1199 /*
 1200  *      Routine:        mach_port_request_notification [kernel call]
 1201  *      Purpose:
 1202  *              Requests a notification.  The caller supplies
 1203  *              a send-once right for the notification to use,
 1204  *              and the call returns the previously registered
 1205  *              send-once right, if any.  Possible types:
 1206  *
 1207  *              MACH_NOTIFY_PORT_DESTROYED
 1208  *                      Requests a port-destroyed notification
 1209  *                      for a receive right.  Sync should be zero.
 1210  *              MACH_NOTIFY_NO_SENDERS
 1211  *                      Requests a no-senders notification for a
 1212  *                      receive right.  If there are currently no
 1213  *                      senders, sync is less than or equal to the
 1214  *                      current make-send count, and a send-once right
 1215  *                      is supplied, then an immediate no-senders
 1216  *                      notification is generated.
 1217  *              MACH_NOTIFY_DEAD_NAME
 1218  *                      Requests a dead-name notification for a send
 1219  *                      or receive right.  If the name is already a
 1220  *                      dead name, sync is non-zero, and a send-once
 1221  *                      right is supplied, then an immediate dead-name
 1222  *                      notification is generated.
 1223  *      Conditions:
 1224  *              Nothing locked.
 1225  *      Returns:
 1226  *              KERN_SUCCESS            Requested a notification.
 1227  *              KERN_INVALID_TASK       The space is null.
 1228  *              KERN_INVALID_TASK       The space is dead.
 1229  *              KERN_INVALID_VALUE      Bad id value.
 1230  *              KERN_INVALID_NAME       Name doesn't denote a right.
 1231  *              KERN_INVALID_RIGHT      Name doesn't denote appropriate right.
 1232  *              KERN_INVALID_CAPABILITY The notify port is dead.
 1233  *      MACH_NOTIFY_PORT_DESTROYED:
 1234  *              KERN_INVALID_VALUE      Sync isn't zero.
 1235  *      MACH_NOTIFY_DEAD_NAME:
 1236  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 1237  *              KERN_INVALID_ARGUMENT   Name denotes dead name, but
 1238  *                      sync is zero or notify is IP_NULL.
 1239  *              KERN_UREFS_OVERFLOW     Name denotes dead name, but
 1240  *                      generating immediate notif. would overflow urefs.
 1241  */
 1242 
 1243 kern_return_t
 1244 mach_port_request_notification(
 1245         ipc_space_t space,
 1246         mach_port_t name,
 1247         mach_msg_id_t id,
 1248         mach_port_mscount_t sync,
 1249         ipc_port_t notify,
 1250         ipc_port_t *previousp)
 1251 {
 1252         kern_return_t kr;
 1253 
 1254         if (space == IS_NULL)
 1255                 return KERN_INVALID_TASK;
 1256 
 1257         if (notify == IP_DEAD)
 1258                 return KERN_INVALID_CAPABILITY;
 1259 
 1260         switch (id) {
 1261             case MACH_NOTIFY_PORT_DESTROYED: {
 1262                 ipc_port_t port, previous;
 1263 
 1264                 if (sync != 0)
 1265                         return KERN_INVALID_VALUE;
 1266 
 1267                 kr = ipc_port_translate_receive(space, name, &port);
 1268                 if (kr != KERN_SUCCESS)
 1269                         return kr;
 1270                 /* port is locked and active */
 1271 
 1272                 ipc_port_pdrequest(port, notify, &previous);
 1273                 /* port is unlocked */
 1274 
 1275 #if     MACH_IPC_COMPAT
 1276                 /*
 1277                  *      If previous was a send right instead of a send-once
 1278                  *      right, we can't return it in the reply message.
 1279                  *      So destroy it instead.
 1280                  */
 1281 
 1282                 if ((previous != IP_NULL) && ip_pdsendp(previous)) {
 1283                         ipc_port_release_send(ip_pdsend(previous));
 1284                         previous = IP_NULL;
 1285                 }
 1286 #endif  /* MACH_IPC_COMPAT */
 1287 
 1288                 *previousp = previous;
 1289                 break;
 1290             }
 1291 
 1292             case MACH_NOTIFY_NO_SENDERS: {
 1293                 ipc_port_t port;
 1294 
 1295                 kr = ipc_port_translate_receive(space, name, &port);
 1296                 if (kr != KERN_SUCCESS)
 1297                         return kr;
 1298                 /* port is locked and active */
 1299 
 1300                 ipc_port_nsrequest(port, sync, notify, previousp);
 1301                 /* port is unlocked */
 1302                 break;
 1303             }
 1304 
 1305             case MACH_NOTIFY_DEAD_NAME:
 1306                 kr = ipc_right_dnrequest(space, name, sync != 0,
 1307                                          notify, previousp);
 1308                 if (kr != KERN_SUCCESS)
 1309                         return kr;
 1310                 break;
 1311 
 1312             default:
 1313                 return KERN_INVALID_VALUE;
 1314         }
 1315 
 1316         return KERN_SUCCESS;
 1317 }
 1318 
 1319 /*
 1320  *      Routine:        mach_port_insert_right [kernel call]
 1321  *      Purpose:
 1322  *              Inserts a right into a space, as if the space
 1323  *              voluntarily received the right in a message,
 1324  *              except that the right gets the specified name.
 1325  *      Conditions:
 1326  *              Nothing locked.
 1327  *      Returns:
 1328  *              KERN_SUCCESS            Inserted the right.
 1329  *              KERN_INVALID_TASK       The space is null.
 1330  *              KERN_INVALID_TASK       The space is dead.
 1331  *              KERN_INVALID_VALUE      The name isn't a legal name.
 1332  *              KERN_NAME_EXISTS        The name already denotes a right.
 1333  *              KERN_INVALID_VALUE      Message doesn't carry a port right.
 1334  *              KERN_INVALID_CAPABILITY Port is null or dead.
 1335  *              KERN_UREFS_OVERFLOW     Urefs limit would be exceeded.
 1336  *              KERN_RIGHT_EXISTS       Space has rights under another name.
 1337  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 1338  */
 1339 
 1340 kern_return_t
 1341 mach_port_insert_right(
 1342         ipc_space_t space,
 1343         mach_port_t name,
 1344         ipc_object_t poly,
 1345         mach_msg_type_name_t polyPoly)
 1346 {
 1347         if (space == IS_NULL)
 1348                 return KERN_INVALID_TASK;
 1349 
 1350         if (!MACH_PORT_VALID(name) ||
 1351             !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
 1352                 return KERN_INVALID_VALUE;
 1353 
 1354         if (!IO_VALID(poly))
 1355                 return KERN_INVALID_CAPABILITY;
 1356 
 1357         return ipc_object_copyout_name(space, poly, polyPoly, FALSE, name);
 1358 }
 1359 
 1360 /*
 1361  *      Routine:        mach_port_extract_right [kernel call]
 1362  *      Purpose:
 1363  *              Extracts a right from a space, as if the space
 1364  *              voluntarily sent the right to the caller.
 1365  *      Conditions:
 1366  *              Nothing locked.
 1367  *      Returns:
 1368  *              KERN_SUCCESS            Extracted the right.
 1369  *              KERN_INVALID_TASK       The space is null.
 1370  *              KERN_INVALID_TASK       The space is dead.
 1371  *              KERN_INVALID_VALUE      Requested type isn't a port right.
 1372  *              KERN_INVALID_NAME       Name doesn't denote a right.
 1373  *              KERN_INVALID_RIGHT      Name doesn't denote appropriate right.
 1374  */
 1375 
 1376 kern_return_t
 1377 mach_port_extract_right(
 1378         ipc_space_t space,
 1379         mach_port_t name,
 1380         mach_msg_type_name_t msgt_name,
 1381         ipc_object_t *poly,
 1382         mach_msg_type_name_t *polyPoly)
 1383 {
 1384         kern_return_t kr;
 1385 
 1386         if (space == IS_NULL)
 1387                 return KERN_INVALID_TASK;
 1388 
 1389         if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
 1390                 return KERN_INVALID_VALUE;
 1391 
 1392         kr = ipc_object_copyin(space, name, msgt_name, poly);
 1393 
 1394         if (kr == KERN_SUCCESS)
 1395                 *polyPoly = ipc_object_copyin_type(msgt_name);
 1396         return kr;
 1397 }
 1398 
 1399 /*
 1400  *      Routine:        mach_port_get_receive_status [kernel call]
 1401  *      Purpose:
 1402  *              Retrieves mucho info about a receive right.
 1403  *      Conditions:
 1404  *              Nothing locked.
 1405  *      Returns:
 1406  *              KERN_SUCCESS            Retrieved status.
 1407  *              KERN_INVALID_TASK       The space is null.
 1408  *              KERN_INVALID_TASK       The space is dead.
 1409  *              KERN_INVALID_NAME       The name doesn't denote a right.
 1410  *              KERN_INVALID_RIGHT      Name doesn't denote receive rights.
 1411  */
 1412 
 1413 kern_return_t
 1414 mach_port_get_receive_status(
 1415         ipc_space_t space,
 1416         mach_port_t name,
 1417         mach_port_status_t *statusp)
 1418 {
 1419         ipc_port_t port;
 1420         kern_return_t kr;
 1421 
 1422         if (space == IS_NULL)
 1423                 return KERN_INVALID_TASK;
 1424 
 1425         kr = ipc_port_translate_receive(space, name, &port);
 1426         if (kr != KERN_SUCCESS)
 1427                 return kr;
 1428         /* port is locked and active */
 1429 
 1430         if (port->ip_pset != IPS_NULL) {
 1431                 ipc_pset_t pset = port->ip_pset;
 1432 
 1433                 ips_lock(pset);
 1434                 if (!ips_active(pset)) {
 1435                         ipc_pset_remove(pset, port);
 1436                         ips_check_unlock(pset);
 1437                         goto no_port_set;
 1438                 } else {
 1439                         statusp->mps_pset = pset->ips_local_name;
 1440                         imq_lock(&pset->ips_messages);
 1441                         statusp->mps_seqno = port->ip_seqno;
 1442                         imq_unlock(&pset->ips_messages);
 1443                         ips_unlock(pset);
 1444                         assert(MACH_PORT_VALID(statusp->mps_pset));
 1445                 }
 1446         } else {
 1447             no_port_set:
 1448                 statusp->mps_pset = MACH_PORT_NULL;
 1449                 imq_lock(&port->ip_messages);
 1450                 statusp->mps_seqno = port->ip_seqno;
 1451                 imq_unlock(&port->ip_messages);
 1452         }
 1453 
 1454         statusp->mps_mscount = port->ip_mscount;
 1455         statusp->mps_qlimit = port->ip_qlimit;
 1456         statusp->mps_msgcount = port->ip_msgcount;
 1457         statusp->mps_sorights = port->ip_sorights;
 1458         statusp->mps_srights = port->ip_srights > 0;
 1459         statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
 1460         statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
 1461         ip_unlock(port);
 1462 
 1463         return KERN_SUCCESS;
 1464 }
 1465 
 1466 #if     MACH_IPC_COMPAT
 1467 
 1468 /*
 1469  *      Routine:        port_translate_compat
 1470  *      Purpose:
 1471  *              Converts a name to a receive right.
 1472  *      Conditions:
 1473  *              Nothing locked.  If successful, the port
 1474  *              is returned locked and active.
 1475  *      Returns:
 1476  *              KERN_SUCCESS            Port is returned.
 1477  *              KERN_INVALID_ARGUMENT   The space is dead.
 1478  *              KERN_INVALID_ARGUMENT   Name doesn't denote port rights.
 1479  *              KERN_NOT_RECEIVER       Name denotes send, not receive, rights.
 1480  *              KERN_NOT_RECEIVER       Name denotes a send-once right.
 1481  *              KERN_NOT_RECEIVER       Name denotes a dead name.
 1482  */
 1483 
 1484 kern_return_t
 1485 port_translate_compat(
 1486         ipc_space_t space,
 1487         mach_port_t name,
 1488         ipc_port_t *portp)
 1489 {
 1490         ipc_entry_t entry;
 1491         mach_port_type_t type;
 1492         mach_port_urefs_t urefs;
 1493         ipc_port_t port;
 1494         kern_return_t kr;
 1495 
 1496         kr = ipc_right_lookup_write(space, name, &entry);
 1497         if (kr != KERN_SUCCESS)
 1498                 return KERN_INVALID_ARGUMENT;
 1499         /* space is write-locked and active */
 1500 
 1501         kr = ipc_right_info(space, name, entry, &type, &urefs);
 1502         if (kr != KERN_SUCCESS)
 1503                 return KERN_INVALID_ARGUMENT; /* space is unlocked */
 1504 
 1505         if ((type & (MACH_PORT_TYPE_RECEIVE)) == 0) {
 1506                 is_write_unlock(space);
 1507                 if (type & MACH_PORT_TYPE_PORT_OR_DEAD)
 1508                         return KERN_NOT_RECEIVER;
 1509                 else
 1510                         return KERN_INVALID_ARGUMENT;
 1511         }
 1512 
 1513         port = (ipc_port_t) entry->ie_object;
 1514         assert(port != IP_NULL);
 1515 
 1516         ip_lock(port);
 1517         is_write_unlock(space);
 1518         assert(ip_active(port));
 1519 
 1520         *portp = port;
 1521         return KERN_SUCCESS;
 1522 }
 1523 
 1524 /*
 1525  *      Routine:        convert_port_type
 1526  *      Purpose:
 1527  *              Convert a new mach_port_type_t to an old value.
 1528  *              Note send-once rights and dead names get
 1529  *              represented as send rights.  The extra info
 1530  *              bits get dropped.
 1531  */
 1532 
 1533 mach_port_type_t
 1534 convert_port_type(
 1535         mach_port_type_t type)
 1536 {
 1537         switch (type & MACH_PORT_TYPE_ALL_RIGHTS) {
 1538             case MACH_PORT_TYPE_SEND:
 1539             case MACH_PORT_TYPE_SEND_ONCE:
 1540             case MACH_PORT_TYPE_DEAD_NAME:
 1541                 return PORT_TYPE_SEND;
 1542 
 1543             case MACH_PORT_TYPE_RECEIVE:
 1544             case MACH_PORT_TYPE_SEND_RECEIVE:
 1545                 return PORT_TYPE_RECEIVE_OWN;
 1546 
 1547             case MACH_PORT_TYPE_PORT_SET:
 1548                 return PORT_TYPE_SET;
 1549 
 1550             default:
 1551 #if MACH_ASSERT
 1552                 assert(!"convert_port_type: strange port type");
 1553 #else
 1554                 panic("convert_port_type: strange port type");
 1555 #endif
 1556                 return 0;       /* lint */
 1557         }
 1558 }
 1559 
 1560 /*
 1561  *      Routine:        port_names [kernel call]
 1562  *      Purpose:
 1563  *              Retrieve all the names in the task's port name space.
 1564  *              As a (major) convenience, return port type information.
 1565  *              The port name space includes port sets.
 1566  *      Conditions:
 1567  *              Nothing locked.
 1568  *      Returns:
 1569  *              KERN_SUCCESS            Retrieved names.
 1570  *              KERN_INVALID_ARGUMENT   Task is null.
 1571  *              KERN_INVALID_ARGUMENT   Task is not active.
 1572  *      Additions:
 1573  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 1574  */
 1575 
 1576 kern_return_t
 1577 port_names(
 1578         ipc_space_t space,
 1579         mach_port_t **namesp,
 1580         mach_msg_type_number_t *namesCnt,
 1581         mach_port_type_t **typesp,
 1582         mach_msg_type_number_t *typesCnt)
 1583 {
 1584         kern_return_t kr;
 1585 
 1586         kr = mach_port_names(space, namesp, namesCnt, typesp, typesCnt);
 1587         if (kr == KERN_SUCCESS) {
 1588                 ipc_entry_num_t actual = (ipc_entry_num_t) *typesCnt;
 1589                 mach_port_type_t *types;
 1590                 ipc_entry_num_t i;
 1591 
 1592                 vm_map_copy_t copy = (vm_map_copy_t) *typesp;
 1593                 vm_offset_t addr;
 1594                 vm_size_t size = round_page(actual * sizeof(mach_port_type_t));
 1595 
 1596                 /* convert copy object back to something we can use */
 1597 
 1598                 kr = vm_map_copyout(ipc_kernel_map, &addr, copy);
 1599                 if (kr != KERN_SUCCESS) {
 1600                         vm_map_copy_discard((vm_map_copy_t) *typesp);
 1601                         vm_map_copy_discard((vm_map_copy_t) *namesp);
 1602                         return KERN_RESOURCE_SHORTAGE;
 1603                 }
 1604 
 1605                 types = (mach_port_type_t *) addr;
 1606 
 1607                 for (i = 0; i < actual; i++)
 1608                         types[i] = convert_port_type(types[i]);
 1609 
 1610                 /* convert memory back into a copy object */
 1611 
 1612                 kr = vm_map_copyin(ipc_kernel_map, addr, size,
 1613                                    TRUE, &copy);
 1614                 assert(kr == KERN_SUCCESS);
 1615 
 1616                 *typesp = (mach_port_type_t *) copy;
 1617         } else if (kr != KERN_RESOURCE_SHORTAGE)
 1618                 kr = KERN_INVALID_ARGUMENT;
 1619 
 1620         return kr;
 1621 }
 1622 
 1623 /*
 1624  *      Routine:        port_type [kernel call]
 1625  *      Purpose:
 1626  *              Return type of the capability named.
 1627  *      Conditions:
 1628  *              Nothing locked.
 1629  *      Returns:
 1630  *              KERN_SUCCESS            Retrieved type.
 1631  *              KERN_INVALID_ARGUMENT   Task is null.
 1632  *              KERN_INVALID_ARGUMENT   Task is not active.
 1633  *              KERN_INVALID_ARGUMENT   The name doesn't denote a right.
 1634  */
 1635 
 1636 kern_return_t
 1637 port_type(
 1638         ipc_space_t space,
 1639         mach_port_t name,
 1640         mach_port_type_t *typep)
 1641 {
 1642         mach_port_type_t type;
 1643         kern_return_t kr;
 1644 
 1645         kr = mach_port_type(space, name, &type);
 1646         if (kr != KERN_SUCCESS)
 1647                 return KERN_INVALID_ARGUMENT;
 1648 
 1649         *typep = convert_port_type(type);
 1650         return KERN_SUCCESS;
 1651 }
 1652 
 1653 /*
 1654  *      Routine:        port_rename [kernel call]
 1655  *      Purpose:
 1656  *              Change the name of a capability.
 1657  *              The new name can't be in use.
 1658  *      Conditions:
 1659  *              Nothing locked.
 1660  *      Returns:
 1661  *              KERN_SUCCESS            Retrieved type.
 1662  *              KERN_INVALID_ARGUMENT   Task is null.
 1663  *              KERN_INVALID_ARGUMENT   Task is not active.
 1664  *              KERN_INVALID_ARGUMENT   The new name is reserved.
 1665  *              KERN_NAME_EXISTS        The new name already denotes a right.
 1666  *              KERN_INVALID_ARGUMENT   The old name doesn't denote a right.
 1667  */
 1668 
 1669 kern_return_t
 1670 port_rename(
 1671         ipc_space_t space,
 1672         mach_port_t old_name,
 1673         mach_port_t new_name)
 1674 {
 1675         kern_return_t kr;
 1676 
 1677         kr = mach_port_rename(space, old_name, new_name);
 1678         if ((kr != KERN_SUCCESS) && (kr != KERN_NAME_EXISTS))
 1679                 kr = KERN_INVALID_ARGUMENT;
 1680 
 1681         return kr;
 1682 }
 1683 
 1684 /*
 1685  *      Routine:        port_allocate [kernel call]
 1686  *      Purpose:
 1687  *              Allocate a new port, giving all rights to "task".
 1688  *
 1689  *              Returns in "port_name" the task's local name for the port.
 1690  *              Doesn't return a reference to the port.
 1691  *      Conditions:
 1692  *              Nothing locked.
 1693  *      Returns:
 1694  *              KERN_SUCCESS            Allocated a port.
 1695  *              KERN_INVALID_ARGUMENT   Task is null.
 1696  *              KERN_INVALID_ARGUMENT   Task is not active.
 1697  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 1698  */
 1699 
 1700 kern_return_t
 1701 port_allocate(
 1702         ipc_space_t space,
 1703         mach_port_t *namep)
 1704 {
 1705         ipc_port_t port;
 1706         kern_return_t kr;
 1707 
 1708         if (space == IS_NULL)
 1709                 return KERN_INVALID_ARGUMENT;
 1710 
 1711         kr = ipc_port_alloc_compat(space, namep, &port);
 1712         if (kr == KERN_SUCCESS)
 1713                 ip_unlock(port);
 1714         else if (kr != KERN_RESOURCE_SHORTAGE)
 1715                 kr = KERN_INVALID_ARGUMENT;
 1716 
 1717         return kr;
 1718 }
 1719 
 1720 /*
 1721  *      Routine:        port_deallocate [kernel call]
 1722  *      Purpose:
 1723  *              Delete port rights (send and receive) from a task.
 1724  *      Conditions:
 1725  *              Nothing locked.
 1726  *      Returns:
 1727  *              KERN_SUCCESS            Deallocated the port right.
 1728  *              KERN_INVALID_ARGUMENT   Task is null.
 1729  *              KERN_INVALID_ARGUMENT   Task is not active.
 1730  *              KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
 1731  *      Additions:
 1732  *              KERN_SUCCESS            Deallocated a send-once right.
 1733  *              KERN_SUCCESS            Destroyed a dead name.
 1734  */
 1735 
 1736 kern_return_t
 1737 port_deallocate(
 1738         ipc_space_t space,
 1739         mach_port_t name)
 1740 {
 1741         ipc_entry_t entry;
 1742         mach_port_type_t type;
 1743         mach_port_urefs_t urefs;
 1744         kern_return_t kr;
 1745 
 1746         if (space == IS_NULL)
 1747                 return KERN_INVALID_ARGUMENT;
 1748 
 1749         kr = ipc_right_lookup_write(space, name, &entry);
 1750         if (kr != KERN_SUCCESS)
 1751                 return KERN_INVALID_ARGUMENT;
 1752         /* space is write-locked and active */
 1753 
 1754         /*
 1755          *      We serialize with port destruction with the
 1756          *      ipc_right_info call, not ipc_right_destroy.
 1757          *      After ipc_right_info, we pretend that the
 1758          *      port doesn't get destroyed.
 1759          */
 1760 
 1761         kr = ipc_right_info(space, name, entry, &type, &urefs);
 1762         if (kr != KERN_SUCCESS)
 1763                 return KERN_INVALID_ARGUMENT; /* space is unlocked */
 1764 
 1765         if ((type & (MACH_PORT_TYPE_PORT_OR_DEAD)) == 0) {
 1766                 is_write_unlock(space);
 1767                 return KERN_INVALID_ARGUMENT;
 1768         }
 1769 
 1770         (void) ipc_right_destroy(space, name, entry);
 1771         /* space is unlocked */
 1772 
 1773         return KERN_SUCCESS;
 1774 }
 1775 
 1776 /*
 1777  *      Routine:        port_set_backlog [kernel call]
 1778  *      Purpose:
 1779  *              Change the queueing backlog on "port_name" to "backlog";
 1780  *              the specified "task" must be the current receiver.
 1781  *
 1782  *              Valid backlog values are 0 < backlog <= PORT_BACKLOG_MAX.
 1783  *      Conditions:
 1784  *              Nothing locked.
 1785  *      Returns:
 1786  *              KERN_SUCCESS            Set the backlog.
 1787  *              KERN_INVALID_ARGUMENT   Task is null.
 1788  *              KERN_INVALID_ARGUMENT   Task is not active.
 1789  *              KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
 1790  *              KERN_NOT_RECEIVER       Name denotes send rights, not receive.
 1791  *              KERN_INVALID_ARGUMENT   Backlog value is invalid.
 1792  *      Additions:
 1793  *              KERN_NOT_RECEIVER       Name denotes a send-once right.
 1794  *              KERN_NOT_RECEIVER       Name denotes a dead name.
 1795  */
 1796 
 1797 kern_return_t
 1798 port_set_backlog(
 1799         ipc_space_t space,
 1800         mach_port_t name,
 1801         int backlog)
 1802 {
 1803         ipc_port_t port;
 1804         kern_return_t kr;
 1805 
 1806         if ((space == IS_NULL) ||
 1807             (backlog <= 0) ||
 1808             (backlog > PORT_BACKLOG_MAX))
 1809                 return KERN_INVALID_ARGUMENT;
 1810 
 1811         kr = port_translate_compat(space, name, &port);
 1812         if (kr != KERN_SUCCESS)
 1813                 return kr;
 1814         /* port is locked and active */
 1815 
 1816         ipc_port_set_qlimit(port, (mach_port_msgcount_t) backlog);
 1817 
 1818         ip_unlock(port);
 1819         return KERN_SUCCESS;
 1820 }
 1821 
 1822 /*
 1823  *      Routine:        port_set_backup [kernel call]
 1824  *      Purpose:
 1825  *              Changes the backup port for the the named port.
 1826  *              The specified "task" must be the current receiver.
 1827  *              Returns the old backup port, if any.
 1828  *      Conditions:
 1829  *              Nothing locked.
 1830  *      Returns:
 1831  *              KERN_SUCCESS            Set the backup.
 1832  *              KERN_INVALID_ARGUMENT   Task is null.
 1833  *              KERN_INVALID_ARGUMENT   Task is not active.
 1834  *              KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
 1835  *              KERN_NOT_RECEIVER       Name denotes send rights, not receive.
 1836  *      Additions:
 1837  *              KERN_NOT_RECEIVER       Name denotes a send-once right.
 1838  *              KERN_NOT_RECEIVER       Name denotes a dead name.
 1839  */
 1840 
 1841 kern_return_t
 1842 port_set_backup(
 1843         ipc_space_t space,
 1844         mach_port_t name,
 1845         ipc_port_t backup,
 1846         ipc_port_t *previousp)
 1847 {
 1848         ipc_port_t port, previous;
 1849         kern_return_t kr;
 1850 
 1851         if (space == IS_NULL)
 1852                 return KERN_INVALID_ARGUMENT;
 1853 
 1854         if (backup == IP_DEAD)
 1855                 backup = IP_NULL;
 1856         else if (backup != IP_NULL)
 1857                 backup = ip_pdsendm(backup);
 1858 
 1859         kr = port_translate_compat(space, name, &port);
 1860         if (kr != KERN_SUCCESS)
 1861                 return kr;
 1862         /* port is locked and active */
 1863 
 1864         ipc_port_pdrequest(port, backup, &previous);
 1865         /* port is unlocked */
 1866 
 1867         /*
 1868          *      If previous was a send-once right instead of a send
 1869          *      right, we can't return it in the reply message.
 1870          *      So get rid of it in a notification instead.
 1871          */
 1872 
 1873         if (previous != IP_NULL) {
 1874                 if (ip_pdsendp(previous))
 1875                         previous = ip_pdsend(previous);
 1876                 else {
 1877                         ipc_notify_send_once(previous);
 1878                         previous = IP_NULL;
 1879                 }
 1880         }
 1881 
 1882         *previousp = previous;
 1883         return KERN_SUCCESS;
 1884 }
 1885 
 1886 /*
 1887  *      Routine:        port_status [kernel call]
 1888  *      Purpose:
 1889  *              Returns statistics related to "port_name", as seen by "task".
 1890  *              Only the receiver for a given port will see true message
 1891  *              counts.
 1892  *      Conditions:
 1893  *              Nothing locked.
 1894  *      Returns:
 1895  *              KERN_SUCCESS            Retrieved status.
 1896  *              KERN_INVALID_ARGUMENT   Task is null.
 1897  *              KERN_INVALID_ARGUMENT   Task is not active.
 1898  *              KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
 1899  *      Additions:
 1900  *              KERN_SUCCESS            Send-once right.
 1901  *              KERN_SUCCESS            Dead name.
 1902  */
 1903 
 1904 kern_return_t
 1905 port_status(
 1906         ipc_space_t space,
 1907         mach_port_t name,
 1908         mach_port_t *enabledp,
 1909         int *num_msgs,
 1910         int *backlog,
 1911         boolean_t *ownership,
 1912         boolean_t *receive_rights)
 1913 {
 1914         ipc_entry_t entry;
 1915         mach_port_type_t type;
 1916         mach_port_urefs_t urefs;
 1917         kern_return_t kr;
 1918 
 1919         if (space == IS_NULL)
 1920                 return KERN_INVALID_ARGUMENT;
 1921 
 1922         kr = ipc_right_lookup_write(space, name, &entry);
 1923         if (kr != KERN_SUCCESS)
 1924                 return KERN_INVALID_ARGUMENT;
 1925         /* space is write-locked and active */
 1926 
 1927         kr = ipc_right_info(space, name, entry, &type, &urefs);
 1928         if (kr != KERN_SUCCESS)
 1929                 return KERN_INVALID_ARGUMENT; /* space is unlocked */
 1930 
 1931         if ((type & MACH_PORT_TYPE_PORT_OR_DEAD) == 0) {
 1932                 is_write_unlock(space);
 1933                 return KERN_INVALID_ARGUMENT;
 1934         }
 1935 
 1936         if (type & MACH_PORT_TYPE_RECEIVE) {
 1937                 mach_port_t enabled;
 1938                 mach_port_msgcount_t qlimit;
 1939                 mach_port_msgcount_t msgcount;
 1940                 ipc_port_t port;
 1941 
 1942                 port = (ipc_port_t) entry->ie_object;
 1943                 assert(port != IP_NULL);
 1944 
 1945                 ip_lock(port);
 1946                 is_write_unlock(space);
 1947                 assert(ip_active(port));
 1948 
 1949                 if (port->ip_pset != IPS_NULL) {
 1950                         ipc_pset_t pset = port->ip_pset;
 1951 
 1952                         ips_lock(pset);
 1953                         if (!ips_active(pset)) {
 1954                                 ipc_pset_remove(pset, port);
 1955                                 ips_check_unlock(pset);
 1956                                 enabled = MACH_PORT_NULL;
 1957                         } else {
 1958                                 enabled = pset->ips_local_name;
 1959                                 ips_unlock(pset);
 1960                                 assert(MACH_PORT_VALID(enabled));
 1961                         }
 1962                 } else
 1963                         enabled = MACH_PORT_NULL;
 1964 
 1965                 qlimit = port->ip_qlimit;
 1966                 msgcount = port->ip_msgcount;
 1967                 ip_unlock(port);
 1968 
 1969                 *ownership = TRUE;
 1970                 *receive_rights = TRUE;
 1971                 *enabledp = enabled;
 1972                 *num_msgs = (int) msgcount;
 1973                 *backlog = (int) qlimit;
 1974         } else {
 1975                 is_write_unlock(space);
 1976 
 1977                 *ownership = FALSE;
 1978                 *receive_rights = FALSE;
 1979                 *enabledp = MACH_PORT_NULL;
 1980                 *num_msgs = -1;
 1981                 *backlog = 0;
 1982         }
 1983 
 1984         return KERN_SUCCESS;
 1985 }
 1986 
 1987 /*
 1988  *      Routine:        port_set_allocate [kernel call]
 1989  *      Purpose:
 1990  *              Create a new port set, give rights to task, and
 1991  *              return task's local name for the set.
 1992  *      Conditions:
 1993  *              Nothing locked.
 1994  *      Returns:
 1995  *              KERN_SUCCESS            Allocated a port set.
 1996  *              KERN_INVALID_ARGUMENT   Task is null.
 1997  *              KERN_INVALID_ARGUMENT   Task is not active.
 1998  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 1999  */
 2000 
 2001 kern_return_t
 2002 port_set_allocate(
 2003         ipc_space_t space,
 2004         mach_port_t *namep)
 2005 {
 2006         ipc_pset_t pset;
 2007         kern_return_t kr;
 2008 
 2009         if (space == IS_NULL)
 2010                 return KERN_INVALID_ARGUMENT;
 2011 
 2012         kr = ipc_pset_alloc(space, namep, &pset);
 2013         if (kr == KERN_SUCCESS)
 2014                 ips_unlock(pset);
 2015         else if (kr != KERN_RESOURCE_SHORTAGE)
 2016                 kr = KERN_INVALID_ARGUMENT;
 2017 
 2018         return kr;
 2019 }
 2020 
 2021 /*
 2022  *      Routine:        port_set_deallocate [kernel call]
 2023  *      Purpose:
 2024  *              Destroys the task's port set.  If there are any
 2025  *              receive rights in the set, they are removed.
 2026  *      Conditions:
 2027  *              Nothing locked.
 2028  *      Returns:
 2029  *              KERN_SUCCESS            Deallocated the port set.
 2030  *              KERN_INVALID_ARGUMENT   Task is null.
 2031  *              KERN_INVALID_ARGUMENT   Task is not active.
 2032  *              KERN_INVALID_ARGUMENT   Name doesn't denote a port set.
 2033  */
 2034 
 2035 kern_return_t
 2036 port_set_deallocate(
 2037         ipc_space_t space,
 2038         mach_port_t name)
 2039 {
 2040         ipc_entry_t entry;
 2041         kern_return_t kr;
 2042 
 2043         if (space == IS_NULL)
 2044                 return KERN_INVALID_ARGUMENT;
 2045 
 2046         kr = ipc_right_lookup_write(space, name, &entry);
 2047         if (kr != KERN_SUCCESS)
 2048                 return kr;
 2049         /* space is write-locked and active */
 2050 
 2051         if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
 2052                 is_write_unlock(space);
 2053                 return KERN_INVALID_ARGUMENT;
 2054         }
 2055 
 2056         kr = ipc_right_destroy(space, name, entry);
 2057         /* space is unlocked */
 2058         assert(kr == KERN_SUCCESS);
 2059         return kr;
 2060 }
 2061 
 2062 /*
 2063  *      Routine:        port_set_add [kernel call]
 2064  *      Purpose:
 2065  *              Moves receive rights into the port set.
 2066  *      Conditions:
 2067  *              Nothing locked.
 2068  *      Returns:
 2069  *              KERN_SUCCESS            Moved the receive right.
 2070  *              KERN_INVALID_ARGUMENT   Task is null.
 2071  *              KERN_INVALID_ARGUMENT   Task is not active.
 2072  *              KERN_INVALID_ARGUMENT   port_name doesn't denote port rights.
 2073  *              KERN_NOT_RECEIVER       port_name doesn't denote receive right.
 2074  *              KERN_INVALID_ARGUMENT   set_name doesn't denote a port set.
 2075  *      Additions:
 2076  *              KERN_NOT_RECEIVER       port_name denotes a send-once right.
 2077  *              KERN_NOT_RECEIVER       port_name denotes a dead name.
 2078  */
 2079 
 2080 kern_return_t
 2081 port_set_add(
 2082         ipc_space_t space,
 2083         mach_port_t set_name,
 2084         mach_port_t port_name)
 2085 {
 2086         ipc_entry_t entry;
 2087         mach_port_type_t type;
 2088         mach_port_urefs_t urefs;
 2089         ipc_port_t port;
 2090         ipc_pset_t pset;
 2091         kern_return_t kr;
 2092 
 2093         if (space == IS_NULL)
 2094                 return KERN_INVALID_ARGUMENT;
 2095 
 2096         kr = ipc_right_lookup_write(space, port_name, &entry);
 2097         if (kr != KERN_SUCCESS)
 2098                 return KERN_INVALID_ARGUMENT;
 2099         /* space is write-locked and active */
 2100 
 2101         /* use ipc_right_info to check for dead compat entries */
 2102 
 2103         kr = ipc_right_info(space, port_name, entry, &type, &urefs);
 2104         if (kr != KERN_SUCCESS)
 2105                 return KERN_INVALID_ARGUMENT; /* space is unlocked */
 2106 
 2107         if ((type & MACH_PORT_TYPE_RECEIVE) == 0) {
 2108                 is_write_unlock(space);
 2109                 if (type & MACH_PORT_TYPE_PORT_OR_DEAD)
 2110                         return KERN_NOT_RECEIVER;
 2111                 else
 2112                         return KERN_INVALID_ARGUMENT;
 2113         }
 2114 
 2115         is_write_to_read_lock(space);
 2116         port = (ipc_port_t) entry->ie_object;
 2117         assert(port != IP_NULL);
 2118 
 2119         entry = ipc_entry_lookup(space, set_name);
 2120         if ((entry == IE_NULL) ||
 2121             ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0)) {
 2122                 is_read_unlock(space);
 2123                 return KERN_INVALID_ARGUMENT;
 2124         }
 2125 
 2126         pset = (ipc_pset_t) entry->ie_object;
 2127         assert(pset != IPS_NULL);
 2128 
 2129         kr = ipc_pset_move(space, port, pset);
 2130         /* space is unlocked */
 2131         assert(kr == KERN_SUCCESS);
 2132         return kr;
 2133 }
 2134 
 2135 /*
 2136  *      Routine:        port_set_remove [kernel call]
 2137  *      Purpose:
 2138  *              Removes the receive rights from the set they are in.
 2139  *      Conditions:
 2140  *              Nothing locked.
 2141  *      Returns:
 2142  *              KERN_SUCCESS            Removed the receive right.
 2143  *              KERN_INVALID_ARGUMENT   Task is null.
 2144  *              KERN_INVALID_ARGUMENT   Task is not active.
 2145  *              KERN_INVALID_ARGUMENT   Name doesn't denote a port right.
 2146  *              KERN_NOT_RECEIVER       Name denotes send rights, not receive.
 2147  *              KERN_NOT_IN_SET         Port isn't in a port set.
 2148  *      Additions:
 2149  *              KERN_NOT_RECEIVER       Name denotes a send-once right.
 2150  *              KERN_NOT_RECEIVER       Name denotes a dead name.
 2151  */
 2152 
 2153 kern_return_t
 2154 port_set_remove(
 2155         ipc_space_t space,
 2156         mach_port_t name)
 2157 {
 2158         ipc_entry_t entry;
 2159         mach_port_type_t type;
 2160         mach_port_urefs_t urefs;
 2161         ipc_port_t port;
 2162         kern_return_t kr;
 2163 
 2164         if (space == IS_NULL)
 2165                 return KERN_INVALID_ARGUMENT;
 2166 
 2167         kr = ipc_right_lookup_write(space, name, &entry);
 2168         if (kr != KERN_SUCCESS)
 2169                 return KERN_INVALID_ARGUMENT;
 2170         /* space is write-locked and active */
 2171 
 2172         /* use ipc_right_info to check for dead compat entries */
 2173 
 2174         kr = ipc_right_info(space, name, entry, &type, &urefs);
 2175         if (kr != KERN_SUCCESS)
 2176                 return KERN_INVALID_ARGUMENT; /* space is unlocked */
 2177 
 2178         if ((type & (MACH_PORT_TYPE_RECEIVE)) == 0) {
 2179                 is_write_unlock(space);
 2180                 if (type & MACH_PORT_TYPE_PORT_OR_DEAD)
 2181                         return KERN_NOT_RECEIVER;
 2182                 else
 2183                         return KERN_INVALID_ARGUMENT;
 2184         }
 2185 
 2186         is_write_to_read_lock(space);
 2187         port = (ipc_port_t) entry->ie_object;
 2188         assert(port != IP_NULL);
 2189 
 2190         kr = ipc_pset_move(space, port, IPS_NULL);
 2191         /* space is unlocked */
 2192         return kr;
 2193 }
 2194 
 2195 /*
 2196  *      Routine:        port_set_status [kernel call]
 2197  *      Purpose:
 2198  *              Retrieve list of members of a port set.
 2199  *      Conditions:
 2200  *              Nothing locked.
 2201  *      Returns:
 2202  *              KERN_SUCCESS            Retrieved port set status.
 2203  *              KERN_INVALID_ARGUMENT   Task is null.
 2204  *              KERN_INVALID_ARGUMENT   Task is not active.
 2205  *              KERN_INVALID_ARGUMENT   Name doesn't denote a port set.
 2206  *      Additions:
 2207  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 2208  */
 2209 
 2210 kern_return_t
 2211 port_set_status(
 2212         ipc_space_t space,
 2213         mach_port_t name,
 2214         mach_port_t **members,
 2215         mach_msg_type_number_t *membersCnt)
 2216 {
 2217         kern_return_t kr;
 2218 
 2219         kr = mach_port_get_set_status(space, name, members, membersCnt);
 2220         if ((kr != KERN_SUCCESS) && (kr != KERN_RESOURCE_SHORTAGE))
 2221                 kr = KERN_INVALID_ARGUMENT;
 2222 
 2223         return kr;
 2224 }
 2225 
 2226 /*
 2227  *      Routine:        port_insert_send [kernel call]
 2228  *      Purpose:
 2229  *              Inserts send rights to a port into a task,
 2230  *              at a given name.  The name must not be in use.
 2231  *      Conditions:
 2232  *              Nothing locked.
 2233  *      Returns:
 2234  *              KERN_SUCCESS            Inserted send right.
 2235  *              KERN_INVALID_ARGUMENT   Task is null.
 2236  *              KERN_INVALID_ARGUMENT   Task is not active.
 2237  *              KERN_INVALID_ARGUMENT   Port is null or dead.
 2238  *              KERN_INVALID_ARGUMENT   Name is reserved.
 2239  *              KERN_NAME_EXISTS        Name already denotes a right.
 2240  *              KERN_FAILURE            Task already has rights for the port.
 2241  *      Additions:
 2242  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 2243  */
 2244 
 2245 kern_return_t
 2246 port_insert_send(
 2247         ipc_space_t space,
 2248         ipc_port_t port,
 2249         mach_port_t name)
 2250 {
 2251         kern_return_t kr;
 2252 
 2253         if ((space == IS_NULL) ||
 2254             !MACH_PORT_VALID(name) ||
 2255             !IP_VALID(port))
 2256                 return KERN_INVALID_ARGUMENT;
 2257 
 2258         kr = ipc_object_copyout_name_compat(space, (ipc_object_t) port,
 2259                                             MACH_MSG_TYPE_PORT_SEND, name);
 2260         switch (kr) {
 2261             case KERN_SUCCESS:
 2262             case KERN_NAME_EXISTS:
 2263             case KERN_RESOURCE_SHORTAGE:
 2264                 break;
 2265 
 2266             case KERN_RIGHT_EXISTS:
 2267                 kr = KERN_FAILURE;
 2268                 break;
 2269 
 2270             default:
 2271                 kr = KERN_INVALID_ARGUMENT;
 2272                 break;
 2273         }
 2274 
 2275         return kr;
 2276 }
 2277 
 2278 /*
 2279  *      Routine:        port_extract_send [kernel call]
 2280  *      Purpose:
 2281  *              Extracts send rights from "task"'s "his_name" port.
 2282  *              The task is left with no rights for the port.
 2283  *      Conditions:
 2284  *              Nothing locked.
 2285  *      Returns:
 2286  *              KERN_SUCCESS            Extracted send right.
 2287  *              KERN_INVALID_ARGUMENT   Task is null.
 2288  *              KERN_INVALID_ARGUMENT   Task is not active.
 2289  *              KERN_INVALID_ARGUMENT   Name doesn't denote pure send rights.
 2290  */
 2291 
 2292 kern_return_t
 2293 port_extract_send(
 2294         ipc_space_t space,
 2295         mach_port_t name,
 2296         ipc_port_t *portp)
 2297 {
 2298         kern_return_t kr;
 2299 
 2300         if (space == IS_NULL)
 2301                 return KERN_INVALID_ARGUMENT;
 2302 
 2303         kr = ipc_object_copyin_compat(space, name,
 2304                                       MSG_TYPE_PORT, TRUE,
 2305                                       (ipc_object_t *) portp);
 2306         if (kr != KERN_SUCCESS)
 2307                 kr = KERN_INVALID_ARGUMENT;
 2308 
 2309         return kr;
 2310 }
 2311 
 2312 /*
 2313  *      Routine:        port_insert_receive [kernel call]
 2314  *      Purpose:
 2315  *              Inserts receive/ownership rights to a port into a task,
 2316  *              at a given name.
 2317  *      Conditions:
 2318  *              Nothing locked.
 2319  *      Returns:
 2320  *              KERN_SUCCESS            Inserted receive right.
 2321  *              KERN_INVALID_ARGUMENT   Task is null.
 2322  *              KERN_INVALID_ARGUMENT   Task is not active.
 2323  *              KERN_INVALID_ARGUMENT   Port is null.  (Can't be dead.)
 2324  *              KERN_INVALID_ARGUMENT   Name is reserved.
 2325  *              KERN_NAME_EXISTS        Name already denotes a right.
 2326  *              KERN_FAILURE            Task already has rights for the port.
 2327  *      Additions:
 2328  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 2329  */
 2330 
 2331 kern_return_t
 2332 port_insert_receive(
 2333         ipc_space_t space,
 2334         ipc_port_t port,
 2335         mach_port_t name)
 2336 {
 2337         kern_return_t kr;
 2338 
 2339         if ((space == IS_NULL) ||
 2340             !MACH_PORT_VALID(name) ||
 2341             !IP_VALID(port))
 2342                 return KERN_INVALID_ARGUMENT;
 2343 
 2344         kr = ipc_object_copyout_name_compat(space, (ipc_object_t) port,
 2345                                             MACH_MSG_TYPE_PORT_RECEIVE, name);
 2346         switch (kr) {
 2347             case KERN_SUCCESS:
 2348             case KERN_NAME_EXISTS:
 2349             case KERN_RESOURCE_SHORTAGE:
 2350                 break;
 2351 
 2352             case KERN_RIGHT_EXISTS:
 2353                 kr = KERN_FAILURE;
 2354                 break;
 2355 
 2356             default:
 2357                 kr = KERN_INVALID_ARGUMENT;
 2358                 break;
 2359         }
 2360 
 2361         return kr;
 2362 }
 2363 
 2364 /*
 2365  *      Routine:        port_extract_receive [kernel call]
 2366  *      Purpose:
 2367  *              Extracts receive/ownership rights
 2368  *              from "task"'s "his_name" port.
 2369  *
 2370  *              The task is left with no rights for the port.
 2371  *      Conditions:
 2372  *              Nothing locked.
 2373  *      Returns:
 2374  *              KERN_SUCCESS            Extracted receive right.
 2375  *              KERN_INVALID_ARGUMENT   Task is null.
 2376  *              KERN_INVALID_ARGUMENT   Task is not active.
 2377  *              KERN_INVALID_ARGUMENT   Name doesn't denote receive rights.
 2378  */
 2379 
 2380 kern_return_t
 2381 port_extract_receive(
 2382         ipc_space_t space,
 2383         mach_port_t name,
 2384         ipc_port_t *portp)
 2385 {
 2386         kern_return_t kr;
 2387 
 2388         if (space == IS_NULL)
 2389                 return KERN_INVALID_ARGUMENT;
 2390 
 2391         kr = ipc_object_copyin_compat(space, name,
 2392                                       MSG_TYPE_PORT_ALL, TRUE,
 2393                                       (ipc_object_t *) portp);
 2394         if (kr != KERN_SUCCESS)
 2395                 kr = KERN_INVALID_ARGUMENT;
 2396 
 2397         return kr;
 2398 }
 2399 
 2400 #endif  /* MACH_IPC_COMPAT */

Cache object: ab647c271b2423427fbb0fc5c351c37f


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