]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_kmsg.c
xnu-792.6.61.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_kmsg.c
CommitLineData
1c79356b 1/*
3a60a9f5 2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
43866e37 11 *
37839358
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
25/*
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50/*
51 */
52/*
53 * File: ipc/ipc_kmsg.c
54 * Author: Rich Draves
55 * Date: 1989
56 *
57 * Operations on kernel messages.
58 */
59
1c79356b
A
60#include <norma_vm.h>
61
91447636 62#include <mach/mach_types.h>
1c79356b
A
63#include <mach/boolean.h>
64#include <mach/kern_return.h>
65#include <mach/message.h>
66#include <mach/port.h>
91447636
A
67#include <mach/vm_map.h>
68#include <mach/mach_vm.h>
1c79356b 69#include <mach/vm_statistics.h>
91447636
A
70
71#include <kern/kern_types.h>
1c79356b 72#include <kern/assert.h>
91447636 73#include <kern/ipc_kobject.h>
1c79356b 74#include <kern/kalloc.h>
91447636
A
75#include <kern/zalloc.h>
76#include <kern/processor.h>
1c79356b
A
77#include <kern/thread.h>
78#include <kern/sched_prim.h>
79#include <kern/spl.h>
80#include <kern/misc_protos.h>
81#include <kern/counters.h>
91447636
A
82#include <kern/cpu_data.h>
83
1c79356b
A
84#include <vm/vm_map.h>
85#include <vm/vm_object.h>
86#include <vm/vm_kern.h>
91447636 87
1c79356b 88#include <ipc/port.h>
91447636 89#include <ipc/ipc_types.h>
1c79356b
A
90#include <ipc/ipc_entry.h>
91#include <ipc/ipc_kmsg.h>
92#include <ipc/ipc_notify.h>
93#include <ipc/ipc_object.h>
94#include <ipc/ipc_space.h>
95#include <ipc/ipc_port.h>
96#include <ipc/ipc_right.h>
97#include <ipc/ipc_hash.h>
98#include <ipc/ipc_table.h>
99
100#include <string.h>
101
55e303ae
A
102#ifdef ppc
103#include <ppc/Firmware.h>
104#include <ppc/low_trace.h>
105#endif
106
107
1c79356b
A
108extern vm_map_t ipc_kernel_copy_map;
109extern vm_size_t ipc_kmsg_max_vm_space;
110extern vm_size_t msg_ool_size_small;
111
112#define MSG_OOL_SIZE_SMALL msg_ool_size_small
113
91447636
A
114#if defined(__LP64__)
115#define MAP_SIZE_DIFFERS(map) (map->max_offset < MACH_VM_MAX_ADDRESS)
116#define OTHER_OOL_DESCRIPTOR mach_msg_ool_descriptor32_t
117#define OTHER_OOL_PORTS_DESCRIPTOR mach_msg_ool_ports_descriptor32_t
118#else
119#define MAP_SIZE_DIFFERS(map) (map->max_offset > VM_MAX_ADDRESS)
120#define OTHER_OOL_DESCRIPTOR mach_msg_ool_descriptor64_t
121#define OTHER_OOL_PORTS_DESCRIPTOR mach_msg_ool_ports_descriptor64_t
122#endif
123
124#define DESC_SIZE_ADJUSTMENT (sizeof(OTHER_OOL_DESCRIPTOR) - \
125 sizeof(mach_msg_ool_descriptor_t))
126
127/* scatter list macros */
128
129#define SKIP_PORT_DESCRIPTORS(s, c) \
130MACRO_BEGIN \
131 if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \
132 while ((c) > 0) { \
133 if ((s)->type.type != MACH_MSG_PORT_DESCRIPTOR) \
134 break; \
135 (s)++; (c)--; \
136 } \
137 if (c == 0) \
138 (s) = MACH_MSG_DESCRIPTOR_NULL; \
139 } \
140MACRO_END
141
142#define INCREMENT_SCATTER(s, c, d) \
143MACRO_BEGIN \
144 if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \
145 s = (d) ? (mach_msg_descriptor_t *) \
146 ((OTHER_OOL_DESCRIPTOR *)(s) + 1) : \
147 (s + 1); \
148 (c)--; \
149 } \
150MACRO_END
151
152/* zone for cached ipc_kmsg_t structures */
153zone_t ipc_kmsg_zone;
1c79356b
A
154
155/*
156 * Forward declarations
157 */
158
159void ipc_kmsg_clean(
160 ipc_kmsg_t kmsg);
161
162void ipc_kmsg_clean_body(
163 ipc_kmsg_t kmsg,
91447636
A
164 mach_msg_type_number_t number,
165 mach_msg_descriptor_t *desc);
1c79356b
A
166
167void ipc_kmsg_clean_partial(
168 ipc_kmsg_t kmsg,
169 mach_msg_type_number_t number,
91447636 170 mach_msg_descriptor_t *desc,
1c79356b
A
171 vm_offset_t paddr,
172 vm_size_t length);
173
1c79356b
A
174mach_msg_return_t ipc_kmsg_copyin_body(
175 ipc_kmsg_t kmsg,
176 ipc_space_t space,
177 vm_map_t map);
178
1c79356b
A
179/*
180 * We keep a per-processor cache of kernel message buffers.
181 * The cache saves the overhead/locking of using kalloc/kfree.
182 * The per-processor cache seems to miss less than a per-thread cache,
183 * and it also uses less memory. Access to the cache doesn't
184 * require locking.
185 */
1c79356b
A
186
187/*
188 * Routine: ipc_kmsg_alloc
189 * Purpose:
190 * Allocate a kernel message structure. If we can get one from
191 * the cache, that is best. Otherwise, allocate a new one.
192 * Conditions:
193 * Nothing locked.
194 */
195ipc_kmsg_t
196ipc_kmsg_alloc(
197 mach_msg_size_t msg_and_trailer_size)
198{
91447636 199 mach_msg_size_t max_expanded_size;
1c79356b
A
200 ipc_kmsg_t kmsg;
201
91447636
A
202#if !defined(__LP64__)
203 mach_msg_size_t size = msg_and_trailer_size - MAX_TRAILER_SIZE;
204
205 /*
206 * LP64support -
207 * Pad the allocation in case we need to expand the
208 * message descrptors for user spaces with pointers larger than
209 * the kernel's own. We don't know how many descriptors
210 * there are yet, so just assume the whole body could be
211 * descriptors (if there could be any at all).
212 *
213 * The expansion space is left in front of the header,
214 * because it is easier to pull the header and descriptors
215 * forward as we process them than it is to push all the
216 * data backwards.
217 */
218 max_expanded_size =
219 (size > sizeof(mach_msg_base_t)) ?
220 (msg_and_trailer_size + DESC_SIZE_ADJUSTMENT *
221 ((size - sizeof(mach_msg_base_t)) /
222 (sizeof(mach_msg_ool_descriptor_t))))
223 :
224 (msg_and_trailer_size);
225#else
226 max_expanded_size = msg_and_trailer_size;
227#endif
228
229 /* round up for ikm_cache */
230 if (max_expanded_size < IKM_SAVED_MSG_SIZE)
231 max_expanded_size = IKM_SAVED_MSG_SIZE;
232
233 if (max_expanded_size == IKM_SAVED_MSG_SIZE) {
234 struct ikm_cache *cache;
235 unsigned int i;
1c79356b
A
236
237 disable_preemption();
91447636
A
238 cache = &PROCESSOR_DATA(current_processor(), ikm_cache);
239 if ((i = cache->avail) > 0) {
1c79356b 240 assert(i <= IKM_STASH);
91447636
A
241 kmsg = cache->entries[--i];
242 cache->avail = i;
243 ikm_check_init(kmsg, max_expanded_size);
1c79356b 244 enable_preemption();
91447636
A
245 kmsg->ikm_header = (mach_msg_header_t *)
246 ((vm_offset_t)(kmsg + 1) +
247 max_expanded_size -
248 msg_and_trailer_size);
1c79356b
A
249 return (kmsg);
250 }
251 enable_preemption();
91447636
A
252 kmsg = (ipc_kmsg_t)zalloc(ipc_kmsg_zone);
253 } else {
254 kmsg = (ipc_kmsg_t)kalloc(ikm_plus_overhead(max_expanded_size));
1c79356b
A
255 }
256
1c79356b 257 if (kmsg != IKM_NULL) {
91447636
A
258 ikm_init(kmsg, max_expanded_size);
259 kmsg->ikm_header = (mach_msg_header_t *)
260 ((vm_offset_t)(kmsg + 1) +
261 max_expanded_size -
262 msg_and_trailer_size);
1c79356b
A
263 }
264 return(kmsg);
265}
266
267/*
268 * Routine: ipc_kmsg_free
269 * Purpose:
270 * Free a kernel message buffer. If the kms is preallocated
271 * to a port, just "put it back (marked unused)." We have to
272 * do this with the port locked. The port may have its hold
273 * on our message released. In that case, we have to just
274 * revert the message to a traditional one and free it normally.
275 * Conditions:
276 * Nothing locked.
277 */
278
279void
280ipc_kmsg_free(
281 ipc_kmsg_t kmsg)
282{
283 mach_msg_size_t size = kmsg->ikm_size;
284 ipc_port_t port;
285
286 /*
287 * Check to see if the message is bound to the port. If so,
288 * mark it not in use. If the port isn't already dead, then
91447636 289 * leave the message associated with it. Otherwise, free it.
1c79356b
A
290 */
291 port = ikm_prealloc_inuse_port(kmsg);
292 if (port != IP_NULL) {
293 ip_lock(port);
294 ikm_prealloc_clear_inuse(kmsg, port);
295 if (ip_active(port) && (port->ip_premsg == kmsg)) {
296 assert(IP_PREALLOC(port));
297 ip_unlock(port);
298 return;
299 }
9bccf70c 300 ip_check_unlock(port); /* May be last reference */
1c79356b
A
301 }
302
303 /*
304 * Peek and see if it has to go back in the cache.
305 */
91447636
A
306 if (kmsg->ikm_size == IKM_SAVED_MSG_SIZE) {
307 struct ikm_cache *cache;
308 unsigned int i;
1c79356b
A
309
310 disable_preemption();
91447636
A
311 cache = &PROCESSOR_DATA(current_processor(), ikm_cache);
312 if ((i = cache->avail) < IKM_STASH) {
313 cache->entries[i] = kmsg;
314 cache->avail = i + 1;
1c79356b
A
315 enable_preemption();
316 return;
317 }
318 enable_preemption();
91447636
A
319 zfree(ipc_kmsg_zone, kmsg);
320 return;
1c79356b 321 }
91447636 322 kfree(kmsg, ikm_plus_overhead(size));
1c79356b
A
323}
324
325
326/*
327 * Routine: ipc_kmsg_enqueue
328 * Purpose:
329 * Enqueue a kmsg.
330 */
331
332void
333ipc_kmsg_enqueue(
334 ipc_kmsg_queue_t queue,
335 ipc_kmsg_t kmsg)
336{
337 ipc_kmsg_enqueue_macro(queue, kmsg);
338}
339
340/*
341 * Routine: ipc_kmsg_dequeue
342 * Purpose:
343 * Dequeue and return a kmsg.
344 */
345
346ipc_kmsg_t
347ipc_kmsg_dequeue(
348 ipc_kmsg_queue_t queue)
349{
350 ipc_kmsg_t first;
351
352 first = ipc_kmsg_queue_first(queue);
353
354 if (first != IKM_NULL)
355 ipc_kmsg_rmqueue_first_macro(queue, first);
356
357 return first;
358}
359
360/*
361 * Routine: ipc_kmsg_rmqueue
362 * Purpose:
363 * Pull a kmsg out of a queue.
364 */
365
366void
367ipc_kmsg_rmqueue(
368 ipc_kmsg_queue_t queue,
369 ipc_kmsg_t kmsg)
370{
371 ipc_kmsg_t next, prev;
372
373 assert(queue->ikmq_base != IKM_NULL);
374
375 next = kmsg->ikm_next;
376 prev = kmsg->ikm_prev;
377
378 if (next == kmsg) {
379 assert(prev == kmsg);
380 assert(queue->ikmq_base == kmsg);
381
382 queue->ikmq_base = IKM_NULL;
383 } else {
384 if (queue->ikmq_base == kmsg)
385 queue->ikmq_base = next;
386
387 next->ikm_prev = prev;
388 prev->ikm_next = next;
389 }
390 /* XXX Temporary debug logic */
391 assert(kmsg->ikm_next = IKM_BOGUS);
392 assert(kmsg->ikm_prev = IKM_BOGUS);
393}
394
395/*
396 * Routine: ipc_kmsg_queue_next
397 * Purpose:
398 * Return the kmsg following the given kmsg.
399 * (Or IKM_NULL if it is the last one in the queue.)
400 */
401
402ipc_kmsg_t
403ipc_kmsg_queue_next(
404 ipc_kmsg_queue_t queue,
405 ipc_kmsg_t kmsg)
406{
407 ipc_kmsg_t next;
408
409 assert(queue->ikmq_base != IKM_NULL);
410
411 next = kmsg->ikm_next;
412 if (queue->ikmq_base == next)
413 next = IKM_NULL;
414
415 return next;
416}
417
418/*
419 * Routine: ipc_kmsg_destroy
420 * Purpose:
421 * Destroys a kernel message. Releases all rights,
422 * references, and memory held by the message.
423 * Frees the message.
424 * Conditions:
425 * No locks held.
426 */
427
428void
429ipc_kmsg_destroy(
430 ipc_kmsg_t kmsg)
431{
432 ipc_kmsg_queue_t queue;
433 boolean_t empty;
434
435 /*
436 * ipc_kmsg_clean can cause more messages to be destroyed.
437 * Curtail recursion by queueing messages. If a message
438 * is already queued, then this is a recursive call.
439 */
440
441 queue = &(current_thread()->ith_messages);
442 empty = ipc_kmsg_queue_empty(queue);
443 ipc_kmsg_enqueue(queue, kmsg);
444
445 if (empty) {
446 /* must leave kmsg in queue while cleaning it */
447
448 while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
449 ipc_kmsg_clean(kmsg);
450 ipc_kmsg_rmqueue(queue, kmsg);
451 ipc_kmsg_free(kmsg);
452 }
453 }
454}
455
456/*
457 * Routine: ipc_kmsg_destroy_dest
458 * Purpose:
459 * Destroys a kernel message. Releases all rights,
460 * references, and memory held by the message (including
461 * the destination port reference.
462 * Frees the message.
463 * Conditions:
464 * No locks held.
465 */
91447636 466void
1c79356b
A
467ipc_kmsg_destroy_dest(
468 ipc_kmsg_t kmsg)
469{
470 ipc_port_t port;
471
91447636 472 port = kmsg->ikm_header->msgh_remote_port;
1c79356b
A
473
474 ipc_port_release(port);
91447636 475 kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL;
1c79356b
A
476 ipc_kmsg_destroy(kmsg);
477}
478
479/*
480 * Routine: ipc_kmsg_clean_body
481 * Purpose:
482 * Cleans the body of a kernel message.
483 * Releases all rights, references, and memory.
484 *
485 * Conditions:
486 * No locks held.
487 */
488
489void
490ipc_kmsg_clean_body(
91447636
A
491 __unused ipc_kmsg_t kmsg,
492 mach_msg_type_number_t number,
493 mach_msg_descriptor_t *saddr)
1c79356b 494{
91447636 495 mach_msg_descriptor_t *eaddr;
1c79356b
A
496
497 if ( number == 0 )
498 return;
499
1c79356b
A
500 eaddr = saddr + number;
501
502 for ( ; saddr < eaddr; saddr++ ) {
503
504 switch (saddr->type.type) {
505
506 case MACH_MSG_PORT_DESCRIPTOR: {
507 mach_msg_port_descriptor_t *dsc;
508
509 dsc = &saddr->port;
510
511 /*
512 * Destroy port rights carried in the message
513 */
514 if (!IO_VALID((ipc_object_t) dsc->name))
515 continue;
516 ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
517 break;
518 }
519 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
520 case MACH_MSG_OOL_DESCRIPTOR : {
521 mach_msg_ool_descriptor_t *dsc;
522
523 dsc = &saddr->out_of_line;
524
525 /*
526 * Destroy memory carried in the message
527 */
528 if (dsc->size == 0) {
529 assert(dsc->address == (void *) 0);
530 } else {
531 vm_map_copy_discard((vm_map_copy_t) dsc->address);
532 }
533 break;
534 }
535 case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
536 ipc_object_t *objects;
537 mach_msg_type_number_t j;
538 mach_msg_ool_ports_descriptor_t *dsc;
539
540 dsc = &saddr->ool_ports;
541 objects = (ipc_object_t *) dsc->address;
542
543 if (dsc->count == 0) {
544 break;
545 }
546
547 assert(objects != (ipc_object_t *) 0);
548
549 /* destroy port rights carried in the message */
550
551 for (j = 0; j < dsc->count; j++) {
552 ipc_object_t object = objects[j];
553
554 if (!IO_VALID(object))
555 continue;
556
557 ipc_object_destroy(object, dsc->disposition);
558 }
559
560 /* destroy memory carried in the message */
561
562 assert(dsc->count != 0);
563
91447636 564 kfree(dsc->address,
1c79356b
A
565 (vm_size_t) dsc->count * sizeof(mach_port_name_t));
566 break;
567 }
568 default : {
569 printf("cleanup: don't understand this type of descriptor\n");
570 }
571 }
572 }
573}
574
575/*
576 * Routine: ipc_kmsg_clean_partial
577 * Purpose:
578 * Cleans a partially-acquired kernel message.
579 * number is the index of the type descriptor
580 * in the body of the message that contained the error.
581 * If dolast, the memory and port rights in this last
582 * type spec are also cleaned. In that case, number
583 * specifies the number of port rights to clean.
584 * Conditions:
585 * Nothing locked.
586 */
587
588void
589ipc_kmsg_clean_partial(
590 ipc_kmsg_t kmsg,
591 mach_msg_type_number_t number,
91447636 592 mach_msg_descriptor_t *desc,
1c79356b
A
593 vm_offset_t paddr,
594 vm_size_t length)
595{
596 ipc_object_t object;
91447636 597 mach_msg_bits_t mbits = kmsg->ikm_header->msgh_bits;
1c79356b 598
91447636 599 object = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
1c79356b
A
600 assert(IO_VALID(object));
601 ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
602
91447636 603 object = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
1c79356b
A
604 if (IO_VALID(object))
605 ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
606
607 if (paddr) {
608 (void) vm_deallocate(ipc_kernel_copy_map, paddr, length);
609 }
610
91447636 611 ipc_kmsg_clean_body(kmsg, number, desc);
1c79356b
A
612}
613
614/*
615 * Routine: ipc_kmsg_clean
616 * Purpose:
617 * Cleans a kernel message. Releases all rights,
618 * references, and memory held by the message.
619 * Conditions:
620 * No locks held.
621 */
622
623void
624ipc_kmsg_clean(
625 ipc_kmsg_t kmsg)
626{
627 ipc_object_t object;
628 mach_msg_bits_t mbits;
629
91447636
A
630 mbits = kmsg->ikm_header->msgh_bits;
631 object = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
1c79356b
A
632 if (IO_VALID(object))
633 ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
634
91447636 635 object = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
1c79356b
A
636 if (IO_VALID(object))
637 ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
638
639 if (mbits & MACH_MSGH_BITS_COMPLEX) {
640 mach_msg_body_t *body;
641
91447636
A
642 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
643 ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count,
644 (mach_msg_descriptor_t *)(body + 1));
1c79356b
A
645 }
646}
647
648/*
649 * Routine: ipc_kmsg_set_prealloc
650 * Purpose:
651 * Assign a kmsg as a preallocated message buffer to a port.
652 * Conditions:
653 * port locked.
654 */
655
656void
657ipc_kmsg_set_prealloc(
658 ipc_kmsg_t kmsg,
659 ipc_port_t port)
660{
661 assert(kmsg->ikm_prealloc == IP_NULL);
662
663 kmsg->ikm_prealloc = IP_NULL;
664 IP_SET_PREALLOC(port, kmsg);
665}
666
667/*
668 * Routine: ipc_kmsg_clear_prealloc
669 * Purpose:
670 * Release the Assignment of a preallocated message buffer from a port.
671 * Conditions:
672 * port locked.
673 */
674void
675ipc_kmsg_clear_prealloc(
676 ipc_kmsg_t kmsg,
677 ipc_port_t port)
678{
679 assert(kmsg->ikm_prealloc == port);
680
681 kmsg->ikm_prealloc = IP_NULL;
682 IP_CLEAR_PREALLOC(port, kmsg);
683}
684
91447636
A
685
686
1c79356b
A
687/*
688 * Routine: ipc_kmsg_get
689 * Purpose:
690 * Allocates a kernel message buffer.
691 * Copies a user message to the message buffer.
692 * Conditions:
693 * Nothing locked.
694 * Returns:
695 * MACH_MSG_SUCCESS Acquired a message buffer.
696 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
697 * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
698 * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
699 * MACH_SEND_INVALID_DATA Couldn't copy message data.
700 */
701
702mach_msg_return_t
703ipc_kmsg_get(
91447636
A
704 mach_vm_address_t msg_addr,
705 mach_msg_size_t size,
1c79356b
A
706 ipc_kmsg_t *kmsgp)
707{
708 mach_msg_size_t msg_and_trailer_size;
709 ipc_kmsg_t kmsg;
55e303ae 710 mach_msg_max_trailer_t *trailer;
1c79356b
A
711
712 if ((size < sizeof(mach_msg_header_t)) || (size & 3))
713 return MACH_SEND_MSG_TOO_SMALL;
714
715 msg_and_trailer_size = size + MAX_TRAILER_SIZE;
716
717 kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
718
719 if (kmsg == IKM_NULL)
720 return MACH_SEND_NO_BUFFER;
721
91447636 722 if (copyinmsg(msg_addr, (char *) kmsg->ikm_header, size)) {
1c79356b
A
723 ipc_kmsg_free(kmsg);
724 return MACH_SEND_INVALID_DATA;
725 }
726
91447636 727 kmsg->ikm_header->msgh_size = size;
1c79356b
A
728
729 /*
730 * I reserve for the trailer the largest space (MAX_TRAILER_SIZE)
731 * However, the internal size field of the trailer (msgh_trailer_size)
732 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
733 * the cases where no implicit data is requested.
734 */
91447636
A
735 trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + size);
736 trailer->msgh_sender = current_thread()->task->sec_token;
737 trailer->msgh_audit = current_thread()->task->audit_token;
1c79356b
A
738 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
739 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
55e303ae
A
740
741#ifdef ppc
b36670ce 742 if(trcWork.traceMask) dbgTrace(0x1100, (unsigned int)kmsg->ikm_header->msgh_id,
91447636
A
743 (unsigned int)kmsg->ikm_header->msgh_remote_port,
744 (unsigned int)kmsg->ikm_header->msgh_local_port, 0);
55e303ae 745#endif
1c79356b
A
746 *kmsgp = kmsg;
747 return MACH_MSG_SUCCESS;
748}
749
750/*
751 * Routine: ipc_kmsg_get_from_kernel
752 * Purpose:
91447636
A
753 * First checks for a preallocated message
754 * reserved for kernel clients. If not found -
755 * allocates a new kernel message buffer.
1c79356b
A
756 * Copies a kernel message to the message buffer.
757 * Only resource errors are allowed.
758 * Conditions:
759 * Nothing locked.
760 * Ports in header are ipc_port_t.
761 * Returns:
762 * MACH_MSG_SUCCESS Acquired a message buffer.
763 * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
764 */
765
766mach_msg_return_t
767ipc_kmsg_get_from_kernel(
768 mach_msg_header_t *msg,
91447636 769 mach_msg_size_t size,
1c79356b
A
770 ipc_kmsg_t *kmsgp)
771{
772 ipc_kmsg_t kmsg;
773 mach_msg_size_t msg_and_trailer_size;
55e303ae 774 mach_msg_max_trailer_t *trailer;
1c79356b
A
775 ipc_port_t dest_port;
776
777 assert(size >= sizeof(mach_msg_header_t));
3a60a9f5 778// assert((size & 3) == 0);
1c79356b
A
779
780 assert(IP_VALID((ipc_port_t) msg->msgh_remote_port));
781 dest_port = (ipc_port_t)msg->msgh_remote_port;
782
783 msg_and_trailer_size = size + MAX_TRAILER_SIZE;
784
785 /*
786 * See if the port has a pre-allocated kmsg for kernel
787 * clients. These are set up for those kernel clients
788 * which cannot afford to wait.
789 */
790 if (IP_PREALLOC(dest_port)) {
791 ip_lock(dest_port);
792 if (!ip_active(dest_port)) {
793 ip_unlock(dest_port);
794 return MACH_SEND_NO_BUFFER;
795 }
796 assert(IP_PREALLOC(dest_port));
797 kmsg = dest_port->ip_premsg;
798 if (msg_and_trailer_size > kmsg->ikm_size) {
799 ip_unlock(dest_port);
800 return MACH_SEND_TOO_LARGE;
801 }
802 if (ikm_prealloc_inuse(kmsg)) {
803 ip_unlock(dest_port);
804 return MACH_SEND_NO_BUFFER;
805 }
806 ikm_prealloc_set_inuse(kmsg, dest_port);
807 ip_unlock(dest_port);
808 } else {
809 kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
810 if (kmsg == IKM_NULL)
811 return MACH_SEND_NO_BUFFER;
812 }
813
91447636 814 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, size);
1c79356b 815
91447636 816 kmsg->ikm_header->msgh_size = size;
1c79356b
A
817
818 /*
819 * I reserve for the trailer the largest space (MAX_TRAILER_SIZE)
820 * However, the internal size field of the trailer (msgh_trailer_size)
821 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to
822 * optimize the cases where no implicit data is requested.
823 */
55e303ae 824 trailer = (mach_msg_max_trailer_t *)
91447636 825 ((vm_offset_t)kmsg->ikm_header + size);
1c79356b 826 trailer->msgh_sender = KERNEL_SECURITY_TOKEN;
55e303ae 827 trailer->msgh_audit = KERNEL_AUDIT_TOKEN;
1c79356b
A
828 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
829 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
830
831 *kmsgp = kmsg;
832 return MACH_MSG_SUCCESS;
833}
834
835/*
836 * Routine: ipc_kmsg_send
837 * Purpose:
838 * Send a message. The message holds a reference
839 * for the destination port in the msgh_remote_port field.
840 *
841 * If unsuccessful, the caller still has possession of
842 * the message and must do something with it. If successful,
843 * the message is queued, given to a receiver, destroyed,
844 * or handled directly by the kernel via mach_msg.
845 * Conditions:
846 * Nothing locked.
847 * Returns:
848 * MACH_MSG_SUCCESS The message was accepted.
849 * MACH_SEND_TIMED_OUT Caller still has message.
850 * MACH_SEND_INTERRUPTED Caller still has message.
851 */
852mach_msg_return_t
853ipc_kmsg_send(
854 ipc_kmsg_t kmsg,
855 mach_msg_option_t option,
91447636 856 mach_msg_timeout_t send_timeout)
1c79356b 857{
1c79356b 858 ipc_port_t port;
91447636
A
859
860 port = (ipc_port_t) kmsg->ikm_header->msgh_remote_port;
1c79356b
A
861 assert(IP_VALID(port));
862
863 ip_lock(port);
864
865 if (port->ip_receiver == ipc_space_kernel) {
866
867 /*
868 * We can check ip_receiver == ipc_space_kernel
869 * before checking that the port is active because
870 * ipc_port_dealloc_kernel clears ip_receiver
871 * before destroying a kernel port.
872 */
873 assert(ip_active(port));
874 port->ip_messages.imq_seqno++;
875 ip_unlock(port);
876
877 current_task()->messages_sent++;
878
879 /*
880 * Call the server routine, and get the reply message to send.
881 */
882 kmsg = ipc_kobject_server(kmsg);
883 if (kmsg == IKM_NULL)
884 return MACH_MSG_SUCCESS;
885
91447636 886 port = (ipc_port_t) kmsg->ikm_header->msgh_remote_port;
1c79356b
A
887 assert(IP_VALID(port));
888 ip_lock(port);
889 /* fall thru with reply - same options */
890 }
891
892 /*
893 * Can't deliver to a dead port.
894 * However, we can pretend it got sent
895 * and was then immediately destroyed.
896 */
897 if (!ip_active(port)) {
898 /*
899 * We can't let ipc_kmsg_destroy deallocate
900 * the port right, because we might end up
901 * in an infinite loop trying to deliver
902 * a send-once notification.
903 */
904
905 ip_release(port);
906 ip_check_unlock(port);
91447636 907 kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL;
1c79356b
A
908 ipc_kmsg_destroy(kmsg);
909 return MACH_MSG_SUCCESS;
910 }
911
91447636 912 if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
1c79356b
A
913 ip_unlock(port);
914
915 /* don't allow the creation of a circular loop */
916
917 ipc_kmsg_destroy(kmsg);
918 return MACH_MSG_SUCCESS;
919 }
920
921 /*
922 * We have a valid message and a valid reference on the port.
923 * we can unlock the port and call mqueue_send() on it's message
924 * queue.
925 */
926 ip_unlock(port);
91447636 927 return (ipc_mqueue_send(&port->ip_messages, kmsg, option, send_timeout));
1c79356b
A
928}
929
930/*
931 * Routine: ipc_kmsg_put
932 * Purpose:
933 * Copies a message buffer to a user message.
934 * Copies only the specified number of bytes.
935 * Frees the message buffer.
936 * Conditions:
937 * Nothing locked. The message buffer must have clean
938 * header fields.
939 * Returns:
940 * MACH_MSG_SUCCESS Copied data out of message buffer.
941 * MACH_RCV_INVALID_DATA Couldn't copy to user message.
942 */
943
944mach_msg_return_t
945ipc_kmsg_put(
91447636 946 mach_vm_address_t msg_addr,
1c79356b
A
947 ipc_kmsg_t kmsg,
948 mach_msg_size_t size)
949{
950 mach_msg_return_t mr;
951
91447636 952 if (copyoutmsg((const char *) kmsg->ikm_header, msg_addr, size))
1c79356b
A
953 mr = MACH_RCV_INVALID_DATA;
954 else
955 mr = MACH_MSG_SUCCESS;
956
957 ipc_kmsg_free(kmsg);
958 return mr;
959}
960
961/*
962 * Routine: ipc_kmsg_put_to_kernel
963 * Purpose:
964 * Copies a message buffer to a kernel message.
965 * Frees the message buffer.
966 * No errors allowed.
967 * Conditions:
968 * Nothing locked.
969 */
970
971void
972ipc_kmsg_put_to_kernel(
973 mach_msg_header_t *msg,
974 ipc_kmsg_t kmsg,
975 mach_msg_size_t size)
976{
91447636 977 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, size);
1c79356b
A
978
979 ipc_kmsg_free(kmsg);
980}
981
982/*
983 * Routine: ipc_kmsg_copyin_header
984 * Purpose:
985 * "Copy-in" port rights in the header of a message.
986 * Operates atomically; if it doesn't succeed the
987 * message header and the space are left untouched.
988 * If it does succeed the remote/local port fields
989 * contain object pointers instead of port names,
990 * and the bits field is updated. The destination port
991 * will be a valid port pointer.
992 *
993 * The notify argument implements the MACH_SEND_CANCEL option.
994 * If it is not MACH_PORT_NULL, it should name a receive right.
995 * If the processing of the destination port would generate
996 * a port-deleted notification (because the right for the
997 * destination port is destroyed and it had a request for
998 * a dead-name notification registered), and the port-deleted
999 * notification would be sent to the named receive right,
1000 * then it isn't sent and the send-once right for the notify
1001 * port is quietly destroyed.
1002 *
1003 * Conditions:
1004 * Nothing locked.
1005 * Returns:
1006 * MACH_MSG_SUCCESS Successful copyin.
1007 * MACH_SEND_INVALID_HEADER
1008 * Illegal value in the message header bits.
1009 * MACH_SEND_INVALID_DEST The space is dead.
1010 * MACH_SEND_INVALID_NOTIFY
1011 * Notify is non-null and doesn't name a receive right.
1012 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
1013 * MACH_SEND_INVALID_DEST Can't copyin destination port.
1014 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
1015 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
1016 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
1017 */
1018
1019mach_msg_return_t
1020ipc_kmsg_copyin_header(
1021 mach_msg_header_t *msg,
1022 ipc_space_t space,
1023 mach_port_name_t notify)
1024{
1025 mach_msg_bits_t mbits = msg->msgh_bits & MACH_MSGH_BITS_USER;
1026 mach_port_name_t dest_name = (mach_port_name_t)msg->msgh_remote_port;
1027 mach_port_name_t reply_name = (mach_port_name_t)msg->msgh_local_port;
1028 kern_return_t kr;
1029
1030 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
1031 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
1032 ipc_object_t dest_port, reply_port;
1033 ipc_port_t dest_soright, reply_soright;
1034 ipc_port_t notify_port;
1035
1036 if ((mbits != msg->msgh_bits) ||
1037 (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type)) ||
1038 ((reply_type == 0) ?
1039 (reply_name != MACH_PORT_NULL) :
1040 !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type)))
1041 return MACH_SEND_INVALID_HEADER;
1042
1043 reply_soright = IP_NULL; /* in case we go to invalid dest early */
1044
1045 is_write_lock(space);
1046 if (!space->is_active)
1047 goto invalid_dest;
1048
1049 if (!MACH_PORT_VALID(dest_name))
1050 goto invalid_dest;
1051
1052 if (notify != MACH_PORT_NULL) {
1053 ipc_entry_t entry;
1054
1055 if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
1056 is_write_unlock(space);
1057 return MACH_SEND_INVALID_NOTIFY;
1058 }
1059 if((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1060 is_write_unlock(space);
1061 return MACH_SEND_INVALID_NOTIFY;
1062 }
1063
1064 notify_port = (ipc_port_t) entry->ie_object;
91447636
A
1065 } else
1066 notify_port = IP_NULL;
1c79356b
A
1067
1068 if (dest_name == reply_name) {
1069 ipc_entry_t entry;
1070 mach_port_name_t name = dest_name;
1071
1072 /*
1073 * Destination and reply ports are the same!
1074 * This is a little tedious to make atomic, because
1075 * there are 25 combinations of dest_type/reply_type.
1076 * However, most are easy. If either is move-sonce,
1077 * then there must be an error. If either are
1078 * make-send or make-sonce, then we must be looking
1079 * at a receive right so the port can't die.
1080 * The hard cases are the combinations of
1081 * copy-send and make-send.
1082 */
1083
1084 entry = ipc_entry_lookup(space, name);
1085 if (entry == IE_NULL)
1086 goto invalid_dest;
1087
1088 assert(reply_type != 0); /* because name not null */
1089
1090 if (!ipc_right_copyin_check(space, name, entry, reply_type))
1091 goto invalid_reply;
1092
1093 if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
1094 (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
1095 /*
1096 * Why must there be an error? To get a valid
1097 * destination, this entry must name a live
1098 * port (not a dead name or dead port). However
1099 * a successful move-sonce will destroy a
1100 * live entry. Therefore the other copyin,
1101 * whatever it is, would fail. We've already
1102 * checked for reply port errors above,
1103 * so report a destination error.
1104 */
1105
1106 goto invalid_dest;
1107 } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
1108 (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
1109 (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
1110 (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
1111 kr = ipc_right_copyin(space, name, entry,
1112 dest_type, FALSE,
1113 &dest_port, &dest_soright);
1114 if (kr != KERN_SUCCESS)
1115 goto invalid_dest;
1116
1117 /*
1118 * Either dest or reply needs a receive right.
1119 * We know the receive right is there, because
1120 * of the copyin_check and copyin calls. Hence
1121 * the port is not in danger of dying. If dest
1122 * used the receive right, then the right needed
1123 * by reply (and verified by copyin_check) will
1124 * still be there.
1125 */
1126
1127 assert(IO_VALID(dest_port));
1128 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
1129 assert(dest_soright == IP_NULL);
1130
1131 kr = ipc_right_copyin(space, name, entry,
1132 reply_type, TRUE,
1133 &reply_port, &reply_soright);
1134
1135 assert(kr == KERN_SUCCESS);
1136 assert(reply_port == dest_port);
1137 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
1138 assert(reply_soright == IP_NULL);
1139 } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
1140 (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
1141 /*
1142 * To make this atomic, just do one copy-send,
1143 * and dup the send right we get out.
1144 */
1145
1146 kr = ipc_right_copyin(space, name, entry,
1147 dest_type, FALSE,
1148 &dest_port, &dest_soright);
1149 if (kr != KERN_SUCCESS)
1150 goto invalid_dest;
1151
1152 assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
1153 assert(dest_soright == IP_NULL);
1154
1155 /*
1156 * It's OK if the port we got is dead now,
1157 * so reply_port is IP_DEAD, because the msg
1158 * won't go anywhere anyway.
1159 */
1160
1161 reply_port = (ipc_object_t)
1162 ipc_port_copy_send((ipc_port_t) dest_port);
1163 reply_soright = IP_NULL;
1164 } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1165 (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
1166 /*
1167 * This is an easy case. Just use our
1168 * handy-dandy special-purpose copyin call
1169 * to get two send rights for the price of one.
1170 */
1171
1172 kr = ipc_right_copyin_two(space, name, entry,
1173 &dest_port, &dest_soright);
1174 if (kr != KERN_SUCCESS)
1175 goto invalid_dest;
1176
1177 /* the entry might need to be deallocated */
1178 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
1179 ipc_entry_dealloc(space, name, entry);
1180
1181 reply_port = dest_port;
1182 reply_soright = IP_NULL;
1183 } else {
1184 ipc_port_t soright;
1185
1186 assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
1187 (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
1188 ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1189 (reply_type == MACH_MSG_TYPE_COPY_SEND)));
1190
1191 /*
1192 * To make this atomic, just do a move-send,
1193 * and dup the send right we get out.
1194 */
1195
1196 kr = ipc_right_copyin(space, name, entry,
1197 MACH_MSG_TYPE_MOVE_SEND, FALSE,
1198 &dest_port, &soright);
1199 if (kr != KERN_SUCCESS)
1200 goto invalid_dest;
1201
1202 /* the entry might need to be deallocated */
1203
1204 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
1205 ipc_entry_dealloc(space, name, entry);
1206
1207 /*
1208 * It's OK if the port we got is dead now,
1209 * so reply_port is IP_DEAD, because the msg
1210 * won't go anywhere anyway.
1211 */
1212
1213 reply_port = (ipc_object_t)
1214 ipc_port_copy_send((ipc_port_t) dest_port);
1215
1216 if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
1217 dest_soright = soright;
1218 reply_soright = IP_NULL;
1219 } else {
1220 dest_soright = IP_NULL;
1221 reply_soright = soright;
1222 }
1223 }
1224 } else if (!MACH_PORT_VALID(reply_name)) {
1225 ipc_entry_t entry;
1226
1227 /*
1228 * No reply port! This is an easy case
1229 * to make atomic. Just copyin the destination.
1230 */
1231
1232 entry = ipc_entry_lookup(space, dest_name);
1233 if (entry == IE_NULL)
1234 goto invalid_dest;
1235
1236 kr = ipc_right_copyin(space, dest_name, entry,
1237 dest_type, FALSE,
1238 &dest_port, &dest_soright);
1239 if (kr != KERN_SUCCESS)
1240 goto invalid_dest;
1241
1242 /* the entry might need to be deallocated */
1243
1244 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
1245 ipc_entry_dealloc(space, dest_name, entry);
1246
1247 reply_port = (ipc_object_t) reply_name;
1248 reply_soright = IP_NULL;
1249 } else {
1250 ipc_entry_t dest_entry, reply_entry;
1c79356b
A
1251
1252 /*
1253 * This is the tough case to make atomic.
1254 * The difficult problem is serializing with port death.
1255 * At the time we copyin dest_port, it must be alive.
1256 * If reply_port is alive when we copyin it, then
1257 * we are OK, because we serialize before the death
1258 * of both ports. Assume reply_port is dead at copyin.
1259 * Then if dest_port dies/died after reply_port died,
1260 * we are OK, because we serialize between the death
1261 * of the two ports. So the bad case is when dest_port
1262 * dies after its copyin, reply_port dies before its
1263 * copyin, and dest_port dies before reply_port. Then
1264 * the copyins operated as if dest_port was alive
1265 * and reply_port was dead, which shouldn't have happened
1266 * because they died in the other order.
1267 *
1268 * Note that it is easy for a user task to tell if
1269 * a copyin happened before or after a port died.
1270 * For example, suppose both dest and reply are
1271 * send-once rights (types are both move-sonce) and
1272 * both rights have dead-name requests registered.
1273 * If a port dies before copyin, a dead-name notification
1274 * is generated and the dead name's urefs are incremented,
1275 * and if the copyin happens first, a port-deleted
1276 * notification is generated.
1277 *
1278 * Note that although the entries are different,
1279 * dest_port and reply_port might still be the same.
1280 *
1281 * JMM - The code to handle this was too expensive and, anyway,
1282 * we intend to separate the dest lookup from the reply copyin
1283 * by a wide margin, so the user will have to learn to deal!
1284 * I will be making the change soon!
1285 */
1286
1287 dest_entry = ipc_entry_lookup(space, dest_name);
1288 if (dest_entry == IE_NULL)
1289 goto invalid_dest;
1290
1291 reply_entry = ipc_entry_lookup(space, reply_name);
1292 if (reply_entry == IE_NULL)
1293 goto invalid_reply;
1294
1295 assert(dest_entry != reply_entry); /* names are not equal */
1296 assert(reply_type != 0); /* because reply_name not null */
1297
1298 if (!ipc_right_copyin_check(space, reply_name, reply_entry,
1299 reply_type))
1300 goto invalid_reply;
1301
1302 kr = ipc_right_copyin(space, dest_name, dest_entry,
1303 dest_type, FALSE,
1304 &dest_port, &dest_soright);
1305 if (kr != KERN_SUCCESS)
1306 goto invalid_dest;
1307
1308 assert(IO_VALID(dest_port));
1309
1310 kr = ipc_right_copyin(space, reply_name, reply_entry,
1311 reply_type, TRUE,
1312 &reply_port, &reply_soright);
1313
1314 assert(kr == KERN_SUCCESS);
1315
1316 /* the entries might need to be deallocated */
1317
1318 if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1319 ipc_entry_dealloc(space, reply_name, reply_entry);
1320
1321 if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1322 ipc_entry_dealloc(space, dest_name, dest_entry);
1323 }
1324
1325 /*
1326 * At this point, dest_port, reply_port,
1327 * dest_soright, reply_soright are all initialized.
1328 * Any defunct entries have been deallocated.
1329 * The space is still write-locked, and we need to
1330 * make the MACH_SEND_CANCEL check. The notify_port pointer
1331 * is still usable, because the copyin code above won't ever
1332 * deallocate a receive right, so its entry still exists
1333 * and holds a ref. Note notify_port might even equal
1334 * dest_port or reply_port.
1335 */
1336
1337 if ((notify != MACH_PORT_NULL) &&
1338 (dest_soright == notify_port)) {
1339 ipc_port_release_sonce(dest_soright);
1340 dest_soright = IP_NULL;
1341 }
1342
1343 is_write_unlock(space);
1344
1345 if (dest_soright != IP_NULL)
1346 ipc_notify_port_deleted(dest_soright, dest_name);
1347
1348 if (reply_soright != IP_NULL)
1349 ipc_notify_port_deleted(reply_soright, reply_name);
1350
1351 dest_type = ipc_object_copyin_type(dest_type);
1352 reply_type = ipc_object_copyin_type(reply_type);
1353
1354 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1355 MACH_MSGH_BITS(dest_type, reply_type));
1356 msg->msgh_remote_port = (ipc_port_t)dest_port;
1357 msg->msgh_local_port = (ipc_port_t)reply_port;
1358
1359 return MACH_MSG_SUCCESS;
1360
1361invalid_reply:
1362 is_write_unlock(space);
1363 return MACH_SEND_INVALID_REPLY;
1364
1365invalid_dest:
1366 is_write_unlock(space);
1367 if (reply_soright != IP_NULL)
1368 ipc_notify_port_deleted(reply_soright, reply_name);
1369 return MACH_SEND_INVALID_DEST;
1370}
1371
1372/*
1373 * Routine: ipc_kmsg_copyin_body
1374 * Purpose:
1375 * "Copy-in" port rights and out-of-line memory
1376 * in the message body.
1377 *
1378 * In all failure cases, the message is left holding
1379 * no rights or memory. However, the message buffer
1380 * is not deallocated. If successful, the message
1381 * contains a valid destination port.
1382 * Conditions:
1383 * Nothing locked.
1384 * Returns:
1385 * MACH_MSG_SUCCESS Successful copyin.
1386 * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
1387 * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
1388 * MACH_SEND_INVALID_TYPE Bad type specification.
1389 * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
1390 * MACH_SEND_INVALID_RT_OOL_SIZE OOL Buffer too large for RT
1391 * MACH_MSG_INVALID_RT_DESCRIPTOR Dealloc and RT are incompatible
1392 */
1393
91447636
A
1394#define DESC_COUNT_SMALL 64
1395
1c79356b
A
1396mach_msg_return_t
1397ipc_kmsg_copyin_body(
1398 ipc_kmsg_t kmsg,
1399 ipc_space_t space,
1400 vm_map_t map)
1401{
1402 ipc_object_t dest;
1403 mach_msg_body_t *body;
91447636
A
1404 mach_msg_descriptor_t *daddr, *naddr;
1405 mach_msg_type_number_t dsc_count;
1406 boolean_t differs = MAP_SIZE_DIFFERS(map);
1407 boolean_t complex = FALSE;
1c79356b 1408 vm_size_t space_needed = 0;
91447636
A
1409 vm_size_t desc_size_space[DESC_COUNT_SMALL];
1410 vm_size_t *user_desc_sizes = NULL;
1c79356b 1411 vm_offset_t paddr = 0;
1c79356b 1412 vm_map_copy_t copy = VM_MAP_COPY_NULL;
91447636
A
1413 kern_return_t kr;
1414 mach_msg_type_number_t i;
1415 mach_msg_return_t mr = MACH_MSG_SUCCESS;
1c79356b
A
1416
1417 /*
1418 * Determine if the target is a kernel port.
1419 */
91447636
A
1420 dest = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
1421 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
1422 naddr = (mach_msg_descriptor_t *) (body + 1);
1c79356b 1423
91447636
A
1424 dsc_count = body->msgh_descriptor_count;
1425 if (dsc_count == 0)
1426 return MACH_MSG_SUCCESS;
1427
1428 if (differs) {
1429 user_desc_sizes = (dsc_count <= DESC_COUNT_SMALL) ?
1430 &desc_size_space : kalloc(dsc_count * sizeof(vm_size_t));
1431 if (user_desc_sizes == NULL) {
1432 ipc_kmsg_clean_partial(kmsg,0,0,0,0);
1433 return KERN_RESOURCE_SHORTAGE;
1434 }
1c79356b 1435 }
91447636 1436
1c79356b
A
1437 /*
1438 * Make an initial pass to determine kernal VM space requirements for
91447636
A
1439 * physical copies and possible contraction of the descriptors from
1440 * processes with pointers larger than the kernel's.
1c79356b 1441 */
91447636
A
1442 daddr = 0;
1443 for (i = 0; i < dsc_count; i++) {
1444 daddr = naddr;
1445
1446 /* make sure the descriptor fits in the message */
1447 if (differs) {
1448 switch (daddr->type.type) {
1449 case MACH_MSG_OOL_DESCRIPTOR:
1450 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
1451 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
1452 user_desc_sizes[i] = sizeof(OTHER_OOL_DESCRIPTOR);
1453 break;
1454 default:
1455 user_desc_sizes[i] = sizeof(*daddr);
1456 break;
1457 }
1458 naddr = (mach_msg_descriptor_t *)
1459 ((vm_offset_t)daddr + user_desc_sizes[i]);
1460 } else {
1461 naddr = daddr + 1;
1462 }
1463
1464 if (naddr > (mach_msg_descriptor_t *)
1465 ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size)) {
1466 ipc_kmsg_clean_partial(kmsg,0,0,0,0);
1467 mr = MACH_SEND_MSG_TOO_SMALL;
1468 goto out;
1469 }
1c79356b 1470
91447636
A
1471 switch (daddr->type.type) {
1472 mach_msg_size_t size;
1c79356b 1473
91447636
A
1474 case MACH_MSG_OOL_DESCRIPTOR:
1475 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
1476 size = (differs) ?
1477 ((OTHER_OOL_DESCRIPTOR *)daddr)->size :
1478 daddr->out_of_line.size;
1479
1480 if (daddr->out_of_line.copy != MACH_MSG_PHYSICAL_COPY &&
1481 daddr->out_of_line.copy != MACH_MSG_VIRTUAL_COPY) {
1482 /*
1483 * Invalid copy option
1484 */
1485 ipc_kmsg_clean_partial(kmsg,0,0,0,0);
1486 mr = MACH_SEND_INVALID_TYPE;
1487 goto out;
1488 }
1489
1490 if ((size >= MSG_OOL_SIZE_SMALL) &&
1491 (daddr->out_of_line.copy == MACH_MSG_PHYSICAL_COPY) &&
1492 !(daddr->out_of_line.deallocate)) {
1493
1494 /*
1495 * Out-of-line memory descriptor, accumulate kernel
1496 * memory requirements
1497 */
1498 space_needed += round_page(size);
1499 if (space_needed > ipc_kmsg_max_vm_space) {
1500
1c79356b 1501 /*
91447636 1502 * Per message kernel memory limit exceeded
1c79356b 1503 */
91447636
A
1504 ipc_kmsg_clean_partial(kmsg,0,0,0,0);
1505 mr = MACH_MSG_VM_KERNEL;
1506 goto out;
1c79356b 1507 }
91447636 1508 }
1c79356b
A
1509 }
1510 }
1511
1512 /*
1513 * Allocate space in the pageable kernel ipc copy map for all the
1514 * ool data that is to be physically copied. Map is marked wait for
1515 * space.
1516 */
1517 if (space_needed) {
91447636 1518 if (vm_allocate(ipc_kernel_copy_map, &paddr, space_needed, VM_FLAGS_ANYWHERE) !=
1c79356b 1519 KERN_SUCCESS) {
91447636
A
1520 ipc_kmsg_clean_partial(kmsg,0,0,0,0);
1521 mr = MACH_MSG_VM_KERNEL;
1522 goto out;
1c79356b
A
1523 }
1524 }
1525
1526 /*
1527 * handle the OOL regions and port descriptors.
91447636
A
1528 * We process them in reverse order starting with the last one
1529 * scanned above. That way, we can compact them up against
1530 * the message body (if the user-descriptor size is larger than
1531 * the kernel representation).
1c79356b 1532 */
91447636
A
1533 naddr -= 1;
1534 do {
1535
1536 switch (daddr->type.type) {
1c79356b 1537
91447636 1538 /* port descriptors are the same size everywhere, how nice */
1c79356b 1539 case MACH_MSG_PORT_DESCRIPTOR: {
91447636
A
1540 mach_msg_type_name_t user_disp;
1541 mach_msg_type_name_t result_disp;
1542 mach_port_name_t name;
1c79356b 1543 ipc_object_t object;
91447636
A
1544 volatile mach_msg_port_descriptor_t *dsc;
1545 volatile mach_msg_port_descriptor_t *user_dsc;
1c79356b 1546
91447636
A
1547 user_dsc = &daddr->port;
1548 dsc = &naddr->port;
1c79356b 1549
91447636
A
1550 user_disp = user_dsc->disposition;
1551 result_disp = ipc_object_copyin_type(user_disp);
1c79356b 1552
91447636
A
1553 name = (mach_port_name_t)user_dsc->name;
1554 if (MACH_PORT_VALID(name)) {
1555
1556 kr = ipc_object_copyin(space, name, user_disp, &object);
1557 if (kr != KERN_SUCCESS) {
1558 mr = MACH_SEND_INVALID_RIGHT;
1559 break;
1560 }
1561
1562 if ((result_disp == MACH_MSG_TYPE_PORT_RECEIVE) &&
1563 ipc_port_check_circularity((ipc_port_t) object,
1564 (ipc_port_t) dest)) {
1565 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
1566 }
1567 dsc->name = (ipc_port_t) object;
1568 } else {
1569 dsc->name = (mach_port_t)name;
1c79356b 1570 }
91447636
A
1571 dsc->disposition = result_disp;
1572 dsc->type = MACH_MSG_PORT_DESCRIPTOR;
1c79356b
A
1573 complex = TRUE;
1574 break;
1575 }
91447636
A
1576
1577 /* out of line descriptors differ in size between 32 and 64 bit processes */
1c79356b
A
1578 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
1579 case MACH_MSG_OOL_DESCRIPTOR: {
1580 vm_size_t length;
1581 boolean_t dealloc;
91447636
A
1582 mach_msg_copy_options_t copy_options;
1583 mach_vm_offset_t addr;
1584 mach_msg_descriptor_type_t dsc_type;
1585
1586 volatile mach_msg_ool_descriptor_t *dsc;
1587
1588 if (differs) {
1589 volatile OTHER_OOL_DESCRIPTOR *user_dsc;
1590
1591 user_dsc = (OTHER_OOL_DESCRIPTOR *)&daddr->out_of_line;
1592 addr = (mach_vm_offset_t) user_dsc->address;
1593 length = user_dsc->size;
1594 dealloc = user_dsc->deallocate;
1595 copy_options = user_dsc->copy;
1596 dsc_type = user_dsc->type;
1597 } else {
1598 volatile mach_msg_ool_descriptor_t *user_dsc;
1c79356b 1599
91447636
A
1600 user_dsc = &daddr->out_of_line;
1601 addr = CAST_USER_ADDR_T(user_dsc->address);
1602 dealloc = user_dsc->deallocate;
1603 copy_options = user_dsc->copy;
1604 dsc_type = user_dsc->type;
1605 length = user_dsc->size;
1606 }
1607
1608 dsc = &naddr->out_of_line;
1609 dsc->size = length;
1610 dsc->deallocate = dealloc;
1611 dsc->copy = copy_options;
1612 dsc->type = dsc_type;
1613
1c79356b
A
1614 if (length == 0) {
1615 dsc->address = 0;
1c79356b 1616 } else if ((length >= MSG_OOL_SIZE_SMALL) &&
91447636 1617 (copy_options == MACH_MSG_PHYSICAL_COPY) && !dealloc) {
1c79356b
A
1618
1619 /*
1620 * If the request is a physical copy and the source
1621 * is not being deallocated, then allocate space
1622 * in the kernel's pageable ipc copy map and copy
1623 * the data in. The semantics guarantee that the
1624 * data will have been physically copied before
1625 * the send operation terminates. Thus if the data
1626 * is not being deallocated, we must be prepared
1627 * to page if the region is sufficiently large.
1628 */
91447636
A
1629 if (copyin(addr, (char *) paddr, length)) {
1630 mr = MACH_SEND_INVALID_MEMORY;
1631 break;
1c79356b
A
1632 }
1633
1634 /*
1635 * The kernel ipc copy map is marked no_zero_fill.
1636 * If the transfer is not a page multiple, we need
1637 * to zero fill the balance.
1638 */
1639 if (!page_aligned(length)) {
1640 (void) memset((void *) (paddr + length), 0,
91447636 1641 round_page(length) - length);
1c79356b 1642 }
91447636
A
1643 if (vm_map_copyin(ipc_kernel_copy_map, (vm_map_address_t)paddr,
1644 (vm_map_size_t)length, TRUE, &copy) != KERN_SUCCESS) {
1645 mr = MACH_MSG_VM_KERNEL;
1646 break;
1c79356b
A
1647 }
1648 dsc->address = (void *) copy;
91447636
A
1649 paddr += round_page(length);
1650 space_needed -= round_page(length);
1c79356b
A
1651 } else {
1652
1653 /*
1654 * Make a vm_map_copy_t of the of the data. If the
1655 * data is small, this will do an optimized physical
1656 * copy. Otherwise, it will do a virtual copy.
1657 *
1658 * NOTE: A virtual copy is OK if the original is being
1659 * deallocted, even if a physical copy was requested.
1660 */
91447636
A
1661 kr = vm_map_copyin(map, addr,
1662 (vm_map_size_t)length, dealloc, &copy);
1c79356b 1663 if (kr != KERN_SUCCESS) {
91447636 1664 mr = (kr == KERN_RESOURCE_SHORTAGE) ?
1c79356b
A
1665 MACH_MSG_VM_KERNEL :
1666 MACH_SEND_INVALID_MEMORY;
91447636 1667 break;
1c79356b
A
1668 }
1669 dsc->address = (void *) copy;
1670 }
1671 complex = TRUE;
1672 break;
1673 }
1674 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
1675 vm_size_t length;
91447636 1676 void *data;
1c79356b 1677 ipc_object_t *objects;
91447636
A
1678 unsigned int j;
1679 mach_vm_offset_t addr;
1680 mach_msg_type_name_t user_disp;
1681 mach_msg_type_name_t result_disp;
1682 mach_msg_type_number_t count;
1683 mach_msg_copy_options_t copy_option;
1684 boolean_t deallocate;
1685
1686 volatile mach_msg_ool_ports_descriptor_t *dsc;
1687
1688 if (differs) {
1689 volatile OTHER_OOL_PORTS_DESCRIPTOR *user_dsc;
1690
1691 user_dsc = (OTHER_OOL_PORTS_DESCRIPTOR *)&daddr->ool_ports;
1692 addr = (mach_vm_offset_t)user_dsc->address;
1693 count = user_dsc->count;
1694 deallocate = user_dsc->deallocate;
1695 copy_option = user_dsc->copy;
1696 user_disp = user_dsc->disposition;
1697 } else {
1698 volatile mach_msg_ool_ports_descriptor_t *user_dsc;
1699
1700 user_dsc = &daddr->ool_ports;
1701 addr = CAST_USER_ADDR_T(user_dsc->address);
1702 count = user_dsc->count;
1703 deallocate = user_dsc->deallocate;
1704 copy_option = user_dsc->copy;
1705 user_disp = user_dsc->disposition;
1706 }
1707
1708 dsc = &naddr->ool_ports;
1709 dsc->deallocate = deallocate;
1710 dsc->copy = copy_option;
1711 dsc->type = daddr->type.type;
1712 dsc->count = count;
1c79356b
A
1713
1714 /* calculate length of data in bytes, rounding up */
91447636 1715 length = count * sizeof(mach_port_name_t);
1c79356b
A
1716
1717 if (length == 0) {
1718 complex = TRUE;
1719 dsc->address = (void *) 0;
1720 break;
1721 }
1722
1723 data = kalloc(length);
1724
91447636
A
1725 if (data == NULL) {
1726 mr = MACH_SEND_NO_BUFFER;
1727 break;
1c79356b
A
1728 }
1729
91447636 1730 if (copyinmap(map, addr, data, length) != KERN_SUCCESS) {
1c79356b 1731 kfree(data, length);
91447636
A
1732 mr = MACH_SEND_INVALID_MEMORY;
1733 break;
1c79356b
A
1734 }
1735
91447636
A
1736 if (deallocate) {
1737 (void) mach_vm_deallocate(map, addr, (mach_vm_size_t)length);
1c79356b
A
1738 }
1739
91447636 1740 dsc->address = data;
1c79356b 1741
91447636
A
1742 result_disp = ipc_object_copyin_type(user_disp);
1743 dsc->disposition = result_disp;
1744
1c79356b
A
1745 objects = (ipc_object_t *) data;
1746
91447636 1747 for ( j = 0; j < count; j++) {
1c79356b
A
1748 mach_port_name_t port = (mach_port_name_t) objects[j];
1749 ipc_object_t object;
1750
1751 if (!MACH_PORT_VALID(port))
1752 continue;
1753
91447636 1754 kr = ipc_object_copyin(space, port, user_disp, &object);
1c79356b
A
1755
1756 if (kr != KERN_SUCCESS) {
91447636 1757 unsigned int k;
1c79356b
A
1758
1759 for(k = 0; k < j; k++) {
1760 object = objects[k];
55e303ae 1761 if (IPC_OBJECT_VALID(object))
91447636 1762 ipc_object_destroy(object, result_disp);
1c79356b
A
1763 }
1764 kfree(data, length);
91447636
A
1765 mr = MACH_SEND_INVALID_RIGHT;
1766 break;
1c79356b
A
1767 }
1768
1769 if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
1770 ipc_port_check_circularity(
1771 (ipc_port_t) object,
1772 (ipc_port_t) dest))
91447636 1773 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
1c79356b
A
1774
1775 objects[j] = object;
1776 }
1777
1778 complex = TRUE;
1779 break;
1780 }
1781 default: {
1782 /*
1783 * Invalid descriptor
1784 */
91447636
A
1785 mr = MACH_SEND_INVALID_TYPE;
1786 break;
1c79356b
A
1787 }
1788 }
91447636
A
1789
1790 if (MACH_MSG_SUCCESS != mr) {
1791 ipc_kmsg_clean_partial(kmsg, dsc_count - i,
1792 naddr + 1, paddr, space_needed);
1793 goto out;
1794 }
1795
1796 } while (--i > 0
1797 &&
1798 (daddr = (differs) ? (mach_msg_descriptor_t *)((vm_offset_t)(daddr) -
1799 user_desc_sizes[i - 1]) : daddr - 1)
1800 &&
1801 naddr--);
1c79356b 1802
91447636
A
1803 if (!complex) {
1804 kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
1805 }
1806
1807 if (differs && naddr != daddr) {
1808 mach_msg_base_t *old_base = (mach_msg_base_t *)kmsg->ikm_header;
1809 mach_msg_base_t *new_base = (mach_msg_base_t *)naddr - 1;
1810
1811 memmove(new_base, old_base, sizeof(mach_msg_base_t));
1812 new_base->header.msgh_size -= (vm_offset_t)naddr - (vm_offset_t)daddr;
1813 kmsg->ikm_header = &new_base->header;
1814 }
1815
1816 out:
1817 if (differs && dsc_count > DESC_COUNT_SMALL)
1818 kfree(user_desc_sizes, body->msgh_descriptor_count * sizeof(vm_size_t));
1819
1820 return mr;
1c79356b
A
1821}
1822
1823
1824/*
1825 * Routine: ipc_kmsg_copyin
1826 * Purpose:
1827 * "Copy-in" port rights and out-of-line memory
1828 * in the message.
1829 *
1830 * In all failure cases, the message is left holding
1831 * no rights or memory. However, the message buffer
1832 * is not deallocated. If successful, the message
1833 * contains a valid destination port.
1834 * Conditions:
1835 * Nothing locked.
1836 * Returns:
1837 * MACH_MSG_SUCCESS Successful copyin.
1838 * MACH_SEND_INVALID_HEADER
1839 * Illegal value in the message header bits.
1840 * MACH_SEND_INVALID_NOTIFY Bad notify port.
1841 * MACH_SEND_INVALID_DEST Can't copyin destination port.
1842 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
1843 * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
1844 * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
1845 * MACH_SEND_INVALID_TYPE Bad type specification.
1846 * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
1847 */
1848
1849mach_msg_return_t
1850ipc_kmsg_copyin(
1851 ipc_kmsg_t kmsg,
1852 ipc_space_t space,
1853 vm_map_t map,
1854 mach_port_name_t notify)
1855{
1856 mach_msg_return_t mr;
1857
91447636 1858 mr = ipc_kmsg_copyin_header(kmsg->ikm_header, space, notify);
1c79356b
A
1859 if (mr != MACH_MSG_SUCCESS)
1860 return mr;
1861
91447636 1862 if ((kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
1c79356b
A
1863 return MACH_MSG_SUCCESS;
1864
1865 return( ipc_kmsg_copyin_body( kmsg, space, map) );
1866}
1867
1868/*
1869 * Routine: ipc_kmsg_copyin_from_kernel
1870 * Purpose:
1871 * "Copy-in" port rights and out-of-line memory
1872 * in a message sent from the kernel.
1873 *
1874 * Because the message comes from the kernel,
1875 * the implementation assumes there are no errors
1876 * or peculiarities in the message.
1877 *
1878 * Returns TRUE if queueing the message
1879 * would result in a circularity.
1880 * Conditions:
1881 * Nothing locked.
1882 */
1883
1884void
1885ipc_kmsg_copyin_from_kernel(
1886 ipc_kmsg_t kmsg)
1887{
91447636 1888 mach_msg_bits_t bits = kmsg->ikm_header->msgh_bits;
1c79356b
A
1889 mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
1890 mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
91447636
A
1891 ipc_object_t remote = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
1892 ipc_object_t local = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
1c79356b
A
1893
1894 /* translate the destination and reply ports */
1895
1896 ipc_object_copyin_from_kernel(remote, rname);
1897 if (IO_VALID(local))
1898 ipc_object_copyin_from_kernel(local, lname);
1899
1900 /*
1901 * The common case is a complex message with no reply port,
1902 * because that is what the memory_object interface uses.
1903 */
1904
1905 if (bits == (MACH_MSGH_BITS_COMPLEX |
1906 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
1907 bits = (MACH_MSGH_BITS_COMPLEX |
1908 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
1909
91447636 1910 kmsg->ikm_header->msgh_bits = bits;
1c79356b
A
1911 } else {
1912 bits = (MACH_MSGH_BITS_OTHER(bits) |
1913 MACH_MSGH_BITS(ipc_object_copyin_type(rname),
1914 ipc_object_copyin_type(lname)));
1915
91447636 1916 kmsg->ikm_header->msgh_bits = bits;
1c79356b
A
1917 if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
1918 return;
1919 }
1920 {
1921 mach_msg_descriptor_t *saddr, *eaddr;
1922 mach_msg_body_t *body;
1923
91447636 1924 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
1c79356b
A
1925 saddr = (mach_msg_descriptor_t *) (body + 1);
1926 eaddr = (mach_msg_descriptor_t *) saddr + body->msgh_descriptor_count;
1927
1928 for ( ; saddr < eaddr; saddr++) {
1929
1930 switch (saddr->type.type) {
1931
1932 case MACH_MSG_PORT_DESCRIPTOR: {
1933 mach_msg_type_name_t name;
1934 ipc_object_t object;
1935 mach_msg_port_descriptor_t *dsc;
1936
1937 dsc = &saddr->port;
1938
1939 /* this is really the type SEND, SEND_ONCE, etc. */
1940 name = dsc->disposition;
1941 object = (ipc_object_t) dsc->name;
1942 dsc->disposition = ipc_object_copyin_type(name);
1943
1944 if (!IO_VALID(object)) {
1945 break;
1946 }
1947
1948 ipc_object_copyin_from_kernel(object, name);
1949
1950 /* CDY avoid circularity when the destination is also */
1951 /* the kernel. This check should be changed into an */
1952 /* assert when the new kobject model is in place since*/
1953 /* ports will not be used in kernel to kernel chats */
1954
1955 if (((ipc_port_t)remote)->ip_receiver != ipc_space_kernel) {
1956 if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
1957 ipc_port_check_circularity((ipc_port_t) object,
1958 (ipc_port_t) remote)) {
91447636 1959 kmsg->ikm_header->msgh_bits |=
1c79356b
A
1960 MACH_MSGH_BITS_CIRCULAR;
1961 }
1962 }
1963 break;
1964 }
1965 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
1966 case MACH_MSG_OOL_DESCRIPTOR: {
1967 /*
1968 * The sender should supply ready-made memory, i.e.
1969 * a vm_map_copy_t, so we don't need to do anything.
1970 */
1971 break;
1972 }
1973 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
1974 ipc_object_t *objects;
91447636 1975 unsigned int j;
1c79356b
A
1976 mach_msg_type_name_t name;
1977 mach_msg_ool_ports_descriptor_t *dsc;
1978
1979 dsc = &saddr->ool_ports;
1980
1981 /* this is really the type SEND, SEND_ONCE, etc. */
1982 name = dsc->disposition;
1983 dsc->disposition = ipc_object_copyin_type(name);
1984
1985 objects = (ipc_object_t *) dsc->address;
1986
1987 for ( j = 0; j < dsc->count; j++) {
1988 ipc_object_t object = objects[j];
1989
1990 if (!IO_VALID(object))
1991 continue;
1992
1993 ipc_object_copyin_from_kernel(object, name);
1994
1995 if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
1996 ipc_port_check_circularity(
1997 (ipc_port_t) object,
1998 (ipc_port_t) remote))
91447636 1999 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
1c79356b
A
2000 }
2001 break;
2002 }
2003 default: {
2004#if MACH_ASSERT
2005 panic("ipc_kmsg_copyin_from_kernel: bad descriptor");
2006#endif /* MACH_ASSERT */
2007 }
2008 }
2009 }
2010 }
2011}
2012
2013/*
2014 * Routine: ipc_kmsg_copyout_header
2015 * Purpose:
2016 * "Copy-out" port rights in the header of a message.
2017 * Operates atomically; if it doesn't succeed the
2018 * message header and the space are left untouched.
2019 * If it does succeed the remote/local port fields
2020 * contain port names instead of object pointers,
2021 * and the bits field is updated.
2022 *
2023 * The notify argument implements the MACH_RCV_NOTIFY option.
2024 * If it is not MACH_PORT_NULL, it should name a receive right.
2025 * If the process of receiving the reply port creates a
2026 * new right in the receiving task, then the new right is
2027 * automatically registered for a dead-name notification,
2028 * with the notify port supplying the send-once right.
2029 * Conditions:
2030 * Nothing locked.
2031 * Returns:
2032 * MACH_MSG_SUCCESS Copied out port rights.
2033 * MACH_RCV_INVALID_NOTIFY
2034 * Notify is non-null and doesn't name a receive right.
2035 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
2036 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
2037 * The space is dead.
2038 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
2039 * No room in space for another name.
2040 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
2041 * Couldn't allocate memory for the reply port.
2042 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
2043 * Couldn't allocate memory for the dead-name request.
2044 */
2045
2046mach_msg_return_t
2047ipc_kmsg_copyout_header(
2048 mach_msg_header_t *msg,
2049 ipc_space_t space,
2050 mach_port_name_t notify)
2051{
2052 mach_msg_bits_t mbits = msg->msgh_bits;
2053 ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
2054
2055 assert(IP_VALID(dest));
2056
2057 {
2058 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2059 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2060 ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
2061 mach_port_name_t dest_name, reply_name;
2062
2063 if (IP_VALID(reply)) {
2064 ipc_port_t notify_port;
2065 ipc_entry_t entry;
2066 kern_return_t kr;
2067
2068 /*
2069 * Handling notify (for MACH_RCV_NOTIFY) is tricky.
2070 * The problem is atomically making a send-once right
2071 * from the notify port and installing it for a
2072 * dead-name request in the new entry, because this
2073 * requires two port locks (on the notify port and
2074 * the reply port). However, we can safely make
2075 * and consume send-once rights for the notify port
2076 * as long as we hold the space locked. This isn't
2077 * an atomicity problem, because the only way
2078 * to detect that a send-once right has been created
2079 * and then consumed if it wasn't needed is by getting
2080 * at the receive right to look at ip_sorights, and
2081 * because the space is write-locked status calls can't
2082 * lookup the notify port receive right. When we make
2083 * the send-once right, we lock the notify port,
2084 * so any status calls in progress will be done.
2085 */
2086
2087 is_write_lock(space);
2088
2089 for (;;) {
2090 ipc_port_request_index_t request;
2091
2092 if (!space->is_active) {
2093 is_write_unlock(space);
2094 return (MACH_RCV_HEADER_ERROR|
2095 MACH_MSG_IPC_SPACE);
2096 }
2097
2098 if (notify != MACH_PORT_NULL) {
2099 notify_port = ipc_port_lookup_notify(space,
2100 notify);
2101 if (notify_port == IP_NULL) {
2102 is_write_unlock(space);
2103 return MACH_RCV_INVALID_NOTIFY;
2104 }
2105 } else
2106 notify_port = IP_NULL;
2107
2108 if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
2109 ipc_right_reverse(space, (ipc_object_t) reply,
2110 &reply_name, &entry)) {
2111 /* reply port is locked and active */
2112
2113 /*
2114 * We don't need the notify_port
2115 * send-once right, but we can't release
2116 * it here because reply port is locked.
2117 * Wait until after the copyout to
2118 * release the notify port right.
2119 */
2120
2121 assert(entry->ie_bits &
2122 MACH_PORT_TYPE_SEND_RECEIVE);
2123 break;
2124 }
2125
2126 ip_lock(reply);
2127 if (!ip_active(reply)) {
2128 ip_release(reply);
2129 ip_check_unlock(reply);
2130
2131 if (notify_port != IP_NULL)
2132 ipc_port_release_sonce(notify_port);
2133
2134 ip_lock(dest);
2135 is_write_unlock(space);
2136
2137 reply = IP_DEAD;
2138 reply_name = MACH_PORT_DEAD;
2139 goto copyout_dest;
2140 }
2141
2142 reply_name = (mach_port_name_t)reply;
2143 kr = ipc_entry_get(space, &reply_name, &entry);
2144 if (kr != KERN_SUCCESS) {
2145 ip_unlock(reply);
2146
2147 if (notify_port != IP_NULL)
2148 ipc_port_release_sonce(notify_port);
2149
2150 /* space is locked */
2151 kr = ipc_entry_grow_table(space,
2152 ITS_SIZE_NONE);
2153 if (kr != KERN_SUCCESS) {
2154 /* space is unlocked */
2155
2156 if (kr == KERN_RESOURCE_SHORTAGE)
2157 return (MACH_RCV_HEADER_ERROR|
2158 MACH_MSG_IPC_KERNEL);
2159 else
2160 return (MACH_RCV_HEADER_ERROR|
2161 MACH_MSG_IPC_SPACE);
2162 }
2163 /* space is locked again; start over */
2164
2165 continue;
2166 }
2167 assert(IE_BITS_TYPE(entry->ie_bits) ==
2168 MACH_PORT_TYPE_NONE);
2169 assert(entry->ie_object == IO_NULL);
2170
2171 if (notify_port == IP_NULL) {
2172 /* not making a dead-name request */
2173
2174 entry->ie_object = (ipc_object_t) reply;
2175 break;
2176 }
2177
2178 kr = ipc_port_dnrequest(reply, reply_name,
2179 notify_port, &request);
2180 if (kr != KERN_SUCCESS) {
2181 ip_unlock(reply);
2182
2183 ipc_port_release_sonce(notify_port);
2184
2185 ipc_entry_dealloc(space, reply_name, entry);
2186 is_write_unlock(space);
2187
2188 ip_lock(reply);
2189 if (!ip_active(reply)) {
2190 /* will fail next time around loop */
2191
2192 ip_unlock(reply);
2193 is_write_lock(space);
2194 continue;
2195 }
2196
2197 kr = ipc_port_dngrow(reply, ITS_SIZE_NONE);
2198 /* port is unlocked */
2199 if (kr != KERN_SUCCESS)
2200 return (MACH_RCV_HEADER_ERROR|
2201 MACH_MSG_IPC_KERNEL);
2202
2203 is_write_lock(space);
2204 continue;
2205 }
2206
2207 notify_port = IP_NULL; /* don't release right below */
2208
2209 entry->ie_object = (ipc_object_t) reply;
2210 entry->ie_request = request;
2211 break;
2212 }
2213
2214 /* space and reply port are locked and active */
2215
2216 ip_reference(reply); /* hold onto the reply port */
2217
2218 kr = ipc_right_copyout(space, reply_name, entry,
2219 reply_type, TRUE, (ipc_object_t) reply);
2220 /* reply port is unlocked */
2221 assert(kr == KERN_SUCCESS);
2222
2223 if (notify_port != IP_NULL)
2224 ipc_port_release_sonce(notify_port);
2225
2226 ip_lock(dest);
2227 is_write_unlock(space);
2228 } else {
2229 /*
2230 * No reply port! This is an easy case.
2231 * We only need to have the space locked
2232 * when checking notify and when locking
2233 * the destination (to ensure atomicity).
2234 */
2235
2236 is_read_lock(space);
2237 if (!space->is_active) {
2238 is_read_unlock(space);
2239 return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
2240 }
2241
2242 if (notify != MACH_PORT_NULL) {
2243 ipc_entry_t entry;
2244
2245 /* must check notify even though it won't be used */
2246
2247 if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
2248 is_read_unlock(space);
2249 return MACH_RCV_INVALID_NOTIFY;
2250 }
2251
2252 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
2253 is_read_unlock(space);
2254 return MACH_RCV_INVALID_NOTIFY;
2255 }
2256 }
2257
2258 ip_lock(dest);
2259 is_read_unlock(space);
2260
2261 reply_name = (mach_port_name_t) reply;
2262 }
2263
2264 /*
2265 * At this point, the space is unlocked and the destination
2266 * port is locked. (Lock taken while space was locked.)
2267 * reply_name is taken care of; we still need dest_name.
2268 * We still hold a ref for reply (if it is valid).
2269 *
2270 * If the space holds receive rights for the destination,
2271 * we return its name for the right. Otherwise the task
2272 * managed to destroy or give away the receive right between
2273 * receiving the message and this copyout. If the destination
2274 * is dead, return MACH_PORT_DEAD, and if the receive right
2275 * exists somewhere else (another space, in transit)
2276 * return MACH_PORT_NULL.
2277 *
2278 * Making this copyout operation atomic with the previous
2279 * copyout of the reply port is a bit tricky. If there was
2280 * no real reply port (it wasn't IP_VALID) then this isn't
2281 * an issue. If the reply port was dead at copyout time,
2282 * then we are OK, because if dest is dead we serialize
2283 * after the death of both ports and if dest is alive
2284 * we serialize after reply died but before dest's (later) death.
2285 * So assume reply was alive when we copied it out. If dest
2286 * is alive, then we are OK because we serialize before
2287 * the ports' deaths. So assume dest is dead when we look at it.
2288 * If reply dies/died after dest, then we are OK because
2289 * we serialize after dest died but before reply dies.
2290 * So the hard case is when reply is alive at copyout,
2291 * dest is dead at copyout, and reply died before dest died.
2292 * In this case pretend that dest is still alive, so
2293 * we serialize while both ports are alive.
2294 *
2295 * Because the space lock is held across the copyout of reply
2296 * and locking dest, the receive right for dest can't move
2297 * in or out of the space while the copyouts happen, so
2298 * that isn't an atomicity problem. In the last hard case
2299 * above, this implies that when dest is dead that the
2300 * space couldn't have had receive rights for dest at
2301 * the time reply was copied-out, so when we pretend
2302 * that dest is still alive, we can return MACH_PORT_NULL.
2303 *
2304 * If dest == reply, then we have to make it look like
2305 * either both copyouts happened before the port died,
2306 * or both happened after the port died. This special
2307 * case works naturally if the timestamp comparison
2308 * is done correctly.
2309 */
2310
2311 copyout_dest:
2312
2313 if (ip_active(dest)) {
2314 ipc_object_copyout_dest(space, (ipc_object_t) dest,
2315 dest_type, &dest_name);
2316 /* dest is unlocked */
2317 } else {
2318 ipc_port_timestamp_t timestamp;
2319
2320 timestamp = dest->ip_timestamp;
2321 ip_release(dest);
2322 ip_check_unlock(dest);
2323
2324 if (IP_VALID(reply)) {
2325 ip_lock(reply);
2326 if (ip_active(reply) ||
2327 IP_TIMESTAMP_ORDER(timestamp,
2328 reply->ip_timestamp))
2329 dest_name = MACH_PORT_DEAD;
2330 else
2331 dest_name = MACH_PORT_NULL;
2332 ip_unlock(reply);
2333 } else
2334 dest_name = MACH_PORT_DEAD;
2335 }
2336
2337 if (IP_VALID(reply))
2338 ipc_port_release(reply);
2339
2340 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2341 MACH_MSGH_BITS(reply_type, dest_type));
2342 msg->msgh_local_port = (ipc_port_t)dest_name;
2343 msg->msgh_remote_port = (ipc_port_t)reply_name;
2344 }
2345
2346 return MACH_MSG_SUCCESS;
2347}
2348
2349/*
2350 * Routine: ipc_kmsg_copyout_object
2351 * Purpose:
2352 * Copy-out a port right. Always returns a name,
2353 * even for unsuccessful return codes. Always
2354 * consumes the supplied object.
2355 * Conditions:
2356 * Nothing locked.
2357 * Returns:
2358 * MACH_MSG_SUCCESS The space acquired the right
2359 * (name is valid) or the object is dead (MACH_PORT_DEAD).
2360 * MACH_MSG_IPC_SPACE No room in space for the right,
2361 * or the space is dead. (Name is MACH_PORT_NULL.)
2362 * MACH_MSG_IPC_KERNEL Kernel resource shortage.
2363 * (Name is MACH_PORT_NULL.)
2364 */
2365
2366mach_msg_return_t
2367ipc_kmsg_copyout_object(
2368 ipc_space_t space,
2369 ipc_object_t object,
2370 mach_msg_type_name_t msgt_name,
2371 mach_port_name_t *namep)
2372{
2373 kern_return_t kr;
2374
2375 if (!IO_VALID(object)) {
2376 *namep = (mach_port_name_t) object;
2377 return MACH_MSG_SUCCESS;
2378 }
2379
2380 kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
2381 if (kr != KERN_SUCCESS) {
2382 ipc_object_destroy(object, msgt_name);
2383
2384 if (kr == KERN_INVALID_CAPABILITY)
2385 *namep = MACH_PORT_DEAD;
2386 else {
2387 *namep = MACH_PORT_NULL;
2388
2389 if (kr == KERN_RESOURCE_SHORTAGE)
2390 return MACH_MSG_IPC_KERNEL;
2391 else
2392 return MACH_MSG_IPC_SPACE;
2393 }
2394 }
2395
2396 return MACH_MSG_SUCCESS;
2397}
2398
2399/*
2400 * Routine: ipc_kmsg_copyout_body
2401 * Purpose:
2402 * "Copy-out" port rights and out-of-line memory
2403 * in the body of a message.
2404 *
2405 * The error codes are a combination of special bits.
2406 * The copyout proceeds despite errors.
2407 * Conditions:
2408 * Nothing locked.
2409 * Returns:
2410 * MACH_MSG_SUCCESS Successful copyout.
2411 * MACH_MSG_IPC_SPACE No room for port right in name space.
2412 * MACH_MSG_VM_SPACE No room for memory in address space.
2413 * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2414 * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2415 * MACH_MSG_INVALID_RT_DESCRIPTOR Descriptor incompatible with RT
2416 */
2417
2418mach_msg_return_t
2419ipc_kmsg_copyout_body(
2420 ipc_kmsg_t kmsg,
2421 ipc_space_t space,
2422 vm_map_t map,
2423 mach_msg_body_t *slist)
2424{
2425 mach_msg_body_t *body;
91447636
A
2426 mach_msg_descriptor_t *daddr, *naddr;
2427 mach_msg_descriptor_t *saddr;
2428 mach_msg_type_number_t i, dsc_count, sdsc_count;
1c79356b
A
2429 mach_msg_return_t mr = MACH_MSG_SUCCESS;
2430 kern_return_t kr;
91447636
A
2431 void *data;
2432 boolean_t differs = MAP_SIZE_DIFFERS(map);
1c79356b 2433
91447636
A
2434 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
2435 dsc_count = body->msgh_descriptor_count;
2436 daddr = (mach_msg_descriptor_t *) (body + 1);
1c79356b
A
2437
2438 /*
2439 * Do scatter list setup
2440 */
2441 if (slist != MACH_MSG_BODY_NULL) {
91447636
A
2442 saddr = (mach_msg_descriptor_t *) (slist + 1);
2443 sdsc_count = slist->msgh_descriptor_count;
1c79356b
A
2444 }
2445 else {
91447636
A
2446 saddr = MACH_MSG_DESCRIPTOR_NULL;
2447 sdsc_count = 0;
1c79356b
A
2448 }
2449
91447636
A
2450 /*
2451 * Compute the true size of the resulting descriptors
2452 * after potential expansion and adjust the header
2453 * and body location accordingly.
2454 */
2455 if (differs) {
2456 mach_msg_size_t dsc_adjust;
2457
2458 naddr = daddr;
2459 dsc_adjust = 0;
2460 for (i = 0; i < dsc_count; i++, naddr++)
2461 switch (naddr->type.type) {
2462 case MACH_MSG_OOL_DESCRIPTOR:
2463 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
2464 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2465 dsc_adjust += DESC_SIZE_ADJUSTMENT;
2466 break;
2467 default:
2468 break;
2469 }
2470 if (dsc_adjust) {
2471 mach_msg_base_t *old_base = (mach_msg_base_t *)kmsg->ikm_header;
2472 mach_msg_base_t *new_base;
2473
2474 new_base = (mach_msg_base_t *)((vm_offset_t)old_base - dsc_adjust);
2475 memmove(new_base, old_base, sizeof(mach_msg_base_t));
2476 kmsg->ikm_header = &new_base->header;
2477 kmsg->ikm_header->msgh_size += dsc_adjust;
2478 naddr = (mach_msg_descriptor_t *)(new_base + 1);
2479 } else {
2480 naddr = daddr;
2481 }
2482 } else {
2483 naddr = daddr;
2484 }
2485
2486 /*
2487 * Now process the descriptors
2488 */
2489 for ( i = 0; i < dsc_count; i++, daddr++ ) {
2490 switch (daddr->type.type) {
1c79356b
A
2491
2492 case MACH_MSG_PORT_DESCRIPTOR: {
91447636
A
2493 volatile mach_msg_port_descriptor_t *dsc;
2494 volatile mach_msg_port_descriptor_t *user_dsc;
2495 mach_port_t port;
2496 mach_port_name_t name;
2497 mach_msg_type_name_t disp;
1c79356b
A
2498
2499 /*
2500 * Copyout port right carried in the message
2501 */
91447636
A
2502 dsc = &daddr->port;
2503 user_dsc = &naddr->port;
2504 port = dsc->name;
2505 disp = dsc->disposition;
1c79356b 2506 mr |= ipc_kmsg_copyout_object(space,
91447636
A
2507 (ipc_object_t)port,
2508 disp,
2509 &name);
2510 user_dsc->name = (mach_port_t)name;
2511 user_dsc->disposition = disp;
2512 user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
2513 naddr++;
1c79356b
A
2514 break;
2515 }
91447636 2516
1c79356b
A
2517 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
2518 case MACH_MSG_OOL_DESCRIPTOR : {
91447636
A
2519 vm_map_copy_t copy;
2520 mach_vm_offset_t rcv_addr;
1c79356b 2521 mach_msg_ool_descriptor_t *dsc;
91447636
A
2522 mach_msg_copy_options_t copy_options;
2523 mach_msg_size_t size;
2524 mach_msg_descriptor_type_t dsc_type;
1c79356b 2525
91447636 2526 SKIP_PORT_DESCRIPTORS(saddr, sdsc_count);
1c79356b 2527
91447636
A
2528 dsc = &daddr->out_of_line;
2529 copy = (vm_map_copy_t) dsc->address;
2530 size = dsc->size;
2531 copy_options = dsc->copy;
2532 assert(copy_options != MACH_MSG_KALLOC_COPY_T);
2533 dsc_type = dsc->type;
1c79356b 2534
91447636
A
2535 if (copy != VM_MAP_COPY_NULL) {
2536 /*
2537 * Check to see if there is an overwrite descriptor
2538 * specified in the scatter list for this ool data.
2539 * The descriptor has already been verified.
2540 */
2541 if (saddr != MACH_MSG_DESCRIPTOR_NULL) {
2542 if (differs) {
2543 OTHER_OOL_DESCRIPTOR *scatter_dsc;
2544
2545 scatter_dsc = (OTHER_OOL_DESCRIPTOR *)saddr;
2546 if (scatter_dsc->copy == MACH_MSG_OVERWRITE) {
2547 rcv_addr = (mach_vm_offset_t) scatter_dsc->address;
2548 copy_options = MACH_MSG_OVERWRITE;
2549 } else {
2550 rcv_addr = 0;
2551 copy_options = MACH_MSG_VIRTUAL_COPY;
2552 }
2553 } else {
2554 mach_msg_ool_descriptor_t *scatter_dsc;
1c79356b 2555
91447636
A
2556 scatter_dsc = &saddr->out_of_line;
2557 if (scatter_dsc->copy == MACH_MSG_OVERWRITE) {
2558 rcv_addr = CAST_USER_ADDR_T(scatter_dsc->address);
2559 copy_options = MACH_MSG_OVERWRITE;
2560 } else {
2561 rcv_addr = 0;
2562 copy_options = MACH_MSG_VIRTUAL_COPY;
2563 }
2564 }
2565 INCREMENT_SCATTER(saddr, sdsc_count, differs);
1c79356b
A
2566 }
2567
91447636 2568
1c79356b
A
2569 /*
2570 * Whether the data was virtually or physically
2571 * copied we have a vm_map_copy_t for it.
2572 * If there's an overwrite region specified
2573 * overwrite it, otherwise do a virtual copy out.
2574 */
91447636 2575 if (copy_options == MACH_MSG_OVERWRITE) {
1c79356b 2576 kr = vm_map_copy_overwrite(map, rcv_addr,
91447636 2577 copy, TRUE);
1c79356b 2578 } else {
91447636 2579 kr = vm_map_copyout(map, &rcv_addr, copy);
1c79356b
A
2580 }
2581 if (kr != KERN_SUCCESS) {
2582 if (kr == KERN_RESOURCE_SHORTAGE)
2583 mr |= MACH_MSG_VM_KERNEL;
2584 else
2585 mr |= MACH_MSG_VM_SPACE;
91447636
A
2586 vm_map_copy_discard(copy);
2587 rcv_addr = 0;
2588 size = 0;
1c79356b 2589 }
91447636
A
2590 } else {
2591 rcv_addr = 0;
2592 size = 0;
2593 }
2594
2595 /*
2596 * Now update the descriptor as the user would see it.
2597 * This may require expanding the descriptor to the user
2598 * visible size. There is already space allocated for
2599 * this in what naddr points to.
2600 */
2601 if (differs) {
2602 volatile OTHER_OOL_DESCRIPTOR *user_dsc;
2603
2604 user_dsc = (OTHER_OOL_DESCRIPTOR *)naddr;
2605 user_dsc->address = rcv_addr;
2606 user_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
2607 TRUE : FALSE;
2608 user_dsc->copy = copy_options;
2609 user_dsc->type = dsc_type;
2610 user_dsc->size = size;
2611 naddr = (mach_msg_descriptor_t *)((OTHER_OOL_DESCRIPTOR *)naddr + 1);
2612 } else {
2613 volatile mach_msg_ool_descriptor_t *user_dsc;
2614
2615 user_dsc = &naddr->out_of_line;
2616 user_dsc->address = CAST_DOWN(void *, rcv_addr);
2617 user_dsc->size = size;
2618 user_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
2619 TRUE : FALSE;
2620 user_dsc->copy = copy_options;
2621 user_dsc->type = dsc_type;
2622 naddr++;
1c79356b 2623 }
1c79356b
A
2624 break;
2625 }
91447636 2626
1c79356b 2627 case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
91447636 2628 mach_vm_offset_t rcv_addr;
1c79356b 2629 mach_port_name_t *objects;
91447636
A
2630 mach_msg_type_name_t disp;
2631 mach_msg_type_number_t count, j;
1c79356b 2632 vm_size_t length;
1c79356b 2633
91447636
A
2634 volatile mach_msg_ool_ports_descriptor_t *dsc;
2635 mach_msg_copy_options_t copy_options = MACH_MSG_VIRTUAL_COPY;
1c79356b 2636
91447636 2637 SKIP_PORT_DESCRIPTORS(saddr, sdsc_count);
1c79356b 2638
91447636
A
2639 dsc = &daddr->ool_ports;
2640 count = dsc->count;
2641 disp = dsc->disposition;
2642 length = count * sizeof(mach_port_name_t);
1c79356b 2643
91447636 2644 if (length != 0 && dsc->address != 0) {
1c79356b 2645
91447636
A
2646 /*
2647 * Check to see if there is an overwrite descriptor
2648 * specified in the scatter list for this ool data.
2649 * The descriptor has already been verified.
2650 */
2651 if (saddr != MACH_MSG_DESCRIPTOR_NULL) {
2652 if (differs) {
2653 OTHER_OOL_DESCRIPTOR *scatter_dsc;
2654
2655 scatter_dsc = (OTHER_OOL_DESCRIPTOR *)saddr;
2656 rcv_addr = (mach_vm_offset_t) scatter_dsc->address;
2657 copy_options = scatter_dsc->copy;
2658 } else {
2659 mach_msg_ool_descriptor_t *scatter_dsc;
1c79356b 2660
91447636
A
2661 scatter_dsc = &saddr->out_of_line;
2662 rcv_addr = CAST_USER_ADDR_T(scatter_dsc->address);
2663 copy_options = scatter_dsc->copy;
2664 }
2665 INCREMENT_SCATTER(saddr, sdsc_count, differs);
2666 }
2667
2668 if (copy_options == MACH_MSG_VIRTUAL_COPY) {
1c79356b
A
2669 /*
2670 * Dynamically allocate the region
2671 */
2672 int anywhere = VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|
2673 VM_FLAGS_ANYWHERE;
2674
91447636
A
2675 if ((kr = mach_vm_allocate(map, &rcv_addr,
2676 (mach_vm_size_t)length,
1c79356b 2677 anywhere)) != KERN_SUCCESS) {
91447636
A
2678 ipc_kmsg_clean_body(kmsg, 1, daddr);
2679 rcv_addr = 0;
1c79356b
A
2680
2681 if (kr == KERN_RESOURCE_SHORTAGE){
2682 mr |= MACH_MSG_VM_KERNEL;
2683 } else {
2684 mr |= MACH_MSG_VM_SPACE;
2685 }
91447636 2686 }
1c79356b 2687 }
1c79356b 2688
91447636
A
2689
2690 /*
2691 * Handle the port rights and copy out the names
2692 * for those rights out to user-space.
2693 */
2694 if (rcv_addr != 0) {
2695 objects = (mach_port_name_t *) dsc->address ;
1c79356b 2696
91447636 2697 /* copyout port rights carried in the message */
1c79356b 2698
91447636
A
2699 for ( j = 0; j < count ; j++) {
2700 ipc_object_t object =
2701 (ipc_object_t) objects[j];
1c79356b 2702
91447636
A
2703 mr |= ipc_kmsg_copyout_object(space, object,
2704 disp, &objects[j]);
2705 }
2706
2707 /* copyout to memory allocated above */
2708 data = dsc->address;
2709 if (copyoutmap(map, data, rcv_addr, length) != KERN_SUCCESS)
2710 mr |= MACH_MSG_VM_SPACE;
2711 kfree(data, length);
2712 }
2713 } else {
2714 rcv_addr = 0;
1c79356b
A
2715 }
2716
91447636
A
2717 /*
2718 * Now update the descriptor based on the information
2719 * calculated above.
2720 */
2721 if (differs) {
2722 volatile OTHER_OOL_PORTS_DESCRIPTOR *user_dsc;
2723
2724 user_dsc = (OTHER_OOL_PORTS_DESCRIPTOR *)naddr;
2725 user_dsc->address = rcv_addr;
2726 user_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
2727 TRUE : FALSE;
2728 user_dsc->copy = copy_options;
2729 user_dsc->disposition = disp;
2730 user_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
2731 user_dsc->count = count;
2732 naddr = (mach_msg_descriptor_t *)((OTHER_OOL_PORTS_DESCRIPTOR *)naddr + 1);
2733 } else {
2734 volatile mach_msg_ool_ports_descriptor_t *user_dsc;
2735
2736 user_dsc = &naddr->ool_ports;
2737 user_dsc->address = CAST_DOWN(void *, rcv_addr);
2738 user_dsc->count = count;
2739 user_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
2740 TRUE : FALSE;
2741 user_dsc->copy = copy_options;
2742 user_dsc->disposition = disp;
2743 user_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
2744 naddr++;
2745 }
1c79356b
A
2746 break;
2747 }
2748 default : {
2749 panic("untyped IPC copyout body: invalid message descriptor");
2750 }
2751 }
2752 }
2753 return mr;
2754}
2755
91447636
A
2756/*
2757 * Routine: ipc_kmsg_copyout_size
2758 * Purpose:
2759 * Compute the size of the message as copied out to the given
2760 * map. If the destination map's pointers are a different size
2761 * than the kernel's, we have to allow for expansion/
2762 * contraction of the descriptors as appropriate.
2763 * Conditions:
2764 * Nothing locked.
2765 * Returns:
2766 * size of the message as it would be received.
2767 */
2768
2769mach_msg_size_t
2770ipc_kmsg_copyout_size(
2771 ipc_kmsg_t kmsg,
2772 vm_map_t map)
2773{
2774 mach_msg_size_t send_size;
2775
2776 send_size = kmsg->ikm_header->msgh_size;
2777
2778 if ((kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
2779 MAP_SIZE_DIFFERS(map)) {
2780
2781 mach_msg_body_t *body;
2782 mach_msg_descriptor_t *saddr, *eaddr;
2783
2784 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
2785 saddr = (mach_msg_descriptor_t *) (body + 1);
2786 eaddr = saddr + body->msgh_descriptor_count;
2787
2788 for ( ; saddr < eaddr; saddr++ ) {
2789 switch (saddr->type.type) {
2790
2791 case MACH_MSG_OOL_DESCRIPTOR:
2792 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
2793 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2794 send_size += DESC_SIZE_ADJUSTMENT;
2795 break;
2796
2797 default:
2798 break;
2799 }
2800 }
2801 }
2802 return send_size;
2803}
2804
1c79356b
A
2805/*
2806 * Routine: ipc_kmsg_copyout
2807 * Purpose:
2808 * "Copy-out" port rights and out-of-line memory
2809 * in the message.
2810 * Conditions:
2811 * Nothing locked.
2812 * Returns:
2813 * MACH_MSG_SUCCESS Copied out all rights and memory.
2814 * MACH_RCV_INVALID_NOTIFY Bad notify port.
2815 * Rights and memory in the message are intact.
2816 * MACH_RCV_HEADER_ERROR + special bits
2817 * Rights and memory in the message are intact.
2818 * MACH_RCV_BODY_ERROR + special bits
2819 * The message header was successfully copied out.
2820 * As much of the body was handled as possible.
2821 */
2822
2823mach_msg_return_t
2824ipc_kmsg_copyout(
2825 ipc_kmsg_t kmsg,
2826 ipc_space_t space,
2827 vm_map_t map,
2828 mach_port_name_t notify,
2829 mach_msg_body_t *slist)
2830{
2831 mach_msg_return_t mr;
2832
91447636 2833 mr = ipc_kmsg_copyout_header(kmsg->ikm_header, space, notify);
1c79356b
A
2834 if (mr != MACH_MSG_SUCCESS)
2835 return mr;
2836
91447636 2837 if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1c79356b
A
2838 mr = ipc_kmsg_copyout_body(kmsg, space, map, slist);
2839
2840 if (mr != MACH_MSG_SUCCESS)
2841 mr |= MACH_RCV_BODY_ERROR;
2842 }
2843
2844 return mr;
2845}
2846
2847/*
2848 * Routine: ipc_kmsg_copyout_pseudo
2849 * Purpose:
2850 * Does a pseudo-copyout of the message.
2851 * This is like a regular copyout, except
2852 * that the ports in the header are handled
2853 * as if they are in the body. They aren't reversed.
2854 *
2855 * The error codes are a combination of special bits.
2856 * The copyout proceeds despite errors.
2857 * Conditions:
2858 * Nothing locked.
2859 * Returns:
2860 * MACH_MSG_SUCCESS Successful copyout.
2861 * MACH_MSG_IPC_SPACE No room for port right in name space.
2862 * MACH_MSG_VM_SPACE No room for memory in address space.
2863 * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2864 * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2865 */
2866
2867mach_msg_return_t
2868ipc_kmsg_copyout_pseudo(
2869 ipc_kmsg_t kmsg,
2870 ipc_space_t space,
2871 vm_map_t map,
2872 mach_msg_body_t *slist)
2873{
91447636
A
2874 mach_msg_bits_t mbits = kmsg->ikm_header->msgh_bits;
2875 ipc_object_t dest = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
2876 ipc_object_t reply = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
1c79356b
A
2877 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2878 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2879 mach_port_name_t dest_name, reply_name;
2880 mach_msg_return_t mr;
2881
2882 assert(IO_VALID(dest));
2883
2884 mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
2885 ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
2886
91447636
A
2887 kmsg->ikm_header->msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
2888 kmsg->ikm_header->msgh_remote_port = (ipc_port_t)dest_name;
2889 kmsg->ikm_header->msgh_local_port = (ipc_port_t)reply_name;
1c79356b
A
2890
2891 if (mbits & MACH_MSGH_BITS_COMPLEX) {
2892 mr |= ipc_kmsg_copyout_body(kmsg, space, map, slist);
2893 }
2894
2895 return mr;
2896}
2897
2898/*
2899 * Routine: ipc_kmsg_copyout_dest
2900 * Purpose:
2901 * Copies out the destination port in the message.
2902 * Destroys all other rights and memory in the message.
2903 * Conditions:
2904 * Nothing locked.
2905 */
2906
2907void
2908ipc_kmsg_copyout_dest(
2909 ipc_kmsg_t kmsg,
2910 ipc_space_t space)
2911{
2912 mach_msg_bits_t mbits;
2913 ipc_object_t dest;
2914 ipc_object_t reply;
2915 mach_msg_type_name_t dest_type;
2916 mach_msg_type_name_t reply_type;
2917 mach_port_name_t dest_name, reply_name;
2918
91447636
A
2919 mbits = kmsg->ikm_header->msgh_bits;
2920 dest = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
2921 reply = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
1c79356b
A
2922 dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2923 reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2924
2925 assert(IO_VALID(dest));
2926
2927 io_lock(dest);
2928 if (io_active(dest)) {
2929 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
2930 /* dest is unlocked */
2931 } else {
2932 io_release(dest);
2933 io_check_unlock(dest);
2934 dest_name = MACH_PORT_DEAD;
2935 }
2936
2937 if (IO_VALID(reply)) {
2938 ipc_object_destroy(reply, reply_type);
2939 reply_name = MACH_PORT_NULL;
2940 } else
2941 reply_name = (mach_port_name_t) reply;
2942
91447636 2943 kmsg->ikm_header->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1c79356b 2944 MACH_MSGH_BITS(reply_type, dest_type));
91447636
A
2945 kmsg->ikm_header->msgh_local_port = (ipc_port_t)dest_name;
2946 kmsg->ikm_header->msgh_remote_port = (ipc_port_t)reply_name;
1c79356b
A
2947
2948 if (mbits & MACH_MSGH_BITS_COMPLEX) {
2949 mach_msg_body_t *body;
2950
91447636
A
2951 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
2952 ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count,
2953 (mach_msg_descriptor_t *)(body + 1));
1c79356b
A
2954 }
2955}
91447636 2956
1c79356b
A
2957/*
2958 * Routine: ipc_kmsg_copyin_scatter
2959 * Purpose:
2960 * allocate and copyin a scatter list
2961 * Algorithm:
2962 * The gather (kmsg) is valid since it has been copied in.
2963 * Gather list descriptors are sequentially paired with scatter
2964 * list descriptors, with port descriptors in either list ignored.
2965 * Descriptors are consistent if the type fileds match and size
2966 * of the scatter descriptor is less than or equal to the
2967 * size of the gather descriptor. A MACH_MSG_ALLOCATE copy
2968 * strategy in a scatter descriptor matches any size in the
2969 * corresponding gather descriptor assuming they are the same type.
2970 * Either list may be larger than the other. During the
2971 * subsequent copy out, excess scatter descriptors are ignored
2972 * and excess gather descriptors default to dynamic allocation.
2973 *
2974 * In the case of a size error, the scatter list is released.
2975 * Conditions:
2976 * Nothing locked.
2977 * Returns:
2978 * the allocated message body containing the scatter list.
2979 */
2980
2981mach_msg_body_t *
91447636
A
2982ipc_kmsg_get_scatter(
2983 mach_vm_address_t msg_addr,
2984 mach_msg_size_t slist_size,
2985 ipc_kmsg_t kmsg)
1c79356b
A
2986{
2987 mach_msg_body_t *slist;
2988 mach_msg_body_t *body;
2989 mach_msg_descriptor_t *gstart, *gend;
2990 mach_msg_descriptor_t *sstart, *send;
2991
2992
2993 if (slist_size < sizeof(mach_msg_base_t))
2994 return MACH_MSG_BODY_NULL;
2995
2996 slist_size -= sizeof(mach_msg_header_t);
2997 slist = (mach_msg_body_t *)kalloc(slist_size);
2998 if (slist == MACH_MSG_BODY_NULL)
2999 return slist;
3000
91447636
A
3001 if (copyin(msg_addr + sizeof(mach_msg_header_t), (char *)slist, slist_size)) {
3002 kfree(slist, slist_size);
1c79356b
A
3003 return MACH_MSG_BODY_NULL;
3004 }
3005
3006 if ((slist->msgh_descriptor_count* sizeof(mach_msg_descriptor_t)
3007 + sizeof(mach_msg_size_t)) > slist_size) {
91447636 3008 kfree(slist, slist_size);
1c79356b
A
3009 return MACH_MSG_BODY_NULL;
3010 }
3011
91447636 3012 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
1c79356b
A
3013 gstart = (mach_msg_descriptor_t *) (body + 1);
3014 gend = gstart + body->msgh_descriptor_count;
3015
3016 sstart = (mach_msg_descriptor_t *) (slist + 1);
3017 send = sstart + slist->msgh_descriptor_count;
3018
3019 while (gstart < gend) {
3020 mach_msg_descriptor_type_t g_type;
3021
3022 /*
3023 * Skip port descriptors in gather list.
3024 */
3025 g_type = gstart->type.type;
3026
3027 if (g_type != MACH_MSG_PORT_DESCRIPTOR) {
3028
3029 /*
3030 * A scatter list with a 0 descriptor count is treated as an
3031 * automatic size mismatch.
3032 */
3033 if (slist->msgh_descriptor_count == 0) {
91447636 3034 kfree(slist, slist_size);
1c79356b
A
3035 return MACH_MSG_BODY_NULL;
3036 }
3037
3038 /*
3039 * Skip port descriptors in scatter list.
3040 */
3041 while (sstart < send) {
3042 if (sstart->type.type != MACH_MSG_PORT_DESCRIPTOR)
3043 break;
3044 sstart++;
3045 }
3046
3047 /*
3048 * No more scatter descriptors, we're done
3049 */
3050 if (sstart >= send) {
3051 break;
3052 }
3053
3054 /*
3055 * Check type, copy and size fields
3056 */
3057 if (g_type == MACH_MSG_OOL_DESCRIPTOR ||
3058 g_type == MACH_MSG_OOL_VOLATILE_DESCRIPTOR) {
3059 if (sstart->type.type != MACH_MSG_OOL_DESCRIPTOR &&
3060 sstart->type.type != MACH_MSG_OOL_VOLATILE_DESCRIPTOR) {
91447636 3061 kfree(slist, slist_size);
1c79356b
A
3062 return MACH_MSG_BODY_NULL;
3063 }
3064 if (sstart->out_of_line.copy == MACH_MSG_OVERWRITE &&
3065 gstart->out_of_line.size > sstart->out_of_line.size) {
91447636 3066 kfree(slist, slist_size);
1c79356b
A
3067 return MACH_MSG_BODY_NULL;
3068 }
3069 }
3070 else {
3071 if (sstart->type.type != MACH_MSG_OOL_PORTS_DESCRIPTOR) {
91447636 3072 kfree(slist, slist_size);
1c79356b
A
3073 return MACH_MSG_BODY_NULL;
3074 }
3075 if (sstart->ool_ports.copy == MACH_MSG_OVERWRITE &&
3076 gstart->ool_ports.count > sstart->ool_ports.count) {
91447636 3077 kfree(slist, slist_size);
1c79356b
A
3078 return MACH_MSG_BODY_NULL;
3079 }
3080 }
3081 sstart++;
3082 }
3083 gstart++;
3084 }
3085 return slist;
3086}
3087
3088
3089/*
3090 * Routine: ipc_kmsg_free_scatter
3091 * Purpose:
3092 * Deallocate a scatter list. Since we actually allocated
3093 * a body without a header, and since the header was originally
3094 * accounted for in slist_size, we have to ajust it down
3095 * before freeing the scatter list.
3096 */
3097void
3098ipc_kmsg_free_scatter(
3099 mach_msg_body_t *slist,
3100 mach_msg_size_t slist_size)
3101{
3102 slist_size -= sizeof(mach_msg_header_t);
91447636 3103 kfree(slist, slist_size);
1c79356b
A
3104}
3105
3106
3107/*
3108 * Routine: ipc_kmsg_copyout_to_kernel
3109 * Purpose:
3110 * Copies out the destination and reply ports in the message.
3111 * Leaves all other rights and memory in the message alone.
3112 * Conditions:
3113 * Nothing locked.
3114 *
3115 * Derived from ipc_kmsg_copyout_dest.
3116 * Use by mach_msg_rpc_from_kernel (which used to use copyout_dest).
3117 * We really do want to save rights and memory.
3118 */
3119
3120void
3121ipc_kmsg_copyout_to_kernel(
3122 ipc_kmsg_t kmsg,
3123 ipc_space_t space)
3124{
3125 ipc_object_t dest;
3126 ipc_object_t reply;
3127 mach_msg_type_name_t dest_type;
3128 mach_msg_type_name_t reply_type;
3129 mach_port_name_t dest_name, reply_name;
3130
91447636
A
3131 dest = (ipc_object_t) kmsg->ikm_header->msgh_remote_port;
3132 reply = (ipc_object_t) kmsg->ikm_header->msgh_local_port;
3133 dest_type = MACH_MSGH_BITS_REMOTE(kmsg->ikm_header->msgh_bits);
3134 reply_type = MACH_MSGH_BITS_LOCAL(kmsg->ikm_header->msgh_bits);
1c79356b
A
3135
3136 assert(IO_VALID(dest));
3137
3138 io_lock(dest);
3139 if (io_active(dest)) {
3140 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
3141 /* dest is unlocked */
3142 } else {
3143 io_release(dest);
3144 io_check_unlock(dest);
3145 dest_name = MACH_PORT_DEAD;
3146 }
3147
3148 reply_name = (mach_port_name_t) reply;
3149
91447636
A
3150 kmsg->ikm_header->msgh_bits =
3151 (MACH_MSGH_BITS_OTHER(kmsg->ikm_header->msgh_bits) |
1c79356b 3152 MACH_MSGH_BITS(reply_type, dest_type));
91447636
A
3153 kmsg->ikm_header->msgh_local_port = (ipc_port_t)dest_name;
3154 kmsg->ikm_header->msgh_remote_port = (ipc_port_t)reply_name;
1c79356b
A
3155}
3156
3157#include <mach_kdb.h>
3158#if MACH_KDB
3159
3160#include <ddb/db_output.h>
3161#include <ipc/ipc_print.h>
3162/*
3163 * Forward declarations
3164 */
3165void ipc_msg_print_untyped(
3166 mach_msg_body_t *body);
3167
91447636 3168const char * ipc_type_name(
1c79356b
A
3169 int type_name,
3170 boolean_t received);
3171
3172void ipc_print_type_name(
3173 int type_name);
3174
91447636 3175const char *
1c79356b
A
3176msgh_bit_decode(
3177 mach_msg_bits_t bit);
3178
91447636 3179const char *
1c79356b
A
3180mm_copy_options_string(
3181 mach_msg_copy_options_t option);
3182
3183void db_print_msg_uid(mach_msg_header_t *);
3184
3185
91447636 3186const char *
1c79356b
A
3187ipc_type_name(
3188 int type_name,
3189 boolean_t received)
3190{
3191 switch (type_name) {
3192 case MACH_MSG_TYPE_PORT_NAME:
3193 return "port_name";
3194
3195 case MACH_MSG_TYPE_MOVE_RECEIVE:
3196 if (received) {
3197 return "port_receive";
3198 } else {
3199 return "move_receive";
3200 }
3201
3202 case MACH_MSG_TYPE_MOVE_SEND:
3203 if (received) {
3204 return "port_send";
3205 } else {
3206 return "move_send";
3207 }
3208
3209 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
3210 if (received) {
3211 return "port_send_once";
3212 } else {
3213 return "move_send_once";
3214 }
3215
3216 case MACH_MSG_TYPE_COPY_SEND:
3217 return "copy_send";
3218
3219 case MACH_MSG_TYPE_MAKE_SEND:
3220 return "make_send";
3221
3222 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
3223 return "make_send_once";
3224
3225 default:
3226 return (char *) 0;
3227 }
3228}
3229
3230void
3231ipc_print_type_name(
3232 int type_name)
3233{
91447636 3234 const char *name = ipc_type_name(type_name, TRUE);
1c79356b
A
3235 if (name) {
3236 printf("%s", name);
3237 } else {
3238 printf("type%d", type_name);
3239 }
3240}
3241
3242/*
3243 * ipc_kmsg_print [ debug ]
3244 */
3245void
3246ipc_kmsg_print(
3247 ipc_kmsg_t kmsg)
3248{
3249 iprintf("kmsg=0x%x\n", kmsg);
3250 iprintf("ikm_next=0x%x, prev=0x%x, size=%d",
3251 kmsg->ikm_next,
3252 kmsg->ikm_prev,
3253 kmsg->ikm_size);
3254 printf("\n");
91447636 3255 ipc_msg_print(kmsg->ikm_header);
1c79356b
A
3256}
3257
91447636 3258const char *
1c79356b
A
3259msgh_bit_decode(
3260 mach_msg_bits_t bit)
3261{
3262 switch (bit) {
3263 case MACH_MSGH_BITS_COMPLEX: return "complex";
3264 case MACH_MSGH_BITS_CIRCULAR: return "circular";
3265 default: return (char *) 0;
3266 }
3267}
3268
3269/*
3270 * ipc_msg_print [ debug ]
3271 */
3272void
3273ipc_msg_print(
3274 mach_msg_header_t *msgh)
3275{
3276 mach_msg_bits_t mbits;
3277 unsigned int bit, i;
91447636 3278 const char *bit_name;
1c79356b
A
3279 int needs_comma;
3280
3281 mbits = msgh->msgh_bits;
3282 iprintf("msgh_bits=0x%x: l=0x%x,r=0x%x\n",
3283 mbits,
3284 MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
3285 MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
3286
3287 mbits = MACH_MSGH_BITS_OTHER(mbits) & MACH_MSGH_BITS_USED;
3288 db_indent += 2;
3289 if (mbits)
3290 iprintf("decoded bits: ");
3291 needs_comma = 0;
3292 for (i = 0, bit = 1; i < sizeof(mbits) * 8; ++i, bit <<= 1) {
3293 if ((mbits & bit) == 0)
3294 continue;
3295 bit_name = msgh_bit_decode((mach_msg_bits_t)bit);
3296 if (bit_name)
3297 printf("%s%s", needs_comma ? "," : "", bit_name);
3298 else
3299 printf("%sunknown(0x%x),", needs_comma ? "," : "", bit);
3300 ++needs_comma;
3301 }
3302 if (msgh->msgh_bits & ~MACH_MSGH_BITS_USED) {
3303 printf("%sunused=0x%x,", needs_comma ? "," : "",
3304 msgh->msgh_bits & ~MACH_MSGH_BITS_USED);
3305 }
3306 printf("\n");
3307 db_indent -= 2;
3308
3309 needs_comma = 1;
3310 if (msgh->msgh_remote_port) {
3311 iprintf("remote=0x%x(", msgh->msgh_remote_port);
3312 ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
3313 printf(")");
3314 } else {
3315 iprintf("remote=null");
3316 }
3317
3318 if (msgh->msgh_local_port) {
3319 printf("%slocal=0x%x(", needs_comma ? "," : "",
3320 msgh->msgh_local_port);
3321 ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
3322 printf(")\n");
3323 } else {
3324 printf("local=null\n");
3325 }
3326
3327 iprintf("msgh_id=%d, size=%d\n",
3328 msgh->msgh_id,
3329 msgh->msgh_size);
3330
3331 if (mbits & MACH_MSGH_BITS_COMPLEX) {
3332 ipc_msg_print_untyped((mach_msg_body_t *) (msgh + 1));
3333 }
3334}
3335
3336
91447636 3337const char *
1c79356b
A
3338mm_copy_options_string(
3339 mach_msg_copy_options_t option)
3340{
91447636 3341 const char *name;
1c79356b
A
3342
3343 switch (option) {
3344 case MACH_MSG_PHYSICAL_COPY:
3345 name = "PHYSICAL";
3346 break;
3347 case MACH_MSG_VIRTUAL_COPY:
3348 name = "VIRTUAL";
3349 break;
3350 case MACH_MSG_OVERWRITE:
3351 name = "OVERWRITE";
3352 break;
3353 case MACH_MSG_ALLOCATE:
3354 name = "ALLOCATE";
3355 break;
3356 case MACH_MSG_KALLOC_COPY_T:
3357 name = "KALLOC_COPY_T";
3358 break;
1c79356b
A
3359 default:
3360 name = "unknown";
3361 break;
3362 }
3363 return name;
3364}
3365
3366void
3367ipc_msg_print_untyped(
3368 mach_msg_body_t *body)
3369{
3370 mach_msg_descriptor_t *saddr, *send;
3371 mach_msg_descriptor_type_t type;
3372
3373 iprintf("%d descriptors %d: \n", body->msgh_descriptor_count);
3374
3375 saddr = (mach_msg_descriptor_t *) (body + 1);
3376 send = saddr + body->msgh_descriptor_count;
3377
3378 for ( ; saddr < send; saddr++ ) {
3379
3380 type = saddr->type.type;
3381
3382 switch (type) {
3383
3384 case MACH_MSG_PORT_DESCRIPTOR: {
3385 mach_msg_port_descriptor_t *dsc;
3386
3387 dsc = &saddr->port;
3388 iprintf("-- PORT name = 0x%x disp = ", dsc->name);
3389 ipc_print_type_name(dsc->disposition);
3390 printf("\n");
3391 break;
3392 }
3393 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
3394 case MACH_MSG_OOL_DESCRIPTOR: {
3395 mach_msg_ool_descriptor_t *dsc;
3396
3397 dsc = &saddr->out_of_line;
3398 iprintf("-- OOL%s addr = 0x%x size = 0x%x copy = %s %s\n",
3399 type == MACH_MSG_OOL_DESCRIPTOR ? "" : " VOLATILE",
3400 dsc->address, dsc->size,
3401 mm_copy_options_string(dsc->copy),
3402 dsc->deallocate ? "DEALLOC" : "");
3403 break;
3404 }
3405 case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
3406 mach_msg_ool_ports_descriptor_t *dsc;
3407
3408 dsc = &saddr->ool_ports;
3409
3410 iprintf("-- OOL_PORTS addr = 0x%x count = 0x%x ",
3411 dsc->address, dsc->count);
3412 printf("disp = ");
3413 ipc_print_type_name(dsc->disposition);
3414 printf(" copy = %s %s\n",
3415 mm_copy_options_string(dsc->copy),
3416 dsc->deallocate ? "DEALLOC" : "");
3417 break;
3418 }
3419
3420 default: {
3421 iprintf("-- UNKNOWN DESCRIPTOR 0x%x\n", type);
3422 break;
3423 }
3424 }
3425 }
3426}
3427#endif /* MACH_KDB */