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