No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / mach / mach_message.c
blob6bd959f318f7978e108b7b2a2d39e8ab39c21e09
1 /* $NetBSD: mach_message.c,v 1.58 2009/03/14 21:04:18 dsl Exp $ */
3 /*-
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.58 2009/03/14 21:04:18 dsl Exp $");
35 #include "opt_compat_mach.h" /* For COMPAT_MACH in <sys/ktrace.h> */
36 #include "opt_compat_darwin.h"
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/signal.h>
42 #include <sys/proc.h>
43 #include <sys/kernel.h>
44 #include <sys/queue.h>
45 #include <sys/malloc.h>
46 #include <sys/pool.h>
47 #include <sys/ktrace.h>
49 #include <uvm/uvm_extern.h>
50 #include <uvm/uvm_map.h>
52 #include <compat/mach/mach_types.h>
53 #include <compat/mach/mach_message.h>
54 #include <compat/mach/mach_port.h>
55 #include <compat/mach/mach_exec.h>
56 #include <compat/mach/mach_clock.h>
57 #include <compat/mach/mach_syscallargs.h>
59 #ifdef COMPAT_DARWIN
60 #include <compat/darwin/darwin_exec.h>
61 #endif
63 /* Mach message pool */
64 static struct pool mach_message_pool;
66 static inline
67 int mach_msg_send(struct lwp *, mach_msg_header_t *, int *, size_t);
68 static inline int mach_msg_recv(struct lwp *, mach_msg_header_t *,
69 int, size_t, unsigned int, mach_port_t);
70 static inline
71 struct lwp *mach_get_target_task(struct lwp *, struct mach_port *);
72 static inline void mach_drop_rights(struct mach_right *, int);
73 static inline
74 void mach_trade_rights(struct lwp *, struct lwp *, mach_port_t *, int);
75 static inline
76 int mach_trade_rights_complex(struct lwp *, struct mach_message *);
78 int
79 mach_sys_msg_overwrite_trap(struct lwp *l, const struct mach_sys_msg_overwrite_trap_args *uap, register_t *retval)
81 /* {
82 syscallarg(mach_msg_header_t *) msg;
83 syscallarg(mach_msg_option_t) option;
84 syscallarg(mach_msg_size_t) send_size;
85 syscallarg(mach_msg_size_t) rcv_size;
86 syscallarg(mach_port_name_t) rcv_name;
87 syscallarg(mach_msg_timeout_t) timeout;
88 syscallarg(mach_port_name_t) notify;
89 syscallarg(mach_msg_header_t *) rcv_msg;
90 syscallarg(mach_msg_size_t) scatter_list_size;
91 } */
92 size_t send_size, recv_size;
93 mach_msg_header_t *msg;
94 int opt;
96 *retval = MACH_MSG_SUCCESS;
97 send_size = SCARG(uap, send_size);
98 recv_size = SCARG(uap, rcv_size);
99 opt = SCARG(uap, option);
101 /* XXX not safe enough: lots of big messages will kill us */
102 if (send_size > MACH_MAX_MSG_LEN) {
103 *retval = MACH_SEND_TOO_LARGE;
104 return 0;
106 if (recv_size > MACH_MAX_MSG_LEN) {
107 *retval = MACH_RCV_TOO_LARGE;
108 return 0;
112 * Two options: receive or send. If both are
113 * set, we must send, and then receive. If
114 * send fail, then we skip recieve.
116 msg = SCARG(uap, msg);
117 if (opt & MACH_SEND_MSG)
118 *retval = mach_msg_send(l, msg, &opt, send_size);
120 if ((opt & MACH_RCV_MSG) && (*retval == MACH_MSG_SUCCESS)) {
122 * Find a buffer for the reply.
124 if (SCARG(uap, rcv_msg) != NULL)
125 msg = SCARG(uap, rcv_msg);
126 else if (SCARG(uap, msg) != NULL)
127 msg = SCARG(uap, msg);
128 else {
129 *retval = MACH_RCV_INVALID_DATA;
130 return 0;
133 *retval = mach_msg_recv(l, msg, opt, recv_size,
134 SCARG(uap, timeout), SCARG(uap, rcv_name));
137 return 0;
141 * Send a Mach message. This returns a Mach message error code.
143 static inline int
144 mach_msg_send(struct lwp *l, mach_msg_header_t *msg, int *option, size_t send_size)
146 struct mach_emuldata *med;
147 struct mach_port *mp;
148 struct proc *p = l->l_proc;
149 mach_msg_header_t *sm;
150 struct mach_service *srv;
151 mach_port_t ln;
152 mach_port_t rn;
153 struct mach_right *lr = NULL;
154 struct mach_right *rr;
155 int rights;
156 int bits;
157 int ret;
158 size_t reply_size;
159 int error = 0;
161 if (msg == NULL)
162 return MACH_SEND_INVALID_DATA;
165 * Allocate memory for the message and its reply,
166 * and copy the whole message in the kernel.
168 sm = malloc(send_size, M_EMULDATA, M_WAITOK);
169 if ((error = copyin(msg, sm, send_size)) != 0) {
170 ret = MACH_SEND_INVALID_DATA;
171 goto out1;
174 /* Dump the Mach message */
175 ktrmmsg((char *)sm, send_size);
178 * Handle rights in the message
180 ln = sm->msgh_local_port;
181 rn = sm->msgh_remote_port;
183 lr = mach_right_check(ln, l, MACH_PORT_TYPE_ALL_RIGHTS);
184 rr = mach_right_check(rn, l, MACH_PORT_TYPE_ALL_RIGHTS);
185 if ((rr == NULL) || (rr->mr_port == NULL)) {
186 #ifdef DEBUG_MACH
187 printf("msg id %d: invalid dest\n", sm->msgh_id);
188 #endif
189 ret = MACH_SEND_INVALID_DEST;
190 goto out1;
194 * Check that the process has a send right on
195 * the remote port.
197 rights = (MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_SEND_ONCE);
198 if (mach_right_check(rn, l, rights) == NULL) {
199 ret = MACH_SEND_INVALID_RIGHT;
200 goto out1;
204 * If the remote port is a special port (host, kernel,
205 * clock, or io_master), the message will be handled
206 * by the kernel.
208 med = (struct mach_emuldata *)p->p_emuldata;
209 mp = rr->mr_port;
210 if (mp->mp_flags & MACH_MP_INKERNEL) {
211 struct mach_trap_args args;
212 mach_msg_header_t *rm;
213 size_t min_reqlen, max_replen;
216 * Look for the function that will handle it,
217 * using the message id.
219 for (srv = mach_services_table; srv->srv_id; srv++)
220 if (srv->srv_id == sm->msgh_id)
221 break;
224 * If no match, give up, and display a warning.
226 if (srv->srv_handler == NULL) {
227 uprintf("No mach server for id = %d\n",
228 sm->msgh_id);
229 ret = MACH_SEND_INVALID_DEST;
230 goto out1;
232 min_reqlen = srv->srv_reqlen;
233 max_replen = srv->srv_replen;
236 * Special case when the kernel behaves as
237 * the client: replies to exceptions and
238 * notifications. There will be no reply,
239 * as we already receive a reply.
240 * - request and reply are swapped
241 * - there will be no reply, so set lr to NULL.
242 * - skip the lr == NULL tests
243 * XXX This is inelegant.
245 if ((sm->msgh_id >= 2501) && (sm->msgh_id <= 2503)) {
246 min_reqlen = srv->srv_replen;
247 max_replen = srv->srv_reqlen;
248 lr = NULL;
249 goto skip_null_lr;
253 * Check that the local port is valid, else
254 * we will not be able to send the reply
256 if ((lr == NULL) ||
257 (lr->mr_port == NULL) ||
258 (lr->mr_port->mp_recv == NULL)) {
259 #ifdef DEBUG_MACH
260 printf("msg id %d: invalid src\n", sm->msgh_id);
261 #endif
262 ret = MACH_SEND_INVALID_REPLY;
263 goto out1;
265 skip_null_lr:
268 * Sanity check message length. We do not want the
269 * server to:
270 * 1) use kernel memory located after
271 * the end of the request message.
273 if (send_size < min_reqlen) {
274 #ifdef DEBUG_MACH
275 printf("mach server %s: smsg overflow: "
276 "send = %d, min = %d\n",
277 srv->srv_name, send_size, min_reqlen);
278 #endif
279 ret = MACH_SEND_MSG_TOO_SMALL;
280 goto out1;
284 * 2) Overwrite kernel memory after the end of the
285 * reply message buffer. This check is the
286 * responsibility of the server.
291 * Invoke the server. We give it the opportunity
292 * to shorten recv_size if there is less data in
293 * the reply than what the sender expected.
294 * If lr is NULL, this is a no reply operation.
296 reply_size = max_replen;
297 if (lr != NULL)
298 rm = malloc(reply_size, M_EMULDATA, M_WAITOK | M_ZERO);
299 else
300 rm = NULL;
302 args.l = l;
303 args.tl = mach_get_target_task(l, mp);
304 args.smsg = sm;
305 args.rmsg = rm;
306 args.rsize = &reply_size;
307 args.ssize = send_size;
308 if ((ret = (*srv->srv_handler)(&args)) != 0)
309 goto out1;
312 * No-reply opration: everything is done.
313 * Change option so that we skip the
314 * receive stage.
316 if (lr == NULL) {
317 *option &= ~MACH_RCV_MSG;
318 return MACH_MSG_SUCCESS;
321 #ifdef DIAGNOSTIC
323 * Catch potential bug in the server (sanity
324 * check #2): did it output a larger message
325 * then the one that was allocated?
327 if ((*option & MACH_RCV_MSG) && (reply_size > max_replen)) {
328 uprintf("mach_msg: reply too big in %s\n",
329 srv->srv_name);
331 #endif
334 * Queue the reply.
336 mp = lr->mr_port;
337 (void)mach_message_get(rm, reply_size, mp, NULL);
338 #ifdef DEBUG_MACH_MSG
339 printf("pid %d: message queued on port %p (%d) [%p]\n",
340 p->p_pid, mp, rm->msgh_id,
341 mp->mp_recv->mr_sethead);
342 if (sm->msgh_id == 404)
343 printf("*** msg to bootstrap. port = %p, "
344 "recv = %p [%p]\n", mach_bootstrap_port,
345 mach_bootstrap_port->mp_recv,
346 mach_bootstrap_port->mp_recv->mr_sethead);
347 #endif
348 wakeup(mp->mp_recv->mr_sethead);
349 ret = MACH_MSG_SUCCESS;
350 out1:
351 free(sm, M_EMULDATA);
353 return ret;
357 * The message is not to be handled by the kernel.
358 * Check that there is a valid receiver, and
359 * queue the message in the remote port.
361 mp = rr->mr_port; /* (mp != NULL) already checked */
362 if (mp->mp_recv == NULL) {
363 #ifdef DEBUG_MACH
364 printf("msg id %d: invalid dst\n", sm->msgh_id);
365 #endif
366 free(sm, M_EMULDATA);
367 return MACH_SEND_INVALID_DEST;
370 (void)mach_message_get(sm, send_size, mp, l);
371 #ifdef DEBUG_MACH_MSG
372 printf("pid %d: message queued on port %p (%d) [%p]\n",
373 p->p_pid, mp, sm->msgh_id,
374 mp->mp_recv->mr_sethead);
375 #endif
377 * Drop any right carried by the message.
379 if (lr != NULL) {
380 bits = MACH_MSGH_LOCAL_BITS(sm->msgh_bits);
381 mach_drop_rights(lr, bits);
384 if (rr != NULL) {
385 bits = MACH_MSGH_REMOTE_BITS(sm->msgh_bits);
386 mach_drop_rights(rr, bits);
390 * Wakeup any process awaiting for this message.
392 wakeup(mp->mp_recv->mr_sethead);
394 return MACH_MSG_SUCCESS;
398 * Receive a Mach message. This returns a Mach message error code.
400 static inline int
401 mach_msg_recv(struct lwp *l, mach_msg_header_t *urm, int option, size_t recv_size, unsigned int timeout, mach_port_t mn)
403 struct mach_port *mp;
404 #if defined(DEBUG_MACH_MSG) || defined(KTRACE)
405 struct proc *p = l->l_proc;
406 #endif
407 struct mach_message *mm;
408 mach_port_t tmp;
409 struct mach_right *cmr;
410 struct mach_right *mr;
411 int bits;
412 int ret;
413 int error = 0;
415 mp = NULL;
417 if (option & MACH_RCV_TIMEOUT)
418 timeout = timeout * hz / 1000;
419 else
420 timeout = 0;
423 * Check for receive right on the port.
425 mr = mach_right_check(mn, l, MACH_PORT_TYPE_RECEIVE);
426 if (mr == NULL) {
429 * Is it a port set?
431 mr = mach_right_check(mn, l, MACH_PORT_TYPE_PORT_SET);
432 if (mr == NULL)
433 return MACH_RCV_INVALID_NAME;
436 * This is a port set. For each port in the
437 * port set, check we have receive right, and
438 * and check if we have some message.
440 LIST_FOREACH(cmr, &mr->mr_set, mr_setlist) {
441 if ((mach_right_check(cmr->mr_name, l,
442 MACH_PORT_TYPE_RECEIVE)) == NULL)
443 return MACH_RCV_INVALID_NAME;
445 mp = cmr->mr_port;
446 #ifdef DEBUG_MACH
447 if (mp->mp_recv != cmr)
448 uprintf("mach_msg_trap: bad receive "
449 "port/right\n");
450 #endif
451 if (mp->mp_count != 0)
452 break;
456 * If cmr is NULL then we found no message on
457 * any port. Sleep on the port set until we get
458 * some or until we get a timeout.
460 if (cmr == NULL) {
461 #ifdef DEBUG_MACH_MSG
462 printf("pid %d: wait on port %p [%p]\n",
463 p->p_pid, mp, mr->mr_sethead);
464 #endif
465 error = tsleep(mr->mr_sethead, PZERO|PCATCH,
466 "mach_msg", timeout);
467 if ((error == ERESTART) || (error == EINTR))
468 return MACH_RCV_INTERRUPTED;
471 * Check we did not loose the receive right
472 * while we were sleeping.
474 if ((mach_right_check(mn, l,
475 MACH_PORT_TYPE_PORT_SET)) == NULL)
476 return MACH_RCV_PORT_DIED;
479 * Is there any pending message for
480 * a port in the port set?
482 LIST_FOREACH(cmr, &mr->mr_set, mr_setlist) {
483 mp = cmr->mr_port;
484 if (mp->mp_count != 0)
485 break;
488 if (cmr == NULL)
489 return MACH_RCV_TIMED_OUT;
493 * We found a port with a pending message.
495 mp = cmr->mr_port;
497 } else {
499 * This is a receive on a simple port (no port set).
500 * If there is no message queued on the port,
501 * block until we get some.
503 mp = mr->mr_port;
505 #ifdef DEBUG_MACH
506 if (mp->mp_recv != mr)
507 uprintf("mach_msg_trap: bad receive "
508 "port/right\n");
509 #endif
510 #ifdef DEBUG_MACH_MSG
511 printf("pid %d: wait on port %p [%p]\n",
512 p->p_pid, mp, mr->mr_sethead);
513 #endif
514 if (mp->mp_count == 0) {
515 error = tsleep(mr->mr_sethead, PZERO|PCATCH,
516 "mach_msg", timeout);
517 if ((error == ERESTART) || (error == EINTR))
518 return MACH_RCV_INTERRUPTED;
521 * Check we did not lose the receive right
522 * while we were sleeping.
524 if ((mach_right_check(mn, l,
525 MACH_PORT_TYPE_RECEIVE)) == NULL)
526 return MACH_RCV_PORT_DIED;
528 if (mp->mp_count == 0)
529 return MACH_RCV_TIMED_OUT;
534 * Dequeue the message.
535 * XXX Do we really need to lock here? There could be
536 * only one reader process, so mm will not disapear
537 * except if there is a port refcount error in our code.
539 rw_enter(&mp->mp_msglock, RW_READER);
540 mm = TAILQ_FIRST(&mp->mp_msglist);
541 #ifdef DEBUG_MACH_MSG
542 printf("pid %d: dequeue message on port %p (id %d)\n",
543 p->p_pid, mp, mm->mm_msg->msgh_id);
544 #endif
546 ret = MACH_MSG_SUCCESS;
547 if (mm->mm_size > recv_size) {
548 struct mach_short_reply sr;
550 ret = MACH_RCV_TOO_LARGE;
552 * If MACH_RCV_LARGE was not set, destroy the message.
554 if ((option & MACH_RCV_LARGE) == 0) {
555 free(mm->mm_msg, M_EMULDATA);
556 mach_message_put_shlocked(mm);
557 goto unlock;
561 * If MACH_RCV_TOO_LARGE is set, then return
562 * a message with just header and trailer. The
563 * size in the header should correspond to the
564 * whole message, so just copy the whole header.
566 memcpy(&sr, mm->mm_msg, sizeof(mach_msg_header_t));
567 mach_set_trailer(&sr, sizeof(sr));
569 if ((error = copyout(&sr, urm, sizeof(sr))) != 0) {
570 ret = MACH_RCV_INVALID_DATA;
571 goto unlock;
574 /* Dump the Mach message */
575 ktrmmsg((char *)&sr, sizeof(sr));
576 goto unlock;
580 * Get rights carried by the message if it is not a
581 * reply from the kernel.
582 * XXX mm->mm_l could contain stall data. Reference
583 * the thread's kernel port instead?
585 if (mm->mm_l != NULL) {
586 mach_port_t *mnp;
587 #ifdef DEBUG_MACH
588 printf("mach_msg: non kernel-reply message\n");
589 #endif
591 * Turn local and remote port names into
592 * names in the local process namespace.
594 bits = MACH_MSGH_LOCAL_BITS(mm->mm_msg->msgh_bits);
595 mnp = &mm->mm_msg->msgh_local_port;
596 mach_trade_rights(l, mm->mm_l, mnp, bits);
598 bits = MACH_MSGH_REMOTE_BITS(mm->mm_msg->msgh_bits);
599 mnp = &mm->mm_msg->msgh_remote_port;
600 mach_trade_rights(l, mm->mm_l, mnp, bits);
603 * The same operation must be done to all
604 * port descriptors carried with the message.
606 if ((mm->mm_msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
607 ((ret = mach_trade_rights_complex(l, mm)) != 0))
608 goto unlock;
611 * swap local and remote ports, and
612 * corresponding bits as well.
614 bits = (bits & 0xffff0000) |
615 ((bits & 0xff00) >> 8) |
616 ((bits & 0x00ff) << 8);
617 tmp = mm->mm_msg->msgh_remote_port;
618 mm->mm_msg->msgh_remote_port =
619 mm->mm_msg->msgh_local_port;
620 mm->mm_msg->msgh_local_port = tmp;
624 * Copy the message to userland.
626 if ((error = copyout(mm->mm_msg, urm, mm->mm_size)) != 0) {
627 ret = MACH_RCV_INVALID_DATA;
628 goto unlock;
631 /* Dump the Mach message */
632 ktrmmsg((char *)mm->mm_msg, mm->mm_size);
634 free(mm->mm_msg, M_EMULDATA);
635 mach_message_put_shlocked(mm); /* decrease mp_count */
636 unlock:
637 rw_exit(&mp->mp_msglock);
639 return ret;
644 mach_sys_msg_trap(struct lwp *l, const struct mach_sys_msg_trap_args *uap, register_t *retval)
646 /* {
647 syscallarg(mach_msg_header_t *) msg;
648 syscallarg(mach_msg_option_t) option;
649 syscallarg(mach_msg_size_t) send_size;
650 syscallarg(mach_msg_size_t) rcv_size;
651 syscallarg(mach_port_name_t) rcv_name;
652 syscallarg(mach_msg_timeout_t) timeout;
653 syscallarg(mach_port_name_t) notify;
654 } */
655 struct mach_sys_msg_overwrite_trap_args cup;
657 SCARG(&cup, msg) = SCARG(uap, msg);
658 SCARG(&cup, option) = SCARG(uap, option);
659 SCARG(&cup, send_size) = SCARG(uap, send_size);
660 SCARG(&cup, rcv_size) = SCARG(uap, rcv_size);
661 SCARG(&cup, rcv_name) = SCARG(uap, rcv_name);
662 SCARG(&cup, timeout) = SCARG(uap, timeout);
663 SCARG(&cup, notify) = SCARG(uap, notify);
664 SCARG(&cup, rcv_msg) = NULL;
665 SCARG(&cup, scatter_list_size) = 0;
667 return mach_sys_msg_overwrite_trap(l, &cup, retval);
670 static inline struct lwp *
671 mach_get_target_task(struct lwp *l, struct mach_port *mp)
673 struct proc *tp;
674 struct lwp *tl;
676 switch (mp->mp_datatype) {
677 case MACH_MP_PROC:
678 tp = (struct proc *)mp->mp_data;
679 tl = LIST_FIRST(&tp->p_lwps);
680 KASSERT(tl != NULL);
681 break;
683 case MACH_MP_LWP:
684 tl = (struct lwp *)mp->mp_data;
685 break;
687 default:
688 tl = l;
689 break;
692 return tl;
695 static inline void
696 mach_drop_rights(struct mach_right *mr, int bits)
698 int rights;
700 switch (bits) {
701 case MACH_MSG_TYPE_MOVE_SEND:
702 rights = MACH_PORT_TYPE_SEND;
703 break;
704 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
705 rights = MACH_PORT_TYPE_SEND_ONCE;
706 break;
707 case MACH_MSG_TYPE_MOVE_RECEIVE:
708 /* Recv. right is lost when msg is received */
709 case MACH_MSG_TYPE_MAKE_SEND:
710 case MACH_MSG_TYPE_COPY_SEND:
711 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
712 default:
713 rights = 0;
714 break;
717 if (rights != 0)
718 mach_right_put(mr, rights);
720 return;
724 * When a messages is transmitted from one process to another,
725 * we need to make sure the port names are in the receiver process
726 * namespace.
728 static inline void
729 mach_trade_rights(struct lwp *ll, struct lwp *rl, mach_port_t *mnp, int bits)
730 /* ll: local lwp (receiver, current lwp) */
731 /* rl: remote lwp (sender) */
732 /* mnp: pointer to the port name */
733 /* bits: right bits */
735 int lr; /* local right type (to be added) */
736 int rr; /* remote right type */
737 struct mach_right *lmr; /* right in the local process */
738 struct mach_right *rmr; /* right in the remote process */
740 switch (bits) {
741 case MACH_MSG_TYPE_MAKE_SEND:
742 rr = MACH_PORT_TYPE_RECEIVE;
743 lr = MACH_PORT_TYPE_SEND;
744 break;
746 case MACH_MSG_TYPE_COPY_SEND:
747 case MACH_MSG_TYPE_MOVE_SEND:
748 rr = MACH_PORT_TYPE_SEND;
749 lr = MACH_PORT_TYPE_SEND;
750 break;
752 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
753 rr = MACH_PORT_TYPE_RECEIVE;
754 lr = MACH_PORT_TYPE_SEND_ONCE;
755 break;
757 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
758 rr = MACH_PORT_TYPE_SEND_ONCE;
759 lr = MACH_PORT_TYPE_SEND_ONCE;
760 break;
762 case MACH_MSG_TYPE_MOVE_RECEIVE:
763 rr = MACH_PORT_TYPE_RECEIVE;
764 lr = MACH_PORT_TYPE_RECEIVE;
765 break;
767 default:
768 rr = 0;
769 lr = 0;
770 break;
773 /* Get the right in the remote process (sender) */
774 rmr = NULL;
775 if (lr != 0)
776 rmr = mach_right_check(*mnp, rl, rr);
778 /* Translate it into a right in the local process (receiver) */
779 if (rmr != NULL) {
780 lmr = mach_right_get(rmr->mr_port, ll, lr, 0);
781 *mnp = lmr->mr_name;
782 } else {
783 *mnp = 0;
786 return;
790 * Turn rights carried by complex messages into rights in
791 * the local namespace. Returns a Mach messsage error
792 * XXX Nothing is there yet to remove the rights from the
793 * sender namespace, it should be done at send time and it
794 * is not done yet.
796 static inline int
797 mach_trade_rights_complex(struct lwp *l, struct mach_message *mm)
799 struct mach_complex_msg *mcm;
800 unsigned int i, count;
801 unsigned long begin, end;
804 * Sanity check the descriptor count.
805 * Note that all descriptor types
806 * have the same size, hence it is
807 * safe to not take the descriptor
808 * type into account here.
810 mcm = (struct mach_complex_msg *)mm->mm_msg;
811 count = mcm->mcm_body.msgh_descriptor_count;
812 begin = (u_long)mcm;
813 end = (u_long)&mcm->mcm_desc.gen[count];
815 if ((end - begin) > mm->mm_size) {
816 #ifdef DEBUG_MACH
817 printf("msg id %d: invalid count\n", mm->mm_msg->msgh_id);
818 #endif
819 return MACH_SEND_INVALID_DATA;
822 for (i = 0; i < count; i++) {
823 switch (mcm->mcm_desc.gen[i].type) {
824 case MACH_MSG_PORT_DESCRIPTOR:
825 mach_trade_rights(l, mm->mm_l,
826 &mcm->mcm_desc.port[i].name,
827 mcm->mcm_desc.port[i].disposition);
828 break;
830 case MACH_MSG_OOL_PORTS_DESCRIPTOR: { /* XXX untested */
831 struct lwp *rl; /* remote LWP */
832 void *lumnp; /* local user address */
833 void *rumnp; /* remote user address */
834 int disp; /* disposition*/
835 size_t size; /* data size */
836 int mcount; /* descriptor count */
837 mach_port_t *kmnp;
838 void *kaddr;
839 int error;
840 int j;
842 rl = mm->mm_l;
843 disp = mcm->mcm_desc.ool_ports[i].disposition;
844 rumnp = mcm->mcm_desc.ool_ports[i].address;
845 mcount = mcm->mcm_desc.ool_ports[i].count;
846 size = mcount * sizeof(*kmnp);
847 kaddr = NULL;
848 lumnp = NULL;
850 /* This allocates kmnp */
851 error = mach_ool_copyin(rl, rumnp, &kaddr, size, 0);
852 if (error != 0)
853 return MACH_SEND_INVALID_DATA;
855 kmnp = (mach_port_t *)kaddr;
856 for (j = 0; j < mcount; j++)
857 mach_trade_rights(l, mm->mm_l, &kmnp[j], disp);
859 /* This frees kmnp */
860 if ((error = mach_ool_copyout(l, kmnp, &lumnp,
861 size, MACH_OOL_FREE|MACH_OOL_TRACE)) != 0)
862 return MACH_SEND_INVALID_DATA;
864 mcm->mcm_desc.ool_ports[i].address = lumnp;
865 break;
868 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
869 #ifdef DEBUG_MACH
870 printf("MACH_MSG_OOL_VOLATILE_DESCRIPTOR\n");
871 #endif
872 /* FALLTHROUGH */
873 case MACH_MSG_OOL_DESCRIPTOR: { /* XXX untested */
874 struct lwp *rl; /* remote LWP */
875 void *ludata; /* local user address */
876 void *rudata; /* remote user address */
877 size_t size; /* data size */
878 void *kdata;
879 int error;
881 rl = mm->mm_l;
882 rudata = mcm->mcm_desc.ool[i].address;
883 size = mcm->mcm_desc.ool[i].size;
884 kdata = NULL;
885 ludata = NULL;
888 * XXX This is inefficient for large chunk of OOL
889 * memory. Think about remapping COW when possible.
892 /* This allocates kdata */
893 error = mach_ool_copyin(rl, rudata, &kdata, size, 0);
894 if (error != 0)
895 return MACH_SEND_INVALID_DATA;
897 /* This frees kdata */
898 if ((error = mach_ool_copyout(l, kdata, &ludata,
899 size, MACH_OOL_FREE|MACH_OOL_TRACE)) != 0)
900 return MACH_SEND_INVALID_DATA;
902 mcm->mcm_desc.ool_ports[i].address = ludata;
903 break;
905 default:
906 #ifdef DEBUG_MACH
907 printf("unknown descriptor type %d\n",
908 mcm->mcm_desc.gen[i].type);
909 #endif
910 break;
914 return MACH_MSG_SUCCESS;
917 inline int
918 mach_ool_copyin(struct lwp *l, const void *uaddr, void **kaddr, size_t size, int flags)
920 int error;
921 void *kbuf;
922 struct proc *p = l->l_proc;
925 * Sanity check OOL size to avoid DoS on malloc: useless once
926 * we remap data instead of copying it. In the meantime,
927 * disabled since it makes some OOL transfer fail.
929 #if 0
930 if (size > MACH_MAX_OOL_LEN)
931 return ENOMEM;
932 #endif
934 if (*kaddr == NULL)
935 kbuf = malloc(size, M_EMULDATA, M_WAITOK);
936 else
937 kbuf = *kaddr;
939 if ((error = copyin_proc(p, uaddr, kbuf, size)) != 0) {
940 if (*kaddr == NULL)
941 free(kbuf, M_EMULDATA);
942 return error;
945 if (size > PAGE_SIZE)
946 size = PAGE_SIZE;
947 if ((flags & MACH_OOL_TRACE))
948 ktrmool(kaddr, size, uaddr);
950 *kaddr = kbuf;
951 return 0;
954 inline int
955 mach_ool_copyout(struct lwp *l, const void *kaddr, void **uaddr, size_t size, int flags)
957 vaddr_t ubuf;
958 int error = 0;
959 struct proc *p = l->l_proc;
962 * Sanity check OOL size to avoid DoS on malloc: useless once
963 * we remap data instead of copying it. In the meantime,
964 * disabled since it makes some OOL transfer fail.
966 #if 0
967 if (size > MACH_MAX_OOL_LEN) {
968 error = ENOMEM;
969 goto out;
971 #endif
973 if (*uaddr == NULL)
974 ubuf = (vaddr_t)vm_map_min(&p->p_vmspace->vm_map);
975 else
976 ubuf = (vaddr_t)*uaddr;
978 /* Never map anything at address zero: this is a red zone */
979 if (ubuf == (vaddr_t)NULL)
980 ubuf += PAGE_SIZE;
982 if ((error = uvm_map(&p->p_vmspace->vm_map, &ubuf,
983 round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0,
984 UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL,
985 UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0)
986 goto out;
988 if ((error = copyout_proc(p, kaddr, (void *)ubuf, size)) != 0)
989 goto out;
991 if (size > PAGE_SIZE)
992 size = PAGE_SIZE;
993 if ((flags & MACH_OOL_TRACE))
994 ktrmool(kaddr, size, (void *)ubuf);
996 out:
997 if (flags & MACH_OOL_FREE)
998 free(__UNCONST(kaddr), M_EMULDATA); /*XXXUNCONST*/
1000 if (error == 0)
1001 *uaddr = (void *)ubuf;
1002 return error;
1006 inline void
1007 mach_set_trailer(void *msgh, size_t size)
1009 mach_msg_trailer_t *trailer;
1010 char *msg = (char *)msgh;
1012 trailer = (mach_msg_trailer_t *)&msg[size - sizeof(*trailer)];
1013 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
1014 trailer->msgh_trailer_size = sizeof(*trailer);
1016 return;
1019 inline void
1020 mach_set_header(void *rep, void *req, size_t size)
1022 mach_msg_header_t *rephdr = rep;
1023 mach_msg_header_t *reqhdr = req;
1025 rephdr->msgh_bits =
1026 MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
1027 rephdr->msgh_size = size - sizeof(mach_msg_trailer_t);
1028 rephdr->msgh_local_port = reqhdr->msgh_local_port;
1029 rephdr->msgh_remote_port = 0;
1030 rephdr->msgh_id = reqhdr->msgh_id + 100;
1032 return;
1035 inline void
1036 mach_add_port_desc(void *msg, mach_port_name_t name)
1038 struct mach_complex_msg *mcm = msg;
1039 int i;
1041 if ((mcm->mcm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) {
1042 mcm->mcm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
1043 mcm->mcm_body.msgh_descriptor_count = 0;
1046 i = mcm->mcm_body.msgh_descriptor_count;
1048 mcm->mcm_desc.port[i].name = name;
1049 mcm->mcm_desc.port[i].disposition = MACH_MSG_TYPE_MOVE_SEND;
1050 mcm->mcm_desc.port[i].type = MACH_MSG_PORT_DESCRIPTOR;
1052 mcm->mcm_body.msgh_descriptor_count++;
1053 return;
1056 inline void
1057 mach_add_ool_ports_desc(void *msg, void *addr, int count)
1059 struct mach_complex_msg *mcm = msg;
1060 int i;
1062 if ((mcm->mcm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) {
1063 mcm->mcm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
1064 mcm->mcm_body.msgh_descriptor_count = 0;
1067 i = mcm->mcm_body.msgh_descriptor_count;
1069 mcm->mcm_desc.ool_ports[i].address = addr;
1070 mcm->mcm_desc.ool_ports[i].count = count;
1071 mcm->mcm_desc.ool_ports[i].copy = MACH_MSG_ALLOCATE;
1072 mcm->mcm_desc.ool_ports[i].disposition = MACH_MSG_TYPE_MOVE_SEND;
1073 mcm->mcm_desc.ool_ports[i].type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
1075 mcm->mcm_body.msgh_descriptor_count++;
1076 return;
1079 inline void mach_add_ool_desc(msg, addr, size)
1080 void *msg;
1081 void *addr;
1082 size_t size;
1084 struct mach_complex_msg *mcm = msg;
1085 int i;
1087 if ((mcm->mcm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) {
1088 mcm->mcm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
1089 mcm->mcm_body.msgh_descriptor_count = 0;
1092 i = mcm->mcm_body.msgh_descriptor_count;
1094 mcm->mcm_desc.ool[i].address = addr;
1095 mcm->mcm_desc.ool[i].size = size;
1096 mcm->mcm_desc.ool[i].deallocate = 0;
1097 mcm->mcm_desc.ool[i].copy = MACH_MSG_ALLOCATE;
1098 mcm->mcm_desc.ool[i].type = MACH_MSG_OOL_DESCRIPTOR;
1100 mcm->mcm_body.msgh_descriptor_count++;
1101 return;
1104 void
1105 mach_message_init(void)
1107 pool_init(&mach_message_pool, sizeof (struct mach_message),
1108 0, 0, 0, "mach_message_pool", NULL, IPL_NONE);
1109 return;
1112 struct mach_message *
1113 mach_message_get(mach_msg_header_t *msgh, size_t size, struct mach_port *mp, struct lwp *l)
1115 struct mach_message *mm;
1117 mm = (struct mach_message *)pool_get(&mach_message_pool, PR_WAITOK);
1118 memset(mm, 0, sizeof(*mm));
1119 mm->mm_msg = msgh;
1120 mm->mm_size = size;
1121 mm->mm_port = mp;
1122 mm->mm_l = l;
1124 rw_enter(&mp->mp_msglock, RW_WRITER);
1125 TAILQ_INSERT_TAIL(&mp->mp_msglist, mm, mm_list);
1126 mp->mp_count++;
1127 rw_exit(&mp->mp_msglock);
1129 return mm;
1132 void
1133 mach_message_put(struct mach_message *mm)
1135 struct mach_port *mp;
1137 mp = mm->mm_port;
1139 rw_enter(&mp->mp_msglock, RW_WRITER);
1140 mach_message_put_exclocked(mm);
1141 rw_exit(&mp->mp_msglock);
1143 return;
1146 void
1147 mach_message_put_shlocked(struct mach_message *mm)
1149 struct mach_port *mp;
1151 mp = mm->mm_port;
1153 if (!rw_tryupgrade(&mp->mp_msglock)) {
1154 /* XXX */
1155 rw_exit(&mp->mp_msglock);
1156 rw_enter(&mp->mp_msglock, RW_WRITER);
1158 mach_message_put_exclocked(mm);
1159 rw_downgrade(&mp->mp_msglock);
1161 return;
1164 void
1165 mach_message_put_exclocked(struct mach_message *mm)
1167 struct mach_port *mp;
1169 mp = mm->mm_port;
1171 TAILQ_REMOVE(&mp->mp_msglist, mm, mm_list);
1172 mp->mp_count--;
1174 pool_put(&mach_message_pool, mm);
1176 return;
1179 #ifdef DEBUG_MACH
1180 void
1181 mach_debug_message(void)
1183 struct lwp *l;
1184 struct mach_emuldata *med;
1185 struct mach_right *mr;
1186 struct mach_right *mrs;
1187 struct mach_port *mp;
1188 struct mach_message *mm;
1190 LIST_FOREACH(l, &alllwp, l_list) {
1191 if ((l->l_proc->p_emul != &emul_mach) &&
1192 #ifdef COMPAT_DARWIN
1193 (l->l_proc->p_emul != &emul_darwin) &&
1194 #endif
1196 continue;
1198 med = l->l_proc->p_emuldata;
1199 LIST_FOREACH(mr, &med->med_right, mr_list)
1200 if ((mr->mr_type & MACH_PORT_TYPE_PORT_SET) == 0) {
1201 mp = mr->mr_port;
1202 if (mp == NULL)
1203 continue;
1205 printf("port %p(%d) ", mp, mp->mp_count);
1207 TAILQ_FOREACH(mm, &mp->mp_msglist, mm_list)
1208 printf("%d ", mm->mm_msg->msgh_id);
1210 printf("\n");
1211 continue;
1213 /* Port set... */
1214 LIST_FOREACH(mrs, &mr->mr_set, mr_setlist) {
1215 mp = mrs->mr_port;
1216 if (mp == NULL)
1217 continue;
1219 printf("port %p(%d) ", mp, mp->mp_count);
1221 TAILQ_FOREACH(mm, &mp->mp_msglist, mm_list)
1222 printf("%d ", mm->mm_msg->msgh_id);
1224 printf("\n");
1227 return;
1230 #endif /* DEBUG_MACH */