|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_FREE_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: /* ! 53: * File: ipc/ipc_right.c ! 54: * Author: Rich Draves ! 55: * Date: 1989 ! 56: * ! 57: * Functions to manipulate IPC capabilities. ! 58: */ ! 59: ! 60: #include <dipc.h> ! 61: ! 62: #include <mach/boolean.h> ! 63: #include <mach/kern_return.h> ! 64: #include <mach/port.h> ! 65: #include <mach/message.h> ! 66: #include <kern/assert.h> ! 67: #include <kern/misc_protos.h> ! 68: #include <kern/ipc_subsystem.h> ! 69: #include <ipc/port.h> ! 70: #include <ipc/ipc_entry.h> ! 71: #include <ipc/ipc_space.h> ! 72: #include <ipc/ipc_object.h> ! 73: #include <ipc/ipc_hash.h> ! 74: #include <ipc/ipc_port.h> ! 75: #include <ipc/ipc_pset.h> ! 76: #include <ipc/ipc_right.h> ! 77: #include <ipc/ipc_notify.h> ! 78: #include <ipc/ipc_table.h> ! 79: ! 80: /* ! 81: * Routine: ipc_right_lookup_write ! 82: * Purpose: ! 83: * Finds an entry in a space, given the name. ! 84: * Conditions: ! 85: * Nothing locked. If successful, the space is write-locked. ! 86: * Returns: ! 87: * KERN_SUCCESS Found an entry. ! 88: * KERN_INVALID_TASK The space is dead. ! 89: * KERN_INVALID_NAME Name doesn't exist in space. ! 90: */ ! 91: ! 92: kern_return_t ! 93: ipc_right_lookup_write( ! 94: ipc_space_t space, ! 95: mach_port_name_t name, ! 96: ipc_entry_t *entryp) ! 97: { ! 98: ipc_entry_t entry; ! 99: ! 100: assert(space != IS_NULL); ! 101: ! 102: is_write_lock(space); ! 103: ! 104: if (!space->is_active) { ! 105: is_write_unlock(space); ! 106: return KERN_INVALID_TASK; ! 107: } ! 108: ! 109: if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) { ! 110: is_write_unlock(space); ! 111: return KERN_INVALID_NAME; ! 112: } ! 113: ! 114: *entryp = entry; ! 115: return KERN_SUCCESS; ! 116: } ! 117: ! 118: /* ! 119: * Routine: ipc_right_reverse ! 120: * Purpose: ! 121: * Translate (space, object) -> (name, entry). ! 122: * Only finds send/receive rights. ! 123: * Returns TRUE if an entry is found; if so, ! 124: * the object is locked and active. ! 125: * Conditions: ! 126: * The space must be locked (read or write) and active. ! 127: * Nothing else locked. ! 128: */ ! 129: ! 130: boolean_t ! 131: ipc_right_reverse( ! 132: ipc_space_t space, ! 133: ipc_object_t object, ! 134: mach_port_name_t *namep, ! 135: ipc_entry_t *entryp) ! 136: { ! 137: ipc_port_t port; ! 138: mach_port_name_t name; ! 139: ipc_entry_t entry; ! 140: ! 141: /* would switch on io_otype to handle multiple types of object */ ! 142: ! 143: assert(space->is_active); ! 144: assert(io_otype(object) == IOT_PORT); ! 145: ! 146: port = (ipc_port_t) object; ! 147: ! 148: ip_lock(port); ! 149: if (!ip_active(port)) { ! 150: ip_unlock(port); ! 151: ! 152: return FALSE; ! 153: } ! 154: ! 155: if (port->ip_receiver == space) { ! 156: name = port->ip_receiver_name; ! 157: assert(name != MACH_PORT_NULL); ! 158: ! 159: entry = ipc_entry_lookup(space, name); ! 160: ! 161: assert(entry != IE_NULL); ! 162: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); ! 163: assert(port == (ipc_port_t) entry->ie_object); ! 164: ! 165: *namep = name; ! 166: *entryp = entry; ! 167: return TRUE; ! 168: } ! 169: ! 170: if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) { ! 171: assert((entry = *entryp) != IE_NULL); ! 172: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND); ! 173: assert(port == (ipc_port_t) entry->ie_object); ! 174: ! 175: return TRUE; ! 176: } ! 177: ! 178: ip_unlock(port); ! 179: return FALSE; ! 180: } ! 181: ! 182: /* ! 183: * Routine: ipc_right_dnrequest ! 184: * Purpose: ! 185: * Make a dead-name request, returning the previously ! 186: * registered send-once right. If notify is IP_NULL, ! 187: * just cancels the previously registered request. ! 188: * ! 189: * This interacts with the IE_BITS_COMPAT, because they ! 190: * both use ie_request. If this is a compat entry, then ! 191: * previous always gets IP_NULL. If notify is IP_NULL, ! 192: * then the entry remains a compat entry. Otherwise ! 193: * the real dead-name request is registered and the entry ! 194: * is no longer a compat entry. ! 195: * Conditions: ! 196: * Nothing locked. May allocate memory. ! 197: * Only consumes/returns refs if successful. ! 198: * Returns: ! 199: * KERN_SUCCESS Made/canceled dead-name request. ! 200: * KERN_INVALID_TASK The space is dead. ! 201: * KERN_INVALID_NAME Name doesn't exist in space. ! 202: * KERN_INVALID_RIGHT Name doesn't denote port/dead rights. ! 203: * KERN_INVALID_ARGUMENT Name denotes dead name, but ! 204: * immediate is FALSE or notify is IP_NULL. ! 205: * KERN_UREFS_OVERFLOW Name denotes dead name, but ! 206: * generating immediate notif. would overflow urefs. ! 207: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 208: */ ! 209: ! 210: kern_return_t ! 211: ipc_right_dnrequest( ! 212: ipc_space_t space, ! 213: mach_port_name_t name, ! 214: boolean_t immediate, ! 215: ipc_port_t notify, ! 216: ipc_port_t *previousp) ! 217: { ! 218: ipc_port_t previous; ! 219: ! 220: for (;;) { ! 221: ipc_entry_t entry; ! 222: ipc_entry_bits_t bits; ! 223: kern_return_t kr; ! 224: ! 225: kr = ipc_right_lookup_write(space, name, &entry); ! 226: if (kr != KERN_SUCCESS) ! 227: return kr; ! 228: /* space is write-locked and active */ ! 229: bits = entry->ie_bits; ! 230: if (bits & MACH_PORT_TYPE_PORT_RIGHTS) { ! 231: ipc_port_t port; ! 232: ipc_port_request_index_t request; ! 233: ! 234: port = (ipc_port_t) entry->ie_object; ! 235: assert(port != IP_NULL); ! 236: ! 237: if (!ipc_right_check(space, port, name, entry)) { ! 238: /* port is locked and active */ ! 239: ! 240: if (notify == IP_NULL) { ! 241: previous = ipc_right_dncancel_macro( ! 242: space, port, name, entry); ! 243: ! 244: ip_unlock(port); ! 245: is_write_unlock(space); ! 246: break; ! 247: } ! 248: ! 249: /* ! 250: * If a registered soright exists, ! 251: * want to atomically switch with it. ! 252: * If ipc_port_dncancel finds us a ! 253: * soright, then the following ! 254: * ipc_port_dnrequest will reuse ! 255: * that slot, so we are guaranteed ! 256: * not to unlock and retry. ! 257: */ ! 258: ! 259: previous = ipc_right_dncancel_macro(space, ! 260: port, name, entry); ! 261: ! 262: kr = ipc_port_dnrequest(port, name, notify, ! 263: &request); ! 264: if (kr != KERN_SUCCESS) { ! 265: assert(previous == IP_NULL); ! 266: is_write_unlock(space); ! 267: ! 268: kr = ipc_port_dngrow(port, ! 269: ITS_SIZE_NONE); ! 270: /* port is unlocked */ ! 271: if (kr != KERN_SUCCESS) ! 272: return kr; ! 273: ! 274: continue; ! 275: } ! 276: ! 277: assert(request != 0); ! 278: ip_unlock(port); ! 279: ! 280: entry->ie_request = request; ! 281: is_write_unlock(space); ! 282: break; ! 283: } else { ! 284: ! 285: /* ! 286: * Our capability bits were changed by ipc_right_check ! 287: * because it found an inactive port and removed our ! 288: * references to it (converting our entry into a dead ! 289: * one). Reload the bits (and obviously we can't use ! 290: * the port name anymore). ! 291: */ ! 292: bits = entry->ie_bits; ! 293: ! 294: } ! 295: ! 296: assert(bits & MACH_PORT_TYPE_DEAD_NAME); ! 297: } ! 298: ! 299: if ((bits & MACH_PORT_TYPE_DEAD_NAME) && ! 300: immediate && (notify != IP_NULL)) { ! 301: mach_port_urefs_t urefs = IE_BITS_UREFS(bits); ! 302: ! 303: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 304: assert(urefs > 0); ! 305: ! 306: if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) { ! 307: is_write_unlock(space); ! 308: return KERN_UREFS_OVERFLOW; ! 309: } ! 310: ! 311: (entry->ie_bits)++; /* increment urefs */ ! 312: is_write_unlock(space); ! 313: ! 314: ipc_notify_dead_name(notify, name); ! 315: previous = IP_NULL; ! 316: break; ! 317: } ! 318: ! 319: is_write_unlock(space); ! 320: if (bits & MACH_PORT_TYPE_PORT_OR_DEAD) ! 321: return KERN_INVALID_ARGUMENT; ! 322: else ! 323: return KERN_INVALID_RIGHT; ! 324: } ! 325: ! 326: *previousp = previous; ! 327: return KERN_SUCCESS; ! 328: } ! 329: ! 330: /* ! 331: * Routine: ipc_right_dncancel ! 332: * Purpose: ! 333: * Cancel a dead-name request and return the send-once right. ! 334: * Afterwards, entry->ie_request == 0. ! 335: * Conditions: ! 336: * The space must be write-locked; the port must be locked. ! 337: * The port must be active; the space doesn't have to be. ! 338: */ ! 339: ! 340: ipc_port_t ! 341: ipc_right_dncancel( ! 342: ipc_space_t space, ! 343: ipc_port_t port, ! 344: mach_port_name_t name, ! 345: ipc_entry_t entry) ! 346: { ! 347: ipc_port_t dnrequest; ! 348: ! 349: assert(ip_active(port)); ! 350: assert(port == (ipc_port_t) entry->ie_object); ! 351: ! 352: dnrequest = ipc_port_dncancel(port, name, entry->ie_request); ! 353: entry->ie_request = 0; ! 354: ! 355: return dnrequest; ! 356: } ! 357: ! 358: /* ! 359: * Routine: ipc_right_inuse ! 360: * Purpose: ! 361: * Check if an entry is being used. ! 362: * Returns TRUE if it is. ! 363: * Conditions: ! 364: * The space is write-locked and active. ! 365: * It is unlocked if the entry is inuse. ! 366: */ ! 367: ! 368: boolean_t ! 369: ipc_right_inuse( ! 370: ipc_space_t space, ! 371: mach_port_name_t name, ! 372: ipc_entry_t entry) ! 373: { ! 374: if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) { ! 375: is_write_unlock(space); ! 376: return TRUE; ! 377: } ! 378: return FALSE; ! 379: } ! 380: ! 381: /* ! 382: * Routine: ipc_right_check ! 383: * Purpose: ! 384: * Check if the port has died. If it has, ! 385: * clean up the entry and return TRUE. ! 386: * Conditions: ! 387: * The space is write-locked; the port is not locked. ! 388: * If returns FALSE, the port is also locked and active. ! 389: * Otherwise, entry is converted to a dead name, freeing ! 390: * a reference to port. ! 391: */ ! 392: ! 393: boolean_t ! 394: ipc_right_check( ! 395: ipc_space_t space, ! 396: ipc_port_t port, ! 397: mach_port_name_t name, ! 398: ipc_entry_t entry) ! 399: { ! 400: ipc_entry_bits_t bits; ! 401: ! 402: assert(space->is_active); ! 403: assert(port == (ipc_port_t) entry->ie_object); ! 404: ! 405: ip_lock(port); ! 406: if (ip_active(port)) ! 407: return FALSE; ! 408: ip_unlock(port); ! 409: ! 410: /* this was either a pure send right or a send-once right */ ! 411: ! 412: bits = entry->ie_bits; ! 413: assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); ! 414: assert(IE_BITS_UREFS(bits) > 0); ! 415: ! 416: if (bits & MACH_PORT_TYPE_SEND) { ! 417: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); ! 418: } else { ! 419: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); ! 420: assert(IE_BITS_UREFS(bits) == 1); ! 421: } ! 422: ! 423: ! 424: ipc_port_release(port); ! 425: ! 426: /* convert entry to dead name */ ! 427: ! 428: if ((bits & MACH_PORT_TYPE_SEND) && !(bits & MACH_PORT_TYPE_RECEIVE)) ! 429: ipc_hash_delete(space, (ipc_object_t)port, name, entry); ! 430: ! 431: bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME; ! 432: ! 433: /* ! 434: * If there was a notification request outstanding on this ! 435: * name, and since the port went dead, that notification ! 436: * must already be on its way up from the port layer. We ! 437: * don't need the index of the notification port anymore. ! 438: * ! 439: * JMM - We also add a reference to the entry since the ! 440: * notification only carries the name and NOT a reference ! 441: * (or right). This makes for pretty loose reference ! 442: * counting, since it is only happenstance that we ! 443: * detected the notification in progress like this. ! 444: * But most (all?) calls that try to deal with this entry ! 445: * will also come through here, so the reference gets added ! 446: * before the entry gets used eventually (I would rather it ! 447: * be explicit in the notification generation, though) ! 448: */ ! 449: if (entry->ie_request != 0) { ! 450: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); ! 451: entry->ie_request = 0; ! 452: bits++; ! 453: } ! 454: entry->ie_bits = bits; ! 455: entry->ie_object = IO_NULL; ! 456: return TRUE; ! 457: } ! 458: ! 459: /* ! 460: * Routine: ipc_right_clean ! 461: * Purpose: ! 462: * Cleans up an entry in a dead space. ! 463: * The entry isn't deallocated or removed ! 464: * from reverse hash tables. ! 465: * Conditions: ! 466: * The space is dead and unlocked. ! 467: */ ! 468: ! 469: void ! 470: ipc_right_clean( ! 471: ipc_space_t space, ! 472: mach_port_name_t name, ! 473: ipc_entry_t entry) ! 474: { ! 475: ipc_entry_bits_t bits; ! 476: mach_port_type_t type; ! 477: ! 478: bits = entry->ie_bits; ! 479: type = IE_BITS_TYPE(bits); ! 480: ! 481: assert(!space->is_active); ! 482: ! 483: /* ! 484: * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this ! 485: * problem, because we check that the port is active. If ! 486: * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy ! 487: * would still work, but dead space refs would accumulate ! 488: * in ip_dnrequests. They would use up slots in ! 489: * ip_dnrequests and keep the spaces from being freed. ! 490: */ ! 491: ! 492: switch (type) { ! 493: case MACH_PORT_TYPE_DEAD_NAME: ! 494: assert(entry->ie_request == 0); ! 495: assert(entry->ie_object == IO_NULL); ! 496: break; ! 497: ! 498: case MACH_PORT_TYPE_PORT_SET: { ! 499: ipc_pset_t pset = (ipc_pset_t) entry->ie_object; ! 500: ! 501: assert(entry->ie_request == 0); ! 502: assert(pset != IPS_NULL); ! 503: ! 504: ips_lock(pset); ! 505: assert(ips_active(pset)); ! 506: ! 507: ipc_pset_destroy(pset); /* consumes ref, unlocks */ ! 508: break; ! 509: } ! 510: ! 511: case MACH_PORT_TYPE_SEND: ! 512: case MACH_PORT_TYPE_RECEIVE: ! 513: case MACH_PORT_TYPE_SEND_RECEIVE: ! 514: case MACH_PORT_TYPE_SEND_ONCE: { ! 515: ipc_port_t port = (ipc_port_t) entry->ie_object; ! 516: ipc_port_t dnrequest; ! 517: ipc_port_t nsrequest = IP_NULL; ! 518: mach_port_mscount_t mscount; ! 519: ! 520: assert(port != IP_NULL); ! 521: ip_lock(port); ! 522: ! 523: if (!ip_active(port)) { ! 524: ip_release(port); ! 525: ip_check_unlock(port); ! 526: break; ! 527: } ! 528: ! 529: dnrequest = ipc_right_dncancel_macro(space, port, ! 530: name, entry); ! 531: ! 532: if (type & MACH_PORT_TYPE_SEND) { ! 533: assert(port->ip_srights > 0); ! 534: if (--port->ip_srights == 0 ! 535: ) { ! 536: nsrequest = port->ip_nsrequest; ! 537: if (nsrequest != IP_NULL) { ! 538: port->ip_nsrequest = IP_NULL; ! 539: mscount = port->ip_mscount; ! 540: } ! 541: } ! 542: } ! 543: ! 544: if (type & MACH_PORT_TYPE_RECEIVE) { ! 545: assert(port->ip_receiver_name == name); ! 546: assert(port->ip_receiver == space); ! 547: ! 548: ipc_port_clear_receiver(port); ! 549: ipc_port_destroy(port); /* consumes our ref, unlocks */ ! 550: } else if (type & MACH_PORT_TYPE_SEND_ONCE) { ! 551: assert(port->ip_sorights > 0); ! 552: ip_unlock(port); ! 553: ! 554: ipc_notify_send_once(port); /* consumes our ref */ ! 555: } else { ! 556: assert(port->ip_receiver != space); ! 557: ! 558: ip_release(port); ! 559: ip_unlock(port); /* port is active */ ! 560: } ! 561: ! 562: if (nsrequest != IP_NULL) ! 563: ipc_notify_no_senders(nsrequest, mscount); ! 564: ! 565: if (dnrequest != IP_NULL) ! 566: ipc_notify_port_deleted(dnrequest, name); ! 567: break; ! 568: } ! 569: ! 570: default: ! 571: panic("ipc_right_clean: strange type"); ! 572: } ! 573: } ! 574: ! 575: /* ! 576: * Routine: ipc_right_destroy ! 577: * Purpose: ! 578: * Destroys an entry in a space. ! 579: * Conditions: ! 580: * The space is write-locked. ! 581: * The space must be active. ! 582: * Returns: ! 583: * KERN_SUCCESS The entry was destroyed. ! 584: */ ! 585: ! 586: kern_return_t ! 587: ipc_right_destroy( ! 588: ipc_space_t space, ! 589: mach_port_name_t name, ! 590: ipc_entry_t entry) ! 591: { ! 592: ipc_entry_bits_t bits; ! 593: mach_port_type_t type; ! 594: ! 595: bits = entry->ie_bits; ! 596: entry->ie_bits &= ~IE_BITS_TYPE_MASK; ! 597: type = IE_BITS_TYPE(bits); ! 598: ! 599: assert(space->is_active); ! 600: ! 601: switch (type) { ! 602: case MACH_PORT_TYPE_DEAD_NAME: ! 603: assert(entry->ie_request == 0); ! 604: assert(entry->ie_object == IO_NULL); ! 605: ! 606: ipc_entry_dealloc(space, name, entry); ! 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(pset != IPS_NULL); ! 614: ! 615: entry->ie_object = IO_NULL; ! 616: /* port sets are not sharable entries on a subspace basis */ ! 617: /* so there is no need to check the subspace array here */ ! 618: ipc_entry_dealloc(space, name, entry); ! 619: ! 620: ips_lock(pset); ! 621: assert(ips_active(pset)); ! 622: ! 623: ipc_pset_destroy(pset); /* consumes ref, unlocks */ ! 624: break; ! 625: } ! 626: ! 627: case MACH_PORT_TYPE_SEND: ! 628: case MACH_PORT_TYPE_RECEIVE: ! 629: case MACH_PORT_TYPE_SEND_RECEIVE: ! 630: case MACH_PORT_TYPE_SEND_ONCE: { ! 631: ipc_port_t port = (ipc_port_t) entry->ie_object; ! 632: ipc_port_t nsrequest = IP_NULL; ! 633: mach_port_mscount_t mscount; ! 634: ipc_port_t dnrequest; ! 635: ! 636: assert(port != IP_NULL); ! 637: ! 638: if (type == MACH_PORT_TYPE_SEND) ! 639: ipc_hash_delete(space, (ipc_object_t) port, ! 640: name, entry); ! 641: ! 642: ip_lock(port); ! 643: ! 644: if (!ip_active(port)) { ! 645: assert((type & MACH_PORT_TYPE_RECEIVE) == 0); ! 646: ip_release(port); ! 647: ip_check_unlock(port); ! 648: ! 649: entry->ie_request = 0; ! 650: entry->ie_object = IO_NULL; ! 651: ipc_entry_dealloc(space, name, entry); ! 652: ! 653: break; ! 654: } ! 655: ! 656: dnrequest = ipc_right_dncancel_macro(space, port, name, entry); ! 657: ! 658: entry->ie_object = IO_NULL; ! 659: ipc_entry_dealloc(space, name, entry); ! 660: ! 661: if (type & MACH_PORT_TYPE_SEND) { ! 662: assert(port->ip_srights > 0); ! 663: if (--port->ip_srights == 0) { ! 664: nsrequest = port->ip_nsrequest; ! 665: if (nsrequest != IP_NULL) { ! 666: port->ip_nsrequest = IP_NULL; ! 667: mscount = port->ip_mscount; ! 668: } ! 669: } ! 670: } ! 671: ! 672: if (type & MACH_PORT_TYPE_RECEIVE) { ! 673: assert(ip_active(port)); ! 674: assert(port->ip_receiver == space); ! 675: ! 676: if (port->ip_subsystem) ! 677: subsystem_deallocate( ! 678: port->ip_subsystem->subsystem); ! 679: ipc_port_clear_receiver(port); ! 680: ipc_port_destroy(port); /* consumes our ref, unlocks */ ! 681: } else if (type & MACH_PORT_TYPE_SEND_ONCE) { ! 682: assert(port->ip_sorights > 0); ! 683: ip_unlock(port); ! 684: ! 685: ipc_notify_send_once(port); /* consumes our ref */ ! 686: } else { ! 687: assert(port->ip_receiver != space); ! 688: ! 689: ip_release(port); ! 690: ip_unlock(port); ! 691: } ! 692: ! 693: if (nsrequest != IP_NULL) ! 694: ipc_notify_no_senders(nsrequest, mscount); ! 695: ! 696: if (dnrequest != IP_NULL) ! 697: ipc_notify_port_deleted(dnrequest, name); ! 698: break; ! 699: } ! 700: ! 701: default: ! 702: panic("ipc_right_destroy: strange type"); ! 703: } ! 704: ! 705: return KERN_SUCCESS; ! 706: } ! 707: ! 708: /* ! 709: * Routine: ipc_right_dealloc ! 710: * Purpose: ! 711: * Releases a send/send-once/dead-name user ref. ! 712: * Like ipc_right_delta with a delta of -1, ! 713: * but looks at the entry to determine the right. ! 714: * Conditions: ! 715: * The space is write-locked, and is unlocked upon return. ! 716: * The space must be active. ! 717: * Returns: ! 718: * KERN_SUCCESS A user ref was released. ! 719: * KERN_INVALID_RIGHT Entry has wrong type. ! 720: */ ! 721: ! 722: kern_return_t ! 723: ipc_right_dealloc( ! 724: ipc_space_t space, ! 725: mach_port_name_t name, ! 726: ipc_entry_t entry) ! 727: { ! 728: ! 729: ipc_entry_bits_t bits; ! 730: mach_port_type_t type; ! 731: ! 732: bits = entry->ie_bits; ! 733: type = IE_BITS_TYPE(bits); ! 734: ! 735: ! 736: assert(space->is_active); ! 737: ! 738: switch (type) { ! 739: case MACH_PORT_TYPE_DEAD_NAME: { ! 740: dead_name: ! 741: ! 742: assert(IE_BITS_UREFS(bits) > 0); ! 743: assert(entry->ie_request == 0); ! 744: assert(entry->ie_object == IO_NULL); ! 745: ! 746: if (IE_BITS_UREFS(bits) == 1) { ! 747: ipc_entry_dealloc(space, name, entry); ! 748: } ! 749: else ! 750: entry->ie_bits = bits-1; /* decrement urefs */ ! 751: ! 752: is_write_unlock(space); ! 753: break; ! 754: } ! 755: ! 756: case MACH_PORT_TYPE_SEND_ONCE: { ! 757: ipc_port_t port, dnrequest; ! 758: ! 759: assert(IE_BITS_UREFS(bits) == 1); ! 760: ! 761: port = (ipc_port_t) entry->ie_object; ! 762: assert(port != IP_NULL); ! 763: ! 764: if (ipc_right_check(space, port, name, entry)) { ! 765: ! 766: bits = entry->ie_bits; ! 767: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 768: goto dead_name; ! 769: } ! 770: /* port is locked and active */ ! 771: ! 772: assert(port->ip_sorights > 0); ! 773: ! 774: dnrequest = ipc_right_dncancel_macro(space, port, name, entry); ! 775: ip_unlock(port); ! 776: ! 777: entry->ie_object = IO_NULL; ! 778: ipc_entry_dealloc(space, name, entry); ! 779: ! 780: is_write_unlock(space); ! 781: ! 782: ipc_notify_send_once(port); ! 783: ! 784: if (dnrequest != IP_NULL) ! 785: ipc_notify_port_deleted(dnrequest, name); ! 786: break; ! 787: } ! 788: ! 789: case MACH_PORT_TYPE_SEND: { ! 790: ipc_port_t port; ! 791: ipc_port_t dnrequest = IP_NULL; ! 792: ipc_port_t nsrequest = IP_NULL; ! 793: mach_port_mscount_t mscount; ! 794: ! 795: ! 796: assert(IE_BITS_UREFS(bits) > 0); ! 797: ! 798: port = (ipc_port_t) entry->ie_object; ! 799: assert(port != IP_NULL); ! 800: ! 801: if (ipc_right_check(space, port, name, entry)) { ! 802: bits = entry->ie_bits; ! 803: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 804: goto dead_name; ! 805: } ! 806: /* port is locked and active */ ! 807: ! 808: assert(port->ip_srights > 0); ! 809: ! 810: if (IE_BITS_UREFS(bits) == 1) { ! 811: if (--port->ip_srights == 0) { ! 812: nsrequest = port->ip_nsrequest; ! 813: if (nsrequest != IP_NULL) { ! 814: port->ip_nsrequest = IP_NULL; ! 815: mscount = port->ip_mscount; ! 816: } ! 817: } ! 818: ! 819: dnrequest = ipc_right_dncancel_macro(space, port, ! 820: name, entry); ! 821: ipc_hash_delete(space, (ipc_object_t) port, ! 822: name, entry); ! 823: ! 824: ip_release(port); ! 825: entry->ie_object = IO_NULL; ! 826: ipc_entry_dealloc(space, name, entry); ! 827: ! 828: } else ! 829: entry->ie_bits = bits-1; /* decrement urefs */ ! 830: ! 831: /* even if dropped a ref, port is active */ ! 832: ip_unlock(port); ! 833: is_write_unlock(space); ! 834: ! 835: if (nsrequest != IP_NULL) ! 836: ipc_notify_no_senders(nsrequest, mscount); ! 837: ! 838: if (dnrequest != IP_NULL) ! 839: ipc_notify_port_deleted(dnrequest, name); ! 840: break; ! 841: } ! 842: ! 843: case MACH_PORT_TYPE_SEND_RECEIVE: { ! 844: ipc_port_t port; ! 845: ipc_port_t nsrequest = IP_NULL; ! 846: mach_port_mscount_t mscount; ! 847: ! 848: assert(IE_BITS_UREFS(bits) > 0); ! 849: ! 850: port = (ipc_port_t) entry->ie_object; ! 851: assert(port != IP_NULL); ! 852: ! 853: ip_lock(port); ! 854: assert(ip_active(port)); ! 855: assert(port->ip_receiver_name == name); ! 856: assert(port->ip_receiver == space); ! 857: assert(port->ip_srights > 0); ! 858: ! 859: if (IE_BITS_UREFS(bits) == 1) { ! 860: if (--port->ip_srights == 0) { ! 861: nsrequest = port->ip_nsrequest; ! 862: if (nsrequest != IP_NULL) { ! 863: port->ip_nsrequest = IP_NULL; ! 864: mscount = port->ip_mscount; ! 865: } ! 866: } ! 867: ! 868: entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK | ! 869: MACH_PORT_TYPE_SEND); ! 870: } else ! 871: entry->ie_bits = bits-1; /* decrement urefs */ ! 872: ! 873: ip_unlock(port); ! 874: is_write_unlock(space); ! 875: ! 876: if (nsrequest != IP_NULL) ! 877: ipc_notify_no_senders(nsrequest, mscount); ! 878: break; ! 879: } ! 880: ! 881: default: ! 882: is_write_unlock(space); ! 883: return KERN_INVALID_RIGHT; ! 884: } ! 885: ! 886: return KERN_SUCCESS; ! 887: } ! 888: ! 889: /* ! 890: * Routine: ipc_right_delta ! 891: * Purpose: ! 892: * Modifies the user-reference count for a right. ! 893: * May deallocate the right, if the count goes to zero. ! 894: * Conditions: ! 895: * The space is write-locked, and is unlocked upon return. ! 896: * The space must be active. ! 897: * Returns: ! 898: * KERN_SUCCESS Count was modified. ! 899: * KERN_INVALID_RIGHT Entry has wrong type. ! 900: * KERN_INVALID_VALUE Bad delta for the right. ! 901: * KERN_UREFS_OVERFLOW OK delta, except would overflow. ! 902: */ ! 903: ! 904: kern_return_t ! 905: ipc_right_delta( ! 906: ipc_space_t space, ! 907: mach_port_name_t name, ! 908: ipc_entry_t entry, ! 909: mach_port_right_t right, ! 910: mach_port_delta_t delta) ! 911: { ! 912: ipc_entry_bits_t bits; ! 913: ! 914: bits = entry->ie_bits; ! 915: ! 916: ! 917: /* ! 918: * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the ! 919: * switch below. It is used to keep track of those cases (in DIPC) ! 920: * where we have postponed the dropping of a port reference. Since ! 921: * the dropping of the reference could cause the port to disappear ! 922: * we postpone doing so when we are holding the space lock. ! 923: */ ! 924: ! 925: assert(space->is_active); ! 926: assert(right < MACH_PORT_RIGHT_NUMBER); ! 927: ! 928: /* Rights-specific restrictions and operations. */ ! 929: ! 930: switch (right) { ! 931: case MACH_PORT_RIGHT_PORT_SET: { ! 932: ipc_pset_t pset; ! 933: ! 934: if ((bits & MACH_PORT_TYPE_PORT_SET) == 0) ! 935: goto invalid_right; ! 936: ! 937: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET); ! 938: assert(IE_BITS_UREFS(bits) == 0); ! 939: assert(entry->ie_request == 0); ! 940: ! 941: if (delta == 0) ! 942: goto success; ! 943: ! 944: if (delta != -1) ! 945: goto invalid_value; ! 946: ! 947: pset = (ipc_pset_t) entry->ie_object; ! 948: assert(pset != IPS_NULL); ! 949: ! 950: ! 951: ! 952: entry->ie_object = IO_NULL; ! 953: ipc_entry_dealloc(space, name, entry); ! 954: ! 955: ! 956: ips_lock(pset); ! 957: assert(ips_active(pset)); ! 958: is_write_unlock(space); ! 959: ! 960: ipc_pset_destroy(pset); /* consumes ref, unlocks */ ! 961: break; ! 962: } ! 963: ! 964: case MACH_PORT_RIGHT_RECEIVE: { ! 965: ipc_port_t port; ! 966: ipc_port_t dnrequest = IP_NULL; ! 967: ! 968: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) ! 969: goto invalid_right; ! 970: ! 971: if (delta == 0) ! 972: goto success; ! 973: ! 974: if (delta != -1) ! 975: goto invalid_value; ! 976: ! 977: port = (ipc_port_t) entry->ie_object; ! 978: assert(port != IP_NULL); ! 979: ! 980: /* ! 981: * The port lock is needed for ipc_right_dncancel; ! 982: * otherwise, we wouldn't have to take the lock ! 983: * until just before dropping the space lock. ! 984: */ ! 985: ! 986: ip_lock(port); ! 987: assert(ip_active(port)); ! 988: assert(port->ip_receiver_name == name); ! 989: assert(port->ip_receiver == space); ! 990: ! 991: if (bits & MACH_PORT_TYPE_SEND) { ! 992: assert(IE_BITS_TYPE(bits) == ! 993: MACH_PORT_TYPE_SEND_RECEIVE); ! 994: assert(IE_BITS_UREFS(bits) > 0); ! 995: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); ! 996: assert(port->ip_srights > 0); ! 997: ! 998: /* ! 999: * The remaining send right turns into a ! 1000: * dead name. Notice we don't decrement ! 1001: * ip_srights, generate a no-senders notif, ! 1002: * or use ipc_right_dncancel, because the ! 1003: * port is destroyed "first". ! 1004: */ ! 1005: bits &= ~IE_BITS_TYPE_MASK; ! 1006: bits |= MACH_PORT_TYPE_DEAD_NAME; ! 1007: if (entry->ie_request) { ! 1008: entry->ie_request = 0; ! 1009: bits++; ! 1010: } ! 1011: entry->ie_bits = bits; ! 1012: entry->ie_object = IO_NULL; ! 1013: } else { ! 1014: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); ! 1015: assert(IE_BITS_UREFS(bits) == 0); ! 1016: ! 1017: dnrequest = ipc_right_dncancel_macro(space, port, ! 1018: name, entry); ! 1019: entry->ie_object = IO_NULL; ! 1020: ipc_entry_dealloc(space, name, entry); ! 1021: } ! 1022: is_write_unlock(space); ! 1023: ! 1024: ipc_port_clear_receiver(port); ! 1025: ipc_port_destroy(port); /* consumes ref, unlocks */ ! 1026: ! 1027: if (dnrequest != IP_NULL) ! 1028: ipc_notify_port_deleted(dnrequest, name); ! 1029: break; ! 1030: } ! 1031: ! 1032: case MACH_PORT_RIGHT_SEND_ONCE: { ! 1033: ipc_port_t port, dnrequest; ! 1034: ! 1035: if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) ! 1036: goto invalid_right; ! 1037: ! 1038: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); ! 1039: assert(IE_BITS_UREFS(bits) == 1); ! 1040: ! 1041: port = (ipc_port_t) entry->ie_object; ! 1042: assert(port != IP_NULL); ! 1043: ! 1044: if (ipc_right_check(space, port, name, entry)) { ! 1045: assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE)); ! 1046: goto invalid_right; ! 1047: } ! 1048: /* port is locked and active */ ! 1049: ! 1050: assert(port->ip_sorights > 0); ! 1051: ! 1052: if ((delta > 0) || (delta < -1)) { ! 1053: ip_unlock(port); ! 1054: goto invalid_value; ! 1055: } ! 1056: ! 1057: if (delta == 0) { ! 1058: ip_unlock(port); ! 1059: goto success; ! 1060: } ! 1061: ! 1062: dnrequest = ipc_right_dncancel_macro(space, port, name, entry); ! 1063: ip_unlock(port); ! 1064: ! 1065: entry->ie_object = IO_NULL; ! 1066: ipc_entry_dealloc(space, name, entry); ! 1067: ! 1068: is_write_unlock(space); ! 1069: ! 1070: ipc_notify_send_once(port); ! 1071: ! 1072: if (dnrequest != IP_NULL) ! 1073: ipc_notify_port_deleted(dnrequest, name); ! 1074: break; ! 1075: } ! 1076: ! 1077: case MACH_PORT_RIGHT_DEAD_NAME: { ! 1078: mach_port_urefs_t urefs; ! 1079: ! 1080: if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { ! 1081: ipc_port_t port; ! 1082: ! 1083: port = (ipc_port_t) entry->ie_object; ! 1084: assert(port != IP_NULL); ! 1085: ! 1086: if (!ipc_right_check(space, port, name, entry)) { ! 1087: /* port is locked and active */ ! 1088: ip_unlock(port); ! 1089: goto invalid_right; ! 1090: } ! 1091: bits = entry->ie_bits; ! 1092: } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0) ! 1093: goto invalid_right; ! 1094: ! 1095: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 1096: assert(IE_BITS_UREFS(bits) > 0); ! 1097: assert(entry->ie_object == IO_NULL); ! 1098: assert(entry->ie_request == 0); ! 1099: ! 1100: urefs = IE_BITS_UREFS(bits); ! 1101: if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) ! 1102: goto invalid_value; ! 1103: if (MACH_PORT_UREFS_OVERFLOW(urefs, delta)) ! 1104: goto urefs_overflow; ! 1105: ! 1106: if ((urefs + delta) == 0) { ! 1107: ipc_entry_dealloc(space, name, entry); ! 1108: } ! 1109: else ! 1110: entry->ie_bits = bits + delta; ! 1111: ! 1112: is_write_unlock(space); ! 1113: ! 1114: break; ! 1115: } ! 1116: ! 1117: case MACH_PORT_RIGHT_SEND: { ! 1118: mach_port_urefs_t urefs; ! 1119: ipc_port_t port; ! 1120: ipc_port_t dnrequest = IP_NULL; ! 1121: ipc_port_t nsrequest = IP_NULL; ! 1122: mach_port_mscount_t mscount; ! 1123: ! 1124: if ((bits & MACH_PORT_TYPE_SEND) == 0) ! 1125: goto invalid_right; ! 1126: ! 1127: /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */ ! 1128: ! 1129: port = (ipc_port_t) entry->ie_object; ! 1130: assert(port != IP_NULL); ! 1131: ! 1132: if (ipc_right_check(space, port, name, entry)) { ! 1133: assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0); ! 1134: goto invalid_right; ! 1135: } ! 1136: /* port is locked and active */ ! 1137: ! 1138: assert(port->ip_srights > 0); ! 1139: ! 1140: urefs = IE_BITS_UREFS(bits); ! 1141: if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) { ! 1142: ip_unlock(port); ! 1143: goto invalid_value; ! 1144: } ! 1145: if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) { ! 1146: ip_unlock(port); ! 1147: goto urefs_overflow; ! 1148: } ! 1149: ! 1150: if ((urefs + delta) == 0) { ! 1151: if (--port->ip_srights == 0) { ! 1152: nsrequest = port->ip_nsrequest; ! 1153: if (nsrequest != IP_NULL) { ! 1154: port->ip_nsrequest = IP_NULL; ! 1155: mscount = port->ip_mscount; ! 1156: } ! 1157: } ! 1158: ! 1159: if (bits & MACH_PORT_TYPE_RECEIVE) { ! 1160: assert(port->ip_receiver_name == name); ! 1161: assert(port->ip_receiver == space); ! 1162: assert(IE_BITS_TYPE(bits) == ! 1163: MACH_PORT_TYPE_SEND_RECEIVE); ! 1164: ! 1165: entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK| ! 1166: MACH_PORT_TYPE_SEND); ! 1167: } else { ! 1168: assert(IE_BITS_TYPE(bits) == ! 1169: MACH_PORT_TYPE_SEND); ! 1170: ! 1171: dnrequest = ipc_right_dncancel_macro(space, port, ! 1172: name, entry); ! 1173: ipc_hash_delete(space, (ipc_object_t) port, ! 1174: name, entry); ! 1175: ! 1176: ip_release(port); ! 1177: ! 1178: entry->ie_object = IO_NULL; ! 1179: ipc_entry_dealloc(space, name, entry); ! 1180: } ! 1181: } else ! 1182: entry->ie_bits = bits + delta; ! 1183: ! 1184: /* even if dropped a ref, port is active */ ! 1185: ip_unlock(port); ! 1186: is_write_unlock(space); ! 1187: ! 1188: if (nsrequest != IP_NULL) ! 1189: ipc_notify_no_senders(nsrequest, mscount); ! 1190: ! 1191: if (dnrequest != IP_NULL) ! 1192: ipc_notify_port_deleted(dnrequest, name); ! 1193: break; ! 1194: } ! 1195: ! 1196: default: ! 1197: panic("ipc_right_delta: strange right"); ! 1198: } ! 1199: ! 1200: return KERN_SUCCESS; ! 1201: ! 1202: success: ! 1203: is_write_unlock(space); ! 1204: return KERN_SUCCESS; ! 1205: ! 1206: invalid_right: ! 1207: is_write_unlock(space); ! 1208: return KERN_INVALID_RIGHT; ! 1209: ! 1210: invalid_value: ! 1211: is_write_unlock(space); ! 1212: return KERN_INVALID_VALUE; ! 1213: ! 1214: urefs_overflow: ! 1215: is_write_unlock(space); ! 1216: return KERN_UREFS_OVERFLOW; ! 1217: } ! 1218: ! 1219: /* ! 1220: * Routine: ipc_right_info ! 1221: * Purpose: ! 1222: * Retrieves information about the right. ! 1223: * Conditions: ! 1224: * The space is write-locked, and is unlocked upon return ! 1225: * if the call is unsuccessful. The space must be active. ! 1226: * Returns: ! 1227: * KERN_SUCCESS Retrieved info; space still locked. ! 1228: */ ! 1229: ! 1230: kern_return_t ! 1231: ipc_right_info( ! 1232: ipc_space_t space, ! 1233: mach_port_name_t name, ! 1234: ipc_entry_t entry, ! 1235: mach_port_type_t *typep, ! 1236: mach_port_urefs_t *urefsp) ! 1237: { ! 1238: ipc_entry_bits_t bits; ! 1239: mach_port_type_t type; ! 1240: ipc_port_request_index_t request; ! 1241: ! 1242: bits = entry->ie_bits; ! 1243: ! 1244: if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { ! 1245: ipc_port_t port = (ipc_port_t) entry->ie_object; ! 1246: ! 1247: if (ipc_right_check(space, port, name, entry)) { ! 1248: bits = entry->ie_bits; ! 1249: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 1250: } else ! 1251: ip_unlock(port); ! 1252: } ! 1253: ! 1254: type = IE_BITS_TYPE(bits); ! 1255: request = entry->ie_request; ! 1256: ! 1257: if (request != 0) ! 1258: type |= MACH_PORT_TYPE_DNREQUEST; ! 1259: ! 1260: *typep = type; ! 1261: *urefsp = IE_BITS_UREFS(bits); ! 1262: return KERN_SUCCESS; ! 1263: } ! 1264: ! 1265: /* ! 1266: * Routine: ipc_right_copyin_check ! 1267: * Purpose: ! 1268: * Check if a subsequent ipc_right_copyin would succeed. ! 1269: * Conditions: ! 1270: * The space is locked (read or write) and active. ! 1271: */ ! 1272: ! 1273: boolean_t ! 1274: ipc_right_copyin_check( ! 1275: ipc_space_t space, ! 1276: mach_port_name_t name, ! 1277: ipc_entry_t entry, ! 1278: mach_msg_type_name_t msgt_name) ! 1279: { ! 1280: ipc_entry_bits_t bits; ! 1281: ! 1282: bits= entry->ie_bits; ! 1283: assert(space->is_active); ! 1284: ! 1285: switch (msgt_name) { ! 1286: case MACH_MSG_TYPE_MAKE_SEND: ! 1287: case MACH_MSG_TYPE_MAKE_SEND_ONCE: ! 1288: case MACH_MSG_TYPE_MOVE_RECEIVE: ! 1289: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) ! 1290: return FALSE; ! 1291: ! 1292: break; ! 1293: ! 1294: case MACH_MSG_TYPE_COPY_SEND: ! 1295: case MACH_MSG_TYPE_MOVE_SEND: ! 1296: case MACH_MSG_TYPE_MOVE_SEND_ONCE: { ! 1297: ipc_port_t port; ! 1298: boolean_t active; ! 1299: ! 1300: if (bits & MACH_PORT_TYPE_DEAD_NAME) ! 1301: break; ! 1302: ! 1303: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) ! 1304: return FALSE; ! 1305: ! 1306: port = (ipc_port_t) entry->ie_object; ! 1307: assert(port != IP_NULL); ! 1308: ! 1309: ip_lock(port); ! 1310: active = ip_active(port); ! 1311: ip_unlock(port); ! 1312: ! 1313: if (!active) { ! 1314: break; ! 1315: } ! 1316: ! 1317: if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) { ! 1318: if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) ! 1319: return FALSE; ! 1320: } else { ! 1321: if ((bits & MACH_PORT_TYPE_SEND) == 0) ! 1322: return FALSE; ! 1323: } ! 1324: ! 1325: break; ! 1326: } ! 1327: ! 1328: default: ! 1329: panic("ipc_right_copyin_check: strange rights"); ! 1330: } ! 1331: ! 1332: return TRUE; ! 1333: } ! 1334: ! 1335: /* ! 1336: * Routine: ipc_right_copyin ! 1337: * Purpose: ! 1338: * Copyin a capability from a space. ! 1339: * If successful, the caller gets a ref ! 1340: * for the resulting object, unless it is IO_DEAD, ! 1341: * and possibly a send-once right which should ! 1342: * be used in a port-deleted notification. ! 1343: * ! 1344: * If deadok is not TRUE, the copyin operation ! 1345: * will fail instead of producing IO_DEAD. ! 1346: * ! 1347: * The entry is never deallocated (except ! 1348: * when KERN_INVALID_NAME), so the caller ! 1349: * should deallocate the entry if its type ! 1350: * is MACH_PORT_TYPE_NONE. ! 1351: * Conditions: ! 1352: * The space is write-locked and active. ! 1353: * Returns: ! 1354: * KERN_SUCCESS Acquired an object, possibly IO_DEAD. ! 1355: * KERN_INVALID_RIGHT Name doesn't denote correct right. ! 1356: */ ! 1357: ! 1358: kern_return_t ! 1359: ipc_right_copyin( ! 1360: ipc_space_t space, ! 1361: mach_port_name_t name, ! 1362: ipc_entry_t entry, ! 1363: mach_msg_type_name_t msgt_name, ! 1364: boolean_t deadok, ! 1365: ipc_object_t *objectp, ! 1366: ipc_port_t *sorightp) ! 1367: { ! 1368: ipc_entry_bits_t bits; ! 1369: ! 1370: bits = entry->ie_bits; ! 1371: ! 1372: assert(space->is_active); ! 1373: ! 1374: switch (msgt_name) { ! 1375: case MACH_MSG_TYPE_MAKE_SEND: { ! 1376: ipc_port_t port; ! 1377: ! 1378: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) ! 1379: goto invalid_right; ! 1380: ! 1381: port = (ipc_port_t) entry->ie_object; ! 1382: assert(port != IP_NULL); ! 1383: ! 1384: ip_lock(port); ! 1385: assert(ip_active(port)); ! 1386: assert(port->ip_receiver_name == name); ! 1387: assert(port->ip_receiver == space); ! 1388: ! 1389: port->ip_mscount++; ! 1390: port->ip_srights++; ! 1391: ip_reference(port); ! 1392: ip_unlock(port); ! 1393: ! 1394: *objectp = (ipc_object_t) port; ! 1395: *sorightp = IP_NULL; ! 1396: break; ! 1397: } ! 1398: ! 1399: case MACH_MSG_TYPE_MAKE_SEND_ONCE: { ! 1400: ipc_port_t port; ! 1401: ! 1402: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) ! 1403: goto invalid_right; ! 1404: ! 1405: port = (ipc_port_t) entry->ie_object; ! 1406: assert(port != IP_NULL); ! 1407: ! 1408: ip_lock(port); ! 1409: assert(ip_active(port)); ! 1410: assert(port->ip_receiver_name == name); ! 1411: assert(port->ip_receiver == space); ! 1412: ! 1413: port->ip_sorights++; ! 1414: ip_reference(port); ! 1415: ip_unlock(port); ! 1416: ! 1417: *objectp = (ipc_object_t) port; ! 1418: *sorightp = IP_NULL; ! 1419: break; ! 1420: } ! 1421: ! 1422: case MACH_MSG_TYPE_MOVE_RECEIVE: { ! 1423: ipc_port_t port; ! 1424: ipc_port_t dnrequest = IP_NULL; ! 1425: ! 1426: if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) ! 1427: goto invalid_right; ! 1428: ! 1429: port = (ipc_port_t) entry->ie_object; ! 1430: assert(port != IP_NULL); ! 1431: ! 1432: ip_lock(port); ! 1433: assert(ip_active(port)); ! 1434: assert(port->ip_receiver_name == name); ! 1435: assert(port->ip_receiver == space); ! 1436: ! 1437: if (bits & MACH_PORT_TYPE_SEND) { ! 1438: assert(IE_BITS_TYPE(bits) == ! 1439: MACH_PORT_TYPE_SEND_RECEIVE); ! 1440: assert(IE_BITS_UREFS(bits) > 0); ! 1441: assert(port->ip_srights > 0); ! 1442: ! 1443: ipc_hash_insert(space, (ipc_object_t) port, ! 1444: name, entry); ! 1445: ip_reference(port); ! 1446: } else { ! 1447: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); ! 1448: assert(IE_BITS_UREFS(bits) == 0); ! 1449: ! 1450: dnrequest = ipc_right_dncancel_macro(space, port, ! 1451: name, entry); ! 1452: entry->ie_object = IO_NULL; ! 1453: } ! 1454: entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE; ! 1455: ! 1456: ipc_port_clear_receiver(port); ! 1457: ! 1458: port->ip_receiver_name = MACH_PORT_NULL; ! 1459: port->ip_destination = IP_NULL; ! 1460: ip_unlock(port); ! 1461: ! 1462: *objectp = (ipc_object_t) port; ! 1463: *sorightp = dnrequest; ! 1464: break; ! 1465: } ! 1466: ! 1467: case MACH_MSG_TYPE_COPY_SEND: { ! 1468: ipc_port_t port; ! 1469: ! 1470: if (bits & MACH_PORT_TYPE_DEAD_NAME) ! 1471: goto copy_dead; ! 1472: ! 1473: /* allow for dead send-once rights */ ! 1474: ! 1475: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) ! 1476: goto invalid_right; ! 1477: ! 1478: assert(IE_BITS_UREFS(bits) > 0); ! 1479: ! 1480: port = (ipc_port_t) entry->ie_object; ! 1481: assert(port != IP_NULL); ! 1482: ! 1483: if (ipc_right_check(space, port, name, entry)) { ! 1484: bits = entry->ie_bits; ! 1485: goto copy_dead; ! 1486: } ! 1487: /* port is locked and active */ ! 1488: ! 1489: if ((bits & MACH_PORT_TYPE_SEND) == 0) { ! 1490: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); ! 1491: assert(port->ip_sorights > 0); ! 1492: ! 1493: ip_unlock(port); ! 1494: goto invalid_right; ! 1495: } ! 1496: ! 1497: assert(port->ip_srights > 0); ! 1498: ! 1499: port->ip_srights++; ! 1500: ip_reference(port); ! 1501: ip_unlock(port); ! 1502: ! 1503: *objectp = (ipc_object_t) port; ! 1504: *sorightp = IP_NULL; ! 1505: break; ! 1506: } ! 1507: ! 1508: case MACH_MSG_TYPE_MOVE_SEND: { ! 1509: ipc_port_t port; ! 1510: ipc_port_t dnrequest = IP_NULL; ! 1511: ! 1512: if (bits & MACH_PORT_TYPE_DEAD_NAME) ! 1513: goto move_dead; ! 1514: ! 1515: /* allow for dead send-once rights */ ! 1516: ! 1517: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) ! 1518: goto invalid_right; ! 1519: ! 1520: assert(IE_BITS_UREFS(bits) > 0); ! 1521: ! 1522: port = (ipc_port_t) entry->ie_object; ! 1523: assert(port != IP_NULL); ! 1524: ! 1525: if (ipc_right_check(space, port, name, entry)) { ! 1526: bits = entry->ie_bits; ! 1527: goto move_dead; ! 1528: } ! 1529: /* port is locked and active */ ! 1530: ! 1531: if ((bits & MACH_PORT_TYPE_SEND) == 0) { ! 1532: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); ! 1533: assert(port->ip_sorights > 0); ! 1534: ! 1535: ip_unlock(port); ! 1536: goto invalid_right; ! 1537: } ! 1538: ! 1539: assert(port->ip_srights > 0); ! 1540: ! 1541: if (IE_BITS_UREFS(bits) == 1) { ! 1542: if (bits & MACH_PORT_TYPE_RECEIVE) { ! 1543: assert(port->ip_receiver_name == name); ! 1544: assert(port->ip_receiver == space); ! 1545: assert(IE_BITS_TYPE(bits) == ! 1546: MACH_PORT_TYPE_SEND_RECEIVE); ! 1547: ! 1548: ip_reference(port); ! 1549: } else { ! 1550: assert(IE_BITS_TYPE(bits) == ! 1551: MACH_PORT_TYPE_SEND); ! 1552: ! 1553: dnrequest = ipc_right_dncancel_macro(space, port, ! 1554: name, entry); ! 1555: ipc_hash_delete(space, (ipc_object_t) port, ! 1556: name, entry); ! 1557: entry->ie_object = IO_NULL; ! 1558: } ! 1559: entry->ie_bits = bits &~ ! 1560: (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND); ! 1561: } else { ! 1562: port->ip_srights++; ! 1563: ip_reference(port); ! 1564: entry->ie_bits = bits-1; /* decrement urefs */ ! 1565: } ! 1566: ! 1567: ip_unlock(port); ! 1568: ! 1569: *objectp = (ipc_object_t) port; ! 1570: *sorightp = dnrequest; ! 1571: break; ! 1572: } ! 1573: ! 1574: case MACH_MSG_TYPE_MOVE_SEND_ONCE: { ! 1575: ipc_port_t port; ! 1576: ipc_port_t dnrequest; ! 1577: ! 1578: if (bits & MACH_PORT_TYPE_DEAD_NAME) ! 1579: goto move_dead; ! 1580: ! 1581: /* allow for dead send rights */ ! 1582: ! 1583: if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) ! 1584: goto invalid_right; ! 1585: ! 1586: assert(IE_BITS_UREFS(bits) > 0); ! 1587: ! 1588: port = (ipc_port_t) entry->ie_object; ! 1589: assert(port != IP_NULL); ! 1590: ! 1591: if (ipc_right_check(space, port, name, entry)) { ! 1592: bits = entry->ie_bits; ! 1593: goto move_dead; ! 1594: } ! 1595: /* port is locked and active */ ! 1596: ! 1597: if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) { ! 1598: assert(bits & MACH_PORT_TYPE_SEND); ! 1599: assert(port->ip_srights > 0); ! 1600: ! 1601: ip_unlock(port); ! 1602: goto invalid_right; ! 1603: } ! 1604: ! 1605: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); ! 1606: assert(IE_BITS_UREFS(bits) == 1); ! 1607: assert(port->ip_sorights > 0); ! 1608: ! 1609: dnrequest = ipc_right_dncancel_macro(space, port, name, entry); ! 1610: ip_unlock(port); ! 1611: ! 1612: entry->ie_object = IO_NULL; ! 1613: entry->ie_bits = bits &~ ! 1614: (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE); ! 1615: ! 1616: *objectp = (ipc_object_t) port; ! 1617: *sorightp = dnrequest; ! 1618: break; ! 1619: } ! 1620: ! 1621: default: ! 1622: panic("ipc_right_copyin: strange rights"); ! 1623: } ! 1624: ! 1625: return KERN_SUCCESS; ! 1626: ! 1627: copy_dead: ! 1628: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 1629: assert(IE_BITS_UREFS(bits) > 0); ! 1630: assert(entry->ie_request == 0); ! 1631: assert(entry->ie_object == 0); ! 1632: ! 1633: if (!deadok) ! 1634: goto invalid_right; ! 1635: ! 1636: *objectp = IO_DEAD; ! 1637: *sorightp = IP_NULL; ! 1638: return KERN_SUCCESS; ! 1639: ! 1640: move_dead: ! 1641: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 1642: assert(IE_BITS_UREFS(bits) > 0); ! 1643: assert(entry->ie_request == 0); ! 1644: assert(entry->ie_object == 0); ! 1645: ! 1646: if (!deadok) ! 1647: goto invalid_right; ! 1648: ! 1649: if (IE_BITS_UREFS(bits) == 1) { ! 1650: bits &= ~MACH_PORT_TYPE_DEAD_NAME; ! 1651: } ! 1652: entry->ie_bits = bits-1; /* decrement urefs */ ! 1653: ! 1654: *objectp = IO_DEAD; ! 1655: *sorightp = IP_NULL; ! 1656: return KERN_SUCCESS; ! 1657: ! 1658: invalid_right: ! 1659: return KERN_INVALID_RIGHT; ! 1660: } ! 1661: ! 1662: /* ! 1663: * Routine: ipc_right_copyin_undo ! 1664: * Purpose: ! 1665: * Undoes the effects of an ipc_right_copyin ! 1666: * of a send/send-once right that is dead. ! 1667: * (Object is either IO_DEAD or a dead port.) ! 1668: * Conditions: ! 1669: * The space is write-locked and active. ! 1670: */ ! 1671: ! 1672: void ! 1673: ipc_right_copyin_undo( ! 1674: ipc_space_t space, ! 1675: mach_port_name_t name, ! 1676: ipc_entry_t entry, ! 1677: mach_msg_type_name_t msgt_name, ! 1678: ipc_object_t object, ! 1679: ipc_port_t soright) ! 1680: { ! 1681: ipc_entry_bits_t bits; ! 1682: ! 1683: bits = entry->ie_bits; ! 1684: ! 1685: assert(space->is_active); ! 1686: ! 1687: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || ! 1688: (msgt_name == MACH_MSG_TYPE_COPY_SEND) || ! 1689: (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE)); ! 1690: ! 1691: if (soright != IP_NULL) { ! 1692: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || ! 1693: (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE)); ! 1694: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); ! 1695: assert(object != IO_DEAD); ! 1696: ! 1697: entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) | ! 1698: MACH_PORT_TYPE_DEAD_NAME | 2); ! 1699: ! 1700: } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) { ! 1701: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || ! 1702: (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE)); ! 1703: ! 1704: entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) | ! 1705: MACH_PORT_TYPE_DEAD_NAME | 1); ! 1706: } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) { ! 1707: assert(object == IO_DEAD); ! 1708: assert(IE_BITS_UREFS(bits) > 0); ! 1709: ! 1710: if (msgt_name != MACH_MSG_TYPE_COPY_SEND) { ! 1711: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); ! 1712: entry->ie_bits = bits+1; /* increment urefs */ ! 1713: } ! 1714: } else { ! 1715: assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || ! 1716: (msgt_name == MACH_MSG_TYPE_COPY_SEND)); ! 1717: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); ! 1718: assert(object != IO_DEAD); ! 1719: assert(entry->ie_object == object); ! 1720: assert(IE_BITS_UREFS(bits) > 0); ! 1721: ! 1722: if (msgt_name != MACH_MSG_TYPE_COPY_SEND) { ! 1723: assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1); ! 1724: entry->ie_bits = bits+1; /* increment urefs */ ! 1725: } ! 1726: ! 1727: /* ! 1728: * May as well convert the entry to a dead name. ! 1729: * (Or if it is a compat entry, destroy it.) ! 1730: */ ! 1731: ! 1732: (void) ipc_right_check(space, (ipc_port_t) object, ! 1733: name, entry); ! 1734: /* object is dead so it is not locked */ ! 1735: } ! 1736: ! 1737: /* release the reference acquired by copyin */ ! 1738: ! 1739: if (object != IO_DEAD) ! 1740: ipc_object_release(object); ! 1741: } ! 1742: ! 1743: /* ! 1744: * Routine: ipc_right_copyin_two ! 1745: * Purpose: ! 1746: * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND ! 1747: * and deadok == FALSE, except that this moves two ! 1748: * send rights at once. ! 1749: * Conditions: ! 1750: * The space is write-locked and active. ! 1751: * The object is returned with two refs/send rights. ! 1752: * Returns: ! 1753: * KERN_SUCCESS Acquired an object. ! 1754: * KERN_INVALID_RIGHT Name doesn't denote correct right. ! 1755: */ ! 1756: ! 1757: kern_return_t ! 1758: ipc_right_copyin_two( ! 1759: ipc_space_t space, ! 1760: mach_port_name_t name, ! 1761: ipc_entry_t entry, ! 1762: ipc_object_t *objectp, ! 1763: ipc_port_t *sorightp) ! 1764: { ! 1765: ipc_entry_bits_t bits; ! 1766: mach_port_urefs_t urefs; ! 1767: ipc_port_t port; ! 1768: ipc_port_t dnrequest = IP_NULL; ! 1769: ! 1770: assert(space->is_active); ! 1771: ! 1772: bits = entry->ie_bits; ! 1773: ! 1774: if ((bits & MACH_PORT_TYPE_SEND) == 0) ! 1775: goto invalid_right; ! 1776: ! 1777: urefs = IE_BITS_UREFS(bits); ! 1778: if (urefs < 2) ! 1779: goto invalid_right; ! 1780: ! 1781: port = (ipc_port_t) entry->ie_object; ! 1782: assert(port != IP_NULL); ! 1783: ! 1784: if (ipc_right_check(space, port, name, entry)) { ! 1785: goto invalid_right; ! 1786: } ! 1787: /* port is locked and active */ ! 1788: ! 1789: assert(port->ip_srights > 0); ! 1790: ! 1791: if (urefs == 2) { ! 1792: if (bits & MACH_PORT_TYPE_RECEIVE) { ! 1793: assert(port->ip_receiver_name == name); ! 1794: assert(port->ip_receiver == space); ! 1795: assert(IE_BITS_TYPE(bits) == ! 1796: MACH_PORT_TYPE_SEND_RECEIVE); ! 1797: ! 1798: port->ip_srights++; ! 1799: ip_reference(port); ! 1800: ip_reference(port); ! 1801: } else { ! 1802: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); ! 1803: ! 1804: dnrequest = ipc_right_dncancel_macro(space, port, ! 1805: name, entry); ! 1806: ! 1807: port->ip_srights++; ! 1808: ip_reference(port); ! 1809: ipc_hash_delete(space, (ipc_object_t) port, ! 1810: name, entry); ! 1811: entry->ie_object = IO_NULL; ! 1812: } ! 1813: entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND); ! 1814: } else { ! 1815: port->ip_srights += 2; ! 1816: ip_reference(port); ! 1817: ip_reference(port); ! 1818: entry->ie_bits = bits-2; /* decrement urefs */ ! 1819: } ! 1820: ip_unlock(port); ! 1821: ! 1822: *objectp = (ipc_object_t) port; ! 1823: *sorightp = dnrequest; ! 1824: return KERN_SUCCESS; ! 1825: ! 1826: invalid_right: ! 1827: return KERN_INVALID_RIGHT; ! 1828: } ! 1829: ! 1830: /* ! 1831: * Routine: ipc_right_copyout ! 1832: * Purpose: ! 1833: * Copyout a capability to a space. ! 1834: * If successful, consumes a ref for the object. ! 1835: * ! 1836: * Always succeeds when given a newly-allocated entry, ! 1837: * because user-reference overflow isn't a possibility. ! 1838: * ! 1839: * If copying out the object would cause the user-reference ! 1840: * count in the entry to overflow, and overflow is TRUE, ! 1841: * then instead the user-reference count is left pegged ! 1842: * to its maximum value and the copyout succeeds anyway. ! 1843: * Conditions: ! 1844: * The space is write-locked and active. ! 1845: * The object is locked and active. ! 1846: * The object is unlocked; the space isn't. ! 1847: * Returns: ! 1848: * KERN_SUCCESS Copied out capability. ! 1849: * KERN_UREFS_OVERFLOW User-refs would overflow; ! 1850: * guaranteed not to happen with a fresh entry ! 1851: * or if overflow=TRUE was specified. ! 1852: */ ! 1853: ! 1854: kern_return_t ! 1855: ipc_right_copyout( ! 1856: ipc_space_t space, ! 1857: mach_port_name_t name, ! 1858: ipc_entry_t entry, ! 1859: mach_msg_type_name_t msgt_name, ! 1860: boolean_t overflow, ! 1861: ipc_object_t object) ! 1862: { ! 1863: ipc_entry_bits_t bits; ! 1864: ipc_port_t port; ! 1865: ! 1866: bits = entry->ie_bits; ! 1867: ! 1868: assert(IO_VALID(object)); ! 1869: assert(io_otype(object) == IOT_PORT); ! 1870: assert(io_active(object)); ! 1871: assert(entry->ie_object == object); ! 1872: ! 1873: port = (ipc_port_t) object; ! 1874: ! 1875: switch (msgt_name) { ! 1876: case MACH_MSG_TYPE_PORT_SEND_ONCE: ! 1877: ! 1878: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); ! 1879: assert(port->ip_sorights > 0); ! 1880: ! 1881: /* transfer send-once right and ref to entry */ ! 1882: ip_unlock(port); ! 1883: ! 1884: entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1); ! 1885: break; ! 1886: ! 1887: case MACH_MSG_TYPE_PORT_SEND: ! 1888: assert(port->ip_srights > 0); ! 1889: ! 1890: if (bits & MACH_PORT_TYPE_SEND) { ! 1891: mach_port_urefs_t urefs = IE_BITS_UREFS(bits); ! 1892: ! 1893: assert(port->ip_srights > 1); ! 1894: assert(urefs > 0); ! 1895: assert(urefs < MACH_PORT_UREFS_MAX); ! 1896: ! 1897: if (urefs+1 == MACH_PORT_UREFS_MAX) { ! 1898: if (overflow) { ! 1899: /* leave urefs pegged to maximum */ ! 1900: ! 1901: port->ip_srights--; ! 1902: ip_release(port); ! 1903: ip_unlock(port); ! 1904: return KERN_SUCCESS; ! 1905: } ! 1906: ! 1907: ip_unlock(port); ! 1908: return KERN_UREFS_OVERFLOW; ! 1909: } ! 1910: ! 1911: port->ip_srights--; ! 1912: ip_release(port); ! 1913: ip_unlock(port); ! 1914: } else if (bits & MACH_PORT_TYPE_RECEIVE) { ! 1915: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); ! 1916: assert(IE_BITS_UREFS(bits) == 0); ! 1917: ! 1918: /* transfer send right to entry */ ! 1919: ip_release(port); ! 1920: ip_unlock(port); ! 1921: } else { ! 1922: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); ! 1923: assert(IE_BITS_UREFS(bits) == 0); ! 1924: ! 1925: /* transfer send right and ref to entry */ ! 1926: ip_unlock(port); ! 1927: ! 1928: /* entry is locked holding ref, so can use port */ ! 1929: ! 1930: ipc_hash_insert(space, (ipc_object_t) port, ! 1931: name, entry); ! 1932: } ! 1933: ! 1934: entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; ! 1935: break; ! 1936: ! 1937: case MACH_MSG_TYPE_PORT_RECEIVE: { ! 1938: ipc_port_t dest; ! 1939: ! 1940: assert(port->ip_mscount == 0); ! 1941: assert(port->ip_receiver_name == MACH_PORT_NULL); ! 1942: dest = port->ip_destination; ! 1943: ! 1944: port->ip_receiver_name = name; ! 1945: port->ip_receiver = space; ! 1946: ! 1947: assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); ! 1948: ! 1949: if (bits & MACH_PORT_TYPE_SEND) { ! 1950: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); ! 1951: assert(IE_BITS_UREFS(bits) > 0); ! 1952: assert(port->ip_srights > 0); ! 1953: ! 1954: ip_release(port); ! 1955: ip_unlock(port); ! 1956: ! 1957: /* entry is locked holding ref, so can use port */ ! 1958: ! 1959: ipc_hash_delete(space, (ipc_object_t) port, ! 1960: name, entry); ! 1961: } else { ! 1962: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); ! 1963: assert(IE_BITS_UREFS(bits) == 0); ! 1964: ! 1965: /* transfer ref to entry */ ! 1966: ip_unlock(port); ! 1967: } ! 1968: entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE; ! 1969: ! 1970: if (dest != IP_NULL) ! 1971: ipc_port_release(dest); ! 1972: break; ! 1973: } ! 1974: ! 1975: default: ! 1976: panic("ipc_right_copyout: strange rights"); ! 1977: } ! 1978: ! 1979: return KERN_SUCCESS; ! 1980: } ! 1981: ! 1982: /* ! 1983: * Routine: ipc_right_rename ! 1984: * Purpose: ! 1985: * Transfer an entry from one name to another. ! 1986: * The old entry is deallocated. ! 1987: * Conditions: ! 1988: * The space is write-locked and active. ! 1989: * The new entry is unused. Upon return, ! 1990: * the space is unlocked. ! 1991: * Returns: ! 1992: * KERN_SUCCESS Moved entry to new name. ! 1993: */ ! 1994: ! 1995: kern_return_t ! 1996: ipc_right_rename( ! 1997: ipc_space_t space, ! 1998: mach_port_name_t oname, ! 1999: ipc_entry_t oentry, ! 2000: mach_port_name_t nname, ! 2001: ipc_entry_t nentry) ! 2002: { ! 2003: ipc_port_request_index_t request = oentry->ie_request; ! 2004: ipc_entry_bits_t bits = oentry->ie_bits; ! 2005: ipc_object_t object = oentry->ie_object; ! 2006: ! 2007: assert(space->is_active); ! 2008: assert(oname != nname); ! 2009: ! 2010: /* ! 2011: * If IE_BITS_COMPAT, we can't allow the entry to be renamed ! 2012: * if the port is dead. (This would foil ipc_port_destroy.) ! 2013: * Instead we should fail because oentry shouldn't exist. ! 2014: * Note IE_BITS_COMPAT implies ie_request != 0. ! 2015: */ ! 2016: ! 2017: if (request != 0) { ! 2018: ipc_port_t port; ! 2019: ! 2020: assert(bits & MACH_PORT_TYPE_PORT_RIGHTS); ! 2021: port = (ipc_port_t) object; ! 2022: assert(port != IP_NULL); ! 2023: ! 2024: if (ipc_right_check(space, port, oname, oentry)) { ! 2025: request = 0; ! 2026: object = IO_NULL; ! 2027: bits = oentry->ie_bits; ! 2028: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); ! 2029: assert(oentry->ie_request == 0); ! 2030: } else { ! 2031: /* port is locked and active */ ! 2032: ! 2033: ipc_port_dnrename(port, request, oname, nname); ! 2034: ip_unlock(port); ! 2035: oentry->ie_request = 0; ! 2036: } ! 2037: } ! 2038: ! 2039: /* initialize nentry before letting ipc_hash_insert see it */ ! 2040: ! 2041: assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0); ! 2042: nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK; ! 2043: nentry->ie_request = request; ! 2044: nentry->ie_object = object; ! 2045: ! 2046: switch (IE_BITS_TYPE(bits)) { ! 2047: case MACH_PORT_TYPE_SEND: { ! 2048: ipc_port_t port; ! 2049: ! 2050: port = (ipc_port_t) object; ! 2051: assert(port != IP_NULL); ! 2052: ! 2053: /* remember, there are no other share entries possible */ ! 2054: /* or we can't do the rename. Therefore we do not need */ ! 2055: /* to check the other subspaces */ ! 2056: ipc_hash_delete(space, (ipc_object_t) port, oname, oentry); ! 2057: ipc_hash_insert(space, (ipc_object_t) port, nname, nentry); ! 2058: break; ! 2059: } ! 2060: ! 2061: case MACH_PORT_TYPE_RECEIVE: ! 2062: case MACH_PORT_TYPE_SEND_RECEIVE: { ! 2063: ipc_port_t port; ! 2064: ! 2065: port = (ipc_port_t) object; ! 2066: assert(port != IP_NULL); ! 2067: ! 2068: ip_lock(port); ! 2069: assert(ip_active(port)); ! 2070: assert(port->ip_receiver_name == oname); ! 2071: assert(port->ip_receiver == space); ! 2072: ! 2073: port->ip_receiver_name = nname; ! 2074: ip_unlock(port); ! 2075: break; ! 2076: } ! 2077: ! 2078: case MACH_PORT_TYPE_PORT_SET: { ! 2079: ipc_pset_t pset; ! 2080: ! 2081: pset = (ipc_pset_t) object; ! 2082: assert(pset != IPS_NULL); ! 2083: ! 2084: ips_lock(pset); ! 2085: assert(ips_active(pset)); ! 2086: assert(pset->ips_local_name == oname); ! 2087: ! 2088: pset->ips_local_name = nname; ! 2089: ips_unlock(pset); ! 2090: break; ! 2091: } ! 2092: ! 2093: case MACH_PORT_TYPE_SEND_ONCE: ! 2094: case MACH_PORT_TYPE_DEAD_NAME: ! 2095: break; ! 2096: ! 2097: default: ! 2098: panic("ipc_right_rename: strange rights"); ! 2099: } ! 2100: ! 2101: assert(oentry->ie_request == 0); ! 2102: oentry->ie_object = IO_NULL; ! 2103: ipc_entry_dealloc(space, oname, oentry); ! 2104: is_write_unlock(space); ! 2105: ! 2106: return KERN_SUCCESS; ! 2107: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.