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