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