]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/mach_port.c
xnu-344.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_port.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50 /*
51 */
52 /*
53 * File: ipc/mach_port.c
54 * Author: Rich Draves
55 * Date: 1989
56 *
57 * Exported kernel calls. See mach/mach_port.defs.
58 */
59
60 #include <mach_debug.h>
61 #include <mach_rt.h>
62
63 #include <mach/port.h>
64 #include <mach/kern_return.h>
65 #include <mach/notify.h>
66 #include <mach/mach_param.h>
67 #include <mach/vm_param.h>
68 #include <mach/vm_prot.h>
69 #include <mach/vm_map.h>
70 #include <kern/task.h>
71 #include <kern/counters.h>
72 #include <kern/thread_act.h>
73 #include <mach/mach_port_server.h>
74 #include <vm/vm_map.h>
75 #include <vm/vm_kern.h>
76 #include <ipc/ipc_entry.h>
77 #include <ipc/ipc_space.h>
78 #include <ipc/ipc_object.h>
79 #include <ipc/ipc_notify.h>
80 #include <ipc/ipc_port.h>
81 #include <ipc/ipc_pset.h>
82 #include <ipc/ipc_right.h>
83 #include <ipc/ipc_kmsg.h>
84 #include <kern/misc_protos.h>
85
86 /*
87 * Forward declarations
88 */
89 void mach_port_names_helper(
90 ipc_port_timestamp_t timestamp,
91 ipc_entry_t entry,
92 mach_port_name_t name,
93 mach_port_name_t *names,
94 mach_port_type_t *types,
95 ipc_entry_num_t *actualp,
96 ipc_space_t space);
97
98 void mach_port_gst_helper(
99 ipc_pset_t pset,
100 ipc_port_t port,
101 ipc_entry_num_t maxnames,
102 mach_port_name_t *names,
103 ipc_entry_num_t *actualp);
104
105
106 /* Zeroed template of qos flags */
107
108 static mach_port_qos_t qos_template;
109
110 /*
111 * Routine: mach_port_names_helper
112 * Purpose:
113 * A helper function for mach_port_names.
114 */
115
116 void
117 mach_port_names_helper(
118 ipc_port_timestamp_t timestamp,
119 ipc_entry_t entry,
120 mach_port_name_t name,
121 mach_port_name_t *names,
122 mach_port_type_t *types,
123 ipc_entry_num_t *actualp,
124 ipc_space_t space)
125 {
126 ipc_entry_bits_t bits;
127 ipc_port_request_index_t request;
128 mach_port_type_t type;
129 ipc_entry_num_t actual;
130
131 bits = entry->ie_bits;
132 request = entry->ie_request;
133 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
134 ipc_port_t port;
135 boolean_t died;
136
137 port = (ipc_port_t) entry->ie_object;
138 assert(port != IP_NULL);
139
140 /*
141 * The timestamp serializes mach_port_names
142 * with ipc_port_destroy. If the port died,
143 * but after mach_port_names started, pretend
144 * that it isn't dead.
145 */
146
147 ip_lock(port);
148 died = (!ip_active(port) &&
149 IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
150 ip_unlock(port);
151
152 if (died) {
153 /* pretend this is a dead-name entry */
154
155 bits &= ~(IE_BITS_TYPE_MASK);
156 bits |= MACH_PORT_TYPE_DEAD_NAME;
157 if (request != 0)
158 bits++;
159 request = 0;
160 }
161 }
162
163 type = IE_BITS_TYPE(bits);
164 if (request != 0)
165 type |= MACH_PORT_TYPE_DNREQUEST;
166
167 actual = *actualp;
168 names[actual] = name;
169 types[actual] = type;
170 *actualp = actual+1;
171 }
172
173 /*
174 * Routine: mach_port_names [kernel call]
175 * Purpose:
176 * Retrieves a list of the rights present in the space,
177 * along with type information. (Same as returned
178 * by mach_port_type.) The names are returned in
179 * no particular order, but they (and the type info)
180 * are an accurate snapshot of the space.
181 * Conditions:
182 * Nothing locked.
183 * Returns:
184 * KERN_SUCCESS Arrays of names and types returned.
185 * KERN_INVALID_TASK The space is null.
186 * KERN_INVALID_TASK The space is dead.
187 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
188 */
189
190 kern_return_t
191 mach_port_names(
192 ipc_space_t space,
193 mach_port_name_t **namesp,
194 mach_msg_type_number_t *namesCnt,
195 mach_port_type_t **typesp,
196 mach_msg_type_number_t *typesCnt)
197 {
198 ipc_entry_bits_t *capability;
199 ipc_tree_entry_t tentry;
200 ipc_entry_t table;
201 ipc_entry_num_t tsize;
202 mach_port_index_t index;
203 ipc_entry_num_t actual; /* this many names */
204 ipc_port_timestamp_t timestamp; /* logical time of this operation */
205 mach_port_name_t *names;
206 mach_port_type_t *types;
207 kern_return_t kr;
208
209 vm_size_t size; /* size of allocated memory */
210 vm_offset_t addr1; /* allocated memory, for names */
211 vm_offset_t addr2; /* allocated memory, for types */
212 vm_map_copy_t memory1; /* copied-in memory, for names */
213 vm_map_copy_t memory2; /* copied-in memory, for types */
214
215 /* safe simplifying assumption */
216 assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
217
218 if (space == IS_NULL)
219 return KERN_INVALID_TASK;
220
221 size = 0;
222
223 for (;;) {
224 ipc_entry_num_t bound;
225 vm_size_t size_needed;
226
227 is_read_lock(space);
228 if (!space->is_active) {
229 is_read_unlock(space);
230 if (size != 0) {
231 kmem_free(ipc_kernel_map, addr1, size);
232 kmem_free(ipc_kernel_map, addr2, size);
233 }
234 return KERN_INVALID_TASK;
235 }
236
237 /* upper bound on number of names in the space */
238
239 bound = space->is_table_size + space->is_tree_total;
240 size_needed = round_page(bound * sizeof(mach_port_name_t));
241
242 if (size_needed <= size)
243 break;
244
245 is_read_unlock(space);
246
247 if (size != 0) {
248 kmem_free(ipc_kernel_map, addr1, size);
249 kmem_free(ipc_kernel_map, addr2, size);
250 }
251 size = size_needed;
252
253 kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE);
254 if (kr != KERN_SUCCESS)
255 return KERN_RESOURCE_SHORTAGE;
256
257 kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE);
258 if (kr != KERN_SUCCESS) {
259 kmem_free(ipc_kernel_map, addr1, size);
260 return KERN_RESOURCE_SHORTAGE;
261 }
262
263 /* can't fault while we hold locks */
264
265 kr = vm_map_wire(ipc_kernel_map, addr1, addr1 + size,
266 VM_PROT_READ|VM_PROT_WRITE, FALSE);
267 if (kr != KERN_SUCCESS) {
268 kmem_free(ipc_kernel_map, addr1, size);
269 kmem_free(ipc_kernel_map, addr2, size);
270 return KERN_RESOURCE_SHORTAGE;
271 }
272
273 kr = vm_map_wire(ipc_kernel_map, addr2, addr2 + size,
274 VM_PROT_READ|VM_PROT_WRITE, FALSE);
275 if (kr != KERN_SUCCESS) {
276 kmem_free(ipc_kernel_map, addr1, size);
277 kmem_free(ipc_kernel_map, addr2, size);
278 return KERN_RESOURCE_SHORTAGE;
279 }
280
281 }
282 /* space is read-locked and active */
283
284 names = (mach_port_name_t *) addr1;
285 types = (mach_port_type_t *) addr2;
286 actual = 0;
287
288 timestamp = ipc_port_timestamp();
289
290 table = space->is_table;
291 tsize = space->is_table_size;
292
293 for (index = 0; index < tsize; index++) {
294 ipc_entry_t entry = &table[index];
295 ipc_entry_bits_t bits = entry->ie_bits;
296
297 if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
298 mach_port_name_t name;
299
300 name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
301 mach_port_names_helper(timestamp, entry, name, names,
302 types, &actual, space);
303 }
304 }
305
306 for (tentry = ipc_splay_traverse_start(&space->is_tree);
307 tentry != ITE_NULL;
308 tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
309 ipc_entry_t entry = &tentry->ite_entry;
310 mach_port_name_t name = tentry->ite_name;
311
312 assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE);
313 mach_port_names_helper(timestamp, entry, name, names,
314 types, &actual, space);
315 }
316 ipc_splay_traverse_finish(&space->is_tree);
317 is_read_unlock(space);
318
319 if (actual == 0) {
320 memory1 = VM_MAP_COPY_NULL;
321 memory2 = VM_MAP_COPY_NULL;
322
323 if (size != 0) {
324 kmem_free(ipc_kernel_map, addr1, size);
325 kmem_free(ipc_kernel_map, addr2, size);
326 }
327 } else {
328 vm_size_t size_used;
329 vm_size_t vm_size_used;
330
331 size_used = actual * sizeof(mach_port_name_t);
332 vm_size_used = round_page(size_used);
333
334 /*
335 * Make used memory pageable and get it into
336 * copied-in form. Free any unused memory.
337 */
338
339 kr = vm_map_unwire(ipc_kernel_map,
340 addr1, addr1 + vm_size_used, FALSE);
341 assert(kr == KERN_SUCCESS);
342
343 kr = vm_map_unwire(ipc_kernel_map,
344 addr2, addr2 + vm_size_used, FALSE);
345 assert(kr == KERN_SUCCESS);
346
347 kr = vm_map_copyin(ipc_kernel_map, addr1, size_used,
348 TRUE, &memory1);
349 assert(kr == KERN_SUCCESS);
350
351 kr = vm_map_copyin(ipc_kernel_map, addr2, size_used,
352 TRUE, &memory2);
353 assert(kr == KERN_SUCCESS);
354
355 if (vm_size_used != size) {
356 kmem_free(ipc_kernel_map,
357 addr1 + vm_size_used, size - vm_size_used);
358 kmem_free(ipc_kernel_map,
359 addr2 + vm_size_used, size - vm_size_used);
360 }
361 }
362
363 *namesp = (mach_port_name_t *) memory1;
364 *namesCnt = actual;
365 *typesp = (mach_port_type_t *) memory2;
366 *typesCnt = actual;
367 return KERN_SUCCESS;
368 }
369
370 /*
371 * Routine: mach_port_type [kernel call]
372 * Purpose:
373 * Retrieves the type of a right in the space.
374 * The type is a bitwise combination of one or more
375 * of the following type bits:
376 * MACH_PORT_TYPE_SEND
377 * MACH_PORT_TYPE_RECEIVE
378 * MACH_PORT_TYPE_SEND_ONCE
379 * MACH_PORT_TYPE_PORT_SET
380 * MACH_PORT_TYPE_DEAD_NAME
381 * In addition, the following pseudo-type bits may be present:
382 * MACH_PORT_TYPE_DNREQUEST
383 * A dead-name notification is requested.
384 * Conditions:
385 * Nothing locked.
386 * Returns:
387 * KERN_SUCCESS Type is returned.
388 * KERN_INVALID_TASK The space is null.
389 * KERN_INVALID_TASK The space is dead.
390 * KERN_INVALID_NAME The name doesn't denote a right.
391 */
392
393 kern_return_t
394 mach_port_type(
395 ipc_space_t space,
396 mach_port_name_t name,
397 mach_port_type_t *typep)
398 {
399 mach_port_urefs_t urefs;
400 ipc_entry_t entry;
401 kern_return_t kr;
402
403 if (space == IS_NULL)
404 return KERN_INVALID_TASK;
405
406 if (name == MACH_PORT_NULL)
407 return KERN_INVALID_NAME;
408
409 if (name == MACH_PORT_DEAD) {
410 *typep = MACH_PORT_TYPE_DEAD_NAME;
411 return KERN_SUCCESS;
412 }
413
414 kr = ipc_right_lookup_write(space, name, &entry);
415 if (kr != KERN_SUCCESS)
416 return kr;
417 /* space is write-locked and active */
418
419 kr = ipc_right_info(space, name, entry, typep, &urefs);
420 if (kr == KERN_SUCCESS)
421 is_write_unlock(space);
422 /* space is unlocked */
423 return kr;
424 }
425
426 /*
427 * Routine: mach_port_rename [kernel call]
428 * Purpose:
429 * Changes the name denoting a right,
430 * from oname to nname.
431 * Conditions:
432 * Nothing locked.
433 * Returns:
434 * KERN_SUCCESS The right is renamed.
435 * KERN_INVALID_TASK The space is null.
436 * KERN_INVALID_TASK The space is dead.
437 * KERN_INVALID_NAME The oname doesn't denote a right.
438 * KERN_INVALID_VALUE The nname isn't a legal name.
439 * KERN_NAME_EXISTS The nname already denotes a right.
440 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
441 */
442
443 kern_return_t
444 mach_port_rename(
445 ipc_space_t space,
446 mach_port_name_t oname,
447 mach_port_name_t nname)
448 {
449 if (space == IS_NULL)
450 return KERN_INVALID_TASK;
451
452 if (!MACH_PORT_VALID(oname))
453 return KERN_INVALID_NAME;
454
455 if (!MACH_PORT_VALID(nname))
456 return KERN_INVALID_VALUE;
457
458 return ipc_object_rename(space, oname, nname);
459 }
460
461 /*
462 * Routine: mach_port_allocate_name [kernel call]
463 * Purpose:
464 * Allocates a right in a space, using a specific name
465 * for the new right. Possible rights:
466 * MACH_PORT_RIGHT_RECEIVE
467 * MACH_PORT_RIGHT_PORT_SET
468 * MACH_PORT_RIGHT_DEAD_NAME
469 *
470 * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
471 * has no extant send or send-once rights and no queued
472 * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
473 * and its make-send count is 0. It is not a member of
474 * a port set. It has no registered no-senders or
475 * port-destroyed notification requests.
476 *
477 * A new port set has no members.
478 *
479 * A new dead name has one user reference.
480 * Conditions:
481 * Nothing locked.
482 * Returns:
483 * KERN_SUCCESS The right is allocated.
484 * KERN_INVALID_TASK The space is null.
485 * KERN_INVALID_TASK The space is dead.
486 * KERN_INVALID_VALUE The name isn't a legal name.
487 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
488 * KERN_NAME_EXISTS The name already denotes a right.
489 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
490 *
491 * Restrictions on name allocation: NT bits are reserved by kernel,
492 * must be set on any chosen name. Can't do this at all in kernel
493 * loaded server.
494 */
495
496 kern_return_t
497 mach_port_allocate_name(
498 ipc_space_t space,
499 mach_port_right_t right,
500 mach_port_name_t name)
501 {
502 kern_return_t kr;
503 mach_port_qos_t qos = qos_template;
504
505 qos.name = TRUE;
506
507 if (!MACH_PORT_VALID(name))
508 return KERN_INVALID_VALUE;
509
510 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
511 &qos, &name);
512 return (kr);
513 }
514
515 /*
516 * Routine: mach_port_allocate [kernel call]
517 * Purpose:
518 * Allocates a right in a space. Like mach_port_allocate_name,
519 * except that the implementation picks a name for the right.
520 * The name may be any legal name in the space that doesn't
521 * currently denote a right.
522 * Conditions:
523 * Nothing locked.
524 * Returns:
525 * KERN_SUCCESS The right is allocated.
526 * KERN_INVALID_TASK The space is null.
527 * KERN_INVALID_TASK The space is dead.
528 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
529 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
530 * KERN_NO_SPACE No room in space for another right.
531 */
532
533 kern_return_t
534 mach_port_allocate(
535 ipc_space_t space,
536 mach_port_right_t right,
537 mach_port_name_t *namep)
538 {
539 kern_return_t kr;
540 mach_port_qos_t qos = qos_template;
541
542 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
543 &qos, namep);
544 return (kr);
545 }
546
547 /*
548 * Routine: mach_port_allocate_qos [kernel call]
549 * Purpose:
550 * Allocates a right, with qos options, in a space. Like
551 * mach_port_allocate_name, except that the implementation
552 * picks a name for the right. The name may be any legal name
553 * in the space that doesn't currently denote a right.
554 * Conditions:
555 * Nothing locked.
556 * Returns:
557 * KERN_SUCCESS The right is allocated.
558 * KERN_INVALID_TASK The space is null.
559 * KERN_INVALID_TASK The space is dead.
560 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
561 * KERN_INVALID_ARGUMENT The qos request was invalid.
562 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
563 * KERN_NO_SPACE No room in space for another right.
564 */
565
566 kern_return_t
567 mach_port_allocate_qos(
568 ipc_space_t space,
569 mach_port_right_t right,
570 mach_port_qos_t *qosp,
571 mach_port_name_t *namep)
572 {
573 kern_return_t kr;
574
575 if (qosp->name)
576 return KERN_INVALID_ARGUMENT;
577 kr = mach_port_allocate_full (space, right, MACH_PORT_NULL,
578 qosp, namep);
579 return (kr);
580 }
581
582 /*
583 * Routine: mach_port_allocate_full [kernel call]
584 * Purpose:
585 * Allocates a right in a space. Supports all of the
586 * special cases, such as specifying a subsystem,
587 * a specific name, a real-time port, etc.
588 * The name may be any legal name in the space that doesn't
589 * currently denote a right.
590 * Conditions:
591 * Nothing locked.
592 * Returns:
593 * KERN_SUCCESS The right is allocated.
594 * KERN_INVALID_TASK The space is null.
595 * KERN_INVALID_TASK The space is dead.
596 * KERN_INVALID_VALUE "right" isn't a legal kind of right.
597 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
598 * KERN_NO_SPACE No room in space for another right.
599 */
600
601 kern_return_t
602 mach_port_allocate_full(
603 ipc_space_t space,
604 mach_port_right_t right,
605 mach_port_t proto,
606 mach_port_qos_t *qosp,
607 mach_port_name_t *namep)
608 {
609 ipc_kmsg_t kmsg;
610 kern_return_t kr;
611
612 if (space == IS_NULL)
613 return (KERN_INVALID_TASK);
614
615 if (proto != MACH_PORT_NULL)
616 return (KERN_INVALID_VALUE);
617
618 if (qosp->name) {
619 if (!MACH_PORT_VALID (*namep))
620 return (KERN_INVALID_VALUE);
621 if (is_fast_space (space))
622 return (KERN_FAILURE);
623 }
624
625 if (qosp->prealloc) {
626 mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE;
627 if (right != MACH_PORT_RIGHT_RECEIVE)
628 return (KERN_INVALID_VALUE);
629 kmsg = (ipc_kmsg_t)kalloc(ikm_plus_overhead(size));
630 if (kmsg == IKM_NULL)
631 return (KERN_RESOURCE_SHORTAGE);
632 ikm_init(kmsg, size);
633 }
634
635 switch (right) {
636 case MACH_PORT_RIGHT_RECEIVE:
637 {
638 ipc_port_t port;
639
640 if (qosp->name)
641 kr = ipc_port_alloc_name(space, *namep, &port);
642 else
643 kr = ipc_port_alloc(space, namep, &port);
644 if (kr == KERN_SUCCESS) {
645 if (qosp->prealloc)
646 ipc_kmsg_set_prealloc(kmsg, port);
647
648 ip_unlock(port);
649
650 } else if (qosp->prealloc)
651 ipc_kmsg_free(kmsg);
652 break;
653 }
654
655 case MACH_PORT_RIGHT_PORT_SET:
656 {
657 ipc_pset_t pset;
658
659 if (qosp->name)
660 kr = ipc_pset_alloc_name(space, *namep, &pset);
661 else
662 kr = ipc_pset_alloc(space, namep, &pset);
663 if (kr == KERN_SUCCESS)
664 ips_unlock(pset);
665 break;
666 }
667
668 case MACH_PORT_RIGHT_DEAD_NAME:
669 kr = ipc_object_alloc_dead(space, namep);
670 break;
671
672 default:
673 kr = KERN_INVALID_VALUE;
674 break;
675 }
676
677 return (kr);
678 }
679
680 /*
681 * Routine: mach_port_destroy [kernel call]
682 * Purpose:
683 * Cleans up and destroys all rights denoted by a name
684 * in a space. The destruction of a receive right
685 * destroys the port, unless a port-destroyed request
686 * has been made for it; the destruction of a port-set right
687 * destroys the port set.
688 * Conditions:
689 * Nothing locked.
690 * Returns:
691 * KERN_SUCCESS The name is destroyed.
692 * KERN_INVALID_TASK The space is null.
693 * KERN_INVALID_TASK The space is dead.
694 * KERN_INVALID_NAME The name doesn't denote a right.
695 */
696
697 kern_return_t
698 mach_port_destroy(
699 ipc_space_t space,
700 mach_port_name_t name)
701 {
702 ipc_entry_t entry;
703 kern_return_t kr;
704
705 if (space == IS_NULL)
706 return KERN_INVALID_TASK;
707
708 if (!MACH_PORT_VALID(name))
709 return KERN_SUCCESS;
710
711 kr = ipc_right_lookup_write(space, name, &entry);
712 if (kr != KERN_SUCCESS)
713 return kr;
714 /* space is write-locked and active */
715
716 kr = ipc_right_destroy(space, name, entry);
717 is_write_unlock(space);
718 return kr;
719 }
720
721 /*
722 * Routine: mach_port_deallocate [kernel call]
723 * Purpose:
724 * Deallocates a user reference from a send right,
725 * send-once right, or a dead-name right. May
726 * deallocate the right, if this is the last uref,
727 * and destroy the name, if it doesn't denote
728 * other rights.
729 * Conditions:
730 * Nothing locked.
731 * Returns:
732 * KERN_SUCCESS The uref is deallocated.
733 * KERN_INVALID_TASK The space is null.
734 * KERN_INVALID_TASK The space is dead.
735 * KERN_INVALID_NAME The name doesn't denote a right.
736 * KERN_INVALID_RIGHT The right isn't correct.
737 */
738
739 kern_return_t
740 mach_port_deallocate(
741 ipc_space_t space,
742 mach_port_name_t name)
743 {
744 ipc_entry_t entry;
745 kern_return_t kr;
746
747 if (space == IS_NULL)
748 return KERN_INVALID_TASK;
749
750 if (!MACH_PORT_VALID(name))
751 return KERN_SUCCESS;
752
753 kr = ipc_right_lookup_write(space, name, &entry);
754 if (kr != KERN_SUCCESS)
755 return kr;
756 /* space is write-locked */
757
758 kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
759 return kr;
760 }
761
762 /*
763 * Routine: mach_port_get_refs [kernel call]
764 * Purpose:
765 * Retrieves the number of user references held by a right.
766 * Receive rights, port-set rights, and send-once rights
767 * always have one user reference. Returns zero if the
768 * name denotes a right, but not the queried right.
769 * Conditions:
770 * Nothing locked.
771 * Returns:
772 * KERN_SUCCESS Number of urefs returned.
773 * KERN_INVALID_TASK The space is null.
774 * KERN_INVALID_TASK The space is dead.
775 * KERN_INVALID_VALUE "right" isn't a legal value.
776 * KERN_INVALID_NAME The name doesn't denote a right.
777 */
778
779 kern_return_t
780 mach_port_get_refs(
781 ipc_space_t space,
782 mach_port_name_t name,
783 mach_port_right_t right,
784 mach_port_urefs_t *urefsp)
785 {
786 mach_port_type_t type;
787 mach_port_urefs_t urefs;
788 ipc_entry_t entry;
789 kern_return_t kr;
790
791 if (space == IS_NULL)
792 return KERN_INVALID_TASK;
793
794 if (right >= MACH_PORT_RIGHT_NUMBER)
795 return KERN_INVALID_VALUE;
796
797 if (!MACH_PORT_VALID(name)) {
798 if (right == MACH_PORT_RIGHT_SEND ||
799 right == MACH_PORT_RIGHT_SEND_ONCE) {
800 *urefsp = 1;
801 return KERN_SUCCESS;
802 }
803 return KERN_INVALID_NAME;
804 }
805
806 kr = ipc_right_lookup_write(space, name, &entry);
807 if (kr != KERN_SUCCESS)
808 return kr;
809 /* space is write-locked and active */
810
811 kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */
812 if (kr != KERN_SUCCESS)
813 return kr; /* space is unlocked */
814 is_write_unlock(space);
815
816 if (type & MACH_PORT_TYPE(right))
817 switch (right) {
818 case MACH_PORT_RIGHT_SEND_ONCE:
819 assert(urefs == 1);
820 /* fall-through */
821
822 case MACH_PORT_RIGHT_PORT_SET:
823 case MACH_PORT_RIGHT_RECEIVE:
824 *urefsp = 1;
825 break;
826
827 case MACH_PORT_RIGHT_DEAD_NAME:
828 case MACH_PORT_RIGHT_SEND:
829 assert(urefs > 0);
830 *urefsp = urefs;
831 break;
832
833 default:
834 panic("mach_port_get_refs: strange rights");
835 }
836 else
837 *urefsp = 0;
838
839 return kr;
840 }
841
842 /*
843 * Routine: mach_port_mod_refs
844 * Purpose:
845 * Modifies the number of user references held by a right.
846 * The resulting number of user references must be non-negative.
847 * If it is zero, the right is deallocated. If the name
848 * doesn't denote other rights, it is destroyed.
849 * Conditions:
850 * Nothing locked.
851 * Returns:
852 * KERN_SUCCESS Modified number of urefs.
853 * KERN_INVALID_TASK The space is null.
854 * KERN_INVALID_TASK The space is dead.
855 * KERN_INVALID_VALUE "right" isn't a legal value.
856 * KERN_INVALID_NAME The name doesn't denote a right.
857 * KERN_INVALID_RIGHT Name doesn't denote specified right.
858 * KERN_INVALID_VALUE Impossible modification to urefs.
859 * KERN_UREFS_OVERFLOW Urefs would overflow.
860 */
861
862 kern_return_t
863 mach_port_mod_refs(
864 ipc_space_t space,
865 mach_port_name_t name,
866 mach_port_right_t right,
867 mach_port_delta_t delta)
868 {
869 ipc_entry_t entry;
870 kern_return_t kr;
871
872 if (space == IS_NULL)
873 return KERN_INVALID_TASK;
874
875 if (right >= MACH_PORT_RIGHT_NUMBER)
876 return KERN_INVALID_VALUE;
877
878 if (!MACH_PORT_VALID(name)) {
879 if (right == MACH_PORT_RIGHT_SEND ||
880 right == MACH_PORT_RIGHT_SEND_ONCE)
881 return KERN_SUCCESS;
882 return KERN_INVALID_NAME;
883 }
884
885 kr = ipc_right_lookup_write(space, name, &entry);
886 if (kr != KERN_SUCCESS)
887 return kr;
888 /* space is write-locked and active */
889
890 kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
891 return kr;
892 }
893
894
895 /*
896 * Routine: mach_port_set_mscount [kernel call]
897 * Purpose:
898 * Changes a receive right's make-send count.
899 * Conditions:
900 * Nothing locked.
901 * Returns:
902 * KERN_SUCCESS Set make-send count.
903 * KERN_INVALID_TASK The space is null.
904 * KERN_INVALID_TASK The space is dead.
905 * KERN_INVALID_NAME The name doesn't denote a right.
906 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
907 */
908
909 kern_return_t
910 mach_port_set_mscount(
911 ipc_space_t space,
912 mach_port_name_t name,
913 mach_port_mscount_t mscount)
914 {
915 ipc_port_t port;
916 kern_return_t kr;
917
918 if (space == IS_NULL)
919 return KERN_INVALID_TASK;
920
921 if (!MACH_PORT_VALID(name))
922 return KERN_INVALID_RIGHT;
923
924 kr = ipc_port_translate_receive(space, name, &port);
925 if (kr != KERN_SUCCESS)
926 return kr;
927 /* port is locked and active */
928
929 ipc_port_set_mscount(port, mscount);
930
931 ip_unlock(port);
932 return KERN_SUCCESS;
933 }
934
935 /*
936 * Routine: mach_port_set_seqno [kernel call]
937 * Purpose:
938 * Changes a receive right's sequence number.
939 * Conditions:
940 * Nothing locked.
941 * Returns:
942 * KERN_SUCCESS Set sequence number.
943 * KERN_INVALID_TASK The space is null.
944 * KERN_INVALID_TASK The space is dead.
945 * KERN_INVALID_NAME The name doesn't denote a right.
946 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
947 */
948
949 kern_return_t
950 mach_port_set_seqno(
951 ipc_space_t space,
952 mach_port_name_t name,
953 mach_port_seqno_t seqno)
954 {
955 ipc_port_t port;
956 kern_return_t kr;
957
958 if (space == IS_NULL)
959 return KERN_INVALID_TASK;
960
961 if (!MACH_PORT_VALID(name))
962 return KERN_INVALID_RIGHT;
963
964 kr = ipc_port_translate_receive(space, name, &port);
965 if (kr != KERN_SUCCESS)
966 return kr;
967 /* port is locked and active */
968
969 ipc_mqueue_set_seqno(&port->ip_messages, seqno);
970
971 ip_unlock(port);
972 return KERN_SUCCESS;
973 }
974
975 /*
976 * Routine: mach_port_gst_helper
977 * Purpose:
978 * A helper function for mach_port_get_set_status.
979 */
980
981 void
982 mach_port_gst_helper(
983 ipc_pset_t pset,
984 ipc_port_t port,
985 ipc_entry_num_t maxnames,
986 mach_port_name_t *names,
987 ipc_entry_num_t *actualp)
988 {
989 ipc_pset_t ip_pset;
990 mach_port_name_t name;
991
992 assert(port != IP_NULL);
993
994 ip_lock(port);
995 assert(ip_active(port));
996
997 name = port->ip_receiver_name;
998 assert(name != MACH_PORT_NULL);
999
1000 ip_unlock(port);
1001
1002 if (ipc_pset_member(pset, port)) {
1003 ipc_entry_num_t actual = *actualp;
1004
1005 if (actual < maxnames)
1006 names[actual] = name;
1007
1008 *actualp = actual+1;
1009 }
1010 }
1011
1012 /*
1013 * Routine: mach_port_get_set_status [kernel call]
1014 * Purpose:
1015 * Retrieves a list of members in a port set.
1016 * Returns the space's name for each receive right member.
1017 * Conditions:
1018 * Nothing locked.
1019 * Returns:
1020 * KERN_SUCCESS Retrieved list of members.
1021 * KERN_INVALID_TASK The space is null.
1022 * KERN_INVALID_TASK The space is dead.
1023 * KERN_INVALID_NAME The name doesn't denote a right.
1024 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1025 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1026 */
1027
1028 kern_return_t
1029 mach_port_get_set_status(
1030 ipc_space_t space,
1031 mach_port_name_t name,
1032 mach_port_name_t **members,
1033 mach_msg_type_number_t *membersCnt)
1034 {
1035 ipc_entry_num_t actual; /* this many members */
1036 ipc_entry_num_t maxnames; /* space for this many members */
1037 kern_return_t kr;
1038
1039 vm_size_t size; /* size of allocated memory */
1040 vm_offset_t addr; /* allocated memory */
1041 vm_map_copy_t memory; /* copied-in memory */
1042
1043 if (space == IS_NULL)
1044 return KERN_INVALID_TASK;
1045
1046 if (!MACH_PORT_VALID(name))
1047 return KERN_INVALID_RIGHT;
1048
1049 size = PAGE_SIZE; /* initial guess */
1050
1051 for (;;) {
1052 ipc_tree_entry_t tentry;
1053 ipc_entry_t entry, table;
1054 ipc_entry_num_t tsize;
1055 mach_port_index_t index;
1056 mach_port_name_t *names;
1057 ipc_pset_t pset;
1058
1059 kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE);
1060 if (kr != KERN_SUCCESS)
1061 return KERN_RESOURCE_SHORTAGE;
1062
1063 /* can't fault while we hold locks */
1064
1065 kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
1066 VM_PROT_READ|VM_PROT_WRITE, FALSE);
1067 assert(kr == KERN_SUCCESS);
1068
1069 kr = ipc_right_lookup_read(space, name, &entry);
1070 if (kr != KERN_SUCCESS) {
1071 kmem_free(ipc_kernel_map, addr, size);
1072 return kr;
1073 }
1074 /* space is read-locked and active */
1075
1076 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
1077 is_read_unlock(space);
1078 kmem_free(ipc_kernel_map, addr, size);
1079 return KERN_INVALID_RIGHT;
1080 }
1081
1082 pset = (ipc_pset_t) entry->ie_object;
1083 assert(pset != IPS_NULL);
1084 /* the port set must be active */
1085
1086 names = (mach_port_name_t *) addr;
1087 maxnames = size / sizeof(mach_port_name_t);
1088 actual = 0;
1089
1090 table = space->is_table;
1091 tsize = space->is_table_size;
1092
1093 for (index = 0; index < tsize; index++) {
1094 ipc_entry_t ientry = &table[index];
1095
1096 if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) {
1097 ipc_port_t port =
1098 (ipc_port_t) ientry->ie_object;
1099
1100 mach_port_gst_helper(pset, port,
1101 maxnames, names, &actual);
1102 }
1103 }
1104
1105 for (tentry = ipc_splay_traverse_start(&space->is_tree);
1106 tentry != ITE_NULL;
1107 tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) {
1108 ipc_entry_bits_t bits = tentry->ite_bits;
1109
1110 assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
1111
1112 if (bits & MACH_PORT_TYPE_RECEIVE) {
1113 ipc_port_t port = (ipc_port_t) tentry->ite_object;
1114
1115 mach_port_gst_helper(pset, port, maxnames,
1116 names, &actual);
1117 }
1118 }
1119 ipc_splay_traverse_finish(&space->is_tree);
1120 is_read_unlock(space);
1121
1122 if (actual <= maxnames)
1123 break;
1124
1125 /* didn't have enough memory; allocate more */
1126
1127 kmem_free(ipc_kernel_map, addr, size);
1128 size = round_page(actual * sizeof(mach_port_name_t)) + PAGE_SIZE;
1129 }
1130
1131 if (actual == 0) {
1132 memory = VM_MAP_COPY_NULL;
1133
1134 kmem_free(ipc_kernel_map, addr, size);
1135 } else {
1136 vm_size_t size_used;
1137 vm_size_t vm_size_used;
1138
1139 size_used = actual * sizeof(mach_port_name_t);
1140 vm_size_used = round_page(size_used);
1141
1142 /*
1143 * Make used memory pageable and get it into
1144 * copied-in form. Free any unused memory.
1145 */
1146
1147 kr = vm_map_unwire(ipc_kernel_map,
1148 addr, addr + vm_size_used, FALSE);
1149 assert(kr == KERN_SUCCESS);
1150
1151 kr = vm_map_copyin(ipc_kernel_map, addr, size_used,
1152 TRUE, &memory);
1153 assert(kr == KERN_SUCCESS);
1154
1155 if (vm_size_used != size)
1156 kmem_free(ipc_kernel_map,
1157 addr + vm_size_used, size - vm_size_used);
1158 }
1159
1160 *members = (mach_port_name_t *) memory;
1161 *membersCnt = actual;
1162 return KERN_SUCCESS;
1163 }
1164
1165 /*
1166 * Routine: mach_port_move_member [kernel call]
1167 * Purpose:
1168 * If after is MACH_PORT_NULL, removes member
1169 * from the port set it is in. Otherwise, adds
1170 * member to after, removing it from any set
1171 * it might already be in.
1172 * Conditions:
1173 * Nothing locked.
1174 * Returns:
1175 * KERN_SUCCESS Moved the port.
1176 * KERN_INVALID_TASK The space is null.
1177 * KERN_INVALID_TASK The space is dead.
1178 * KERN_INVALID_NAME Member didn't denote a right.
1179 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1180 * KERN_INVALID_NAME After didn't denote a right.
1181 * KERN_INVALID_RIGHT After didn't denote a port set right.
1182 * KERN_NOT_IN_SET
1183 * After is MACH_PORT_NULL and Member isn't in a port set.
1184 */
1185
1186 kern_return_t
1187 mach_port_move_member(
1188 ipc_space_t space,
1189 mach_port_name_t member,
1190 mach_port_name_t after)
1191 {
1192 ipc_entry_t entry;
1193 ipc_port_t port;
1194 ipc_pset_t nset;
1195 kern_return_t kr;
1196
1197 if (space == IS_NULL)
1198 return KERN_INVALID_TASK;
1199
1200 if (!MACH_PORT_VALID(member))
1201 return KERN_INVALID_RIGHT;
1202
1203 if (after == MACH_PORT_DEAD)
1204 return KERN_INVALID_RIGHT;
1205
1206 kr = ipc_right_lookup_read(space, member, &entry);
1207 if (kr != KERN_SUCCESS)
1208 return kr;
1209 /* space is read-locked and active */
1210
1211 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1212 is_read_unlock(space);
1213 return KERN_INVALID_RIGHT;
1214 }
1215
1216 port = (ipc_port_t) entry->ie_object;
1217 assert(port != IP_NULL);
1218
1219 if (after == MACH_PORT_NULL)
1220 nset = IPS_NULL;
1221 else {
1222 entry = ipc_entry_lookup(space, after);
1223 if (entry == IE_NULL) {
1224 is_read_unlock(space);
1225 return KERN_INVALID_NAME;
1226 }
1227
1228 if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1229 is_read_unlock(space);
1230 return KERN_INVALID_RIGHT;
1231 }
1232
1233 nset = (ipc_pset_t) entry->ie_object;
1234 assert(nset != IPS_NULL);
1235 }
1236 ip_lock(port);
1237 ipc_pset_remove_from_all(port);
1238
1239 if (nset != IPS_NULL) {
1240 ips_lock(nset);
1241 kr = ipc_pset_add(nset, port);
1242 ips_unlock(nset);
1243 }
1244 ip_unlock(port);
1245 is_read_unlock(space);
1246 return kr;
1247 }
1248
1249 /*
1250 * Routine: mach_port_request_notification [kernel call]
1251 * Purpose:
1252 * Requests a notification. The caller supplies
1253 * a send-once right for the notification to use,
1254 * and the call returns the previously registered
1255 * send-once right, if any. Possible types:
1256 *
1257 * MACH_NOTIFY_PORT_DESTROYED
1258 * Requests a port-destroyed notification
1259 * for a receive right. Sync should be zero.
1260 * MACH_NOTIFY_NO_SENDERS
1261 * Requests a no-senders notification for a
1262 * receive right. If there are currently no
1263 * senders, sync is less than or equal to the
1264 * current make-send count, and a send-once right
1265 * is supplied, then an immediate no-senders
1266 * notification is generated.
1267 * MACH_NOTIFY_DEAD_NAME
1268 * Requests a dead-name notification for a send
1269 * or receive right. If the name is already a
1270 * dead name, sync is non-zero, and a send-once
1271 * right is supplied, then an immediate dead-name
1272 * notification is generated.
1273 * Conditions:
1274 * Nothing locked.
1275 * Returns:
1276 * KERN_SUCCESS Requested a notification.
1277 * KERN_INVALID_TASK The space is null.
1278 * KERN_INVALID_TASK The space is dead.
1279 * KERN_INVALID_VALUE Bad id value.
1280 * KERN_INVALID_NAME Name doesn't denote a right.
1281 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1282 * KERN_INVALID_CAPABILITY The notify port is dead.
1283 * MACH_NOTIFY_PORT_DESTROYED:
1284 * KERN_INVALID_VALUE Sync isn't zero.
1285 * MACH_NOTIFY_DEAD_NAME:
1286 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1287 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1288 * sync is zero or notify is IP_NULL.
1289 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1290 * generating immediate notif. would overflow urefs.
1291 */
1292
1293 kern_return_t
1294 mach_port_request_notification(
1295 ipc_space_t space,
1296 mach_port_name_t name,
1297 mach_msg_id_t id,
1298 mach_port_mscount_t sync,
1299 ipc_port_t notify,
1300 ipc_port_t *previousp)
1301 {
1302 kern_return_t kr;
1303 ipc_entry_t entry;
1304 ipc_port_t port;
1305
1306
1307 if (space == IS_NULL)
1308 return KERN_INVALID_TASK;
1309
1310 if (notify == IP_DEAD)
1311 return KERN_INVALID_CAPABILITY;
1312
1313 #if NOTYET
1314 /*
1315 * Requesting notifications on RPC ports is an error.
1316 */
1317 kr = ipc_right_lookup_write(space, name, &entry);
1318 if (kr != KERN_SUCCESS)
1319 return kr;
1320
1321 port = (ipc_port_t) entry->ie_object;
1322
1323 if (port->ip_subsystem != NULL) {
1324 is_write_unlock(space);
1325 panic("mach_port_request_notification: on RPC port!!");
1326 return KERN_INVALID_CAPABILITY;
1327 }
1328 is_write_unlock(space);
1329 #endif /* NOTYET */
1330
1331
1332 switch (id) {
1333 case MACH_NOTIFY_PORT_DESTROYED: {
1334 ipc_port_t port, previous;
1335
1336 if (sync != 0)
1337 return KERN_INVALID_VALUE;
1338
1339 if (!MACH_PORT_VALID(name))
1340 return KERN_INVALID_RIGHT;
1341
1342 kr = ipc_port_translate_receive(space, name, &port);
1343 if (kr != KERN_SUCCESS)
1344 return kr;
1345 /* port is locked and active */
1346
1347 ipc_port_pdrequest(port, notify, &previous);
1348 /* port is unlocked */
1349
1350 *previousp = previous;
1351 break;
1352 }
1353
1354 case MACH_NOTIFY_NO_SENDERS: {
1355 ipc_port_t port;
1356
1357 if (!MACH_PORT_VALID(name))
1358 return KERN_INVALID_RIGHT;
1359
1360 kr = ipc_port_translate_receive(space, name, &port);
1361 if (kr != KERN_SUCCESS)
1362 return kr;
1363 /* port is locked and active */
1364
1365 ipc_port_nsrequest(port, sync, notify, previousp);
1366 /* port is unlocked */
1367 break;
1368 }
1369
1370 case MACH_NOTIFY_DEAD_NAME:
1371
1372 if (!MACH_PORT_VALID(name)) {
1373 /*
1374 * Already dead.
1375 * Should do immediate delivery check -
1376 * will do that in the near future.
1377 */
1378 return KERN_INVALID_ARGUMENT;
1379 }
1380
1381 kr = ipc_right_dnrequest(space, name, sync != 0,
1382 notify, previousp);
1383 if (kr != KERN_SUCCESS)
1384 return kr;
1385 break;
1386
1387 default:
1388 return KERN_INVALID_VALUE;
1389 }
1390
1391 return KERN_SUCCESS;
1392 }
1393
1394 /*
1395 * Routine: mach_port_insert_right [kernel call]
1396 * Purpose:
1397 * Inserts a right into a space, as if the space
1398 * voluntarily received the right in a message,
1399 * except that the right gets the specified name.
1400 * Conditions:
1401 * Nothing locked.
1402 * Returns:
1403 * KERN_SUCCESS Inserted the right.
1404 * KERN_INVALID_TASK The space is null.
1405 * KERN_INVALID_TASK The space is dead.
1406 * KERN_INVALID_VALUE The name isn't a legal name.
1407 * KERN_NAME_EXISTS The name already denotes a right.
1408 * KERN_INVALID_VALUE Message doesn't carry a port right.
1409 * KERN_INVALID_CAPABILITY Port is null or dead.
1410 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1411 * KERN_RIGHT_EXISTS Space has rights under another name.
1412 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1413 */
1414
1415 kern_return_t
1416 mach_port_insert_right(
1417 ipc_space_t space,
1418 mach_port_name_t name,
1419 ipc_port_t poly,
1420 mach_msg_type_name_t polyPoly)
1421 {
1422 if (space == IS_NULL)
1423 return KERN_INVALID_TASK;
1424
1425 if (!MACH_PORT_VALID(name) ||
1426 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
1427 return KERN_INVALID_VALUE;
1428
1429 if (!IO_VALID((ipc_object_t) poly))
1430 return KERN_INVALID_CAPABILITY;
1431
1432 return ipc_object_copyout_name(space, (ipc_object_t) poly,
1433 polyPoly, FALSE, name);
1434 }
1435
1436 /*
1437 * Routine: mach_port_extract_right [kernel call]
1438 * Purpose:
1439 * Extracts a right from a space, as if the space
1440 * voluntarily sent the right to the caller.
1441 * Conditions:
1442 * Nothing locked.
1443 * Returns:
1444 * KERN_SUCCESS Extracted the right.
1445 * KERN_INVALID_TASK The space is null.
1446 * KERN_INVALID_TASK The space is dead.
1447 * KERN_INVALID_VALUE Requested type isn't a port right.
1448 * KERN_INVALID_NAME Name doesn't denote a right.
1449 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1450 */
1451
1452 kern_return_t
1453 mach_port_extract_right(
1454 ipc_space_t space,
1455 mach_port_name_t name,
1456 mach_msg_type_name_t msgt_name,
1457 ipc_port_t *poly,
1458 mach_msg_type_name_t *polyPoly)
1459 {
1460 kern_return_t kr;
1461
1462 if (space == IS_NULL)
1463 return KERN_INVALID_TASK;
1464
1465 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
1466 return KERN_INVALID_VALUE;
1467
1468 if (!MACH_PORT_VALID(name)) {
1469 /*
1470 * really should copy out a dead name, if it is a send or
1471 * send-once right being copied, but instead return an
1472 * error for now.
1473 */
1474 return KERN_INVALID_RIGHT;
1475 }
1476
1477 kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
1478
1479 if (kr == KERN_SUCCESS)
1480 *polyPoly = ipc_object_copyin_type(msgt_name);
1481 return kr;
1482 }
1483
1484
1485 kern_return_t
1486 mach_port_get_attributes(
1487 ipc_space_t space,
1488 mach_port_name_t name,
1489 int flavor,
1490 mach_port_info_t info,
1491 mach_msg_type_number_t *count)
1492 {
1493 ipc_port_t port;
1494 kern_return_t kr;
1495
1496 if (space == IS_NULL)
1497 return KERN_INVALID_TASK;
1498
1499 switch (flavor) {
1500 case MACH_PORT_LIMITS_INFO: {
1501 mach_port_limits_t *lp = (mach_port_limits_t *)info;
1502
1503 if (*count < MACH_PORT_LIMITS_INFO_COUNT)
1504 return KERN_FAILURE;
1505
1506 if (!MACH_PORT_VALID(name)) {
1507 *count = 0;
1508 break;
1509 }
1510
1511 kr = ipc_port_translate_receive(space, name, &port);
1512 if (kr != KERN_SUCCESS)
1513 return kr;
1514 /* port is locked and active */
1515
1516 lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1517 *count = MACH_PORT_LIMITS_INFO_COUNT;
1518 ip_unlock(port);
1519 break;
1520 }
1521
1522 case MACH_PORT_RECEIVE_STATUS: {
1523 mach_port_status_t *statusp = (mach_port_status_t *)info;
1524 spl_t s;
1525
1526 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
1527 return KERN_FAILURE;
1528
1529 if (!MACH_PORT_VALID(name))
1530 return KERN_INVALID_RIGHT;
1531
1532 kr = ipc_port_translate_receive(space, name, &port);
1533 if (kr != KERN_SUCCESS)
1534 return kr;
1535 /* port is locked and active */
1536
1537 statusp->mps_pset = port->ip_pset_count;
1538
1539 s = splsched();
1540 imq_lock(&port->ip_messages);
1541 statusp->mps_seqno = port->ip_messages.imq_seqno;
1542 statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1543 statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1544 imq_unlock(&port->ip_messages);
1545 splx(s);
1546
1547 statusp->mps_mscount = port->ip_mscount;
1548 statusp->mps_sorights = port->ip_sorights;
1549 statusp->mps_srights = port->ip_srights > 0;
1550 statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1551 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1552 statusp->mps_flags = 0;
1553
1554 *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1555 ip_unlock(port);
1556 break;
1557 }
1558
1559 case MACH_PORT_DNREQUESTS_SIZE: {
1560 ipc_port_request_t table;
1561
1562 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1563 return KERN_FAILURE;
1564
1565 if (!MACH_PORT_VALID(name)) {
1566 *(int *)info = 0;
1567 break;
1568 }
1569
1570 kr = ipc_port_translate_receive(space, name, &port);
1571 if (kr != KERN_SUCCESS)
1572 return kr;
1573 /* port is locked and active */
1574
1575 table = port->ip_dnrequests;
1576 if (table == IPR_NULL)
1577 *(int *)info = 0;
1578 else
1579 *(int *)info = table->ipr_size->its_size;
1580 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1581 ip_unlock(port);
1582 break;
1583 }
1584
1585 default:
1586 return KERN_INVALID_ARGUMENT;
1587 /*NOTREACHED*/
1588 }
1589
1590 return KERN_SUCCESS;
1591 }
1592
1593 kern_return_t
1594 mach_port_set_attributes(
1595 ipc_space_t space,
1596 mach_port_name_t name,
1597 int flavor,
1598 mach_port_info_t info,
1599 mach_msg_type_number_t count)
1600 {
1601 ipc_port_t port;
1602 kern_return_t kr;
1603
1604 if (space == IS_NULL)
1605 return KERN_INVALID_TASK;
1606
1607 switch (flavor) {
1608
1609 case MACH_PORT_LIMITS_INFO: {
1610 mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1611
1612 if (count < MACH_PORT_LIMITS_INFO_COUNT)
1613 return KERN_FAILURE;
1614
1615 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
1616 return KERN_INVALID_VALUE;
1617
1618 if (!MACH_PORT_VALID(name))
1619 return KERN_INVALID_RIGHT;
1620
1621 kr = ipc_port_translate_receive(space, name, &port);
1622 if (kr != KERN_SUCCESS)
1623 return kr;
1624 /* port is locked and active */
1625
1626 ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
1627 ip_unlock(port);
1628 break;
1629 }
1630 case MACH_PORT_DNREQUESTS_SIZE: {
1631 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1632 return KERN_FAILURE;
1633
1634 if (!MACH_PORT_VALID(name))
1635 return KERN_INVALID_RIGHT;
1636
1637 kr = ipc_port_translate_receive(space, name, &port);
1638 if (kr != KERN_SUCCESS)
1639 return kr;
1640 /* port is locked and active */
1641
1642 kr = ipc_port_dngrow(port, *(int *)info);
1643 if (kr != KERN_SUCCESS)
1644 return kr;
1645 break;
1646 }
1647 default:
1648 return KERN_INVALID_ARGUMENT;
1649 /*NOTREACHED*/
1650 }
1651 return KERN_SUCCESS;
1652 }
1653
1654 /*
1655 * Routine: mach_port_insert_member [kernel call]
1656 * Purpose:
1657 * Add the receive right, specified by name, to
1658 * a portset.
1659 * The port cannot already be a member of the set.
1660 * Conditions:
1661 * Nothing locked.
1662 * Returns:
1663 * KERN_SUCCESS Moved the port.
1664 * KERN_INVALID_TASK The space is null.
1665 * KERN_INVALID_TASK The space is dead.
1666 * KERN_INVALID_NAME name didn't denote a right.
1667 * KERN_INVALID_RIGHT name didn't denote a receive right.
1668 * KERN_INVALID_NAME pset_name didn't denote a right.
1669 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
1670 * KERN_ALREADY_IN_SET name was already a member of pset.
1671 */
1672
1673 kern_return_t
1674 mach_port_insert_member(
1675 ipc_space_t space,
1676 mach_port_name_t name,
1677 mach_port_name_t psname)
1678 {
1679 ipc_object_t obj;
1680 ipc_object_t psobj;
1681 kern_return_t kr;
1682
1683 if (space == IS_NULL)
1684 return KERN_INVALID_TASK;
1685
1686 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1687 return KERN_INVALID_RIGHT;
1688
1689 kr = ipc_object_translate_two(space,
1690 name, MACH_PORT_RIGHT_RECEIVE, &obj,
1691 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1692 if (kr != KERN_SUCCESS)
1693 return kr;
1694
1695 /* obj and psobj are locked (and were locked in that order) */
1696 assert(psobj != IO_NULL);
1697 assert(obj != IO_NULL);
1698
1699 kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj);
1700 io_unlock(psobj);
1701 io_unlock(obj);
1702 return kr;
1703 }
1704
1705 /*
1706 * Routine: mach_port_extract_member [kernel call]
1707 * Purpose:
1708 * Remove a port from one portset that it is a member of.
1709 * Conditions:
1710 * Nothing locked.
1711 * Returns:
1712 * KERN_SUCCESS Moved the port.
1713 * KERN_INVALID_TASK The space is null.
1714 * KERN_INVALID_TASK The space is dead.
1715 * KERN_INVALID_NAME Member didn't denote a right.
1716 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1717 * KERN_INVALID_NAME After didn't denote a right.
1718 * KERN_INVALID_RIGHT After didn't denote a port set right.
1719 * KERN_NOT_IN_SET
1720 * After is MACH_PORT_NULL and Member isn't in a port set.
1721 */
1722
1723 kern_return_t
1724 mach_port_extract_member(
1725 ipc_space_t space,
1726 mach_port_name_t name,
1727 mach_port_name_t psname)
1728 {
1729 mach_port_name_t oldname;
1730 ipc_object_t psobj;
1731 ipc_object_t obj;
1732 kern_return_t kr;
1733
1734 if (space == IS_NULL)
1735 return KERN_INVALID_TASK;
1736
1737 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1738 return KERN_INVALID_RIGHT;
1739
1740 kr = ipc_object_translate_two(space,
1741 name, MACH_PORT_RIGHT_RECEIVE, &obj,
1742 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1743 if (kr != KERN_SUCCESS)
1744 return kr;
1745
1746 /* obj and psobj are both locked (and were locked in that order) */
1747 assert(psobj != IO_NULL);
1748 assert(obj != IO_NULL);
1749
1750 kr = ipc_pset_remove((ipc_pset_t)psobj, (ipc_port_t)obj);
1751 io_unlock(psobj);
1752 io_unlock(obj);
1753 return kr;
1754 }
1755