1 /*
2 * Copyright 1991-1998 by Open Software Foundation, Inc.
3 * All Rights Reserved
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21 /*
22 * MkLinux
23 */
24 /* CMU_HIST */
25 /*
26 * Revision 2.16.3.2 92/03/03 16:19:04 jeffreyh
27 * Changes from TRUNK
28 * [92/02/26 11:52:59 jeffreyh]
29 *
30 * Revision 2.17 92/01/03 20:13:19 dbg
31 * Add quick dispatch to Mach Kernel messages.
32 * [91/12/18 dbg]
33 *
34 * Revision 2.16 91/12/14 14:28:41 jsb
35 * Removed ipc_fields.h hack.
36 *
37 * Revision 2.15 91/11/14 16:58:17 rpd
38 * Added ipc_fields.h hack.
39 * Use IP_NORMA_IS_PROXY macro instead of ipc_space_remote.
40 * [91/11/00 jsb]
41 *
42 * Revision 2.14 91/10/09 16:11:23 af
43 * Added <ipc/ipc_notify.h>. Fixed type-mismatch in msg_rpc_trap.
44 * [91/09/02 rpd]
45 *
46 * Revision 2.13 91/08/28 11:13:53 jsb
47 * Changed MACH_RCV_TOO_LARGE and MACH_RCV_INVALID_NOTIFY to work
48 * like MACH_RCV_HEADER_ERROR, using ipc_kmsg_copyout_dest.
49 * [91/08/12 rpd]
50 *
51 * Added seqno argument to ipc_mqueue_receive.
52 * Updated mach_msg_trap fast path for seqno processing.
53 * [91/08/10 rpd]
54 * Fixed mach_msg_interrupt to check for MACH_RCV_IN_PROGRESS.
55 * [91/08/03 rpd]
56 * Renamed clport things to norma_ipc things.
57 * [91/08/15 08:24:12 jsb]
58 *
59 * Revision 2.12 91/07/31 17:43:41 dbg
60 * Add mach_msg_interrupt to force a thread waiting in mach_msg_continue
61 * or mach_msg_receive_continue into a stable state.
62 * [91/07/30 17:02:11 dbg]
63 *
64 * Revision 2.11 91/06/25 10:27:47 rpd
65 * Fixed ikm_cache critical sections to avoid blocking operations.
66 * [91/05/23 rpd]
67 *
68 * Revision 2.10 91/06/17 15:46:33 jsb
69 * Renamed NORMA conditionals.
70 * [91/06/17 10:46:35 jsb]
71 *
72 * Revision 2.9 91/06/06 17:06:12 jsb
73 * A little more NORMA_IPC support.
74 * [91/05/13 17:22:08 jsb]
75 *
76 * Revision 2.8 91/05/14 16:38:44 mrt
77 * Correcting copyright
78 *
79 * Revision 2.7 91/03/16 14:49:09 rpd
80 * Replaced ipc_thread_switch with thread_handoff.
81 * Replaced ith_saved with ikm_cache.
82 * [91/02/16 rpd]
83 * Made null mach_msg_trap measurement easier.
84 * [91/01/29 rpd]
85 *
86 * Revision 2.6 91/02/05 17:24:37 mrt
87 * Changed to new Mach copyright
88 * [91/02/01 15:53:02 mrt]
89 *
90 * Revision 2.5 91/01/08 15:15:03 rpd
91 * Added KEEP_STACKS support.
92 * [91/01/07 rpd]
93 * Changed to use thread_syscall_return.
94 * Added msg_receive_continue.
95 * [90/12/18 rpd]
96 * Added mach_msg_continue, mach_msg_receive_continue.
97 * Changes to support kernel stack discarding/hand-off.
98 * [90/12/09 17:29:04 rpd]
99 *
100 * Removed MACH_IPC_GENNOS.
101 * [90/11/08 rpd]
102 *
103 * Revision 2.4 90/12/14 11:01:36 jsb
104 * Added NORMA_IPC support: always ipc_mqueue_send() to a remote port.
105 * [90/12/13 21:25:47 jsb]
106 *
107 * Revision 2.3 90/11/05 14:30:29 rpd
108 * Removed ipc_object_release_macro.
109 * Changed ip_reference to ipc_port_reference.
110 * Changed ip_release to ipc_port_release.
111 * Changed io_release to ipc_object_release.
112 * Use new io_reference and io_release.
113 * Use new ip_reference and ip_release.
114 * [90/10/29 rpd]
115 *
116 * Revision 2.2 90/06/02 14:52:22 rpd
117 * Created for new IPC.
118 * [90/03/26 21:05:49 rpd]
119 *
120 */
121 /* CMU_ENDHIST */
122 /*
123 * Mach Operating System
124 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
125 * All Rights Reserved.
126 *
127 * Permission to use, copy, modify and distribute this software and its
128 * documentation is hereby granted, provided that both the copyright
129 * notice and this permission notice appear in all copies of the
130 * software, derivative works or modified versions, and any portions
131 * thereof, and that both notices appear in supporting documentation.
132 *
133 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
134 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
135 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
136 *
137 * Carnegie Mellon requests users of this software to return to
138 *
139 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
140 * School of Computer Science
141 * Carnegie Mellon University
142 * Pittsburgh PA 15213-3890
143 *
144 * any improvements or extensions that they make and grant Carnegie Mellon
145 * the rights to redistribute these changes.
146 */
147 /*
148 */
149 /*
150 * File: ipc/mach_msg.c
151 * Author: Rich Draves
152 * Date: 1989
153 *
154 * Exported message traps. See mach/message.h.
155 */
156
157 #define MACH_INTERNAL
158 #include <sys/mach/kern_return.h>
159 #include <sys/mach/port.h>
160 #include <sys/mach/message.h>
161 #include <sys/mach/mig_errors.h>
162
163 #include <sys/mach/ipc/ipc_kmsg.h>
164 #include <sys/mach/ipc/ipc_mqueue.h>
165 #include <sys/mach/ipc/ipc_object.h>
166 #include <sys/mach/ipc/ipc_notify.h>
167 #include <sys/mach/ipc/ipc_port.h>
168 #include <sys/mach/ipc/ipc_pset.h>
169 #include <sys/mach/ipc/ipc_space.h>
170 #include <sys/mach/ipc/ipc_thread.h>
171 #include <sys/mach/ipc/ipc_entry.h>
172 #include <sys/mach/ipc/mach_msg.h>
173 #include <sys/mach/thread.h>
174 #include <sys/mach/sched_prim.h>
175 #include <sys/mach/ipc_kobject.h>
176
177
178 /*
179 * Forward declarations
180 */
181
182 mach_msg_return_t mach_msg_send(
183 mach_msg_header_t *msg,
184 mach_msg_option_t option,
185 mach_msg_size_t send_size,
186 mach_msg_timeout_t timeout,
187 mach_port_name_t notify);
188
189 mach_msg_return_t mach_msg_receive(
190 mach_msg_header_t *msg,
191 mach_msg_option_t option,
192 mach_msg_size_t rcv_size,
193 mach_port_name_t rcv_name,
194 mach_msg_timeout_t timeout,
195 mach_msg_size_t slist_size);
196
197 mach_msg_return_t msg_receive_error(
198 ipc_kmsg_t kmsg,
199 mach_msg_header_t *msg,
200 mach_msg_option_t option,
201 mach_port_seqno_t seqno,
202 ipc_space_t space);
203
204 #if 0
205 /* the size of each trailer has to be listed here for copyout purposes */
206 mach_msg_trailer_size_t trailer_size[] = {
207 sizeof(mach_msg_trailer_t),
208 sizeof(mach_msg_seqno_trailer_t),
209 sizeof(mach_msg_security_trailer_t)
210 };
211 #endif
212
213 security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE;
214 audit_token_t KERNEL_AUDIT_TOKEN = KERNEL_AUDIT_TOKEN_VALUE;
215
216 mach_msg_format_0_trailer_t trailer_template = {
217 /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0,
218 /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE,
219 /* mach_port_seqno_t */ 0,
220 /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE
221 };
222
223 /*
224 * Routine: mach_msg_send
225 * Purpose:
226 * Send a message.
227 * Conditions:
228 * Nothing locked.
229 * Returns:
230 * MACH_MSG_SUCCESS Sent the message.
231 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
232 * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
233 * MACH_SEND_INVALID_DATA Couldn't copy message data.
234 * MACH_SEND_INVALID_HEADER
235 * Illegal value in the message header bits.
236 * MACH_SEND_INVALID_DEST The space is dead.
237 * MACH_SEND_INVALID_NOTIFY Bad notify port.
238 * MACH_SEND_INVALID_DEST Can't copyin destination port.
239 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
240 * MACH_SEND_TIMED_OUT Timeout expired without delivery.
241 * MACH_SEND_INTERRUPTED Delivery interrupted.
242 * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
243 * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
244 * MACH_SEND_NOTIFY_IN_PROGRESS
245 * This space has already forced a message to this port.
246 */
247
248 mach_msg_return_t
mach_msg_send(mach_msg_header_t * msg,mach_msg_option_t option,mach_msg_size_t send_size,mach_msg_timeout_t timeout,mach_port_name_t notify)249 mach_msg_send(
250 mach_msg_header_t *msg,
251 mach_msg_option_t option,
252 mach_msg_size_t send_size,
253 mach_msg_timeout_t timeout,
254 mach_port_name_t notify)
255 {
256 ipc_space_t space = current_space();
257 vm_map_t map = current_map();
258 ipc_kmsg_t kmsg;
259 mach_msg_return_t mr;
260
261 mr = ipc_kmsg_get(msg, send_size, &kmsg, space);
262
263 if (mr != MACH_MSG_SUCCESS)
264 return mr;
265
266 MDPRINTF(("send to remote port %d notify %d id %d name %s\n", (int)kmsg->ikm_header->msgh_remote_port,
267 notify, kmsg->ikm_header->msgh_id, curproc->p_comm));
268
269 mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NAME_NULL);
270 if (mr != MACH_MSG_SUCCESS) {
271 ikm_free(kmsg);
272 return mr;
273 }
274
275 mr = ipc_mqueue_send(kmsg, option & MACH_SEND_TIMEOUT, timeout);
276
277 if (mr != MACH_MSG_SUCCESS) {
278 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL);
279 (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header->msgh_size);
280 }
281
282 return mr;
283 }
284
285 #define FREE_SCATTER_LIST(s, l, rt) \
286 MACRO_BEGIN \
287 if((s) != MACH_MSG_BODY_NULL) { \
288 KFREE(((vm_offset_t)(s)), (l), rt); \
289 } \
290 MACRO_END
291
292 /*
293 * Routine: mach_msg_receive
294 * Purpose:
295 * Receive a message.
296 * Conditions:
297 * Nothing locked.
298 * Returns:
299 * MACH_MSG_SUCCESS Received a message.
300 * MACH_RCV_INVALID_NAME The name doesn't denote a right,
301 * or the denoted right is not receive or port set.
302 * MACH_RCV_IN_SET Receive right is a member of a set.
303 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
304 * MACH_RCV_TIMED_OUT Timeout expired without a message.
305 * MACH_RCV_INTERRUPTED Reception interrupted.
306 * MACH_RCV_PORT_DIED Port/set died while receiving.
307 * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
308 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
309 * MACH_RCV_INVALID_NOTIFY Bad notify port.
310 * MACH_RCV_HEADER_ERROR
311 */
312
313 mach_msg_return_t
mach_msg_receive(mach_msg_header_t * msg,mach_msg_option_t option,mach_msg_size_t rcv_size,mach_port_name_t rcv_name,mach_msg_timeout_t timeout,mach_msg_size_t slist_size)314 mach_msg_receive(
315 mach_msg_header_t *msg,
316 mach_msg_option_t option,
317 mach_msg_size_t rcv_size,
318 mach_port_name_t rcv_name,
319 mach_msg_timeout_t timeout,
320 mach_msg_size_t slist_size)
321 {
322 ipc_thread_t self = current_thread();
323 ipc_space_t space = current_space();
324 vm_map_t map = current_map();
325 ipc_object_t object;
326 ipc_kmsg_t kmsg;
327 mach_port_seqno_t seqno;
328 mach_msg_return_t mr;
329 mach_msg_body_t *slist;
330 mach_msg_max_trailer_t *trailer;
331 ipc_entry_bits_t bits;
332
333 mr = ipc_mqueue_copyin(space, rcv_name, &bits, &object);
334 if (mr != MACH_MSG_SUCCESS) {
335 return mr;
336 }
337 /* hold ref for object; mqueue is locked */
338 /*
339 * If MACH_RCV_OVERWRITE was specified, both receive_msg (msg)
340 * and receive_msg_size (slist_size) need to be non NULL.
341 */
342 if (option & MACH_RCV_OVERWRITE) {
343 if (slist_size < sizeof(mach_msg_base_t)) {
344 ipc_object_release(object);
345 return MACH_RCV_SCATTER_SMALL;
346 } else {
347 slist_size -= sizeof(mach_msg_header_t);
348 slist = (mach_msg_body_t *)KALLOC(slist_size, slist_rt);
349 if (slist == MACH_MSG_BODY_NULL ||
350 copyin((char *) (msg + 1), (char *)slist,
351 slist_size)) {
352 ipc_object_release(object);
353 return MACH_RCV_INVALID_DATA;
354 }
355 if ((slist->msgh_descriptor_count*
356 sizeof(mach_msg_descriptor_t)
357 + sizeof(mach_msg_size_t)) > slist_size) {
358 FREE_SCATTER_LIST(slist, slist_size, slist_rt);
359 ipc_object_release(object);
360 return MACH_RCV_INVALID_TYPE;
361 }
362 }
363 } else {
364 slist = MACH_MSG_BODY_NULL;
365 }
366 assert(io_otype(object) == IOT_PORT || io_otype(object) == IOT_PORT_SET);
367 self->ith_option = option;
368 self->ith_scatter_list = slist;
369 self->ith_scatter_list_size = slist_size;
370 self->ith_object = object;
371 assert(object->io_references > 0);
372 mr = ipc_mqueue_receive(bits, option & MACH_RCV_TIMEOUT, rcv_size,
373 timeout, &kmsg, &seqno, self);
374 /* mqueue is unlocked */
375 ipc_object_release(object);
376
377 if (mr != MACH_MSG_SUCCESS) {
378 if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL
379 ) {
380 if (msg_receive_error(kmsg, msg, option, seqno, space)
381 == MACH_RCV_INVALID_DATA)
382 mr = MACH_RCV_INVALID_DATA;
383 }
384 FREE_SCATTER_LIST(slist, slist_size, slist_rt);
385 return mr;
386 }
387 trailer = (mach_msg_max_trailer_t *)
388 ((vm_offset_t)kmsg->ikm_header +
389 round_msg(kmsg->ikm_header->msgh_size));
390 if (option & MACH_RCV_TRAILER_MASK) {
391 trailer->msgh_seqno = seqno;
392 trailer->msgh_context = kmsg->ikm_header->msgh_remote_port->ip_context;
393 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
394 }
395
396 mr = ipc_kmsg_copyout(kmsg, space, map, slist, 0);
397 if (mr != MACH_MSG_SUCCESS) {
398 /* XXX do we know that the message always gets freed */
399 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR
400 ) {
401 if (ipc_kmsg_put(msg, kmsg, kmsg->ikm_header->msgh_size +
402 trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA)
403 mr = MACH_RCV_INVALID_DATA;
404 }
405 else {
406 if (msg_receive_error(kmsg, msg, option, seqno, space)
407 == MACH_RCV_INVALID_DATA)
408 mr = MACH_RCV_INVALID_DATA;
409 }
410
411 FREE_SCATTER_LIST(slist, slist_size, slist_rt);
412 return mr;
413 }
414 mr = ipc_kmsg_put(msg, kmsg,
415 kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size);
416 FREE_SCATTER_LIST(slist, slist_size, slist_rt);
417
418 return mr;
419 }
420
421
422 /*
423 * Routine: mach_msg_overwrite_trap [mach trap]
424 * Purpose:
425 * Possibly send a message; possibly receive a message.
426 * Conditions:
427 * Nothing locked.
428 * Returns:
429 * All of mach_msg_send and mach_msg_receive error codes.
430 */
431
432 mach_msg_return_t
mach_msg_overwrite_trap(mach_msg_header_t * msg,mach_msg_option_t option,mach_msg_size_t send_size,mach_msg_size_t rcv_size,mach_port_name_t rcv_name,mach_msg_timeout_t timeout,mach_port_name_t notify,mach_msg_header_t * rcv_msg,mach_msg_size_t scatter_list_size)433 mach_msg_overwrite_trap(
434 mach_msg_header_t *msg,
435 mach_msg_option_t option,
436 mach_msg_size_t send_size,
437 mach_msg_size_t rcv_size,
438 mach_port_name_t rcv_name,
439 mach_msg_timeout_t timeout,
440 mach_port_name_t notify,
441 mach_msg_header_t *rcv_msg,
442 mach_msg_size_t scatter_list_size)
443 {
444 mach_msg_return_t mr = MACH_MSG_SUCCESS;
445
446 if (option & MACH_SEND_MSG) {
447 mr = mach_msg_send(msg, option, send_size,
448 timeout, notify);
449 if (mr != MACH_MSG_SUCCESS) {
450 return mr;
451 }
452 }
453
454 if (option & MACH_RCV_MSG) {
455 mach_msg_header_t *rcv;
456
457 /*
458 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
459 * and receive buffer
460 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
461 * alternate receive buffer (separate send and receive buffers).
462 */
463 if (option & MACH_RCV_OVERWRITE)
464 rcv = rcv_msg;
465 else if (rcv_msg != MACH_MSG_NULL)
466 rcv = rcv_msg;
467 else
468 rcv = msg;
469
470 MDPRINTF(("%s:%d receiving on %d ... ", curproc->p_comm, curthread->td_tid, rcv_name));
471 mr = mach_msg_receive(rcv, option, rcv_size, rcv_name,
472 timeout, scatter_list_size);
473 MDPRINTF(("%s:%d done on %d\n",curproc->p_comm, curthread->td_tid, rcv_name));
474
475 }
476
477 return (mr);
478 }
479
480 /*
481 * Routine: msg_receive_error [internal]
482 * Purpose:
483 * Builds a minimal header/trailer and copies it to
484 * the user message buffer. Invoked when in the case of a
485 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
486 * Conditions:
487 * Nothing locked.
488 * Returns:
489 * MACH_MSG_SUCCESS minimal header/trailer copied
490 * MACH_RCV_INVALID_DATA copyout to user buffer failed
491 */
492
493 mach_msg_return_t
msg_receive_error(ipc_kmsg_t kmsg,mach_msg_header_t * msg,mach_msg_option_t option,mach_port_seqno_t seqno,ipc_space_t space)494 msg_receive_error(
495 ipc_kmsg_t kmsg,
496 mach_msg_header_t *msg,
497 mach_msg_option_t option,
498 mach_port_seqno_t seqno,
499 ipc_space_t space)
500 {
501 mach_vm_address_t context;
502 mach_msg_max_trailer_t *trailer;
503
504 context = kmsg->ikm_header->msgh_remote_port->ip_context;
505 /*
506 * Copy out the destination port in the message.
507 * Destroy all other rights and memory in the message.
508 */
509 ipc_kmsg_copyout_dest(kmsg, space);
510
511 /*
512 * Build a minimal message with the requested trailer.
513 */
514 trailer = (mach_msg_max_trailer_t *)
515 ((vm_offset_t)kmsg->ikm_header +
516 round_msg(sizeof(mach_msg_header_t)));
517 kmsg->ikm_header->msgh_size = sizeof(mach_msg_header_t);
518 bcopy( (char *)&trailer_template,
519 (char *)trailer,
520 sizeof(trailer_template));
521 if (option & MACH_RCV_TRAILER_MASK) {
522 trailer->msgh_seqno = seqno;
523 trailer->msgh_context = context;
524 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
525 }
526
527 /*
528 * Copy the message to user space
529 */
530 if (ipc_kmsg_put(msg, kmsg, kmsg->ikm_header->msgh_size +
531 trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA)
532 return(MACH_RCV_INVALID_DATA);
533 else
534 return(MACH_MSG_SUCCESS);
535 }
536
537
538 static mach_msg_return_t
mach_msg_receive_results_error(thread_t thread)539 mach_msg_receive_results_error(thread_t thread)
540 {
541 ipc_space_t space = current_space();
542
543 mach_msg_return_t mr = thread->ith_state;
544 mach_vm_address_t msg_addr = thread->ith_msg_addr;
545 mach_msg_option_t option = thread->ith_option;
546 ipc_kmsg_t kmsg = thread->ith_kmsg;
547 mach_port_seqno_t seqno = thread->ith_seqno;
548 mach_msg_header_t *msg = (void *)msg_addr;
549
550 if (mr != MACH_RCV_TOO_LARGE)
551 return (mr);
552
553 if (option & MACH_RCV_LARGE) {
554 /*
555 * We need to inform the user-level code that it needs more
556 * space. The value for how much space was returned in the
557 * msize save area instead of the message (which was left on
558 * the queue).
559 */
560 if (option & MACH_RCV_LARGE_IDENTITY) {
561 if (copyout((char *) &thread->ith_receiver_name,
562 (void *) (msg_addr + offsetof(mach_msg_header_t, msgh_local_port)),
563 sizeof(mach_port_name_t)))
564 mr = MACH_RCV_INVALID_DATA;
565 }
566 if (copyout((char *) &thread->ith_msize,
567 (void *) (msg_addr + offsetof(mach_msg_header_t, msgh_size)),
568 sizeof(mach_msg_size_t)))
569 mr = MACH_RCV_INVALID_DATA;
570 } else {
571
572 if (msg_receive_error(kmsg, msg, option, seqno, space)
573 == MACH_RCV_INVALID_DATA)
574 mr = MACH_RCV_INVALID_DATA;
575 }
576 return (mr);
577 }
578
579 mach_msg_return_t
mach_msg_receive_results(thread_t thread)580 mach_msg_receive_results(thread_t thread)
581 {
582 ipc_space_t space = current_space();
583 vm_map_t map = current_map();
584
585 mach_msg_return_t mr = thread->ith_state;
586 mach_vm_address_t msg_addr = thread->ith_msg_addr;
587 mach_msg_option_t option = thread->ith_option;
588 ipc_kmsg_t kmsg = thread->ith_kmsg;
589 mach_port_seqno_t seqno = thread->ith_seqno;
590 mach_msg_trailer_size_t trailer_size;
591 mach_msg_header_t *msg = (void *)msg_addr;
592
593
594 thread->ith_kmsg = NULL;
595 if (mr != MACH_MSG_SUCCESS)
596 return mach_msg_receive_results_error(thread);
597
598
599 #ifdef notyet
600 trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, thread, seqno, FALSE,
601 kmsg->ikm_header->msgh_remote_port->ip_context);
602 #endif
603 trailer_size = REQUESTED_TRAILER_SIZE(option);
604 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL, option);
605
606 if (mr != MACH_MSG_SUCCESS) {
607 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
608 if (ipc_kmsg_put(msg, kmsg, kmsg->ikm_header->msgh_size +
609 trailer_size) == MACH_RCV_INVALID_DATA)
610 mr = MACH_RCV_INVALID_DATA;
611 } else {
612 if (msg_receive_error(kmsg, msg, option, seqno, space)
613 == MACH_RCV_INVALID_DATA)
614 mr = MACH_RCV_INVALID_DATA;
615 }
616 } else {
617 mr = ipc_kmsg_put(msg,
618 kmsg,
619 kmsg->ikm_header->msgh_size +
620 trailer_size);
621 }
622
623 return (mr);
624 }
625