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