The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/mach/mach_message.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: mach_message.c,v 1.57 2008/07/02 19:49:58 rmind Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Emmanuel Dreyfus
    9  *
   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.
   18  *
   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.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.57 2008/07/02 19:49:58 rmind Exp $");
   34 
   35 #include "opt_compat_mach.h" /* For COMPAT_MACH in <sys/ktrace.h> */
   36 #include "opt_compat_darwin.h"
   37 
   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>
   48 
   49 #include <uvm/uvm_extern.h>
   50 #include <uvm/uvm_map.h>
   51 
   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>
   58 
   59 #ifdef COMPAT_DARWIN
   60 #include <compat/darwin/darwin_exec.h>
   61 #endif
   62 
   63 /* Mach message pool */
   64 static struct pool mach_message_pool;
   65 
   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 *);
   77 
   78 int
   79 mach_sys_msg_overwrite_trap(struct lwp *l, const struct mach_sys_msg_overwrite_trap_args *uap, register_t *retval)
   80 {
   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;
   95 
   96         *retval = MACH_MSG_SUCCESS;
   97         send_size = SCARG(uap, send_size);
   98         recv_size = SCARG(uap, rcv_size);
   99         opt = SCARG(uap, option);
  100 
  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;
  105         }
  106         if (recv_size > MACH_MAX_MSG_LEN) {
  107                 *retval = MACH_RCV_TOO_LARGE;
  108                 return 0;
  109         }
  110 
  111         /*
  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.
  115          */
  116         msg = SCARG(uap, msg);
  117         if (opt & MACH_SEND_MSG)
  118                 *retval = mach_msg_send(l, msg, &opt, send_size);
  119 
  120         if ((opt & MACH_RCV_MSG) && (*retval == MACH_MSG_SUCCESS)) {
  121                 /*
  122                  * Find a buffer for the reply.
  123                  */
  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;
  131                 }
  132 
  133                 *retval = mach_msg_recv(l, msg, opt, recv_size,
  134                     SCARG(uap, timeout), SCARG(uap, rcv_name));
  135         }
  136 
  137         return 0;
  138 }
  139 
  140 /*
  141  * Send a Mach message. This returns a Mach message error code.
  142  */
  143 static inline int
  144 mach_msg_send(struct lwp *l, mach_msg_header_t *msg, int *option, size_t send_size)
  145 {
  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;
  160 
  161         if (msg == NULL)
  162                 return MACH_SEND_INVALID_DATA;
  163 
  164         /*
  165          * Allocate memory for the message and its reply,
  166          * and copy the whole message in the kernel.
  167          */
  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;
  172         }
  173 
  174         /* Dump the Mach message */
  175         ktrmmsg((char *)sm, send_size);
  176 
  177         /*
  178          * Handle rights in the message
  179          */
  180         ln = sm->msgh_local_port;
  181         rn = sm->msgh_remote_port;
  182 
  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;
  191         }
  192 
  193         /*
  194          * Check that the process has a send right on
  195          * the remote port.
  196          */
  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;
  201         }
  202 
  203         /*
  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.
  207          */
  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;
  214 
  215                 /*
  216                  * Look for the function that will handle it,
  217                  * using the message id.
  218                  */
  219                 for (srv = mach_services_table; srv->srv_id; srv++)
  220                         if (srv->srv_id == sm->msgh_id)
  221                                 break;
  222 
  223                 /*
  224                  * If no match, give up, and display a warning.
  225                  */
  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;
  231                 }
  232                 min_reqlen = srv->srv_reqlen;
  233                 max_replen = srv->srv_replen;
  234 
  235                 /*
  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.
  244                  */
  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;
  250                 }
  251 
  252                 /*
  253                  * Check that the local port is valid, else
  254                  * we will not be able to send the reply
  255                  */
  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;
  264                 }
  265 skip_null_lr:
  266 
  267                 /*
  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.
  272                  */
  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;
  281                 }
  282 
  283                 /*
  284                  * 2) Overwrite kernel memory after the end of the
  285                  *    reply message buffer. This check is the
  286                  *    responsibility of the server.
  287                  */
  288 
  289 
  290                 /*
  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.
  295                  */
  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;
  301 
  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;
  310 
  311                 /*
  312                  * No-reply opration: everything is done.
  313                  * Change option so that we skip the
  314                  * receive stage.
  315                  */
  316                 if (lr == NULL) {
  317                         *option &= ~MACH_RCV_MSG;
  318                         return MACH_MSG_SUCCESS;
  319                 }
  320 
  321 #ifdef DIAGNOSTIC
  322                 /*
  323                  * Catch potential bug in the server (sanity
  324                  * check #2): did it output a larger message
  325                  * then the one that was allocated?
  326                  */
  327                 if ((*option & MACH_RCV_MSG) && (reply_size > max_replen)) {
  328                         uprintf("mach_msg: reply too big in %s\n",
  329                             srv->srv_name);
  330                 }
  331 #endif
  332 
  333                 /*
  334                  * Queue the reply.
  335                  */
  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);
  352 
  353                 return ret;
  354         }
  355 
  356         /*
  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.
  360          */
  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;
  368         }
  369 
  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
  376         /*
  377          * Drop any right carried by the message.
  378          */
  379         if (lr != NULL) {
  380                 bits = MACH_MSGH_LOCAL_BITS(sm->msgh_bits);
  381                 mach_drop_rights(lr, bits);
  382         }
  383 
  384         if (rr != NULL) {
  385                 bits = MACH_MSGH_REMOTE_BITS(sm->msgh_bits);
  386                 mach_drop_rights(rr, bits);
  387         }
  388 
  389         /*
  390          * Wakeup any process awaiting for this message.
  391          */
  392         wakeup(mp->mp_recv->mr_sethead);
  393 
  394         return MACH_MSG_SUCCESS;
  395 }
  396 
  397 /*
  398  * Receive a Mach message. This returns a Mach message error code.
  399  */
  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)
  402 {
  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;
  414 
  415         mp = NULL;
  416 
  417         if (option & MACH_RCV_TIMEOUT)
  418                 timeout = timeout * hz / 1000;
  419         else
  420                 timeout = 0;
  421 
  422         /*
  423          * Check for receive right on the port.
  424          */
  425         mr = mach_right_check(mn, l, MACH_PORT_TYPE_RECEIVE);
  426         if (mr == NULL) {
  427 
  428                 /*
  429                  * Is it a port set?
  430                  */
  431                 mr = mach_right_check(mn, l, MACH_PORT_TYPE_PORT_SET);
  432                 if (mr == NULL)
  433                         return MACH_RCV_INVALID_NAME;
  434 
  435                 /*
  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.
  439                  */
  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;
  444 
  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;
  453                 }
  454 
  455                 /*
  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.
  459                  */
  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;
  469 
  470                         /*
  471                          * Check we did not loose the receive right
  472                          * while we were sleeping.
  473                          */
  474                         if ((mach_right_check(mn, l,
  475                              MACH_PORT_TYPE_PORT_SET)) == NULL)
  476                                 return  MACH_RCV_PORT_DIED;
  477 
  478                         /*
  479                          * Is there any pending message for
  480                          * a port in the port set?
  481                          */
  482                         LIST_FOREACH(cmr, &mr->mr_set, mr_setlist) {
  483                                 mp = cmr->mr_port;
  484                                 if (mp->mp_count != 0)
  485                                         break;
  486                         }
  487 
  488                         if (cmr == NULL)
  489                                 return MACH_RCV_TIMED_OUT;
  490                 }
  491 
  492                 /*
  493                  * We found a port with a pending message.
  494                  */
  495                 mp = cmr->mr_port;
  496 
  497         } else {
  498                 /*
  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.
  502                  */
  503                 mp = mr->mr_port;
  504 
  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;
  519 
  520                         /*
  521                          * Check we did not lose the receive right
  522                          * while we were sleeping.
  523                          */
  524                         if ((mach_right_check(mn, l,
  525                              MACH_PORT_TYPE_RECEIVE)) == NULL)
  526                                 return MACH_RCV_PORT_DIED;
  527 
  528                         if (mp->mp_count == 0)
  529                                 return MACH_RCV_TIMED_OUT;
  530                 }
  531         }
  532 
  533         /*
  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.
  538          */
  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
  545 
  546         ret = MACH_MSG_SUCCESS;
  547         if (mm->mm_size > recv_size) {
  548                 struct mach_short_reply sr;
  549 
  550                 ret = MACH_RCV_TOO_LARGE;
  551                 /*
  552                  * If MACH_RCV_LARGE was not set, destroy the message.
  553                  */
  554                 if ((option & MACH_RCV_LARGE) == 0) {
  555                         free(mm->mm_msg, M_EMULDATA);
  556                         mach_message_put_shlocked(mm);
  557                         goto unlock;
  558                 }
  559 
  560                 /*
  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.
  565                  */
  566                 memcpy(&sr, mm->mm_msg, sizeof(mach_msg_header_t));
  567                 mach_set_trailer(&sr, sizeof(sr));
  568 
  569                 if ((error = copyout(&sr, urm, sizeof(sr))) != 0) {
  570                         ret = MACH_RCV_INVALID_DATA;
  571                         goto unlock;
  572                 }
  573 
  574                 /* Dump the Mach message */
  575                 ktrmmsg((char *)&sr, sizeof(sr));
  576                 goto unlock;
  577         }
  578 
  579         /*
  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?
  584          */
  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
  590                 /*
  591                  * Turn local and remote port names into
  592                  * names in the local process namespace.
  593                  */
  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);
  597 
  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);
  601 
  602                 /*
  603                  * The same operation must be done to all
  604                  * port descriptors carried with the message.
  605                  */
  606                 if ((mm->mm_msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
  607                     ((ret = mach_trade_rights_complex(l, mm)) != 0))
  608                         goto unlock;
  609 
  610                 /*
  611                  * swap local and remote ports, and
  612                  * corresponding bits as well.
  613                  */
  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;
  621         }
  622 
  623         /*
  624          * Copy the message to userland.
  625          */
  626         if ((error = copyout(mm->mm_msg, urm, mm->mm_size)) != 0) {
  627                 ret = MACH_RCV_INVALID_DATA;
  628                 goto unlock;
  629         }
  630 
  631         /* Dump the Mach message */
  632         ktrmmsg((char *)mm->mm_msg, mm->mm_size);
  633 
  634         free(mm->mm_msg, M_EMULDATA);
  635         mach_message_put_shlocked(mm); /* decrease mp_count */
  636 unlock:
  637         rw_exit(&mp->mp_msglock);
  638 
  639         return ret;
  640 }
  641 
  642 
  643 int
  644 mach_sys_msg_trap(struct lwp *l, const struct mach_sys_msg_trap_args *uap, register_t *retval)
  645 {
  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;
  656 
  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;
  666 
  667         return mach_sys_msg_overwrite_trap(l, &cup, retval);
  668 }
  669 
  670 static inline  struct lwp *
  671 mach_get_target_task(struct lwp *l, struct mach_port *mp)
  672 {
  673         struct proc *tp;
  674         struct lwp *tl;
  675 
  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;
  682 
  683         case MACH_MP_LWP:
  684                 tl = (struct lwp *)mp->mp_data;
  685                 break;
  686 
  687         default:
  688                 tl = l;
  689                 break;
  690         }
  691 
  692         return tl;
  693 }
  694 
  695 static inline void
  696 mach_drop_rights(struct mach_right *mr, int bits)
  697 {
  698         int rights;
  699 
  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;
  715         }
  716 
  717         if (rights != 0)
  718                 mach_right_put(mr, rights);
  719 
  720         return;
  721 }
  722 
  723 /*
  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.
  727  */
  728 static inline void
  729 mach_trade_rights(ll, rl, mnp, bits)
  730         struct lwp *ll;         /* local lwp (receiver, current lwp) */
  731         struct lwp *rl;         /* remote lwp (sender) */
  732         mach_port_t *mnp;       /* pointer to the port name */
  733         int bits;               /* right bits */
  734 {
  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 */
  739 
  740         switch (bits) {
  741         case MACH_MSG_TYPE_MAKE_SEND:
  742                 rr = MACH_PORT_TYPE_RECEIVE;
  743                 lr = MACH_PORT_TYPE_SEND;
  744                 break;
  745 
  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;
  751 
  752         case MACH_MSG_TYPE_MAKE_SEND_ONCE:
  753                 rr = MACH_PORT_TYPE_RECEIVE;
  754                 lr = MACH_PORT_TYPE_SEND_ONCE;
  755                 break;
  756 
  757         case MACH_MSG_TYPE_MOVE_SEND_ONCE:
  758                 rr = MACH_PORT_TYPE_SEND_ONCE;
  759                 lr = MACH_PORT_TYPE_SEND_ONCE;
  760                 break;
  761 
  762         case MACH_MSG_TYPE_MOVE_RECEIVE:
  763                 rr = MACH_PORT_TYPE_RECEIVE;
  764                 lr = MACH_PORT_TYPE_RECEIVE;
  765                 break;
  766 
  767         default:
  768                 rr = 0;
  769                 lr = 0;
  770                 break;
  771         }
  772 
  773         /* Get the right in the remote process (sender) */
  774         rmr = NULL;
  775         if (lr != 0)
  776                 rmr = mach_right_check(*mnp, rl, rr);
  777 
  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;
  784         }
  785 
  786         return;
  787 }
  788 
  789 /*
  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.
  795  */
  796 static inline int
  797 mach_trade_rights_complex(struct lwp *l, struct mach_message *mm)
  798 {
  799         struct mach_complex_msg *mcm;
  800         unsigned int i, count;
  801         unsigned long begin, end;
  802 
  803         /*
  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.
  809          */
  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];
  814 
  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;
  820         }
  821 
  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;
  829 
  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;
  841 
  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;
  849 
  850                         /* This allocates kmnp */
  851                         error = mach_ool_copyin(rl, rumnp, &kaddr, size, 0);
  852                         if (error != 0)
  853                                 return MACH_SEND_INVALID_DATA;
  854 
  855                         kmnp = (mach_port_t *)kaddr;
  856                         for (j = 0; j < mcount; j++)
  857                                 mach_trade_rights(l, mm->mm_l, &kmnp[j], disp);
  858 
  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;
  863 
  864                         mcm->mcm_desc.ool_ports[i].address = lumnp;
  865                         break;
  866                 }
  867 
  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;
  880 
  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;
  886 
  887                         /*
  888                          * XXX This is inefficient for large chunk of OOL
  889                          * memory. Think about remapping COW when possible.
  890                          */
  891 
  892                         /* This allocates kdata */
  893                         error = mach_ool_copyin(rl, rudata, &kdata, size, 0);
  894                         if (error != 0)
  895                                 return MACH_SEND_INVALID_DATA;
  896 
  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;
  901 
  902                         mcm->mcm_desc.ool_ports[i].address = ludata;
  903                         break;
  904                 }
  905                 default:
  906 #ifdef DEBUG_MACH
  907                         printf("unknown descriptor type %d\n",
  908                             mcm->mcm_desc.gen[i].type);
  909 #endif
  910                         break;
  911                 }
  912         }
  913 
  914         return MACH_MSG_SUCCESS;
  915 }
  916 
  917 inline int
  918 mach_ool_copyin(struct lwp *l, const void *uaddr, void **kaddr, size_t size, int flags)
  919 {
  920         int error;
  921         void *kbuf;
  922         struct proc *p = l->l_proc;
  923 
  924         /*
  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.
  928          */
  929 #if 0
  930         if (size > MACH_MAX_OOL_LEN)
  931                 return ENOMEM;
  932 #endif
  933 
  934         if (*kaddr == NULL)
  935                 kbuf = malloc(size, M_EMULDATA, M_WAITOK);
  936         else
  937                 kbuf = *kaddr;
  938 
  939         if ((error = copyin_proc(p, uaddr, kbuf, size)) != 0) {
  940                 if (*kaddr == NULL)
  941                         free(kbuf, M_EMULDATA);
  942                 return error;
  943         }
  944 
  945         if (size > PAGE_SIZE)
  946                 size = PAGE_SIZE;
  947         if ((flags & MACH_OOL_TRACE))
  948                 ktrmool(kaddr, size, uaddr);
  949 
  950         *kaddr = kbuf;
  951         return 0;
  952 }
  953 
  954 inline int
  955 mach_ool_copyout(struct lwp *l, const void *kaddr, void **uaddr, size_t size, int flags)
  956 {
  957         vaddr_t ubuf;
  958         int error = 0;
  959         struct proc *p = l->l_proc;
  960 
  961         /*
  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.
  965          */
  966 #if 0
  967         if (size > MACH_MAX_OOL_LEN) {
  968                 error = ENOMEM;
  969                 goto out;
  970         }
  971 #endif
  972 
  973         if (*uaddr == NULL)
  974                 ubuf = (vaddr_t)vm_map_min(&p->p_vmspace->vm_map);
  975         else
  976                 ubuf = (vaddr_t)*uaddr;
  977 
  978         /* Never map anything at address zero: this is a red zone */
  979         if (ubuf == (vaddr_t)NULL)
  980                 ubuf += PAGE_SIZE;
  981 
  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;
  987 
  988         if ((error = copyout_proc(p, kaddr, (void *)ubuf, size)) != 0)
  989                 goto out;
  990 
  991         if (size > PAGE_SIZE)
  992                 size = PAGE_SIZE;
  993         if ((flags & MACH_OOL_TRACE))
  994                 ktrmool(kaddr, size, (void *)ubuf);
  995 
  996 out:
  997         if (flags & MACH_OOL_FREE)
  998                 free(__UNCONST(kaddr), M_EMULDATA); /*XXXUNCONST*/
  999 
 1000         if (error == 0)
 1001                 *uaddr = (void *)ubuf;
 1002         return error;
 1003 }
 1004 
 1005 
 1006 inline void
 1007 mach_set_trailer(void *msgh, size_t size)
 1008 {
 1009         mach_msg_trailer_t *trailer;
 1010         char *msg = (char *)msgh;
 1011 
 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);
 1015 
 1016         return;
 1017 }
 1018 
 1019 inline void
 1020 mach_set_header(void *rep, void *req, size_t size)
 1021 {
 1022         mach_msg_header_t *rephdr = rep;
 1023         mach_msg_header_t *reqhdr = req;
 1024 
 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;
 1031 
 1032         return;
 1033 }
 1034 
 1035 inline void
 1036 mach_add_port_desc(void *msg, mach_port_name_t name)
 1037 {
 1038         struct mach_complex_msg *mcm = msg;
 1039         int i;
 1040 
 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;
 1044         }
 1045 
 1046         i = mcm->mcm_body.msgh_descriptor_count;
 1047 
 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;
 1051 
 1052         mcm->mcm_body.msgh_descriptor_count++;
 1053         return;
 1054 }
 1055 
 1056 inline void
 1057 mach_add_ool_ports_desc(void *msg, void *addr, int count)
 1058 {
 1059         struct mach_complex_msg *mcm = msg;
 1060         int i;
 1061 
 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;
 1065         }
 1066 
 1067         i = mcm->mcm_body.msgh_descriptor_count;
 1068 
 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;
 1074 
 1075         mcm->mcm_body.msgh_descriptor_count++;
 1076         return;
 1077 }
 1078 
 1079 inline void mach_add_ool_desc(msg, addr, size)
 1080         void *msg;
 1081         void *addr;
 1082         size_t size;
 1083 {
 1084         struct mach_complex_msg *mcm = msg;
 1085         int i;
 1086 
 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;
 1090         }
 1091 
 1092         i = mcm->mcm_body.msgh_descriptor_count;
 1093 
 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;
 1099 
 1100         mcm->mcm_body.msgh_descriptor_count++;
 1101         return;
 1102 }
 1103 
 1104 void
 1105 mach_message_init(void)
 1106 {
 1107         pool_init(&mach_message_pool, sizeof (struct mach_message),
 1108             0, 0, 0, "mach_message_pool", NULL, IPL_NONE);
 1109         return;
 1110 }
 1111 
 1112 struct mach_message *
 1113 mach_message_get(mach_msg_header_t *msgh, size_t size, struct mach_port *mp, struct lwp *l)
 1114 {
 1115         struct mach_message *mm;
 1116 
 1117         mm = (struct mach_message *)pool_get(&mach_message_pool, PR_WAITOK);
 1118         bzero(mm, sizeof(*mm));
 1119         mm->mm_msg = msgh;
 1120         mm->mm_size = size;
 1121         mm->mm_port = mp;
 1122         mm->mm_l = l;
 1123 
 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);
 1128 
 1129         return mm;
 1130 }
 1131 
 1132 void
 1133 mach_message_put(struct mach_message *mm)
 1134 {
 1135         struct mach_port *mp;
 1136 
 1137         mp = mm->mm_port;
 1138 
 1139         rw_enter(&mp->mp_msglock, RW_WRITER);
 1140         mach_message_put_exclocked(mm);
 1141         rw_exit(&mp->mp_msglock);
 1142 
 1143         return;
 1144 }
 1145 
 1146 void
 1147 mach_message_put_shlocked(struct mach_message *mm)
 1148 {
 1149         struct mach_port *mp;
 1150 
 1151         mp = mm->mm_port;
 1152 
 1153         if (!rw_tryupgrade(&mp->mp_msglock)) {
 1154                 /* XXX  */
 1155                 rw_exit(&mp->mp_msglock);
 1156                 rw_enter(&mp->mp_msglock, RW_WRITER);
 1157         }
 1158         mach_message_put_exclocked(mm);
 1159         rw_downgrade(&mp->mp_msglock);
 1160 
 1161         return;
 1162 }
 1163 
 1164 void
 1165 mach_message_put_exclocked(struct mach_message *mm)
 1166 {
 1167         struct mach_port *mp;
 1168 
 1169         mp = mm->mm_port;
 1170 
 1171         TAILQ_REMOVE(&mp->mp_msglist, mm, mm_list);
 1172         mp->mp_count--;
 1173 
 1174         pool_put(&mach_message_pool, mm);
 1175 
 1176         return;
 1177 }
 1178 
 1179 #ifdef DEBUG_MACH
 1180 void
 1181 mach_debug_message(void)
 1182 {
 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;
 1189 
 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
 1195                     1)
 1196                         continue;
 1197 
 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;
 1204 
 1205                                 printf("port %p(%d) ", mp, mp->mp_count);
 1206 
 1207                                 TAILQ_FOREACH(mm, &mp->mp_msglist, mm_list)
 1208                                         printf("%d ", mm->mm_msg->msgh_id);
 1209 
 1210                                 printf("\n");
 1211                                 continue;
 1212                         }
 1213                         /* Port set... */
 1214                         LIST_FOREACH(mrs, &mr->mr_set, mr_setlist) {
 1215                                 mp = mrs->mr_port;
 1216                                 if (mp == NULL)
 1217                                         continue;
 1218 
 1219                                 printf("port %p(%d) ", mp, mp->mp_count);
 1220 
 1221                                 TAILQ_FOREACH(mm, &mp->mp_msglist, mm_list)
 1222                                         printf("%d ", mm->mm_msg->msgh_id);
 1223 
 1224                                 printf("\n");
 1225                         }
 1226         }
 1227         return;
 1228 }
 1229 
 1230 #endif /* DEBUG_MACH */

Cache object: 131057811a35079173c8fe8fff6f8417


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.