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