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