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