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