1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990 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 [email protected]
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_debug.c
60 * Author: Rich Draves
61 * Date: 1989
62 *
63 * Exported IPC debug calls.
64 */
65 #include <mach/vm_param.h>
66 #include <mach/kern_return.h>
67 #include <mach/machine/vm_types.h>
68 #include <mach/mach_host_server.h>
69 #include <mach/mach_port_server.h>
70 #include <mach_debug/ipc_info.h>
71 #include <mach_debug/hash_info.h>
72 #include <kern/task_ident.h>
73
74 #include <kern/host.h>
75 #include <kern/misc_protos.h>
76 #include <vm/vm_map_xnu.h>
77 #include <vm/vm_memory_entry_xnu.h>
78 #include <vm/vm_kern_xnu.h>
79 #include <ipc/port.h>
80 #include <ipc/ipc_types.h>
81 #include <ipc/ipc_space.h>
82 #include <ipc/ipc_port.h>
83 #include <ipc/ipc_hash.h>
84 #include <ipc/ipc_right.h>
85
86 #include <security/mac_mach_internal.h>
87 #include <device/device_types.h>
88
89 /*
90 * Routine: mach_port_get_srights [kernel call]
91 * Purpose:
92 * Retrieve the number of extant send rights
93 * that a receive right has.
94 * Conditions:
95 * Nothing locked.
96 * Returns:
97 * KERN_SUCCESS Retrieved number of send rights.
98 * KERN_INVALID_TASK The space is null.
99 * KERN_INVALID_TASK The space is dead.
100 * KERN_INVALID_NAME The name doesn't denote a right.
101 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
102 */
103
104 kern_return_t
mach_port_get_srights(ipc_space_t space,mach_port_name_t name,mach_port_rights_t * srightsp)105 mach_port_get_srights(
106 ipc_space_t space,
107 mach_port_name_t name,
108 mach_port_rights_t *srightsp)
109 {
110 ipc_port_t port;
111 kern_return_t kr;
112 mach_port_rights_t srights;
113
114 if (space == IS_NULL) {
115 return KERN_INVALID_TASK;
116 }
117
118 kr = ipc_port_translate_receive(space, name, &port);
119 if (kr != KERN_SUCCESS) {
120 return kr;
121 }
122 /* port is locked and active */
123
124 srights = port->ip_srights;
125 ip_mq_unlock(port);
126
127 *srightsp = srights;
128 return KERN_SUCCESS;
129 }
130
131
132 /*
133 * Routine: mach_port_space_info
134 * Purpose:
135 * Returns information about an IPC space.
136 * Conditions:
137 * Nothing locked. Obeys CountInOut protocol.
138 * Returns:
139 * KERN_SUCCESS Returned information.
140 * KERN_INVALID_TASK The space is null.
141 * KERN_INVALID_TASK The space is dead.
142 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
143 */
144
145 static kern_return_t
mach_port_space_info(ipc_space_t space,ipc_info_space_t * infop,ipc_info_name_array_t * tablep,mach_msg_type_number_t * tableCntp,__unused ipc_info_tree_name_array_t * treep,__unused mach_msg_type_number_t * treeCntp)146 mach_port_space_info(
147 ipc_space_t space,
148 ipc_info_space_t *infop,
149 ipc_info_name_array_t *tablep,
150 mach_msg_type_number_t *tableCntp,
151 __unused ipc_info_tree_name_array_t *treep,
152 __unused mach_msg_type_number_t *treeCntp)
153 {
154 const uint32_t BATCH_SIZE = 4 << 10;
155 ipc_info_name_t *table_info;
156 vm_offset_t table_addr = 0;
157 vm_size_t table_size, table_size_needed;
158 ipc_entry_table_t table;
159 ipc_entry_num_t tsize;
160 kern_return_t kr;
161 vm_map_copy_t copy;
162
163 if (space == IS_NULL) {
164 return KERN_INVALID_TASK;
165 }
166
167 /* start with in-line memory */
168 table_size = 0;
169
170 ipc_object_t *port_pointers = NULL;
171 ipc_entry_num_t pptrsize = 0;
172
173 is_read_lock(space);
174
175 allocate_loop:
176 for (;;) {
177 if (!is_active(space)) {
178 is_read_unlock(space);
179 if (table_size != 0) {
180 kmem_free(ipc_kernel_map,
181 table_addr, table_size);
182 kfree_type(ipc_object_t, pptrsize, port_pointers);
183 port_pointers = NULL;
184 }
185 return KERN_INVALID_TASK;
186 }
187
188 table = is_active_table(space);
189 tsize = ipc_entry_table_count(table);
190
191 table_size_needed =
192 vm_map_round_page(tsize * sizeof(ipc_info_name_t),
193 VM_MAP_PAGE_MASK(ipc_kernel_map));
194
195 if ((table_size_needed <= table_size) &&
196 (pptrsize == tsize)) {
197 break;
198 }
199
200 is_read_unlock(space);
201
202 if (table_size != 0) {
203 kmem_free(ipc_kernel_map, table_addr, table_size);
204 kfree_type(ipc_object_t, pptrsize, port_pointers);
205 }
206 kr = kmem_alloc(ipc_kernel_map, &table_addr, table_size_needed,
207 KMA_DATA, VM_KERN_MEMORY_IPC);
208 if (kr != KERN_SUCCESS) {
209 return KERN_RESOURCE_SHORTAGE;
210 }
211
212 port_pointers = kalloc_type(ipc_object_t, tsize, Z_WAITOK | Z_ZERO);
213 if (port_pointers == NULL) {
214 kmem_free(ipc_kernel_map, table_addr, table_size);
215 return KERN_RESOURCE_SHORTAGE;
216 }
217
218 table_size = table_size_needed;
219 pptrsize = tsize;
220
221 is_read_lock(space);
222 }
223 /* space is read-locked and active; we have enough wired memory */
224
225 /* walk the table for this space */
226 table_info = (ipc_info_name_array_t)table_addr;
227 for (mach_port_index_t index = 0; index < tsize; index++) {
228 ipc_info_name_t *iin = &table_info[index];
229 ipc_entry_t entry = ipc_entry_table_get_nocheck(table, index);
230 ipc_entry_bits_t bits;
231
232 if (index == 0) {
233 bits = IE_BITS_GEN_MASK;
234 } else {
235 bits = entry->ie_bits;
236 }
237 iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
238 iin->iin_collision = 0;
239 iin->iin_type = IE_BITS_TYPE(bits);
240 if ((bits & MACH_PORT_TYPE_PORT_RIGHTS) != MACH_PORT_TYPE_NONE &&
241 entry->ie_request != IE_REQ_NONE) {
242 ipc_port_t port = entry->ie_port;
243
244 assert(IP_VALID(port));
245 ip_mq_lock(port);
246 iin->iin_type |= ipc_port_request_type(port, iin->iin_name, entry->ie_request);
247 ip_mq_unlock(port);
248 }
249
250 iin->iin_urefs = IE_BITS_UREFS(bits);
251 port_pointers[index] = entry->ie_object;
252 iin->iin_next = entry->ie_next;
253 iin->iin_hash = entry->ie_index;
254
255 if (index + 1 < tsize && (index + 1) % BATCH_SIZE == 0) {
256 /*
257 * Give the system some breathing room,
258 * and check if anything changed,
259 * if yes start over.
260 */
261 is_read_unlock(space);
262 is_read_lock(space);
263 if (!is_active(space)) {
264 goto allocate_loop;
265 }
266 table = is_active_table(space);
267 if (tsize < ipc_entry_table_count(table)) {
268 goto allocate_loop;
269 }
270 tsize = ipc_entry_table_count(table);
271 }
272 }
273
274 /* get the overall space info */
275 infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
276 infop->iis_table_size = tsize;
277
278 is_read_unlock(space);
279
280 /* prepare the table out-of-line data for return */
281 if (table_size > 0) {
282 vm_map_size_t used = tsize * sizeof(ipc_info_name_t);
283 vm_map_size_t keep = vm_map_round_page(used,
284 VM_MAP_PAGE_MASK(ipc_kernel_map));
285
286 assert(pptrsize >= tsize);
287 for (int index = 0; index < tsize; index++) {
288 ipc_info_name_t *iin = &table_info[index];
289 iin->iin_object = (natural_t)VM_KERNEL_ADDRHASH((uintptr_t)port_pointers[index]);
290 port_pointers[index] = MACH_PORT_NULL;
291 }
292 kfree_type(ipc_object_t, pptrsize, port_pointers);
293
294 if (keep < table_size) {
295 kmem_free(ipc_kernel_map, table_addr + keep,
296 table_size - keep);
297 table_size = keep;
298 }
299 if (table_size > used) {
300 bzero(&table_info[infop->iis_table_size],
301 table_size - used);
302 }
303
304 kr = vm_map_unwire(ipc_kernel_map, table_addr,
305 table_addr + table_size, FALSE);
306 assert(kr == KERN_SUCCESS);
307 kr = vm_map_copyin(ipc_kernel_map, table_addr, used, TRUE, ©);
308 assert(kr == KERN_SUCCESS);
309 *tablep = (ipc_info_name_t *)copy;
310 *tableCntp = infop->iis_table_size;
311 } else {
312 *tablep = (ipc_info_name_t *)0;
313 *tableCntp = 0;
314 }
315
316 /* splay tree is obsolete, no work to do... */
317 *treep = (ipc_info_tree_name_t *)0;
318 *treeCntp = 0;
319 return KERN_SUCCESS;
320 }
321
322 kern_return_t
mach_port_space_info_from_user(mach_port_t port,ipc_info_space_t * infop,ipc_info_name_array_t * tablep,mach_msg_type_number_t * tableCntp,__unused ipc_info_tree_name_array_t * treep,__unused mach_msg_type_number_t * treeCntp)323 mach_port_space_info_from_user(
324 mach_port_t port,
325 ipc_info_space_t *infop,
326 ipc_info_name_array_t *tablep,
327 mach_msg_type_number_t *tableCntp,
328 __unused ipc_info_tree_name_array_t *treep,
329 __unused mach_msg_type_number_t *treeCntp)
330 {
331 kern_return_t kr;
332
333 ipc_space_t space = convert_port_to_space_read_no_eval(port);
334
335 if (space == IPC_SPACE_NULL) {
336 return KERN_INVALID_ARGUMENT;
337 }
338
339 kr = mach_port_space_info(space, infop, tablep, tableCntp, treep, treeCntp);
340
341 ipc_space_release(space);
342 return kr;
343 }
344
345 /*
346 * Routine: mach_port_space_basic_info
347 * Purpose:
348 * Returns basic information about an IPC space.
349 * Conditions:
350 * Nothing locked.
351 * Returns:
352 * KERN_SUCCESS Returned information.
353 * KERN_FAILURE The call is not supported.
354 * KERN_INVALID_TASK The space is dead.
355 */
356
357 kern_return_t
mach_port_space_basic_info(ipc_space_t space,ipc_info_space_basic_t * infop)358 mach_port_space_basic_info(
359 ipc_space_t space,
360 ipc_info_space_basic_t *infop)
361 {
362 ipc_entry_num_t tsize;
363
364 if (space == IS_NULL) {
365 return KERN_INVALID_TASK;
366 }
367
368 is_read_lock(space);
369 if (!is_active(space)) {
370 is_read_unlock(space);
371 return KERN_INVALID_TASK;
372 }
373
374 tsize = ipc_entry_table_count(is_active_table(space));
375
376 /* get the basic space info */
377 infop->iisb_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
378 infop->iisb_table_size = tsize;
379 infop->iisb_table_inuse = tsize - space->is_table_free - 1;
380 infop->iisb_reserved[0] = 0;
381 infop->iisb_reserved[1] = 0;
382
383 is_read_unlock(space);
384
385 return KERN_SUCCESS;
386 }
387
388 /*
389 * Routine: mach_port_dnrequest_info
390 * Purpose:
391 * Returns information about the dead-name requests
392 * registered with the named receive right.
393 * Conditions:
394 * Nothing locked.
395 * Returns:
396 * KERN_SUCCESS Retrieved information.
397 * KERN_INVALID_TASK The space is null.
398 * KERN_INVALID_TASK The space is dead.
399 * KERN_INVALID_NAME The name doesn't denote a right.
400 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
401 */
402
403 kern_return_t
mach_port_dnrequest_info(ipc_space_t space,mach_port_name_t name,unsigned int * totalp,unsigned int * usedp)404 mach_port_dnrequest_info(
405 ipc_space_t space,
406 mach_port_name_t name,
407 unsigned int *totalp,
408 unsigned int *usedp)
409 {
410 ipc_port_request_table_t requests;
411 unsigned int total = 0, used = 0;
412 ipc_port_t port;
413 kern_return_t kr;
414
415 if (space == IS_NULL) {
416 return KERN_INVALID_TASK;
417 }
418
419 kr = ipc_port_translate_receive(space, name, &port);
420 if (kr != KERN_SUCCESS) {
421 return kr;
422 }
423 /* port is locked and active */
424
425 requests = port->ip_requests;
426 if (requests) {
427 ipc_port_request_t ipr = ipc_port_request_table_base(requests);
428
429 while ((ipr = ipc_port_request_table_next_elem(requests, ipr))) {
430 if (ipr->ipr_soright != IP_NULL &&
431 ipr->ipr_name != IPR_HOST_NOTIFY) {
432 used++;
433 }
434 }
435
436 total = ipc_port_request_table_count(requests);
437 }
438 ip_mq_unlock(port);
439
440 *totalp = total;
441 *usedp = used;
442 return KERN_SUCCESS;
443 }
444
445 static ipc_info_object_type_t
mach_port_kobject_type(ipc_port_t port)446 mach_port_kobject_type(ipc_port_t port)
447 {
448 #define MAKE_CASE(name) \
449 case IKOT_ ## name: return IPC_OTYPE_ ## name
450
451 switch (ip_type(port)) {
452 /* thread ports */
453 MAKE_CASE(THREAD_CONTROL);
454 MAKE_CASE(THREAD_READ);
455 MAKE_CASE(THREAD_INSPECT);
456
457 /* task ports */
458 MAKE_CASE(TASK_CONTROL);
459 MAKE_CASE(TASK_READ);
460 MAKE_CASE(TASK_INSPECT);
461 MAKE_CASE(TASK_NAME);
462
463 MAKE_CASE(TASK_RESUME);
464 MAKE_CASE(TASK_ID_TOKEN);
465 MAKE_CASE(TASK_FATAL);
466
467 /* host services, upcalls, security */
468 MAKE_CASE(HOST);
469 MAKE_CASE(HOST_PRIV);
470 MAKE_CASE(CLOCK);
471 MAKE_CASE(PROCESSOR);
472 MAKE_CASE(PROCESSOR_SET);
473 MAKE_CASE(PROCESSOR_SET_NAME);
474
475 /* common userspace used ports */
476 MAKE_CASE(EVENTLINK);
477 MAKE_CASE(FILEPORT);
478 MAKE_CASE(SEMAPHORE);
479 MAKE_CASE(VOUCHER);
480 MAKE_CASE(WORK_INTERVAL);
481
482 /* VM ports */
483 MAKE_CASE(MEMORY_OBJECT);
484 MAKE_CASE(NAMED_ENTRY);
485
486 /* IOKit & exclaves ports */
487 MAKE_CASE(MAIN_DEVICE);
488 MAKE_CASE(IOKIT_IDENT);
489 MAKE_CASE(IOKIT_CONNECT);
490 MAKE_CASE(IOKIT_OBJECT);
491 MAKE_CASE(UEXT_OBJECT);
492 MAKE_CASE(EXCLAVES_RESOURCE);
493
494 /* misc. */
495 MAKE_CASE(ARCADE_REG);
496 MAKE_CASE(AU_SESSIONPORT);
497 MAKE_CASE(HYPERVISOR);
498 MAKE_CASE(KCDATA);
499 MAKE_CASE(UND_REPLY);
500 MAKE_CASE(UX_HANDLER);
501
502 case IOT_TIMER_PORT:
503 return IPC_OTYPE_TIMER;
504
505 default:
506 return IPC_OTYPE_UNKNOWN;
507 }
508 #undef MAKE_CASE
509 }
510
511 /*
512 * Routine: mach_port_kobject [kernel call]
513 * Purpose:
514 * Retrieve the type and address of the kernel object
515 * represented by a send or receive right. Returns
516 * the kernel address in a mach_vm_address_t to
517 * mask potential differences in kernel address space
518 * size.
519 * Conditions:
520 * Nothing locked.
521 * Returns:
522 * KERN_SUCCESS Retrieved kernel object info.
523 * KERN_INVALID_TASK The space is null.
524 * KERN_INVALID_TASK The space is dead.
525 * KERN_INVALID_NAME The name doesn't denote a right.
526 * KERN_INVALID_RIGHT Name doesn't denote
527 * send or receive rights.
528 */
529
530 static kern_return_t
mach_port_kobject_description(ipc_space_t space,mach_port_name_t name,ipc_info_object_type_t * typep,mach_vm_address_t * addrp,kobject_description_t desc)531 mach_port_kobject_description(
532 ipc_space_t space,
533 mach_port_name_t name,
534 ipc_info_object_type_t *typep,
535 mach_vm_address_t *addrp,
536 kobject_description_t desc)
537 {
538 ipc_entry_bits_t bits;
539 ipc_object_t ipc_object;
540 kern_return_t kr;
541 mach_vm_address_t kaddr = 0;
542
543 if (space == IS_NULL) {
544 return KERN_INVALID_TASK;
545 }
546
547 kr = ipc_right_lookup_read(space, name, &bits, &ipc_object);
548 if (kr != KERN_SUCCESS) {
549 return kr;
550 }
551 /* object is locked and active */
552
553 if ((bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) {
554 io_unlock(ipc_object);
555 return KERN_INVALID_RIGHT;
556 }
557
558 ipc_port_t port = ip_object_to_port(ipc_object);
559 *typep = mach_port_kobject_type(port);
560 if (ip_is_kobject(port)) {
561 kaddr = (mach_vm_address_t)ipc_kobject_get_raw(port, ip_type(port));
562 }
563 *addrp = 0;
564
565 if (desc) {
566 *desc = '\0';
567 switch (ip_type(port)) {
568 case IKOT_IOKIT_OBJECT:
569 case IKOT_IOKIT_CONNECT:
570 case IKOT_IOKIT_IDENT:
571 case IKOT_UEXT_OBJECT:
572 {
573 io_kobject_t io_kobject = (io_kobject_t)kaddr;
574 if (io_kobject) {
575 iokit_kobject_retain(io_kobject);
576 io_unlock(ipc_object);
577
578 // IKOT_IOKIT_OBJECT since iokit_remove_reference() follows
579 io_object_t io_object = iokit_copy_object_for_consumed_kobject(io_kobject);
580 io_kobject = NULL;
581 if (io_object) {
582 iokit_port_object_description(io_object, desc);
583 iokit_remove_reference(io_object);
584 io_object = NULL;
585 }
586 goto unlocked;
587 }
588 break;
589 }
590 case IKOT_TASK_ID_TOKEN:
591 {
592 task_id_token_t token;
593 token = (task_id_token_t)ipc_kobject_get_stable(port, IKOT_TASK_ID_TOKEN);
594 snprintf(desc, KOBJECT_DESCRIPTION_LENGTH, "%d,%llu,%d", token->ident.p_pid, token->ident.p_uniqueid, token->ident.p_idversion);
595 break;
596 }
597 case IKOT_NAMED_ENTRY:
598 {
599 vm_named_entry_t named_entry = (vm_named_entry_t)ipc_kobject_get_stable(port, IKOT_NAMED_ENTRY);
600 mach_memory_entry_describe(named_entry, desc);
601 break;
602 }
603 default:
604 break;
605 }
606 }
607
608 io_unlock(ipc_object);
609
610 unlocked:
611 #if (DEVELOPMENT || DEBUG)
612 *addrp = VM_KERNEL_ADDRHASH(kaddr);
613 #endif
614 return KERN_SUCCESS;
615 }
616
617 kern_return_t
mach_port_kobject_description_from_user(mach_port_t port,mach_port_name_t name,ipc_info_object_type_t * typep,mach_vm_address_t * addrp,kobject_description_t desc)618 mach_port_kobject_description_from_user(
619 mach_port_t port,
620 mach_port_name_t name,
621 ipc_info_object_type_t *typep,
622 mach_vm_address_t *addrp,
623 kobject_description_t desc)
624 {
625 kern_return_t kr;
626
627 ipc_space_t space = convert_port_to_space_read_no_eval(port);
628
629 if (space == IPC_SPACE_NULL) {
630 return KERN_INVALID_ARGUMENT;
631 }
632
633 kr = mach_port_kobject_description(space, name, typep, addrp, desc);
634
635 ipc_space_release(space);
636 return kr;
637 }
638
639 kern_return_t
mach_port_kobject_from_user(mach_port_t port,mach_port_name_t name,ipc_info_object_type_t * typep,mach_vm_address_t * addrp)640 mach_port_kobject_from_user(
641 mach_port_t port,
642 mach_port_name_t name,
643 ipc_info_object_type_t *typep,
644 mach_vm_address_t *addrp)
645 {
646 return mach_port_kobject_description_from_user(port, name, typep, addrp, NULL);
647 }
648
649 #if (DEVELOPMENT || DEBUG)
650 kern_return_t
mach_port_special_reply_port_reset_link(ipc_space_t space,mach_port_name_t name,boolean_t * srp_lost_link)651 mach_port_special_reply_port_reset_link(
652 ipc_space_t space,
653 mach_port_name_t name,
654 boolean_t *srp_lost_link)
655 {
656 ipc_port_t port;
657 kern_return_t kr;
658 thread_t thread = current_thread();
659
660 if (space != current_space()) {
661 return KERN_INVALID_TASK;
662 }
663
664 if (!MACH_PORT_VALID(name)) {
665 return KERN_INVALID_NAME;
666 }
667
668 if (!IP_VALID(thread->ith_special_reply_port)) {
669 return KERN_INVALID_VALUE;
670 }
671
672 kr = ipc_port_translate_receive(space, name, &port);
673 if (kr != KERN_SUCCESS) {
674 return kr;
675 }
676
677 if (thread->ith_special_reply_port != port) {
678 ip_mq_unlock(port);
679 return KERN_INVALID_ARGUMENT;
680 }
681
682 *srp_lost_link = (port->ip_srp_lost_link == 1)? TRUE : FALSE;
683 port->ip_srp_lost_link = 0;
684
685 ip_mq_unlock(port);
686 return KERN_SUCCESS;
687 }
688 #else
689 kern_return_t
mach_port_special_reply_port_reset_link(__unused ipc_space_t space,__unused mach_port_name_t name,__unused boolean_t * srp_lost_link)690 mach_port_special_reply_port_reset_link(
691 __unused ipc_space_t space,
692 __unused mach_port_name_t name,
693 __unused boolean_t *srp_lost_link)
694 {
695 return KERN_NOT_SUPPORTED;
696 }
697 #endif
698