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