xref: /trueos/sys/compat/mach/ipc/mach_msg.c (revision a4e6e577bf8ca5ee389a3fa087949b949ca47235)
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