1/*
2 * Copyright (c) 2000-2004 Apple Computer, 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 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58
59#include <mach/boolean.h>
60#include <mach/port.h>
61#include <mach/mig.h>
62#include <mach/mig_errors.h>
63#include <mach/mach_types.h>
64#include <mach/mach_traps.h>
65
66#include <kern/ipc_tt.h>
67#include <kern/ipc_mig.h>
68#include <kern/kalloc.h>
69#include <kern/task.h>
70#include <kern/thread.h>
71#include <kern/ipc_kobject.h>
72#include <kern/misc_protos.h>
73
74#include <ipc/port.h>
75#include <ipc/ipc_kmsg.h>
76#include <ipc/ipc_entry.h>
77#include <ipc/ipc_object.h>
78#include <ipc/ipc_mqueue.h>
79#include <ipc/ipc_space.h>
80#include <ipc/ipc_port.h>
81#include <ipc/ipc_pset.h>
82#include <ipc/ipc_notify.h>
83#include <vm/vm_map.h>
84#include <mach/thread_act.h>
85
86#include <libkern/OSAtomic.h>
87
88#define KERNEL_DESC_SIZE sizeof(mach_msg_descriptor_t)
89
90void
91mach_msg_receive_results_complete(ipc_object_t object);
92
93/*
94 * Routine: mach_msg_send_from_kernel
95 * Purpose:
96 * Send a message from the kernel.
97 *
98 * This is used by the client side of KernelUser interfaces
99 * to implement SimpleRoutines. Currently, this includes
100 * memory_object messages.
101 * Conditions:
102 * Nothing locked.
103 * Returns:
104 * MACH_MSG_SUCCESS Sent the message.
105 * MACH_SEND_INVALID_DEST Bad destination port.
106 * MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer
107 * or destination is above kernel limit
108 */
109
110mach_msg_return_t
111mach_msg_send_from_kernel_proper(
112 mach_msg_header_t *msg,
113 mach_msg_size_t send_size)
114{
115 mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT;
116 mach_msg_timeout_t timeout_val = MACH_MSG_TIMEOUT_NONE;
117 return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL);
118}
119
120mach_msg_return_t
121mach_msg_send_from_kernel_with_options(
122 mach_msg_header_t *msg,
123 mach_msg_size_t send_size,
124 mach_msg_option_t option,
125 mach_msg_timeout_t timeout_val)
126{
127 return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL);
128}
129
130static mach_msg_return_t
131kernel_mach_msg_send_common(
132 ipc_kmsg_t kmsg,
133 mach_msg_option_t option,
134 mach_msg_timeout_t timeout_val,
135 boolean_t *message_moved)
136{
137 mach_msg_return_t mr;
138
139 mr = ipc_kmsg_copyin_from_kernel(kmsg);
140 if (mr != MACH_MSG_SUCCESS) {
141 ipc_kmsg_free(kmsg);
142 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
143 return mr;
144 }
145
146 if (message_moved) {
147 *message_moved = TRUE;
148 }
149
150 /*
151 * Until we are sure of its effects, we are disabling
152 * importance donation from the kernel-side of user
153 * threads in importance-donating tasks - unless the
154 * option to force importance donation is passed in,
155 * or the thread's SEND_IMPORTANCE option has been set.
156 * (11938665 & 23925818)
157 */
158 if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
159 option &= ~MACH_SEND_NOIMPORTANCE;
160 } else if ((option & MACH_SEND_IMPORTANCE) == 0) {
161 option |= MACH_SEND_NOIMPORTANCE;
162 }
163
164 mr = ipc_kmsg_send(kmsg, option64: option, timeout_val);
165
166 if (mr != MACH_MSG_SUCCESS) {
167 ipc_kmsg_destroy(kmsg, flags: IPC_KMSG_DESTROY_ALL);
168 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
169 }
170
171 return mr;
172}
173
174mach_msg_return_t
175kernel_mach_msg_send(
176 mach_msg_header_t *msg,
177 mach_msg_size_t send_size,
178 mach_msg_option_t option,
179 mach_msg_timeout_t timeout_val,
180 boolean_t *message_moved)
181{
182 ipc_kmsg_t kmsg;
183 mach_msg_return_t mr;
184
185 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
186
187 if (message_moved) {
188 *message_moved = FALSE;
189 }
190
191 mr = ipc_kmsg_get_from_kernel(msg, size: send_size, kmsgp: &kmsg);
192 if (mr != MACH_MSG_SUCCESS) {
193 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
194 return mr;
195 }
196
197 return kernel_mach_msg_send_common(kmsg, option, timeout_val, message_moved);
198}
199
200mach_msg_return_t
201kernel_mach_msg_send_with_builder_internal(
202 mach_msg_size_t desc_count,
203 mach_msg_size_t payload_size, /* Not total send size */
204 mach_msg_option_t option,
205 mach_msg_timeout_t timeout_val,
206 boolean_t *message_moved,
207 void (^builder)(mach_msg_header_t *,
208 mach_msg_descriptor_t *, void *))
209{
210 ipc_kmsg_t kmsg;
211 mach_msg_return_t mr;
212 mach_msg_header_t *hdr;
213 void *udata;
214 bool complex;
215 mach_msg_size_t send_size;
216 mach_msg_descriptor_t *desc;
217
218 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
219
220 /*
221 * If message has descriptors it must be complex and vice versa. We assume
222 * this for messages originated from kernel. The two are not equivalent for
223 * user messages for bin-compat reasons.
224 */
225 complex = (desc_count > 0);
226 send_size = sizeof(mach_msg_header_t) + payload_size;
227
228 if (complex) {
229 send_size += sizeof(mach_msg_body_t) + desc_count * KERNEL_DESC_SIZE;
230 }
231 if (message_moved) {
232 *message_moved = FALSE;
233 }
234
235 kmsg = ipc_kmsg_alloc(msg_size: send_size, aux_size: 0, desc_count,
236 flags: IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO);
237 /* kmsg can be non-linear */
238
239 if (kmsg == IKM_NULL) {
240 mr = MACH_SEND_NO_BUFFER;
241 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
242 return mr;
243 }
244
245 hdr = ikm_header(kmsg);
246 udata = (payload_size > 0) ? ikm_udata(kmsg, desc_count, complex) : NULL;
247 desc = (desc_count > 0) ? (mach_msg_descriptor_t *)((vm_address_t)hdr + sizeof(mach_msg_base_t)) : NULL;
248
249 /* Allow the caller to build the message, and sanity check it */
250 builder(hdr, desc, udata);
251 assert(hdr->msgh_size == send_size);
252 if (complex) {
253 assert(hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX);
254 hdr->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
255 /* Set the correct descriptor count */
256 ((mach_msg_base_t *)hdr)->body.msgh_descriptor_count = desc_count;
257 } else {
258 assert(!(hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX));
259 hdr->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
260 }
261
262 return kernel_mach_msg_send_common(kmsg, option, timeout_val, NULL);
263}
264
265mach_msg_return_t
266kernel_mach_msg_send_with_builder(
267 mach_msg_size_t desc_count,
268 mach_msg_size_t udata_size,
269 void (^builder)(mach_msg_header_t *,
270 mach_msg_descriptor_t *, void *))
271{
272 return kernel_mach_msg_send_with_builder_internal(desc_count, payload_size: udata_size,
273 MACH_SEND_KERNEL_DEFAULT, MACH_MSG_TIMEOUT_NONE, NULL, builder);
274}
275
276/*
277 * Routine: mach_msg_rpc_from_kernel
278 * Purpose:
279 * Send a message from the kernel and receive a reply.
280 * Uses ith_rpc_reply for the reply port.
281 *
282 * This is used by the client side of KernelUser interfaces
283 * to implement Routines.
284 * Conditions:
285 * Nothing locked.
286 * Returns:
287 * MACH_MSG_SUCCESS Sent the message.
288 * MACH_RCV_PORT_DIED The reply port was deallocated.
289 */
290
291mach_msg_return_t
292mach_msg_rpc_from_kernel_proper(
293 mach_msg_header_t *msg,
294 mach_msg_size_t send_size,
295 mach_msg_size_t rcv_size)
296{
297 return kernel_mach_msg_rpc(msg, send_size, rcv_size, TRUE, NULL);
298}
299
300mach_msg_return_t
301kernel_mach_msg_rpc(
302 mach_msg_header_t *msg,
303 mach_msg_size_t send_size,
304 mach_msg_size_t rcv_size,
305 boolean_t interruptible,
306 boolean_t *message_moved)
307{
308 thread_t self = current_thread();
309 ipc_port_t dest = IPC_PORT_NULL;
310 /* Sync IPC from kernel should pass adopted voucher and importance */
311 mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT & ~MACH_SEND_NOIMPORTANCE;
312 ipc_port_t reply;
313 ipc_kmsg_t kmsg;
314 mach_msg_header_t *hdr;
315 mach_port_seqno_t seqno;
316 mach_msg_return_t mr;
317
318 assert(msg->msgh_local_port == MACH_PORT_NULL);
319
320 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
321
322 if (message_moved) {
323 *message_moved = FALSE;
324 }
325
326 if (!IP_VALID(msg->msgh_remote_port)) {
327 return MACH_SEND_INVALID_DEST;
328 }
329
330 mr = ipc_kmsg_get_from_kernel(msg, size: send_size, kmsgp: &kmsg);
331 /* kmsg can be non-linear */
332
333 if (mr != MACH_MSG_SUCCESS) {
334 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
335 return mr;
336 }
337 hdr = ikm_header(kmsg);
338
339 reply = self->ith_kernel_reply_port;
340 if (reply == IP_NULL) {
341 thread_get_kernel_special_reply_port();
342 reply = self->ith_kernel_reply_port;
343 if (reply == IP_NULL) {
344 panic("mach_msg_rpc_from_kernel");
345 }
346 }
347
348 /* Get voucher port for the current thread's voucher */
349 ipc_voucher_t voucher = IPC_VOUCHER_NULL;
350 ipc_port_t voucher_port = IP_NULL;
351
352 /* Kernel server routines do not need voucher */
353 bool has_voucher = !ip_is_kobject(hdr->msgh_remote_port);
354
355 if (has_voucher && thread_get_mach_voucher(thr_act: self, which: 0, voucher: &voucher) == KERN_SUCCESS) {
356 /* If thread does not have a voucher, get the default voucher of the process */
357 if (voucher == IPC_VOUCHER_NULL) {
358 voucher = ipc_voucher_get_default_voucher();
359 }
360 voucher_port = convert_voucher_to_port(voucher);
361 ipc_kmsg_set_voucher_port(kmsg, voucher: voucher_port, MACH_MSG_TYPE_MOVE_SEND);
362 }
363
364 /* insert send-once right for the reply port and send right for the adopted voucher */
365 hdr->msgh_local_port = reply;
366 hdr->msgh_bits |=
367 MACH_MSGH_BITS_SET_PORTS(
368 0,
369 MACH_MSG_TYPE_MAKE_SEND_ONCE,
370 has_voucher ? MACH_MSG_TYPE_MOVE_SEND : 0);
371
372 mr = ipc_kmsg_copyin_from_kernel(kmsg);
373 if (mr != MACH_MSG_SUCCESS) {
374 /* Remove the voucher from the kmsg */
375 if (has_voucher) {
376 voucher_port = ipc_kmsg_get_voucher_port(kmsg);
377 ipc_kmsg_clear_voucher_port(kmsg);
378 ipc_port_release_send(port: voucher_port);
379 }
380
381 ipc_kmsg_free(kmsg);
382 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
383 return mr;
384 }
385
386 if (message_moved) {
387 *message_moved = TRUE;
388 }
389
390 /*
391 * Destination port would be needed during receive for creating
392 * Sync IPC linkage with kernel special reply port, grab a reference
393 * of the destination port before it gets donated to mqueue in ipc_kmsg_send.
394 */
395 dest = hdr->msgh_remote_port;
396 ip_reference(dest);
397
398 mr = ipc_kmsg_send(kmsg, option64: option, MACH_MSG_TIMEOUT_NONE);
399 if (mr != MACH_MSG_SUCCESS) {
400 ip_release(dest);
401 ipc_kmsg_destroy(kmsg, flags: IPC_KMSG_DESTROY_ALL);
402 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
403 return mr;
404 }
405
406 for (;;) {
407 assert(!ip_in_pset(reply));
408 require_ip_active(port: reply);
409
410 /* JMM - why this check? */
411 if (interruptible && !self->active && !self->inspection) {
412 ip_release(dest);
413 thread_dealloc_kernel_special_reply_port(thread: current_thread());
414 return MACH_RCV_INTERRUPTED;
415 }
416
417 /* Setup the sync IPC linkage for the special reply port */
418 ipc_port_link_special_reply_port(special_reply_port: reply,
419 dest_port: dest, FALSE);
420
421 ipc_mqueue_receive(waitq: &reply->ip_waitq,
422 option64: MACH64_MSG_OPTION_NONE,
423 MACH_MSG_SIZE_MAX,
424 max_aux_size: 0,
425 MACH_MSG_TIMEOUT_NONE,
426 interruptible: interruptible ? THREAD_INTERRUPTIBLE : THREAD_UNINT,
427 /* continuation ? */ false);
428
429 mr = self->ith_state;
430 kmsg = self->ith_kmsg;
431 seqno = self->ith_seqno;
432
433 mach_msg_receive_results_complete(ip_to_object(reply));
434
435 if (mr == MACH_MSG_SUCCESS) {
436 break;
437 }
438
439 assert(mr == MACH_RCV_INTERRUPTED);
440 assert(interruptible);
441 assert(reply == self->ith_kernel_reply_port);
442
443 if (thread_ast_peek(self, AST_APC)) {
444 ip_release(dest);
445 thread_dealloc_kernel_special_reply_port(thread: current_thread());
446 return mr;
447 }
448 }
449
450 /* release the destination port ref acquired above */
451 ip_release(dest);
452 dest = IPC_PORT_NULL;
453
454 /* reload hdr from reply kmsg got above */
455 hdr = ikm_header(kmsg);
456
457 mach_msg_size_t kmsg_size = hdr->msgh_size;
458 mach_msg_size_t kmsg_and_max_trailer_size;
459
460 /*
461 * The amount of trailer to receive is flexible (see below),
462 * but the kmsg header must have a size that allows for a maximum
463 * trailer to follow as that's how IPC works (otherwise it might be corrupt).
464 */
465 if (os_add_overflow(kmsg_size, MAX_TRAILER_SIZE, &kmsg_and_max_trailer_size)) {
466 panic("kernel_mach_msg_rpc");
467 }
468
469 /* The message header and body itself must be receivable */
470 if (rcv_size < kmsg_size) {
471 ipc_kmsg_destroy(kmsg, flags: IPC_KMSG_DESTROY_ALL);
472 return MACH_RCV_TOO_LARGE;
473 }
474
475 /*
476 * We want to preserve rights and memory in reply!
477 * We don't have to put them anywhere; just leave them
478 * as they are.
479 */
480 ipc_kmsg_copyout_dest_to_kernel(kmsg, space: ipc_space_reply);
481
482 mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *)
483 ipc_kmsg_get_trailer(kmsg, false);
484
485 /* Determine what trailer bits we can receive (as no option specified) */
486 if (rcv_size < kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE) {
487 rcv_size = kmsg_size;
488 } else {
489 if (rcv_size >= kmsg_and_max_trailer_size) {
490 /*
491 * Enough room for a maximum trailer.
492 * JMM - we really should set the expected receiver-set fields:
493 * (seqno, context, filterid, etc...) but nothing currently
494 * expects them anyway.
495 */
496 trailer->msgh_trailer_size = MAX_TRAILER_SIZE;
497 rcv_size = kmsg_and_max_trailer_size;
498 } else {
499 assert(trailer->msgh_trailer_size == MACH_MSG_TRAILER_MINIMUM_SIZE);
500 rcv_size = kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE;
501 }
502 }
503 assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0);
504 mr = MACH_MSG_SUCCESS;
505
506 ipc_kmsg_put_to_kernel(msg, kmsg, size: rcv_size);
507 return mr;
508}
509
510/*
511 * Routine: mach_msg_destroy_from_kernel_proper
512 * Purpose:
513 * mach_msg_destroy_from_kernel_proper is used to destroy
514 * an unwanted/unexpected reply message from a MIG
515 * kernel-specific user-side stub. It is like ipc_kmsg_destroy(),
516 * except we no longer have the kmsg - just the contents.
517 */
518void
519mach_msg_destroy_from_kernel_proper(mach_msg_header_t *msg)
520{
521 mach_msg_bits_t mbits = msg->msgh_bits;
522 ipc_object_t object;
523
524 object = (ipc_object_t) msg->msgh_remote_port;
525 if (IO_VALID(object)) {
526 ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
527 }
528
529 /*
530 * The destination (now in msg->msgh_local_port via
531 * ipc_kmsg_copyout_dest_to_kernel) has been consumed with
532 * ipc_object_copyout_dest.
533 */
534
535 /* MIG kernel users don't receive vouchers */
536 assert(!MACH_MSGH_BITS_VOUCHER(mbits));
537
538 /* For simple messages, we're done */
539 if ((mbits & MACH_MSGH_BITS_COMPLEX) == 0) {
540 return;
541 }
542
543 /* Discard descriptor contents */
544 mach_msg_body_t *body = (mach_msg_body_t *)(msg + 1);
545 mach_msg_descriptor_t *daddr = (mach_msg_descriptor_t *)(body + 1);
546 mach_msg_size_t i;
547
548 for (i = 0; i < body->msgh_descriptor_count; i++, daddr++) {
549 switch (daddr->type.type) {
550 case MACH_MSG_PORT_DESCRIPTOR: {
551 mach_msg_port_descriptor_t *dsc = &daddr->port;
552 if (IO_VALID((ipc_object_t) dsc->name)) {
553 ipc_object_destroy(object: (ipc_object_t) dsc->name, msgt_name: dsc->disposition);
554 }
555 break;
556 }
557 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
558 case MACH_MSG_OOL_DESCRIPTOR: {
559 mach_msg_ool_descriptor_t *dsc =
560 (mach_msg_ool_descriptor_t *)&daddr->out_of_line;
561
562 if (dsc->size > 0) {
563 vm_map_copy_discard(copy: (vm_map_copy_t) dsc->address);
564 } else {
565 assert(dsc->address == (void *) 0);
566 }
567 break;
568 }
569 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
570 ipc_object_t *objects;
571 mach_msg_type_number_t j;
572 mach_msg_ool_ports_descriptor_t *dsc;
573
574 dsc = (mach_msg_ool_ports_descriptor_t *)&daddr->ool_ports;
575 objects = (ipc_object_t *) dsc->address;
576
577 if (dsc->count == 0) {
578 break;
579 }
580 assert(objects != 0);
581 for (j = 0; j < dsc->count; j++) {
582 object = objects[j];
583 if (IO_VALID(object)) {
584 ipc_object_destroy(object, msgt_name: dsc->disposition);
585 }
586 }
587 kfree_type(mach_port_t, dsc->count, dsc->address);
588 break;
589 }
590 case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
591 mach_msg_guarded_port_descriptor_t *dsc = (mach_msg_guarded_port_descriptor_t *)&daddr->guarded_port;
592 if (IO_VALID((ipc_object_t) dsc->name)) {
593 ipc_object_destroy(object: (ipc_object_t) dsc->name, msgt_name: dsc->disposition);
594 }
595 break;
596 }
597 default:
598 break;
599 }
600 }
601}
602
603/************** These Calls are set up for kernel-loaded tasks/threads **************/
604
605/*
606 * Routine: mig_get_reply_port
607 * Purpose:
608 * Called by client side interfaces living in the kernel
609 * to get a reply port.
610 */
611mach_port_t
612mig_get_reply_port(void)
613{
614 return MACH_PORT_NULL;
615}
616
617/*
618 * Routine: mig_dealloc_reply_port
619 * Purpose:
620 * Called by client side interfaces to get rid of a reply port.
621 */
622
623void
624mig_dealloc_reply_port(
625 __unused mach_port_t reply_port)
626{
627}
628
629/*
630 * Routine: mig_put_reply_port
631 * Purpose:
632 * Called by client side interfaces after each RPC to
633 * let the client recycle the reply port if it wishes.
634 */
635void
636mig_put_reply_port(
637 __unused mach_port_t reply_port)
638{
639}
640
641/*
642 * mig_strncpy.c - by Joshua Block
643 *
644 * mig_strncp -- Bounded string copy. Does what the library routine strncpy
645 * OUGHT to do: Copies the (null terminated) string in src into dest, a
646 * buffer of length len. Assures that the copy is still null terminated
647 * and doesn't overflow the buffer, truncating the copy if necessary.
648 *
649 * Parameters:
650 *
651 * dest - Pointer to destination buffer.
652 *
653 * src - Pointer to source string.
654 *
655 * len - Length of destination buffer.
656 */
657int
658mig_strncpy(
659 char *dest,
660 const char *src,
661 int len)
662{
663 int i = 0;
664
665 if (len > 0) {
666 if (dest != NULL) {
667 if (src != NULL) {
668 for (i = 1; i < len; i++) {
669 if (!(*dest++ = *src++)) {
670 return i;
671 }
672 }
673 }
674 *dest = '\0';
675 }
676 }
677 return i;
678}
679
680/*
681 * mig_strncpy_zerofill -- Bounded string copy. Does what the
682 * library routine strncpy OUGHT to do: Copies the (null terminated)
683 * string in src into dest, a buffer of length len. Assures that
684 * the copy is still null terminated and doesn't overflow the buffer,
685 * truncating the copy if necessary. If the string in src is smaller
686 * than given length len, it will zero fill the remaining bytes in dest.
687 *
688 * Parameters:
689 *
690 * dest - Pointer to destination buffer.
691 *
692 * src - Pointer to source string.
693 *
694 * len - Length of destination buffer.
695 */
696int
697mig_strncpy_zerofill(
698 char *dest,
699 const char *src,
700 int len)
701{
702 int i = 0;
703 boolean_t terminated = FALSE;
704 int retval = 0;
705
706 if (len <= 0 || dest == NULL) {
707 return 0;
708 }
709
710 if (src == NULL) {
711 terminated = TRUE;
712 }
713
714 for (i = 1; i < len; i++) {
715 if (!terminated) {
716 if (!(*dest++ = *src++)) {
717 retval = i;
718 terminated = TRUE;
719 }
720 } else {
721 *dest++ = '\0';
722 }
723 }
724
725 *dest = '\0';
726 if (!terminated) {
727 retval = i;
728 }
729
730 return retval;
731}
732
733void *
734mig_user_allocate(
735 vm_size_t size)
736{
737 return kalloc_type_var_impl(KT_IPC_KMSG_KDATA_OOL,
738 size, Z_WAITOK, NULL);
739}
740
741void
742mig_user_deallocate(
743 char *data,
744 vm_size_t size)
745{
746 kfree_type_var_impl(kt_view: KT_IPC_KMSG_KDATA_OOL, ptr: data, size);
747}
748