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