]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/mach_port.c
xnu-792.24.17.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_port.c
1 /*
2 * Copyright (c) 2000-2004 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.h>
73 #include <kern/kalloc.h>
74 #include <mach/mach_port_server.h>
75 #include <vm/vm_map.h>
76 #include <vm/vm_kern.h>
77 #include <ipc/ipc_entry.h>
78 #include <ipc/ipc_space.h>
79 #include <ipc/ipc_object.h>
80 #include <ipc/ipc_notify.h>
81 #include <ipc/ipc_port.h>
82 #include <ipc/ipc_pset.h>
83 #include <ipc/ipc_right.h>
84 #include <ipc/ipc_kmsg.h>
85 #include <kern/misc_protos.h>
86
87 /*
88 * Forward declarations
89 */
90 void mach_port_names_helper(
91 ipc_port_timestamp_t timestamp,
92 ipc_entry_t entry,
93 mach_port_name_t name,
94 mach_port_name_t *names,
95 mach_port_type_t *types,
96 ipc_entry_num_t *actualp);
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 {
125 ipc_entry_bits_t bits;
126 ipc_port_request_index_t request;
127 mach_port_type_t type;
128 ipc_entry_num_t actual;
129
130 bits = entry->ie_bits;
131 request = entry->ie_request;
132 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
133 ipc_port_t port;
134 boolean_t died;
135
136 port = (ipc_port_t) entry->ie_object;
137 assert(port != IP_NULL);
138
139 /*
140 * The timestamp serializes mach_port_names
141 * with ipc_port_destroy. If the port died,
142 * but after mach_port_names started, pretend
143 * that it isn't dead.
144 */
145
146 ip_lock(port);
147 died = (!ip_active(port) &&
148 IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
149 ip_unlock(port);
150
151 if (died) {
152 /* pretend this is a dead-name entry */
153
154 bits &= ~(IE_BITS_TYPE_MASK);
155 bits |= MACH_PORT_TYPE_DEAD_NAME;
156 if (request != 0)
157 bits++;
158 request = 0;
159 }
160 }
161
162 type = IE_BITS_TYPE(bits);
163 if (request != 0)
164 type |= MACH_PORT_TYPE_DNREQUEST;
165
166 actual = *actualp;
167 names[actual] = name;
168 types[actual] = type;
169 *actualp = actual+1;
170 }
171
172 /*
173 * Routine: mach_port_names [kernel call]
174 * Purpose:
175 * Retrieves a list of the rights present in the space,
176 * along with type information. (Same as returned
177 * by mach_port_type.) The names are returned in
178 * no particular order, but they (and the type info)
179 * are an accurate snapshot of the space.
180 * Conditions:
181 * Nothing locked.
182 * Returns:
183 * KERN_SUCCESS Arrays of names and types returned.
184 * KERN_INVALID_TASK The space is null.
185 * KERN_INVALID_TASK The space is dead.
186 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
187 */
188
189 kern_return_t
190 mach_port_names(
191 ipc_space_t space,
192 mach_port_name_t **namesp,
193 mach_msg_type_number_t *namesCnt,
194 mach_port_type_t **typesp,
195 mach_msg_type_number_t *typesCnt)
196 {
197 ipc_tree_entry_t tentry;
198 ipc_entry_t table;
199 ipc_entry_num_t tsize;
200 mach_port_index_t index;
201 ipc_entry_num_t actual; /* this many names */
202 ipc_port_timestamp_t timestamp; /* logical time of this operation */
203 mach_port_name_t *names;
204 mach_port_type_t *types;
205 kern_return_t kr;
206
207 vm_size_t size; /* size of allocated memory */
208 vm_offset_t addr1; /* allocated memory, for names */
209 vm_offset_t addr2; /* allocated memory, for types */
210 vm_map_copy_t memory1; /* copied-in memory, for names */
211 vm_map_copy_t memory2; /* copied-in memory, for types */
212
213 /* safe simplifying assumption */
214 assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
215
216 if (space == IS_NULL)
217 return KERN_INVALID_TASK;
218
219 size = 0;
220
221 for (;;) {
222 ipc_entry_num_t bound;
223 vm_size_t size_needed;
224
225 is_read_lock(space);
226 if (!space->is_active) {
227 is_read_unlock(space);
228 if (size != 0) {
229 kmem_free(ipc_kernel_map, addr1, size);
230 kmem_free(ipc_kernel_map, addr2, size);
231 }
232 return KERN_INVALID_TASK;
233 }
234
235 /* upper bound on number of names in the space */
236
237 bound = space->is_table_size + space->is_tree_total;
238 size_needed = round_page(bound * sizeof(mach_port_name_t));
239
240 if (size_needed <= size)
241 break;
242
243 is_read_unlock(space);
244
245 if (size != 0) {
246 kmem_free(ipc_kernel_map, addr1, size);
247 kmem_free(ipc_kernel_map, addr2, size);
248 }
249 size = size_needed;
250
251 kr = vm_allocate(ipc_kernel_map, &addr1, size, VM_FLAGS_ANYWHERE);
252 if (kr != KERN_SUCCESS)
253 return KERN_RESOURCE_SHORTAGE;
254
255 kr = vm_allocate(ipc_kernel_map, &addr2, size, VM_FLAGS_ANYWHERE);
256 if (kr != KERN_SUCCESS) {
257 kmem_free(ipc_kernel_map, addr1, size);
258 return KERN_RESOURCE_SHORTAGE;
259 }
260
261 /* can't fault while we hold locks */
262
263 kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(addr1),
264 vm_map_round_page(addr1 + size),
265 VM_PROT_READ|VM_PROT_WRITE, FALSE);
266 if (kr != KERN_SUCCESS) {
267 kmem_free(ipc_kernel_map, addr1, size);
268 kmem_free(ipc_kernel_map, addr2, size);
269 return KERN_RESOURCE_SHORTAGE;
270 }
271
272 kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(addr2),
273 vm_map_round_page(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);
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);
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, vm_map_trunc_page(addr1),
340 vm_map_round_page(addr1 + vm_size_used), FALSE);
341 assert(kr == KERN_SUCCESS);
342
343 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr2),
344 vm_map_round_page(addr2 + vm_size_used), FALSE);
345 assert(kr == KERN_SUCCESS);
346
347 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr1,
348 (vm_map_size_t)size_used, TRUE, &memory1);
349 assert(kr == KERN_SUCCESS);
350
351 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr2,
352 (vm_map_size_t)size_used, 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 = IKM_NULL;
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 if (qosp->len > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) {
627 return KERN_RESOURCE_SHORTAGE;
628 } else {
629 mach_msg_size_t size = qosp->len + MAX_TRAILER_SIZE;
630 if (right != MACH_PORT_RIGHT_RECEIVE)
631 return (KERN_INVALID_VALUE);
632 kmsg = (ipc_kmsg_t)ipc_kmsg_alloc(size);
633 if (kmsg == IKM_NULL)
634 return (KERN_RESOURCE_SHORTAGE);
635 }
636 }
637
638 switch (right) {
639 case MACH_PORT_RIGHT_RECEIVE:
640 {
641 ipc_port_t port;
642
643 if (qosp->name)
644 kr = ipc_port_alloc_name(space, *namep, &port);
645 else
646 kr = ipc_port_alloc(space, namep, &port);
647 if (kr == KERN_SUCCESS) {
648 if (kmsg != IKM_NULL)
649 ipc_kmsg_set_prealloc(kmsg, port);
650
651 ip_unlock(port);
652
653 } else if (kmsg != IKM_NULL)
654 ipc_kmsg_free(kmsg);
655 break;
656 }
657
658 case MACH_PORT_RIGHT_PORT_SET:
659 {
660 ipc_pset_t pset;
661
662 if (qosp->name)
663 kr = ipc_pset_alloc_name(space, *namep, &pset);
664 else
665 kr = ipc_pset_alloc(space, namep, &pset);
666 if (kr == KERN_SUCCESS)
667 ips_unlock(pset);
668 break;
669 }
670
671 case MACH_PORT_RIGHT_DEAD_NAME:
672 kr = ipc_object_alloc_dead(space, namep);
673 break;
674
675 default:
676 kr = KERN_INVALID_VALUE;
677 break;
678 }
679
680 return (kr);
681 }
682
683 /*
684 * Routine: mach_port_destroy [kernel call]
685 * Purpose:
686 * Cleans up and destroys all rights denoted by a name
687 * in a space. The destruction of a receive right
688 * destroys the port, unless a port-destroyed request
689 * has been made for it; the destruction of a port-set right
690 * destroys the port set.
691 * Conditions:
692 * Nothing locked.
693 * Returns:
694 * KERN_SUCCESS The name is destroyed.
695 * KERN_INVALID_TASK The space is null.
696 * KERN_INVALID_TASK The space is dead.
697 * KERN_INVALID_NAME The name doesn't denote a right.
698 */
699
700 kern_return_t
701 mach_port_destroy(
702 ipc_space_t space,
703 mach_port_name_t name)
704 {
705 ipc_entry_t entry;
706 kern_return_t kr;
707
708 if (space == IS_NULL)
709 return KERN_INVALID_TASK;
710
711 if (!MACH_PORT_VALID(name))
712 return KERN_SUCCESS;
713
714 kr = ipc_right_lookup_write(space, name, &entry);
715 if (kr != KERN_SUCCESS)
716 return kr;
717 /* space is write-locked and active */
718
719 kr = ipc_right_destroy(space, name, entry);
720 is_write_unlock(space);
721 return kr;
722 }
723
724 /*
725 * Routine: mach_port_deallocate [kernel call]
726 * Purpose:
727 * Deallocates a user reference from a send right,
728 * send-once right, or a dead-name right. May
729 * deallocate the right, if this is the last uref,
730 * and destroy the name, if it doesn't denote
731 * other rights.
732 * Conditions:
733 * Nothing locked.
734 * Returns:
735 * KERN_SUCCESS The uref is deallocated.
736 * KERN_INVALID_TASK The space is null.
737 * KERN_INVALID_TASK The space is dead.
738 * KERN_INVALID_NAME The name doesn't denote a right.
739 * KERN_INVALID_RIGHT The right isn't correct.
740 */
741
742 kern_return_t
743 mach_port_deallocate(
744 ipc_space_t space,
745 mach_port_name_t name)
746 {
747 ipc_entry_t entry;
748 kern_return_t kr;
749
750 if (space == IS_NULL)
751 return KERN_INVALID_TASK;
752
753 if (!MACH_PORT_VALID(name))
754 return KERN_SUCCESS;
755
756 kr = ipc_right_lookup_write(space, name, &entry);
757 if (kr != KERN_SUCCESS)
758 return kr;
759 /* space is write-locked */
760
761 kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
762 return kr;
763 }
764
765 /*
766 * Routine: mach_port_get_refs [kernel call]
767 * Purpose:
768 * Retrieves the number of user references held by a right.
769 * Receive rights, port-set rights, and send-once rights
770 * always have one user reference. Returns zero if the
771 * name denotes a right, but not the queried right.
772 * Conditions:
773 * Nothing locked.
774 * Returns:
775 * KERN_SUCCESS Number of urefs returned.
776 * KERN_INVALID_TASK The space is null.
777 * KERN_INVALID_TASK The space is dead.
778 * KERN_INVALID_VALUE "right" isn't a legal value.
779 * KERN_INVALID_NAME The name doesn't denote a right.
780 */
781
782 kern_return_t
783 mach_port_get_refs(
784 ipc_space_t space,
785 mach_port_name_t name,
786 mach_port_right_t right,
787 mach_port_urefs_t *urefsp)
788 {
789 mach_port_type_t type;
790 mach_port_urefs_t urefs;
791 ipc_entry_t entry;
792 kern_return_t kr;
793
794 if (space == IS_NULL)
795 return KERN_INVALID_TASK;
796
797 if (right >= MACH_PORT_RIGHT_NUMBER)
798 return KERN_INVALID_VALUE;
799
800 if (!MACH_PORT_VALID(name)) {
801 if (right == MACH_PORT_RIGHT_SEND ||
802 right == MACH_PORT_RIGHT_SEND_ONCE) {
803 *urefsp = 1;
804 return KERN_SUCCESS;
805 }
806 return KERN_INVALID_NAME;
807 }
808
809 kr = ipc_right_lookup_write(space, name, &entry);
810 if (kr != KERN_SUCCESS)
811 return kr;
812 /* space is write-locked and active */
813
814 kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */
815 if (kr != KERN_SUCCESS)
816 return kr; /* space is unlocked */
817 is_write_unlock(space);
818
819 if (type & MACH_PORT_TYPE(right))
820 switch (right) {
821 case MACH_PORT_RIGHT_SEND_ONCE:
822 assert(urefs == 1);
823 /* fall-through */
824
825 case MACH_PORT_RIGHT_PORT_SET:
826 case MACH_PORT_RIGHT_RECEIVE:
827 *urefsp = 1;
828 break;
829
830 case MACH_PORT_RIGHT_DEAD_NAME:
831 case MACH_PORT_RIGHT_SEND:
832 assert(urefs > 0);
833 *urefsp = urefs;
834 break;
835
836 default:
837 panic("mach_port_get_refs: strange rights");
838 }
839 else
840 *urefsp = 0;
841
842 return kr;
843 }
844
845 /*
846 * Routine: mach_port_mod_refs
847 * Purpose:
848 * Modifies the number of user references held by a right.
849 * The resulting number of user references must be non-negative.
850 * If it is zero, the right is deallocated. If the name
851 * doesn't denote other rights, it is destroyed.
852 * Conditions:
853 * Nothing locked.
854 * Returns:
855 * KERN_SUCCESS Modified number of urefs.
856 * KERN_INVALID_TASK The space is null.
857 * KERN_INVALID_TASK The space is dead.
858 * KERN_INVALID_VALUE "right" isn't a legal value.
859 * KERN_INVALID_NAME The name doesn't denote a right.
860 * KERN_INVALID_RIGHT Name doesn't denote specified right.
861 * KERN_INVALID_VALUE Impossible modification to urefs.
862 * KERN_UREFS_OVERFLOW Urefs would overflow.
863 */
864
865 kern_return_t
866 mach_port_mod_refs(
867 ipc_space_t space,
868 mach_port_name_t name,
869 mach_port_right_t right,
870 mach_port_delta_t delta)
871 {
872 ipc_entry_t entry;
873 kern_return_t kr;
874
875 if (space == IS_NULL)
876 return KERN_INVALID_TASK;
877
878 if (right >= MACH_PORT_RIGHT_NUMBER)
879 return KERN_INVALID_VALUE;
880
881 if (!MACH_PORT_VALID(name)) {
882 if (right == MACH_PORT_RIGHT_SEND ||
883 right == MACH_PORT_RIGHT_SEND_ONCE)
884 return KERN_SUCCESS;
885 return KERN_INVALID_NAME;
886 }
887
888 kr = ipc_right_lookup_write(space, name, &entry);
889 if (kr != KERN_SUCCESS)
890 return kr;
891 /* space is write-locked and active */
892
893 kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
894 return kr;
895 }
896
897
898 /*
899 * Routine: mach_port_set_mscount [kernel call]
900 * Purpose:
901 * Changes a receive right's make-send count.
902 * Conditions:
903 * Nothing locked.
904 * Returns:
905 * KERN_SUCCESS Set make-send count.
906 * KERN_INVALID_TASK The space is null.
907 * KERN_INVALID_TASK The space is dead.
908 * KERN_INVALID_NAME The name doesn't denote a right.
909 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
910 */
911
912 kern_return_t
913 mach_port_set_mscount(
914 ipc_space_t space,
915 mach_port_name_t name,
916 mach_port_mscount_t mscount)
917 {
918 ipc_port_t port;
919 kern_return_t kr;
920
921 if (space == IS_NULL)
922 return KERN_INVALID_TASK;
923
924 if (!MACH_PORT_VALID(name))
925 return KERN_INVALID_RIGHT;
926
927 kr = ipc_port_translate_receive(space, name, &port);
928 if (kr != KERN_SUCCESS)
929 return kr;
930 /* port is locked and active */
931
932 ipc_port_set_mscount(port, mscount);
933
934 ip_unlock(port);
935 return KERN_SUCCESS;
936 }
937
938 /*
939 * Routine: mach_port_set_seqno [kernel call]
940 * Purpose:
941 * Changes a receive right's sequence number.
942 * Conditions:
943 * Nothing locked.
944 * Returns:
945 * KERN_SUCCESS Set sequence number.
946 * KERN_INVALID_TASK The space is null.
947 * KERN_INVALID_TASK The space is dead.
948 * KERN_INVALID_NAME The name doesn't denote a right.
949 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
950 */
951
952 kern_return_t
953 mach_port_set_seqno(
954 ipc_space_t space,
955 mach_port_name_t name,
956 mach_port_seqno_t seqno)
957 {
958 ipc_port_t port;
959 kern_return_t kr;
960
961 if (space == IS_NULL)
962 return KERN_INVALID_TASK;
963
964 if (!MACH_PORT_VALID(name))
965 return KERN_INVALID_RIGHT;
966
967 kr = ipc_port_translate_receive(space, name, &port);
968 if (kr != KERN_SUCCESS)
969 return kr;
970 /* port is locked and active */
971
972 ipc_mqueue_set_seqno(&port->ip_messages, seqno);
973
974 ip_unlock(port);
975 return KERN_SUCCESS;
976 }
977
978 /*
979 * Routine: mach_port_gst_helper
980 * Purpose:
981 * A helper function for mach_port_get_set_status.
982 */
983
984 void
985 mach_port_gst_helper(
986 ipc_pset_t pset,
987 ipc_port_t port,
988 ipc_entry_num_t maxnames,
989 mach_port_name_t *names,
990 ipc_entry_num_t *actualp)
991 {
992 mach_port_name_t name;
993
994 assert(port != IP_NULL);
995
996 ip_lock(port);
997 assert(ip_active(port));
998
999 name = port->ip_receiver_name;
1000 assert(name != MACH_PORT_NULL);
1001
1002 ip_unlock(port);
1003
1004 if (ipc_pset_member(pset, port)) {
1005 ipc_entry_num_t actual = *actualp;
1006
1007 if (actual < maxnames)
1008 names[actual] = name;
1009
1010 *actualp = actual+1;
1011 }
1012 }
1013
1014 /*
1015 * Routine: mach_port_get_set_status [kernel call]
1016 * Purpose:
1017 * Retrieves a list of members in a port set.
1018 * Returns the space's name for each receive right member.
1019 * Conditions:
1020 * Nothing locked.
1021 * Returns:
1022 * KERN_SUCCESS Retrieved list of members.
1023 * KERN_INVALID_TASK The space is null.
1024 * KERN_INVALID_TASK The space is dead.
1025 * KERN_INVALID_NAME The name doesn't denote a right.
1026 * KERN_INVALID_RIGHT Name doesn't denote a port set.
1027 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1028 */
1029
1030 kern_return_t
1031 mach_port_get_set_status(
1032 ipc_space_t space,
1033 mach_port_name_t name,
1034 mach_port_name_t **members,
1035 mach_msg_type_number_t *membersCnt)
1036 {
1037 ipc_entry_num_t actual; /* this many members */
1038 ipc_entry_num_t maxnames; /* space for this many members */
1039 kern_return_t kr;
1040
1041 vm_size_t size; /* size of allocated memory */
1042 vm_offset_t addr; /* allocated memory */
1043 vm_map_copy_t memory; /* copied-in memory */
1044
1045 if (space == IS_NULL)
1046 return KERN_INVALID_TASK;
1047
1048 if (!MACH_PORT_VALID(name))
1049 return KERN_INVALID_RIGHT;
1050
1051 size = PAGE_SIZE; /* initial guess */
1052
1053 for (;;) {
1054 ipc_tree_entry_t tentry;
1055 ipc_entry_t entry, table;
1056 ipc_entry_num_t tsize;
1057 mach_port_index_t index;
1058 mach_port_name_t *names;
1059 ipc_pset_t pset;
1060
1061 kr = vm_allocate(ipc_kernel_map, &addr, size, VM_FLAGS_ANYWHERE);
1062 if (kr != KERN_SUCCESS)
1063 return KERN_RESOURCE_SHORTAGE;
1064
1065 /* can't fault while we hold locks */
1066
1067 kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
1068 VM_PROT_READ|VM_PROT_WRITE, FALSE);
1069 assert(kr == KERN_SUCCESS);
1070
1071 kr = ipc_right_lookup_read(space, name, &entry);
1072 if (kr != KERN_SUCCESS) {
1073 kmem_free(ipc_kernel_map, addr, size);
1074 return kr;
1075 }
1076 /* space is read-locked and active */
1077
1078 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
1079 is_read_unlock(space);
1080 kmem_free(ipc_kernel_map, addr, size);
1081 return KERN_INVALID_RIGHT;
1082 }
1083
1084 pset = (ipc_pset_t) entry->ie_object;
1085 assert(pset != IPS_NULL);
1086 /* the port set must be active */
1087
1088 names = (mach_port_name_t *) addr;
1089 maxnames = size / sizeof(mach_port_name_t);
1090 actual = 0;
1091
1092 table = space->is_table;
1093 tsize = space->is_table_size;
1094
1095 for (index = 0; index < tsize; index++) {
1096 ipc_entry_t ientry = &table[index];
1097
1098 if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) {
1099 ipc_port_t port =
1100 (ipc_port_t) ientry->ie_object;
1101
1102 mach_port_gst_helper(pset, port,
1103 maxnames, names, &actual);
1104 }
1105 }
1106
1107 for (tentry = ipc_splay_traverse_start(&space->is_tree);
1108 tentry != ITE_NULL;
1109 tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) {
1110 ipc_entry_bits_t bits = tentry->ite_bits;
1111
1112 assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
1113
1114 if (bits & MACH_PORT_TYPE_RECEIVE) {
1115 ipc_port_t port = (ipc_port_t) tentry->ite_object;
1116
1117 mach_port_gst_helper(pset, port, maxnames,
1118 names, &actual);
1119 }
1120 }
1121 ipc_splay_traverse_finish(&space->is_tree);
1122 is_read_unlock(space);
1123
1124 if (actual <= maxnames)
1125 break;
1126
1127 /* didn't have enough memory; allocate more */
1128
1129 kmem_free(ipc_kernel_map, addr, size);
1130 size = round_page(actual * sizeof(mach_port_name_t)) + PAGE_SIZE;
1131 }
1132
1133 if (actual == 0) {
1134 memory = VM_MAP_COPY_NULL;
1135
1136 kmem_free(ipc_kernel_map, addr, size);
1137 } else {
1138 vm_size_t size_used;
1139 vm_size_t vm_size_used;
1140
1141 size_used = actual * sizeof(mach_port_name_t);
1142 vm_size_used = round_page(size_used);
1143
1144 /*
1145 * Make used memory pageable and get it into
1146 * copied-in form. Free any unused memory.
1147 */
1148
1149 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr),
1150 vm_map_round_page(addr + vm_size_used), FALSE);
1151 assert(kr == KERN_SUCCESS);
1152
1153 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
1154 (vm_map_size_t)size_used, TRUE, &memory);
1155 assert(kr == KERN_SUCCESS);
1156
1157 if (vm_size_used != size)
1158 kmem_free(ipc_kernel_map,
1159 addr + vm_size_used, size - vm_size_used);
1160 }
1161
1162 *members = (mach_port_name_t *) memory;
1163 *membersCnt = actual;
1164 return KERN_SUCCESS;
1165 }
1166
1167 /*
1168 * Routine: mach_port_move_member [kernel call]
1169 * Purpose:
1170 * If after is MACH_PORT_NULL, removes member
1171 * from the port set it is in. Otherwise, adds
1172 * member to after, removing it from any set
1173 * it might already be in.
1174 * Conditions:
1175 * Nothing locked.
1176 * Returns:
1177 * KERN_SUCCESS Moved the port.
1178 * KERN_INVALID_TASK The space is null.
1179 * KERN_INVALID_TASK The space is dead.
1180 * KERN_INVALID_NAME Member didn't denote a right.
1181 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1182 * KERN_INVALID_NAME After didn't denote a right.
1183 * KERN_INVALID_RIGHT After didn't denote a port set right.
1184 * KERN_NOT_IN_SET
1185 * After is MACH_PORT_NULL and Member isn't in a port set.
1186 */
1187
1188 kern_return_t
1189 mach_port_move_member(
1190 ipc_space_t space,
1191 mach_port_name_t member,
1192 mach_port_name_t after)
1193 {
1194 ipc_entry_t entry;
1195 ipc_port_t port;
1196 ipc_pset_t nset;
1197 kern_return_t kr;
1198
1199 if (space == IS_NULL)
1200 return KERN_INVALID_TASK;
1201
1202 if (!MACH_PORT_VALID(member))
1203 return KERN_INVALID_RIGHT;
1204
1205 if (after == MACH_PORT_DEAD)
1206 return KERN_INVALID_RIGHT;
1207
1208 kr = ipc_right_lookup_read(space, member, &entry);
1209 if (kr != KERN_SUCCESS)
1210 return kr;
1211 /* space is read-locked and active */
1212
1213 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1214 is_read_unlock(space);
1215 return KERN_INVALID_RIGHT;
1216 }
1217
1218 port = (ipc_port_t) entry->ie_object;
1219 assert(port != IP_NULL);
1220
1221 if (after == MACH_PORT_NULL)
1222 nset = IPS_NULL;
1223 else {
1224 entry = ipc_entry_lookup(space, after);
1225 if (entry == IE_NULL) {
1226 is_read_unlock(space);
1227 return KERN_INVALID_NAME;
1228 }
1229
1230 if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1231 is_read_unlock(space);
1232 return KERN_INVALID_RIGHT;
1233 }
1234
1235 nset = (ipc_pset_t) entry->ie_object;
1236 assert(nset != IPS_NULL);
1237 }
1238 ip_lock(port);
1239 ipc_pset_remove_from_all(port);
1240
1241 if (nset != IPS_NULL) {
1242 ips_lock(nset);
1243 kr = ipc_pset_add(nset, port);
1244 ips_unlock(nset);
1245 }
1246 ip_unlock(port);
1247 is_read_unlock(space);
1248 return kr;
1249 }
1250
1251 /*
1252 * Routine: mach_port_request_notification [kernel call]
1253 * Purpose:
1254 * Requests a notification. The caller supplies
1255 * a send-once right for the notification to use,
1256 * and the call returns the previously registered
1257 * send-once right, if any. Possible types:
1258 *
1259 * MACH_NOTIFY_PORT_DESTROYED
1260 * Requests a port-destroyed notification
1261 * for a receive right. Sync should be zero.
1262 * MACH_NOTIFY_NO_SENDERS
1263 * Requests a no-senders notification for a
1264 * receive right. If there are currently no
1265 * senders, sync is less than or equal to the
1266 * current make-send count, and a send-once right
1267 * is supplied, then an immediate no-senders
1268 * notification is generated.
1269 * MACH_NOTIFY_DEAD_NAME
1270 * Requests a dead-name notification for a send
1271 * or receive right. If the name is already a
1272 * dead name, sync is non-zero, and a send-once
1273 * right is supplied, then an immediate dead-name
1274 * notification is generated.
1275 * Conditions:
1276 * Nothing locked.
1277 * Returns:
1278 * KERN_SUCCESS Requested a notification.
1279 * KERN_INVALID_TASK The space is null.
1280 * KERN_INVALID_TASK The space is dead.
1281 * KERN_INVALID_VALUE Bad id value.
1282 * KERN_INVALID_NAME Name doesn't denote a right.
1283 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1284 * KERN_INVALID_CAPABILITY The notify port is dead.
1285 * MACH_NOTIFY_PORT_DESTROYED:
1286 * KERN_INVALID_VALUE Sync isn't zero.
1287 * MACH_NOTIFY_DEAD_NAME:
1288 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1289 * KERN_INVALID_ARGUMENT Name denotes dead name, but
1290 * sync is zero or notify is IP_NULL.
1291 * KERN_UREFS_OVERFLOW Name denotes dead name, but
1292 * generating immediate notif. would overflow urefs.
1293 */
1294
1295 kern_return_t
1296 mach_port_request_notification(
1297 ipc_space_t space,
1298 mach_port_name_t name,
1299 mach_msg_id_t id,
1300 mach_port_mscount_t sync,
1301 ipc_port_t notify,
1302 ipc_port_t *previousp)
1303 {
1304 kern_return_t kr;
1305
1306 if (space == IS_NULL)
1307 return KERN_INVALID_TASK;
1308
1309 if (notify == IP_DEAD)
1310 return KERN_INVALID_CAPABILITY;
1311
1312 #if NOTYET
1313 /*
1314 * Requesting notifications on RPC ports is an error.
1315 */
1316 {
1317 ipc_port_t port;
1318 ipc_entry_t entry;
1319
1320 kr = ipc_right_lookup_write(space, name, &entry);
1321 if (kr != KERN_SUCCESS)
1322 return kr;
1323
1324 port = (ipc_port_t) entry->ie_object;
1325
1326 if (port->ip_subsystem != NULL) {
1327 is_write_unlock(space);
1328 panic("mach_port_request_notification: on RPC port!!");
1329 return KERN_INVALID_CAPABILITY;
1330 }
1331 is_write_unlock(space);
1332 }
1333 #endif /* NOTYET */
1334
1335
1336 switch (id) {
1337 case MACH_NOTIFY_PORT_DESTROYED: {
1338 ipc_port_t port, previous;
1339
1340 if (sync != 0)
1341 return KERN_INVALID_VALUE;
1342
1343 if (!MACH_PORT_VALID(name))
1344 return KERN_INVALID_RIGHT;
1345
1346 kr = ipc_port_translate_receive(space, name, &port);
1347 if (kr != KERN_SUCCESS)
1348 return kr;
1349 /* port is locked and active */
1350
1351 ipc_port_pdrequest(port, notify, &previous);
1352 /* port is unlocked */
1353
1354 *previousp = previous;
1355 break;
1356 }
1357
1358 case MACH_NOTIFY_NO_SENDERS: {
1359 ipc_port_t port;
1360
1361 if (!MACH_PORT_VALID(name))
1362 return KERN_INVALID_RIGHT;
1363
1364 kr = ipc_port_translate_receive(space, name, &port);
1365 if (kr != KERN_SUCCESS)
1366 return kr;
1367 /* port is locked and active */
1368
1369 ipc_port_nsrequest(port, sync, notify, previousp);
1370 /* port is unlocked */
1371 break;
1372 }
1373
1374 case MACH_NOTIFY_DEAD_NAME:
1375
1376 if (!MACH_PORT_VALID(name)) {
1377 /*
1378 * Already dead.
1379 * Should do immediate delivery check -
1380 * will do that in the near future.
1381 */
1382 return KERN_INVALID_ARGUMENT;
1383 }
1384
1385 kr = ipc_right_dnrequest(space, name, sync != 0,
1386 notify, previousp);
1387 if (kr != KERN_SUCCESS)
1388 return kr;
1389 break;
1390
1391 default:
1392 return KERN_INVALID_VALUE;
1393 }
1394
1395 return KERN_SUCCESS;
1396 }
1397
1398 /*
1399 * Routine: mach_port_insert_right [kernel call]
1400 * Purpose:
1401 * Inserts a right into a space, as if the space
1402 * voluntarily received the right in a message,
1403 * except that the right gets the specified name.
1404 * Conditions:
1405 * Nothing locked.
1406 * Returns:
1407 * KERN_SUCCESS Inserted the right.
1408 * KERN_INVALID_TASK The space is null.
1409 * KERN_INVALID_TASK The space is dead.
1410 * KERN_INVALID_VALUE The name isn't a legal name.
1411 * KERN_NAME_EXISTS The name already denotes a right.
1412 * KERN_INVALID_VALUE Message doesn't carry a port right.
1413 * KERN_INVALID_CAPABILITY Port is null or dead.
1414 * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1415 * KERN_RIGHT_EXISTS Space has rights under another name.
1416 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1417 */
1418
1419 kern_return_t
1420 mach_port_insert_right(
1421 ipc_space_t space,
1422 mach_port_name_t name,
1423 ipc_port_t poly,
1424 mach_msg_type_name_t polyPoly)
1425 {
1426 if (space == IS_NULL)
1427 return KERN_INVALID_TASK;
1428
1429 if (!MACH_PORT_VALID(name) ||
1430 !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
1431 return KERN_INVALID_VALUE;
1432
1433 if (!IO_VALID((ipc_object_t) poly))
1434 return KERN_INVALID_CAPABILITY;
1435
1436 return ipc_object_copyout_name(space, (ipc_object_t) poly,
1437 polyPoly, FALSE, name);
1438 }
1439
1440 /*
1441 * Routine: mach_port_extract_right [kernel call]
1442 * Purpose:
1443 * Extracts a right from a space, as if the space
1444 * voluntarily sent the right to the caller.
1445 * Conditions:
1446 * Nothing locked.
1447 * Returns:
1448 * KERN_SUCCESS Extracted the right.
1449 * KERN_INVALID_TASK The space is null.
1450 * KERN_INVALID_TASK The space is dead.
1451 * KERN_INVALID_VALUE Requested type isn't a port right.
1452 * KERN_INVALID_NAME Name doesn't denote a right.
1453 * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1454 */
1455
1456 kern_return_t
1457 mach_port_extract_right(
1458 ipc_space_t space,
1459 mach_port_name_t name,
1460 mach_msg_type_name_t msgt_name,
1461 ipc_port_t *poly,
1462 mach_msg_type_name_t *polyPoly)
1463 {
1464 kern_return_t kr;
1465
1466 if (space == IS_NULL)
1467 return KERN_INVALID_TASK;
1468
1469 if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
1470 return KERN_INVALID_VALUE;
1471
1472 if (!MACH_PORT_VALID(name)) {
1473 /*
1474 * really should copy out a dead name, if it is a send or
1475 * send-once right being copied, but instead return an
1476 * error for now.
1477 */
1478 return KERN_INVALID_RIGHT;
1479 }
1480
1481 kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
1482
1483 if (kr == KERN_SUCCESS)
1484 *polyPoly = ipc_object_copyin_type(msgt_name);
1485 return kr;
1486 }
1487
1488
1489 kern_return_t
1490 mach_port_get_attributes(
1491 ipc_space_t space,
1492 mach_port_name_t name,
1493 int flavor,
1494 mach_port_info_t info,
1495 mach_msg_type_number_t *count)
1496 {
1497 ipc_port_t port;
1498 kern_return_t kr;
1499
1500 if (space == IS_NULL)
1501 return KERN_INVALID_TASK;
1502
1503 switch (flavor) {
1504 case MACH_PORT_LIMITS_INFO: {
1505 mach_port_limits_t *lp = (mach_port_limits_t *)info;
1506
1507 if (*count < MACH_PORT_LIMITS_INFO_COUNT)
1508 return KERN_FAILURE;
1509
1510 if (!MACH_PORT_VALID(name)) {
1511 *count = 0;
1512 break;
1513 }
1514
1515 kr = ipc_port_translate_receive(space, name, &port);
1516 if (kr != KERN_SUCCESS)
1517 return kr;
1518 /* port is locked and active */
1519
1520 lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1521 *count = MACH_PORT_LIMITS_INFO_COUNT;
1522 ip_unlock(port);
1523 break;
1524 }
1525
1526 case MACH_PORT_RECEIVE_STATUS: {
1527 mach_port_status_t *statusp = (mach_port_status_t *)info;
1528 spl_t s;
1529
1530 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
1531 return KERN_FAILURE;
1532
1533 if (!MACH_PORT_VALID(name))
1534 return KERN_INVALID_RIGHT;
1535
1536 kr = ipc_port_translate_receive(space, name, &port);
1537 if (kr != KERN_SUCCESS)
1538 return kr;
1539 /* port is locked and active */
1540
1541 statusp->mps_pset = port->ip_pset_count;
1542
1543 s = splsched();
1544 imq_lock(&port->ip_messages);
1545 statusp->mps_seqno = port->ip_messages.imq_seqno;
1546 statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1547 statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1548 imq_unlock(&port->ip_messages);
1549 splx(s);
1550
1551 statusp->mps_mscount = port->ip_mscount;
1552 statusp->mps_sorights = port->ip_sorights;
1553 statusp->mps_srights = port->ip_srights > 0;
1554 statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1555 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1556 statusp->mps_flags = 0;
1557
1558 *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1559 ip_unlock(port);
1560 break;
1561 }
1562
1563 case MACH_PORT_DNREQUESTS_SIZE: {
1564 ipc_port_request_t table;
1565
1566 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1567 return KERN_FAILURE;
1568
1569 if (!MACH_PORT_VALID(name)) {
1570 *(int *)info = 0;
1571 break;
1572 }
1573
1574 kr = ipc_port_translate_receive(space, name, &port);
1575 if (kr != KERN_SUCCESS)
1576 return kr;
1577 /* port is locked and active */
1578
1579 table = port->ip_dnrequests;
1580 if (table == IPR_NULL)
1581 *(int *)info = 0;
1582 else
1583 *(int *)info = table->ipr_size->its_size;
1584 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1585 ip_unlock(port);
1586 break;
1587 }
1588
1589 default:
1590 return KERN_INVALID_ARGUMENT;
1591 /*NOTREACHED*/
1592 }
1593
1594 return KERN_SUCCESS;
1595 }
1596
1597 kern_return_t
1598 mach_port_set_attributes(
1599 ipc_space_t space,
1600 mach_port_name_t name,
1601 int flavor,
1602 mach_port_info_t info,
1603 mach_msg_type_number_t count)
1604 {
1605 ipc_port_t port;
1606 kern_return_t kr;
1607
1608 if (space == IS_NULL)
1609 return KERN_INVALID_TASK;
1610
1611 switch (flavor) {
1612
1613 case MACH_PORT_LIMITS_INFO: {
1614 mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1615
1616 if (count < MACH_PORT_LIMITS_INFO_COUNT)
1617 return KERN_FAILURE;
1618
1619 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
1620 return KERN_INVALID_VALUE;
1621
1622 if (!MACH_PORT_VALID(name))
1623 return KERN_INVALID_RIGHT;
1624
1625 kr = ipc_port_translate_receive(space, name, &port);
1626 if (kr != KERN_SUCCESS)
1627 return kr;
1628 /* port is locked and active */
1629
1630 ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
1631 ip_unlock(port);
1632 break;
1633 }
1634 case MACH_PORT_DNREQUESTS_SIZE: {
1635 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1636 return KERN_FAILURE;
1637
1638 if (!MACH_PORT_VALID(name))
1639 return KERN_INVALID_RIGHT;
1640
1641 kr = ipc_port_translate_receive(space, name, &port);
1642 if (kr != KERN_SUCCESS)
1643 return kr;
1644 /* port is locked and active */
1645
1646 kr = ipc_port_dngrow(port, *(int *)info);
1647 if (kr != KERN_SUCCESS)
1648 return kr;
1649 break;
1650 }
1651 default:
1652 return KERN_INVALID_ARGUMENT;
1653 /*NOTREACHED*/
1654 }
1655 return KERN_SUCCESS;
1656 }
1657
1658 /*
1659 * Routine: mach_port_insert_member [kernel call]
1660 * Purpose:
1661 * Add the receive right, specified by name, to
1662 * a portset.
1663 * The port cannot already be a member of the set.
1664 * Conditions:
1665 * Nothing locked.
1666 * Returns:
1667 * KERN_SUCCESS Moved the port.
1668 * KERN_INVALID_TASK The space is null.
1669 * KERN_INVALID_TASK The space is dead.
1670 * KERN_INVALID_NAME name didn't denote a right.
1671 * KERN_INVALID_RIGHT name didn't denote a receive right.
1672 * KERN_INVALID_NAME pset_name didn't denote a right.
1673 * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
1674 * KERN_ALREADY_IN_SET name was already a member of pset.
1675 */
1676
1677 kern_return_t
1678 mach_port_insert_member(
1679 ipc_space_t space,
1680 mach_port_name_t name,
1681 mach_port_name_t psname)
1682 {
1683 ipc_object_t obj;
1684 ipc_object_t psobj;
1685 kern_return_t kr;
1686
1687 if (space == IS_NULL)
1688 return KERN_INVALID_TASK;
1689
1690 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1691 return KERN_INVALID_RIGHT;
1692
1693 kr = ipc_object_translate_two(space,
1694 name, MACH_PORT_RIGHT_RECEIVE, &obj,
1695 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1696 if (kr != KERN_SUCCESS)
1697 return kr;
1698
1699 /* obj and psobj are locked (and were locked in that order) */
1700 assert(psobj != IO_NULL);
1701 assert(obj != IO_NULL);
1702
1703 kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj);
1704 io_unlock(psobj);
1705 io_unlock(obj);
1706 return kr;
1707 }
1708
1709 /*
1710 * Routine: mach_port_extract_member [kernel call]
1711 * Purpose:
1712 * Remove a port from one portset that it is a member of.
1713 * Conditions:
1714 * Nothing locked.
1715 * Returns:
1716 * KERN_SUCCESS Moved the port.
1717 * KERN_INVALID_TASK The space is null.
1718 * KERN_INVALID_TASK The space is dead.
1719 * KERN_INVALID_NAME Member didn't denote a right.
1720 * KERN_INVALID_RIGHT Member didn't denote a receive right.
1721 * KERN_INVALID_NAME After didn't denote a right.
1722 * KERN_INVALID_RIGHT After didn't denote a port set right.
1723 * KERN_NOT_IN_SET
1724 * After is MACH_PORT_NULL and Member isn't in a port set.
1725 */
1726
1727 kern_return_t
1728 mach_port_extract_member(
1729 ipc_space_t space,
1730 mach_port_name_t name,
1731 mach_port_name_t psname)
1732 {
1733 ipc_object_t psobj;
1734 ipc_object_t obj;
1735 kern_return_t kr;
1736
1737 if (space == IS_NULL)
1738 return KERN_INVALID_TASK;
1739
1740 if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname))
1741 return KERN_INVALID_RIGHT;
1742
1743 kr = ipc_object_translate_two(space,
1744 name, MACH_PORT_RIGHT_RECEIVE, &obj,
1745 psname, MACH_PORT_RIGHT_PORT_SET, &psobj);
1746 if (kr != KERN_SUCCESS)
1747 return kr;
1748
1749 /* obj and psobj are both locked (and were locked in that order) */
1750 assert(psobj != IO_NULL);
1751 assert(obj != IO_NULL);
1752
1753 kr = ipc_pset_remove((ipc_pset_t)psobj, (ipc_port_t)obj);
1754 io_unlock(psobj);
1755 io_unlock(obj);
1756 return kr;
1757 }
1758
1759 /*
1760 * task_set_port_space:
1761 *
1762 * Set port name space of task to specified size.
1763 */
1764 kern_return_t
1765 task_set_port_space(
1766 ipc_space_t space,
1767 int table_entries)
1768 {
1769 kern_return_t kr;
1770
1771 is_write_lock(space);
1772 kr = ipc_entry_grow_table(space, table_entries);
1773 if (kr == KERN_SUCCESS)
1774 is_write_unlock(space);
1775 return kr;
1776 }
1777