]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/mach/mach_msg.c
xnu-2050.7.9.tar.gz
[apple/xnu.git] / libsyscall / mach / mach_msg.c
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53
54 #include <stdlib.h>
55 #include <mach/mach.h>
56 #include <mach/boolean.h>
57 #include <mach/kern_return.h>
58 #include <mach/message.h>
59 #include <mach/mig_errors.h>
60 #include <mach/vm_statistics.h>
61
62 #define MACH_MSG_TRAP(msg, opt, ssize, rsize, rname, to, not) \
63 mach_msg_trap((msg), (opt), (ssize), (rsize), (rname), (to), (not))
64
65 #define LIBMACH_OPTIONS (MACH_SEND_INTERRUPT|MACH_RCV_INTERRUPT)
66
67 /*
68 * Routine: mach_msg
69 * Purpose:
70 * Send and/or receive a message. If the message operation
71 * is interrupted, and the user did not request an indication
72 * of that fact, then restart the appropriate parts of the
73 * operation.
74 */
75 mach_msg_return_t
76 mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify)
77 mach_msg_header_t *msg;
78 mach_msg_option_t option;
79 mach_msg_size_t send_size;
80 mach_msg_size_t rcv_size;
81 mach_port_t rcv_name;
82 mach_msg_timeout_t timeout;
83 mach_port_t notify;
84 {
85 mach_msg_return_t mr;
86
87 /*
88 * Consider the following cases:
89 * 1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
90 * plus special bits).
91 * 2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
92 * 3) RPC calls with interruptions in one/both halves.
93 *
94 * We refrain from passing the option bits that we implement
95 * to the kernel. This prevents their presence from inhibiting
96 * the kernel's fast paths (when it checks the option value).
97 */
98
99 mr = MACH_MSG_TRAP(msg, option &~ LIBMACH_OPTIONS,
100 send_size, rcv_size, rcv_name,
101 timeout, notify);
102 if (mr == MACH_MSG_SUCCESS)
103 return MACH_MSG_SUCCESS;
104
105 if ((option & MACH_SEND_INTERRUPT) == 0)
106 while (mr == MACH_SEND_INTERRUPTED)
107 mr = MACH_MSG_TRAP(msg,
108 option &~ LIBMACH_OPTIONS,
109 send_size, rcv_size, rcv_name,
110 timeout, notify);
111
112 if ((option & MACH_RCV_INTERRUPT) == 0)
113 while (mr == MACH_RCV_INTERRUPTED)
114 mr = MACH_MSG_TRAP(msg,
115 option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
116 0, rcv_size, rcv_name,
117 timeout, notify);
118
119 return mr;
120 }
121
122 /*
123 * Routine: mach_msg_overwrite
124 * Purpose:
125 * Send and/or receive a message. If the message operation
126 * is interrupted, and the user did not request an indication
127 * of that fact, then restart the appropriate parts of the
128 * operation.
129 *
130 * Distinct send and receive buffers may be specified. If
131 * no separate receive buffer is specified, the msg parameter
132 * will be used for both send and receive operations.
133 *
134 * In addition to a distinct receive buffer, that buffer may
135 * already contain scatter control information to direct the
136 * receiving of the message.
137 */
138 mach_msg_return_t
139 mach_msg_overwrite(msg, option, send_size, rcv_limit, rcv_name, timeout,
140 notify, rcv_msg, rcv_scatter_size)
141 mach_msg_header_t *msg;
142 mach_msg_option_t option;
143 mach_msg_size_t send_size;
144 mach_msg_size_t rcv_limit;
145 mach_port_t rcv_name;
146 mach_msg_timeout_t timeout;
147 mach_port_t notify;
148 mach_msg_header_t *rcv_msg;
149 mach_msg_size_t rcv_scatter_size;
150 {
151 mach_msg_return_t mr;
152
153 /*
154 * Consider the following cases:
155 * 1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
156 * plus special bits).
157 * 2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
158 * 3) RPC calls with interruptions in one/both halves.
159 *
160 * We refrain from passing the option bits that we implement
161 * to the kernel. This prevents their presence from inhibiting
162 * the kernel's fast paths (when it checks the option value).
163 */
164
165 mr = mach_msg_overwrite_trap(msg, option &~ LIBMACH_OPTIONS,
166 send_size, rcv_limit, rcv_name,
167 timeout, notify, rcv_msg, rcv_scatter_size);
168 if (mr == MACH_MSG_SUCCESS)
169 return MACH_MSG_SUCCESS;
170
171 if ((option & MACH_SEND_INTERRUPT) == 0)
172 while (mr == MACH_SEND_INTERRUPTED)
173 mr = mach_msg_overwrite_trap(msg,
174 option &~ LIBMACH_OPTIONS,
175 send_size, rcv_limit, rcv_name,
176 timeout, notify, rcv_msg, rcv_scatter_size);
177
178 if ((option & MACH_RCV_INTERRUPT) == 0)
179 while (mr == MACH_RCV_INTERRUPTED)
180 mr = mach_msg_overwrite_trap(msg,
181 option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
182 0, rcv_limit, rcv_name,
183 timeout, notify, rcv_msg, rcv_scatter_size);
184
185 return mr;
186 }
187
188
189 mach_msg_return_t
190 mach_msg_send(mach_msg_header_t *msg)
191 {
192 return mach_msg(msg, MACH_SEND_MSG,
193 msg->msgh_size, 0, MACH_PORT_NULL,
194 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
195 }
196
197 mach_msg_return_t
198 mach_msg_receive(mach_msg_header_t *msg)
199 {
200 return mach_msg(msg, MACH_RCV_MSG,
201 0, msg->msgh_size, msg->msgh_local_port,
202 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
203 }
204
205
206 static void
207 mach_msg_destroy_port(mach_port_t port, mach_msg_type_name_t type)
208 {
209 if (MACH_PORT_VALID(port)) switch (type) {
210 case MACH_MSG_TYPE_MOVE_SEND:
211 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
212 /* destroy the send/send-once right */
213 (void) mach_port_deallocate(mach_task_self_, port);
214 break;
215
216 case MACH_MSG_TYPE_MOVE_RECEIVE:
217 /* destroy the receive right */
218 (void) mach_port_mod_refs(mach_task_self_, port,
219 MACH_PORT_RIGHT_RECEIVE, -1);
220 break;
221
222 case MACH_MSG_TYPE_MAKE_SEND:
223 /* create a send right and then destroy it */
224 (void) mach_port_insert_right(mach_task_self_, port,
225 port, MACH_MSG_TYPE_MAKE_SEND);
226 (void) mach_port_deallocate(mach_task_self_, port);
227 break;
228
229 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
230 /* create a send-once right and then destroy it */
231 (void) mach_port_extract_right(mach_task_self_, port,
232 MACH_MSG_TYPE_MAKE_SEND_ONCE,
233 &port, &type);
234 (void) mach_port_deallocate(mach_task_self_, port);
235 break;
236 }
237 }
238
239 static void
240 mach_msg_destroy_memory(vm_offset_t addr, vm_size_t size)
241 {
242 if (size != 0)
243 (void) vm_deallocate(mach_task_self_, addr, size);
244 }
245
246
247 /*
248 * Routine: mach_msg_destroy
249 * Purpose:
250 * mach_msg_destroy is useful in two contexts.
251 *
252 * First, it can deallocate all port rights and
253 * out-of-line memory in a received message.
254 * When a server receives a request it doesn't want,
255 * it needs this functionality.
256 *
257 * Second, it can mimic the side-effects of a msg-send
258 * operation. The effect is as if the message were sent
259 * and then destroyed inside the kernel. When a server
260 * can't send a reply (because the client died),
261 * it needs this functionality.
262 */
263 void
264 mach_msg_destroy(mach_msg_header_t *msg)
265 {
266 mach_msg_bits_t mbits = msg->msgh_bits;
267
268 /*
269 * The msgh_local_port field doesn't hold a port right.
270 * The receive operation consumes the destination port right.
271 */
272
273 mach_msg_destroy_port(msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(mbits));
274
275 if (mbits & MACH_MSGH_BITS_COMPLEX) {
276 mach_msg_base_t *base;
277 mach_msg_type_number_t count, i;
278 mach_msg_descriptor_t *daddr;
279
280 base = (mach_msg_base_t *) msg;
281 count = base->body.msgh_descriptor_count;
282
283 daddr = (mach_msg_descriptor_t *) (base + 1);
284 for (i = 0; i < count; i++) {
285
286 switch (daddr->type.type) {
287
288 case MACH_MSG_PORT_DESCRIPTOR: {
289 mach_msg_port_descriptor_t *dsc;
290
291 /*
292 * Destroy port rights carried in the message
293 */
294 dsc = &daddr->port;
295 mach_msg_destroy_port(dsc->name, dsc->disposition);
296 daddr = (mach_msg_descriptor_t *)(dsc + 1);
297 break;
298 }
299
300 case MACH_MSG_OOL_DESCRIPTOR: {
301 mach_msg_ool_descriptor_t *dsc;
302
303 /*
304 * Destroy memory carried in the message
305 */
306 dsc = &daddr->out_of_line;
307 if (dsc->deallocate) {
308 mach_msg_destroy_memory((vm_offset_t)dsc->address,
309 dsc->size);
310 }
311 daddr = (mach_msg_descriptor_t *)(dsc + 1);
312 break;
313 }
314
315 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: {
316 mach_msg_ool_descriptor_t *dsc;
317
318 /*
319 * Just skip it.
320 */
321 dsc = &daddr->out_of_line;
322 daddr = (mach_msg_descriptor_t *)(dsc + 1);
323 break;
324 }
325
326 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
327 mach_port_t *ports;
328 mach_msg_ool_ports_descriptor_t *dsc;
329 mach_msg_type_number_t j;
330
331 /*
332 * Destroy port rights carried in the message
333 */
334 dsc = &daddr->ool_ports;
335 ports = (mach_port_t *) dsc->address;
336 for (j = 0; j < dsc->count; j++, ports++) {
337 mach_msg_destroy_port(*ports, dsc->disposition);
338 }
339
340 /*
341 * Destroy memory carried in the message
342 */
343 if (dsc->deallocate) {
344 mach_msg_destroy_memory((vm_offset_t)dsc->address,
345 dsc->count * sizeof(mach_port_t));
346 }
347 daddr = (mach_msg_descriptor_t *)(dsc + 1);
348 break;
349 }
350 }
351 }
352 }
353 }
354
355 /*
356 * Routine: mach_msg_server_once
357 * Purpose:
358 * A simple generic server function. It allows more flexibility
359 * than mach_msg_server by processing only one message request
360 * and then returning to the user. Note that more in the way
361 * of error codes are returned to the user; specifically, any
362 * failing error from mach_msg calls will be returned
363 * (though errors from the demux routine or the routine it
364 * calls will not be).
365 */
366 mach_msg_return_t
367 mach_msg_server_once(
368 boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
369 mach_msg_size_t max_size,
370 mach_port_t rcv_name,
371 mach_msg_options_t options)
372 {
373 mig_reply_error_t *bufRequest, *bufReply;
374 mach_msg_size_t request_size;
375 mach_msg_size_t request_alloc;
376 mach_msg_size_t trailer_alloc;
377 mach_msg_size_t reply_alloc;
378 mach_msg_return_t mr;
379 kern_return_t kr;
380 mach_port_t self = mach_task_self_;
381
382 options &= ~(MACH_SEND_MSG|MACH_RCV_MSG);
383
384 trailer_alloc = REQUESTED_TRAILER_SIZE(options);
385 request_alloc = round_page(max_size + trailer_alloc);
386
387 request_size = (options & MACH_RCV_LARGE) ?
388 request_alloc : max_size + trailer_alloc;
389
390 reply_alloc = round_page((options & MACH_SEND_TRAILER) ?
391 (max_size + MAX_TRAILER_SIZE) :
392 max_size);
393
394 kr = vm_allocate(self,
395 (vm_address_t *)&bufReply,
396 reply_alloc,
397 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
398 if (kr != KERN_SUCCESS)
399 return kr;
400
401 for (;;) {
402 mach_msg_size_t new_request_alloc;
403
404 kr = vm_allocate(self,
405 (vm_address_t *)&bufRequest,
406 request_alloc,
407 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
408 if (kr != KERN_SUCCESS) {
409 vm_deallocate(self,
410 (vm_address_t)bufReply,
411 reply_alloc);
412 return kr;
413 }
414
415 mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
416 0, request_size, rcv_name,
417 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
418
419 if (!((mr == MACH_RCV_TOO_LARGE) && (options & MACH_RCV_LARGE)))
420 break;
421
422 new_request_alloc = round_page(bufRequest->Head.msgh_size +
423 trailer_alloc);
424 vm_deallocate(self,
425 (vm_address_t) bufRequest,
426 request_alloc);
427 request_size = request_alloc = new_request_alloc;
428 }
429
430 if (mr == MACH_MSG_SUCCESS) {
431 /* we have a request message */
432
433 (void) (*demux)(&bufRequest->Head, &bufReply->Head);
434
435 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
436 if (bufReply->RetCode == MIG_NO_REPLY)
437 bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
438 else if ((bufReply->RetCode != KERN_SUCCESS) &&
439 (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
440 /* destroy the request - but not the reply port */
441 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
442 mach_msg_destroy(&bufRequest->Head);
443 }
444 }
445
446 /*
447 * We don't want to block indefinitely because the client
448 * isn't receiving messages from the reply port.
449 * If we have a send-once right for the reply port, then
450 * this isn't a concern because the send won't block.
451 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
452 * To avoid falling off the kernel's fast RPC path unnecessarily,
453 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
454 */
455 if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
456
457 mr = mach_msg(&bufReply->Head,
458 (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
459 MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
460 MACH_SEND_MSG|options :
461 MACH_SEND_MSG|MACH_SEND_TIMEOUT|options,
462 bufReply->Head.msgh_size, 0, MACH_PORT_NULL,
463 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
464
465 if ((mr != MACH_SEND_INVALID_DEST) &&
466 (mr != MACH_SEND_TIMED_OUT))
467 goto done_once;
468 mr = MACH_MSG_SUCCESS;
469 }
470 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
471 mach_msg_destroy(&bufReply->Head);
472 }
473
474 done_once:
475 (void)vm_deallocate(self,
476 (vm_address_t) bufRequest,
477 request_alloc);
478 (void)vm_deallocate(self,
479 (vm_address_t) bufReply,
480 reply_alloc);
481 return mr;
482 }
483
484 /*
485 * Routine: mach_msg_server
486 * Purpose:
487 * A simple generic server function. Note that changes here
488 * should be considered for duplication above.
489 */
490 mach_msg_return_t
491 mach_msg_server(
492 boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
493 mach_msg_size_t max_size,
494 mach_port_t rcv_name,
495 mach_msg_options_t options)
496 {
497 mig_reply_error_t *bufRequest, *bufReply;
498 mach_msg_size_t request_size;
499 mach_msg_size_t new_request_alloc;
500 mach_msg_size_t request_alloc;
501 mach_msg_size_t trailer_alloc;
502 mach_msg_size_t reply_alloc;
503 mach_msg_return_t mr;
504 kern_return_t kr;
505 mach_port_t self = mach_task_self_;
506
507 options &= ~(MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_OVERWRITE);
508
509 reply_alloc = round_page((options & MACH_SEND_TRAILER) ?
510 (max_size + MAX_TRAILER_SIZE) : max_size);
511
512 kr = vm_allocate(self,
513 (vm_address_t *)&bufReply,
514 reply_alloc,
515 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
516 if (kr != KERN_SUCCESS)
517 return kr;
518
519 request_alloc = 0;
520 trailer_alloc = REQUESTED_TRAILER_SIZE(options);
521 new_request_alloc = round_page(max_size + trailer_alloc);
522
523 request_size = (options & MACH_RCV_LARGE) ?
524 new_request_alloc : max_size + trailer_alloc;
525
526 for (;;) {
527 if (request_alloc < new_request_alloc) {
528 request_alloc = new_request_alloc;
529 kr = vm_allocate(self,
530 (vm_address_t *)&bufRequest,
531 request_alloc,
532 VM_MAKE_TAG(VM_MEMORY_MACH_MSG)|TRUE);
533 if (kr != KERN_SUCCESS) {
534 vm_deallocate(self,
535 (vm_address_t)bufReply,
536 reply_alloc);
537 return kr;
538 }
539 }
540
541 mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
542 0, request_size, rcv_name,
543 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
544
545 while (mr == MACH_MSG_SUCCESS) {
546 /* we have another request message */
547
548 (void) (*demux)(&bufRequest->Head, &bufReply->Head);
549
550 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
551 if (bufReply->RetCode == MIG_NO_REPLY)
552 bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
553 else if ((bufReply->RetCode != KERN_SUCCESS) &&
554 (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
555 /* destroy the request - but not the reply port */
556 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
557 mach_msg_destroy(&bufRequest->Head);
558 }
559 }
560
561 /*
562 * We don't want to block indefinitely because the client
563 * isn't receiving messages from the reply port.
564 * If we have a send-once right for the reply port, then
565 * this isn't a concern because the send won't block.
566 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
567 * To avoid falling off the kernel's fast RPC path,
568 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
569 */
570 if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
571 if (request_alloc == reply_alloc) {
572 mig_reply_error_t *bufTemp;
573
574 mr = mach_msg(
575 &bufReply->Head,
576 (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
577 MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
578 MACH_SEND_MSG|MACH_RCV_MSG|options :
579 MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|options,
580 bufReply->Head.msgh_size, request_size, rcv_name,
581 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
582
583 /* swap request and reply */
584 bufTemp = bufRequest;
585 bufRequest = bufReply;
586 bufReply = bufTemp;
587
588 } else {
589 mr = mach_msg_overwrite(
590 &bufReply->Head,
591 (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) ==
592 MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
593 MACH_SEND_MSG|MACH_RCV_MSG|options :
594 MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|options,
595 bufReply->Head.msgh_size, request_size, rcv_name,
596 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
597 &bufRequest->Head, 0);
598 }
599
600 if ((mr != MACH_SEND_INVALID_DEST) &&
601 (mr != MACH_SEND_TIMED_OUT))
602 continue;
603 }
604 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
605 mach_msg_destroy(&bufReply->Head);
606
607 mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG|options,
608 0, request_size, rcv_name,
609 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
610
611 } /* while (mr == MACH_MSG_SUCCESS) */
612
613 if ((mr == MACH_RCV_TOO_LARGE) && (options & MACH_RCV_LARGE)) {
614 new_request_alloc = round_page(bufRequest->Head.msgh_size +
615 trailer_alloc);
616 request_size = new_request_alloc;
617 vm_deallocate(self,
618 (vm_address_t) bufRequest,
619 request_alloc);
620 continue;
621 }
622
623 break;
624
625 } /* for(;;) */
626
627 (void)vm_deallocate(self,
628 (vm_address_t) bufRequest,
629 request_alloc);
630 (void)vm_deallocate(self,
631 (vm_address_t) bufReply,
632 reply_alloc);
633 return mr;
634 }