xref: /NextBSD/lib/libmach/mach/mach_msg.c (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
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 /*
25  * Mach Operating System
26  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
27  * All Rights Reserved.
28  *
29  * Permission to use, copy, modify and distribute this software and its
30  * documentation is hereby granted, provided that both the copyright
31  * notice and this permission notice appear in all copies of the
32  * software, derivative works or modified versions, and any portions
33  * thereof, and that both notices appear in supporting documentation.
34  *
35  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
36  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
37  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
38  *
39  * Carnegie Mellon requests users of this software to return to
40  *
41  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
42  *  School of Computer Science
43  *  Carnegie Mellon University
44  *  Pittsburgh PA 15213-3890
45  *
46  * any improvements or extensions that they make and grant Carnegie Mellon
47  * the rights to redistribute these changes.
48  */
49 
50 #include <sys/cdefs.h>
51 #include <sys/types.h>
52 
53 #include <stdlib.h>
54 #include <sys/queue.h>
55 
56 #include <mach/mach.h>
57 #include <mach/boolean.h>
58 #include <mach/kern_return.h>
59 #include <mach/message.h>
60 #include <mach/mig_errors.h>
61 #include <mach/mach_port.h>
62 #include <mach/mach_vm.h>
63 
64 #define LIBMACH_OPTIONS	(MACH_SEND_INTERRUPT|MACH_RCV_INTERRUPT)
65 
66 mach_msg_return_t
mach_msg(msg,option,send_size,rcv_size,rcv_name,timeout,notify)67 mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify)
68 	mach_msg_header_t *msg;
69 	mach_msg_option_t option;
70 	mach_msg_size_t send_size;
71 	mach_msg_size_t rcv_size;
72 	mach_port_t rcv_name;
73 	mach_msg_timeout_t timeout;
74 	mach_port_t notify;
75 {
76 	mach_msg_return_t mr;
77 
78 	/*
79 	 * Consider the following cases:
80 	 *	1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
81 	 *	plus special bits).
82 	 *	2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
83 	 *	3) RPC calls with interruptions in one/both halves.
84 	 *
85 	 * We refrain from passing the option bits that we implement
86 	 * to the kernel.  This prevents their presence from inhibiting
87 	 * the kernel's fast paths (when it checks the option value).
88 	 */
89 
90 	mr = mach_msg_overwrite_trap(msg, option &~ LIBMACH_OPTIONS,
91 			   send_size, rcv_size, rcv_name,
92 			   timeout, notify, MACH_MSG_NULL, 0);
93 	if (mr == MACH_MSG_SUCCESS)
94 		return MACH_MSG_SUCCESS;
95 
96 	if ((option & MACH_SEND_INTERRUPT) == 0)
97 		while (mr == MACH_SEND_INTERRUPTED)
98 			mr = mach_msg_overwrite_trap(msg,
99 				option &~ LIBMACH_OPTIONS,
100 				send_size, rcv_size, rcv_name,
101 				timeout, notify, MACH_MSG_NULL, 0);
102 
103 	if ((option & MACH_RCV_INTERRUPT) == 0)
104 		while (mr == MACH_RCV_INTERRUPTED)
105 			mr = mach_msg_overwrite_trap(msg,
106 				option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
107 				0, rcv_size, rcv_name,
108 				timeout, notify, MACH_MSG_NULL, 0);
109 
110 	return mr;
111 }
112 
113 mach_msg_return_t
mach_msg_overwrite(msg,option,send_size,rcv_limit,rcv_name,timeout,notify,rcv_msg,rcv_msg_size)114 mach_msg_overwrite(msg, option, send_size, rcv_limit, rcv_name, timeout,
115 		   notify, rcv_msg, rcv_msg_size)
116 	mach_msg_header_t *msg;
117 	mach_msg_option_t option;
118 	mach_msg_size_t send_size;
119 	mach_msg_size_t rcv_limit;
120 	mach_port_t rcv_name;
121 	mach_msg_timeout_t timeout;
122 	mach_port_t notify;
123 	mach_msg_header_t *rcv_msg;
124 	mach_msg_size_t rcv_msg_size;
125 {
126 	mach_msg_return_t mr;
127 
128 	/*
129 	 * Consider the following cases:
130 	 *	1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
131 	 *	plus special bits).
132 	 *	2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
133 	 *	3) RPC calls with interruptions in one/both halves.
134 	 *
135 	 * We refrain from passing the option bits that we implement
136 	 * to the kernel.  This prevents their presence from inhibiting
137 	 * the kernel's fast paths (when it checks the option value).
138 	 */
139 
140 	mr = mach_msg_overwrite_trap(msg, option &~ LIBMACH_OPTIONS,
141 			   send_size, rcv_limit, rcv_name,
142 			   timeout, notify, rcv_msg, rcv_msg_size);
143 	if (mr == MACH_MSG_SUCCESS)
144 		return MACH_MSG_SUCCESS;
145 
146 	if ((option & MACH_SEND_INTERRUPT) == 0)
147 		while (mr == MACH_SEND_INTERRUPTED)
148 			mr = mach_msg_overwrite_trap(msg,
149 				option &~ LIBMACH_OPTIONS,
150 				send_size, rcv_limit, rcv_name,
151 				timeout, notify, rcv_msg, rcv_msg_size);
152 
153 	if ((option & MACH_RCV_INTERRUPT) == 0)
154 		while (mr == MACH_RCV_INTERRUPTED)
155 			mr = mach_msg_overwrite_trap(msg,
156 				option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
157 				0, rcv_limit, rcv_name,
158 				timeout, notify, rcv_msg, rcv_msg_size);
159 
160 	return mr;
161 }
162 
163 mach_msg_return_t
mach_msg_send(mach_msg_header_t * msg)164 mach_msg_send(mach_msg_header_t *msg)
165 {
166 	return mach_msg(msg, MACH_SEND_MSG,
167 			msg->msgh_size, 0, MACH_PORT_NULL,
168 			MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
169 }
170 
171 mach_msg_return_t
mach_msg_receive(mach_msg_header_t * msg)172 mach_msg_receive(mach_msg_header_t *msg)
173 {
174 	return mach_msg(msg, MACH_RCV_MSG,
175 			0, msg->msgh_size, msg->msgh_local_port,
176 			MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
177 }
178 
179 static void
mach_msg_destroy_port(mach_port_t port,mach_msg_type_name_t type)180 mach_msg_destroy_port(mach_port_t port, mach_msg_type_name_t type)
181 {
182     if (MACH_PORT_VALID(port)) switch (type) {
183       case MACH_MSG_TYPE_MOVE_SEND:
184       case MACH_MSG_TYPE_MOVE_SEND_ONCE:
185 	/* destroy the send/send-once right */
186 	(void) mach_port_deallocate(mach_task_self(), port);
187 	break;
188 
189       case MACH_MSG_TYPE_MOVE_RECEIVE:
190 	/* destroy the receive right */
191 	(void) mach_port_mod_refs(mach_task_self(), port,
192 				  MACH_PORT_RIGHT_RECEIVE, -1);
193 	break;
194 
195       case MACH_MSG_TYPE_MAKE_SEND:
196 	/* create a send right and then destroy it */
197 	(void) mach_port_insert_right(mach_task_self(), port,
198 				      port, MACH_MSG_TYPE_MAKE_SEND);
199 	(void) mach_port_deallocate(mach_task_self(), port);
200 	break;
201 
202       case MACH_MSG_TYPE_MAKE_SEND_ONCE:
203 	/* create a send-once right and then destroy it */
204 	(void) mach_port_extract_right(mach_task_self(), port,
205 				       MACH_MSG_TYPE_MAKE_SEND_ONCE,
206 				       &port, &type);
207 	(void) mach_port_deallocate(mach_task_self(), port);
208 	break;
209     }
210 }
211 
212 static void
mach_msg_destroy_memory(vm_offset_t addr,vm_size_t size)213 mach_msg_destroy_memory(vm_offset_t addr, vm_size_t size)
214 {
215     if (size != 0)
216 	(void) mach_vm_deallocate(mach_task_self(), addr, size);
217 }
218 
219 /*
220  *	Routine:	mach_msg_destroy
221  *	Purpose:
222  *		mach_msg_destroy is useful in two contexts.
223  *
224  *		First, it can deallocate all port rights and
225  *		out-of-line memory in a received message.
226  *		When a server receives a request it doesn't want,
227  *		it needs this functionality.
228  *
229  *		Second, it can mimic the side-effects of a msg-send
230  *		operation.  The effect is as if the message were sent
231  *		and then destroyed inside the kernel.  When a server
232  *		can't send a reply (because the client died),
233  *		it needs this functionality.
234  */
235 void
mach_msg_destroy(mach_msg_header_t * msg)236 mach_msg_destroy(mach_msg_header_t *msg)
237 {
238     mach_msg_bits_t mbits = msg->msgh_bits;
239 
240     /*
241      *	The msgh_local_port field doesn't hold a port right.
242      *	The receive operation consumes the destination port right.
243      */
244 
245     mach_msg_destroy_port(msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(mbits));
246 
247     if (mbits & MACH_MSGH_BITS_COMPLEX) {
248 		mach_msg_base_t base __aligned(8);
249 		mach_msg_base_t *basep;
250 		mach_msg_body_t		*body;
251 		mach_msg_descriptor_t	*saddr, *eaddr;
252 
253 		basep = &base;
254 		memcpy(basep, msg, sizeof(base));
255     	body = (mach_msg_body_t *) (msg + 1);
256 		saddr = (mach_msg_descriptor_t *) (uintptr_t)(basep + 1);
257     	eaddr =  saddr + body->msgh_descriptor_count;
258 
259 	for  ( ; saddr < eaddr; saddr++) {
260 	    switch (saddr->type.type) {
261 
262 	        case MACH_MSG_PORT_DESCRIPTOR: {
263 		    mach_msg_port_descriptor_t *dsc;
264 
265 		    /*
266 		     * Destroy port rights carried in the message
267 		     */
268 		    dsc = &saddr->port;
269 		    mach_msg_destroy_port(dsc->name, dsc->disposition);
270 		    break;
271 	        }
272 
273 	        case MACH_MSG_OOL_DESCRIPTOR : {
274 		    mach_msg_ool_descriptor_t *dsc;
275 
276 		    /*
277 		     * Destroy memory carried in the message
278 		     */
279 		    dsc = &saddr->out_of_line;
280 		    if (dsc->deallocate) {
281 		        mach_msg_destroy_memory((vm_offset_t)dsc->address,
282 						dsc->size);
283 		    }
284 		    break;
285 	        }
286 
287 	        case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
288 		    mach_port_t             		*ports;
289 		    mach_msg_ool_ports_descriptor_t	*dsc;
290 		    mach_msg_type_number_t   		j;
291 
292 		    /*
293 		     * Destroy port rights carried in the message
294 		     */
295 		    dsc = &saddr->ool_ports;
296 		    ports = (mach_port_t *) dsc->address;
297 		    for (j = 0; j < dsc->count; j++, ports++)  {
298 		        mach_msg_destroy_port(*ports, dsc->disposition);
299 		    }
300 
301 		    /*
302 		     * Destroy memory carried in the message
303 		     */
304 		    if (dsc->deallocate) {
305 		        mach_msg_destroy_memory((vm_offset_t)dsc->address,
306 					dsc->count * sizeof(mach_port_t));
307 		    }
308 		    break;
309 	        }
310 	    }
311 	}
312     }
313 }
314 
315 /*
316  *	Routine:	mach_msg_server_once
317  *	Purpose:
318  *		A simple generic server function.  It allows more flexibility
319  *		than mach_msg_server by processing only one message request
320  *		and then returning to the user.  Note that more in the way
321  * 		of error codes are returned to the user; specifically, any
322  * 		failing error from mach_msg_overwrite_trap will be returned
323  *		(though errors from the demux routine or the routine it calls
324  *		will not be).
325  */
326 mach_msg_return_t
mach_msg_server_once(boolean_t (* demux)(mach_msg_header_t *,mach_msg_header_t *),mach_msg_size_t max_size,mach_port_t rcv_name,mach_msg_options_t options)327 mach_msg_server_once(
328     boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
329     mach_msg_size_t max_size,
330     mach_port_t rcv_name,
331     mach_msg_options_t options)
332 {
333     mig_reply_error_t *bufRequest = 0, *bufReply = 0, *bufTemp;
334     boolean_t allocatedRequest = FALSE, allocatedReply = FALSE, allocatedTemp;
335     register mach_msg_return_t mr;
336     register kern_return_t kr;
337 
338     if ((kr = mach_vm_allocate(mach_task_self(),
339 		     (vm_address_t *)&bufRequest,
340 		     max_size + MAX_TRAILER_SIZE,
341 		     TRUE)) != KERN_SUCCESS)
342       goto cleanup;
343     allocatedRequest = TRUE;
344 
345     if ((kr = mach_vm_allocate(mach_task_self(),
346 		     (vm_address_t *)&bufReply,
347 		     max_size + MAX_TRAILER_SIZE,
348 		     TRUE)) != KERN_SUCCESS)
349       goto cleanup;
350     allocatedReply = TRUE;
351 
352     mr = mach_msg_overwrite_trap(&bufRequest->Head, MACH_RCV_MSG|options,
353 				 0, max_size, rcv_name,
354 				 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
355 				 (mach_msg_header_t *) 0, 0);
356     if (mr == MACH_MSG_SUCCESS) {
357 	/* we have a request message */
358 
359 	(void) (*demux)(&bufRequest->Head, &bufReply->Head);
360 
361 	if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
362 	    bufReply->RetCode != KERN_SUCCESS) {
363 	    if (bufReply->RetCode == MIG_NO_REPLY) {
364 		/*
365 		 * This return code is a little tricky--
366 		 * it appears that the demux routine found an
367 		 * error of some sort, but since that error
368 		 * would not normally get returned either to
369 		 * the local user or the remote one, we pretend it's
370 		 * ok.
371 		 */
372 
373                 kr = KERN_SUCCESS;
374 		goto cleanup;
375             }
376 
377 	    /* don't destroy the reply port right,
378 	       so we can send an error message */
379 	    bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
380 	    mach_msg_destroy(&bufRequest->Head);
381 	}
382 
383 	if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
384 	    /* no reply port, so destroy the reply */
385 	    if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
386 		mach_msg_destroy(&bufReply->Head);
387 
388             kr = KERN_SUCCESS;
389             goto cleanup;
390 	}
391 
392 	/* send reply.  */
393 
394 	bufTemp = bufRequest;
395 	bufRequest = bufReply;
396 	bufReply = bufTemp;
397 
398         allocatedTemp = allocatedRequest;
399         allocatedRequest = allocatedReply;
400         allocatedReply = allocatedRequest;
401 
402 	/*
403 	 *	We don't want to block indefinitely because the client
404 	 *	isn't receiving messages from the reply port.
405 	 *	If we have a send-once right for the reply port, then
406 	 *	this isn't a concern because the send won't block.
407 	 *	If we have a send right, we need to use MACH_SEND_TIMEOUT.
408 	 *	To avoid falling off the kernel's fast RPC path unnecessarily,
409 	 *	we only supply MACH_SEND_TIMEOUT when absolutely necessary.
410 	 */
411 
412 	mr = mach_msg_overwrite_trap(&bufRequest->Head,
413 			 (MACH_MSGH_BITS_REMOTE(bufRequest->Head.msgh_bits) ==
414 			  MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
415 			 MACH_SEND_MSG|options :
416 			 MACH_SEND_MSG|MACH_SEND_TIMEOUT|options,
417 			 bufRequest->Head.msgh_size, 0, MACH_PORT_NULL,
418 			 0, MACH_PORT_NULL, (mach_msg_header_t *) 0, 0);
419     }
420     /* Has a message error occurred? */
421 
422     switch (mr) {
423       case MACH_SEND_INVALID_DEST:
424       case MACH_SEND_TIMED_OUT:
425 	/* the reply can't be delivered, so destroy it */
426 	mach_msg_destroy(&bufRequest->Head);
427         kr = KERN_SUCCESS;      /* Matches error hiding behavior in
428                                    mach_msg_server.  */
429         goto cleanup;
430 
431 
432       case MACH_RCV_TOO_LARGE:
433 	kr = KERN_SUCCESS;	/* Matches error hiding behavior in
434 				   mach_msg_server.  */
435         goto cleanup;
436 
437       default:
438 	/* Includes success case.  */
439         kr = mr;
440         goto cleanup;
441     }
442 
443 cleanup:
444         if ( allocatedRequest == TRUE )
445 	    (void)mach_vm_deallocate(mach_task_self(),
446 			    (vm_address_t) bufRequest,
447 			    max_size + MAX_TRAILER_SIZE);
448         if ( allocatedReply == TRUE )
449 	    (void)mach_vm_deallocate(mach_task_self(),
450 			    (vm_address_t) bufReply,
451 			    max_size + MAX_TRAILER_SIZE);
452         return kr;
453 
454 }
455 
456 /*
457  *	Routine:	mach_msg_server
458  *	Purpose:
459  *		A simple generic server function.  Note that changes here
460  * 		should be considered for duplication above.
461  */
462 mach_msg_return_t
mach_msg_server(boolean_t (* demux)(mach_msg_header_t *,mach_msg_header_t *),mach_msg_size_t max_size,mach_port_t rcv_name,mach_msg_options_t options)463 mach_msg_server(
464     boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *),
465     mach_msg_size_t max_size,
466     mach_port_t rcv_name,
467     mach_msg_options_t options)
468 {
469     mig_reply_error_t *bufRequest = 0, *bufReply = 0, *bufTemp;
470     boolean_t allocatedRequest = FALSE, allocatedReply = FALSE, allocatedTemp;
471     register mach_msg_return_t mr;
472     register kern_return_t kr;
473 
474     if ((kr = mach_vm_allocate(mach_task_self(),
475 		     (vm_address_t *)&bufRequest,
476 		     max_size + MAX_TRAILER_SIZE,
477 		     TRUE)) != KERN_SUCCESS)
478       goto cleanup;
479     allocatedRequest = TRUE;
480 
481     if ((kr = mach_vm_allocate(mach_task_self(),
482 		     (vm_address_t *)&bufReply,
483 		     max_size + MAX_TRAILER_SIZE,
484 		     TRUE)) != KERN_SUCCESS)
485       goto cleanup;
486     allocatedReply = TRUE;
487 
488     for (;;) {
489       get_request:
490 	mr = mach_msg_overwrite_trap(&bufRequest->Head, MACH_RCV_MSG|options,
491 		      0, max_size, rcv_name,
492 		      MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
493 		      (mach_msg_header_t *) 0, 0);
494 	while (mr == MACH_MSG_SUCCESS) {
495 	    /* we have a request message */
496 
497 	    (void) (*demux)(&bufRequest->Head, &bufReply->Head);
498 
499 	    if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
500 		bufReply->RetCode != KERN_SUCCESS) {
501 		    if (bufReply->RetCode == MIG_NO_REPLY)
502 			goto get_request;
503 
504 		    /* don't destroy the reply port right,
505 			so we can send an error message */
506 		    bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
507 		    mach_msg_destroy(&bufRequest->Head);
508 	    }
509 
510 	    if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
511 		/* no reply port, so destroy the reply */
512 		if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
513 		    mach_msg_destroy(&bufReply->Head);
514 
515 		goto get_request;
516 	    }
517 
518 	    /* send reply and get next request */
519 
520 	    bufTemp = bufRequest;
521 	    bufRequest = bufReply;
522 	    bufReply = bufTemp;
523 
524             allocatedTemp = allocatedRequest;
525             allocatedRequest = allocatedReply;
526             allocatedReply = allocatedTemp;
527 
528 	    /*
529 	     *	We don't want to block indefinitely because the client
530 	     *	isn't receiving messages from the reply port.
531 	     *	If we have a send-once right for the reply port, then
532 	     *	this isn't a concern because the send won't block.
533 	     *	If we have a send right, we need to use MACH_SEND_TIMEOUT.
534 	     *	To avoid falling off the kernel's fast RPC path unnecessarily,
535 	     *	we only supply MACH_SEND_TIMEOUT when absolutely necessary.
536 	     */
537 
538 	    mr = mach_msg_overwrite_trap(&bufRequest->Head,
539 			  (MACH_MSGH_BITS_REMOTE(bufRequest->Head.msgh_bits) ==
540 						MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
541 			  MACH_SEND_MSG|MACH_RCV_MSG|options :
542 			  MACH_SEND_MSG|MACH_SEND_TIMEOUT|MACH_RCV_MSG|options,
543 			  bufRequest->Head.msgh_size, max_size, rcv_name,
544 			  0, MACH_PORT_NULL, (mach_msg_header_t *) 0, 0);
545 	}
546 
547 	/* a message error occurred */
548 
549 	switch (mr) {
550 	  case MACH_SEND_INVALID_DEST:
551 	  case MACH_SEND_TIMED_OUT:
552 	    /* the reply can't be delivered, so destroy it */
553 	    mach_msg_destroy(&bufRequest->Head);
554             goto cleanup;
555 
556 	  case MACH_RCV_TOO_LARGE:
557 	    /* the kernel destroyed the request */
558             goto cleanup;
559 
560 	  default:
561 	    /* should only happen if the server is buggy */
562             kr = mr;
563             goto cleanup;
564 	}
565 
566 cleanup:
567         if ( allocatedRequest == TRUE )
568 	    (void)mach_vm_deallocate(mach_task_self(),
569 				(vm_address_t) bufRequest,
570 				max_size + MAX_TRAILER_SIZE);
571         if ( allocatedReply == TRUE )
572 	    (void)mach_vm_deallocate(mach_task_self(),
573 				(vm_address_t) bufReply,
574 				max_size + MAX_TRAILER_SIZE);
575     }
576 }
577