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