Annotation of kernel/ipc/mach_msg.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990  
                     27:  * Open Software Foundation, Inc. 
                     28:  *  
                     29:  * Permission to use, copy, modify, and distribute this software and 
                     30:  * its documentation for any purpose and without fee is hereby granted, 
                     31:  * provided that the above copyright notice appears in all copies and 
                     32:  * that both the copyright notice and this permission notice appear in 
                     33:  * supporting documentation, and that the name of ("OSF") or Open Software 
                     34:  * Foundation not be used in advertising or publicity pertaining to 
                     35:  * distribution of the software without specific, written prior permission. 
                     36:  *  
                     37:  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
                     38:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
                     39:  * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY 
                     40:  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
                     41:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
                     42:  * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING 
                     43:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE 
                     44:  */
                     45: /*
                     46:  * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
                     47:  */
                     48: /* 
                     49:  * Mach Operating System
                     50:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
                     51:  * All Rights Reserved.
                     52:  * 
                     53:  * Permission to use, copy, modify and distribute this software and its
                     54:  * documentation is hereby granted, provided that both the copyright
                     55:  * notice and this permission notice appear in all copies of the
                     56:  * software, derivative works or modified versions, and any portions
                     57:  * thereof, and that both notices appear in supporting documentation.
                     58:  * 
                     59:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     60:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     61:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     62:  * 
                     63:  * Carnegie Mellon requests users of this software to return to
                     64:  * 
                     65:  *  Software Distribution Coordinator  or  [email protected]
                     66:  *  School of Computer Science
                     67:  *  Carnegie Mellon University
                     68:  *  Pittsburgh PA 15213-3890
                     69:  * 
                     70:  * any improvements or extensions that they make and grant Carnegie Mellon
                     71:  * the rights to redistribute these changes.
                     72:  */
                     73: /*
                     74:  *     File:   ipc/mach_msg.c
                     75:  *     Author: Rich Draves
                     76:  *     Date:   1989
                     77:  *
                     78:  *     Exported message traps.  See mach/message.h.
                     79:  */
                     80: 
                     81: #import <mach/features.h>
                     82: 
                     83: #include <mach/kern_return.h>
                     84: #include <mach/port.h>
                     85: #include <mach/message.h>
                     86: #include <kern/assert.h>
                     87: #include <kern/counters.h>
                     88: #include <kern/lock.h>
                     89: #include <kern/sched_prim.h>
                     90: #include <kern/ipc_sched.h>
                     91: #include <vm/vm_map.h>
                     92: #include <ipc/ipc_kmsg.h>
                     93: #include <ipc/ipc_marequest.h>
                     94: #include <ipc/ipc_mqueue.h>
                     95: #include <ipc/ipc_object.h>
                     96: #include <ipc/ipc_notify.h>
                     97: #include <ipc/ipc_port.h>
                     98: #include <ipc/ipc_pset.h>
                     99: #include <ipc/ipc_space.h>
                    100: #include <ipc/ipc_thread.h>
                    101: #include <ipc/ipc_entry.h>
                    102: #include <ipc/mach_msg.h>
                    103: 
                    104: /*
                    105:  * Forward declarations
                    106:  */
                    107: 
                    108: mach_msg_return_t mach_msg_send(
                    109:        mach_msg_header_t       *msg,
                    110:        mach_msg_option_t       option,
                    111:        mach_msg_size_t         send_size,
                    112:        mach_msg_timeout_t      timeout,
                    113:        mach_port_t             notify);
                    114: 
                    115: mach_msg_return_t mach_msg_receive(
                    116:        mach_msg_header_t       *msg,
                    117:        mach_msg_option_t       option,
                    118:        mach_msg_size_t         rcv_size,
                    119:        mach_port_t             rcv_name,
                    120:        mach_msg_timeout_t      timeout,
                    121:        mach_port_t             notify,
                    122:        mach_msg_size_t         list_size);
                    123: 
                    124: mach_msg_return_t mach_msg_receive_error(
                    125:        ipc_kmsg_t              kmsg,
                    126:        mach_msg_header_t       *msg,
                    127:        mach_msg_option_t       option,
                    128:        mach_port_seqno_t       seqno,
                    129:        ipc_space_t             space);
                    130: 
                    131: /* the size of each trailer has to be listed here for copyout purposes */
                    132: vm_size_t trailer_size[] = {
                    133:           sizeof (mach_msg_trailer_t), 
                    134:          sizeof (mach_msg_seqno_trailer_t),
                    135:          sizeof (mach_msg_security_trailer_t)
                    136: };
                    137: 
                    138: /*
                    139:  *     Routine:        mach_msg_send
                    140:  *     Purpose:
                    141:  *             Send a message.
                    142:  *     Conditions:
                    143:  *             Nothing locked.
                    144:  *     Returns:
                    145:  *             MACH_MSG_SUCCESS        Sent the message.
                    146:  *             MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
                    147:  *             MACH_SEND_NO_BUFFER     Couldn't allocate buffer.
                    148:  *             MACH_SEND_INVALID_DATA  Couldn't copy message data.
                    149:  *             MACH_SEND_INVALID_HEADER
                    150:  *                     Illegal value in the message header bits.
                    151:  *             MACH_SEND_INVALID_DEST  The space is dead.
                    152:  *             MACH_SEND_INVALID_NOTIFY        Bad notify port.
                    153:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
                    154:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
                    155:  *             MACH_SEND_TIMED_OUT     Timeout expired without delivery.
                    156:  *             MACH_SEND_INTERRUPTED   Delivery interrupted.
                    157:  *             MACH_SEND_NO_NOTIFY     Can't allocate a msg-accepted request.
                    158:  *             MACH_SEND_WILL_NOTIFY   Msg-accepted notif. requested.
                    159:  *             MACH_SEND_NOTIFY_IN_PROGRESS
                    160:  *                     This space has already forced a message to this port.
                    161:  */
                    162: 
                    163: mach_msg_return_t
                    164: mach_msg_send(
                    165:        mach_msg_header_t       *msg,
                    166:        mach_msg_option_t       option,
                    167:        mach_msg_size_t         send_size,
                    168:        mach_msg_timeout_t      timeout,
                    169:        mach_port_t             notify)
                    170: {
                    171:        ipc_space_t space = current_space();
                    172:        vm_map_t map = current_map();
                    173:        ipc_kmsg_t kmsg;
                    174:        mach_msg_return_t mr;
                    175: 
                    176:        mr = ipc_kmsg_get(msg, option, send_size, MAX_TRAILER_SIZE, &kmsg);
                    177:        if (mr != MACH_MSG_SUCCESS)
                    178:                return mr;
                    179: 
                    180:        if (option & MACH_SEND_CANCEL) {
                    181:                if (notify == MACH_PORT_NULL)
                    182:                        mr = MACH_SEND_INVALID_NOTIFY;
                    183:                else
                    184:                        mr = ipc_kmsg_copyin(kmsg, space, map, notify);
                    185:        } else
                    186:                mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
                    187:        if (mr != MACH_MSG_SUCCESS) {
                    188:                ikm_free(kmsg);
                    189:                return mr;
                    190:        }
                    191: 
                    192:        mr = ipc_mqueue_send(kmsg, option & MACH_SEND_TIMEOUT,
                    193:                                                timeout, IMQ_NULL_CONTINUE);
                    194:        if (mr != MACH_MSG_SUCCESS) {
                    195:                mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, IKM_NULL);
                    196: 
                    197:                assert(kmsg->ikm_marequest == IMAR_NULL);
                    198:                (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
                    199:        }
                    200: 
                    201:        return mr;
                    202: }
                    203: 
                    204: #define FREE_SCATTER_LIST(l)                           \
                    205: MACRO_BEGIN                                            \
                    206:        if((l) != IKM_NULL) {                           \
                    207:                ikm_free((l));                          \
                    208:        }                                               \
                    209: MACRO_END
                    210: 
                    211: /*
                    212:  *     Routine:        mach_msg_receive
                    213:  *     Purpose:
                    214:  *             Receive a message.
                    215:  *     Conditions:
                    216:  *             Nothing locked.
                    217:  *     Returns:
                    218:  *             MACH_MSG_SUCCESS        Received a message.
                    219:  *             MACH_RCV_INVALID_NAME   The name doesn't denote a right,
                    220:  *                     or the denoted right is not receive or port set.
                    221:  *             MACH_RCV_IN_SET         Receive right is a member of a set.
                    222:  *             MACH_RCV_TOO_LARGE      Message wouldn't fit into buffer.
                    223:  *             MACH_RCV_TIMED_OUT      Timeout expired without a message.
                    224:  *             MACH_RCV_INTERRUPTED    Reception interrupted.
                    225:  *             MACH_RCV_PORT_DIED      Port/set died while receiving.
                    226:  *             MACH_RCV_PORT_CHANGED   Port moved into set while receiving.
                    227:  *             MACH_RCV_INVALID_DATA   Couldn't copy to user buffer.
                    228:  *             MACH_RCV_INVALID_NOTIFY Bad notify port.
                    229:  *             MACH_RCV_HEADER_ERROR
                    230:  */
                    231: 
                    232: mach_msg_return_t
                    233: mach_msg_receive(
                    234:        mach_msg_header_t       *msg,
                    235:        mach_msg_option_t       option,
                    236:        mach_msg_size_t         rcv_size,
                    237:        mach_port_t             rcv_name,
                    238:        mach_msg_timeout_t      timeout,
                    239:        mach_port_t             notify,
                    240:        mach_msg_size_t         list_size)
                    241: {
                    242:        ipc_thread_t self = current_thread();
                    243:        ipc_space_t space = current_space();
                    244:        vm_map_t map = current_map();
                    245:        ipc_object_t object;
                    246:        ipc_mqueue_t mqueue;
                    247:        ipc_kmsg_t kmsg;
                    248:        mach_port_seqno_t seqno;
                    249:        ipc_kmsg_t list;
                    250:        mach_msg_return_t mr;
                    251:        mach_msg_trailer_t *trailer;
                    252: 
                    253:        /*
                    254:         * If MACH_RCV_OVERWRITE was specified, both receive_msg (msg)
                    255:         * and receive_msg_size (list_size) need to be non NULL.
                    256:         */
                    257:        if (option & MACH_RCV_OVERWRITE) {
                    258:                if (list_size < sizeof(mach_msg_base_t)) 
                    259:                        return MACH_RCV_SCATTER_SMALL;
                    260:                else 
                    261:                if (ipc_kmsg_get(msg, MACH_MSG_OPTION_NONE,
                    262:                                list_size, 0, &list) != MACH_MSG_SUCCESS)
                    263:                        return MACH_RCV_INVALID_DATA;
                    264: 
                    265:                else
                    266:                if ((((mach_msg_base_t *)
                    267:                        &kmsg->ikm_header)->body.msgh_descriptor_count *
                    268:                                        sizeof (mach_msg_descriptor_t)) + 
                    269:                                        sizeof (mach_msg_base_t) > list_size) {
                    270:                        FREE_SCATTER_LIST(list);
                    271:                        return MACH_RCV_INVALID_TYPE;
                    272:                }
                    273:        }
                    274:        else
                    275:                list = IKM_NULL;
                    276: 
                    277:        mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
                    278:        if (mr != MACH_MSG_SUCCESS) {
                    279:                FREE_SCATTER_LIST(list);
                    280:                return mr;
                    281:        }
                    282:        /* hold ref for object; mqueue is locked */
                    283: 
                    284:        /*
                    285:         *      ipc_mqueue_receive may not return, because if we block
                    286:         *      then our kernel stack may be discarded.  So we save
                    287:         *      state here for mach_msg_receive_continue to pick up.
                    288:         */
                    289: 
                    290:        self->ith_msg = msg;
                    291:        self->ith_option = option;
                    292:        self->ith_rcv_size = rcv_size;
                    293:        self->ith_timeout = timeout;
                    294:        self->ith_notify = notify;
                    295:        self->ith_object = object;
                    296:        self->ith_mqueue = mqueue;
                    297: 
                    298:        mr = ipc_mqueue_receive(mqueue,
                    299:                                option & (MACH_RCV_TRAILER_MASK|
                    300:                                                MACH_RCV_TIMEOUT|
                    301:                                                MACH_RCV_LARGE),
                    302:                                rcv_size, timeout,
                    303:                                FALSE, mach_msg_receive_continue,
                    304:                                &kmsg, &seqno, &list);
                    305:        /* mqueue is unlocked */
                    306:        ipc_object_release(object);
                    307: 
                    308:        if (mr != MACH_MSG_SUCCESS) {
                    309:                if (mr == MACH_RCV_HEADER_ERROR) {
                    310:                        mach_msg_return_t       pr;
                    311: 
                    312:                        pr = mach_msg_receive_error(kmsg, msg,
                    313:                                                    option, seqno, space);
                    314:                        if (pr != MACH_MSG_SUCCESS)
                    315:                                mr = pr;
                    316:                }
                    317:                else
                    318:                if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) {
                    319:                        if (option & MACH_RCV_LARGE) {
                    320:                                if (list != IKM_NULL) {
                    321:                                        mach_msg_return_t       pr;
                    322: 
                    323:                                        list_size = list->ikm_header.msgh_size;
                    324:                                        list->ikm_header.msgh_size =
                    325:                                                (mach_msg_size_t)kmsg;
                    326:                                        pr = ipc_kmsg_put(
                    327:                                                msg, list, list_size);
                    328:                                        if (pr != MACH_MSG_SUCCESS)
                    329:                                                mr = pr;
                    330:                                }
                    331:                                else                                    
                    332:                                if (copyout((char *) &kmsg,
                    333:                                               (char *) &msg->msgh_size,
                    334:                                               sizeof(mach_msg_size_t)))
                    335:                                        mr = MACH_RCV_INVALID_DATA;
                    336: 
                    337:                                return mr;
                    338:                        }
                    339:                        else {
                    340:                                mach_msg_return_t       pr;
                    341: 
                    342:                                pr = mach_msg_receive_error(kmsg, msg,
                    343:                                                        option, seqno, space);
                    344:                                if (pr != MACH_MSG_SUCCESS)
                    345:                                        mr = pr;
                    346:                        }
                    347:                }
                    348: 
                    349:                FREE_SCATTER_LIST(list);
                    350:                return mr;
                    351:        }
                    352: 
                    353:        /*
                    354:         * Generate requested trailer.
                    355:         */
                    356:        trailer = (mach_msg_trailer_t *)
                    357:                        ((vm_offset_t)&kmsg->ikm_header +
                    358:                                        kmsg->ikm_header.msgh_size);
                    359: 
                    360:        if (option & MACH_RCV_NO_TRAILER) {
                    361:                trailer->msgh_trailer_size = 
                    362:                                trailer->msgh_trailer_type = 0;
                    363:                kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
                    364:        }
                    365:        else
                    366:        if (kmsg->ikm_delta > 0) {
                    367:                /* MACH_SEND_TRAILER */;
                    368:        }
                    369:        else {
                    370:                int     elements = GET_RCV_ELEMENTS(option);
                    371: #define trailer0       ((mach_msg_format_0_trailer_t *)trailer)
                    372:                
                    373:                if (elements == MACH_RCV_TRAILER_SENDER) {
                    374:                        trailer0->msgh_sender = kmsg->ikm_sender;
                    375:                        trailer0->msgh_seqno = seqno;
                    376:                }
                    377:                else
                    378:                if (elements == MACH_RCV_TRAILER_SEQNO)
                    379:                        trailer0->msgh_seqno = seqno;
                    380: 
                    381:                trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
                    382:                trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
                    383: #undef trailer0
                    384:        }
                    385: 
                    386:        if (option & MACH_RCV_NOTIFY) {
                    387:                if (notify == MACH_PORT_NULL)
                    388:                        mr = MACH_RCV_INVALID_NOTIFY;
                    389:                else
                    390:                        mr = ipc_kmsg_copyout(kmsg, space, map, notify, list);
                    391:        } else
                    392:                mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, list);
                    393:        if (mr != MACH_MSG_SUCCESS) {
                    394:                mach_msg_return_t       pr;
                    395: 
                    396:                if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
                    397:                        pr = ipc_kmsg_put(msg, kmsg,
                    398:                                        kmsg->ikm_header.msgh_size +
                    399:                                                trailer->msgh_trailer_size);
                    400:                        if (pr != MACH_MSG_SUCCESS)
                    401:                                mr = pr;
                    402:                                        
                    403:                } else {
                    404:                        pr = mach_msg_receive_error(kmsg, msg,
                    405:                                                option, seqno, space);
                    406:                        if (pr != MACH_MSG_SUCCESS)
                    407:                                mr = pr;
                    408:                }
                    409: 
                    410:                FREE_SCATTER_LIST(list);
                    411:                return mr;
                    412:        }
                    413: 
                    414:        FREE_SCATTER_LIST(list);
                    415:        return ipc_kmsg_put(msg, kmsg,
                    416:                        kmsg->ikm_header.msgh_size +
                    417:                                trailer->msgh_trailer_size);
                    418: }
                    419: 
                    420: /*
                    421:  *     Routine:        mach_msg_receive_continue
                    422:  *     Purpose:
                    423:  *             Continue after blocking for a message.
                    424:  *     Conditions:
                    425:  *             Nothing locked.  We are running on a new kernel stack,
                    426:  *             with the receive state saved in the thread.  From here
                    427:  *             control goes back to user space.
                    428:  */
                    429: 
                    430: void
                    431: mach_msg_receive_continue(void)
                    432: {
                    433:        ipc_thread_t self = current_thread();
                    434:        ipc_space_t space = current_space();
                    435:        vm_map_t map = current_map();
                    436:        mach_msg_header_t *msg = self->ith_msg;
                    437:        mach_msg_option_t option = self->ith_option;
                    438:        mach_msg_trailer_t *trailer;
                    439:        ipc_kmsg_t kmsg;
                    440:        mach_port_seqno_t seqno;
                    441:        ipc_kmsg_t list;
                    442:        mach_msg_return_t mr;
                    443: 
                    444:        mr = ipc_mqueue_receive(self->ith_mqueue,
                    445:                                option & (MACH_RCV_TRAILER_MASK|
                    446:                                                MACH_RCV_TIMEOUT|
                    447:                                                MACH_RCV_LARGE),
                    448:                                self->ith_rcv_size, self->ith_timeout,
                    449:                                TRUE, mach_msg_receive_continue,
                    450:                                &kmsg, &seqno, &list);
                    451:        /* mqueue is unlocked */
                    452:        ipc_object_release(self->ith_object);
                    453: 
                    454:        if (mr != MACH_MSG_SUCCESS) {
                    455:                if (mr == MACH_RCV_HEADER_ERROR) {
                    456:                        mach_msg_return_t       pr;
                    457: 
                    458:                        pr = mach_msg_receive_error(kmsg, msg,
                    459:                                                    option, seqno, space);
                    460:                        if (pr != MACH_MSG_SUCCESS)
                    461:                                mr = pr;
                    462:                }
                    463:                else
                    464:                if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) {
                    465:                        if (option & MACH_RCV_LARGE) {
                    466:                                if (list != IKM_NULL) {
                    467:                                        mach_msg_return_t       pr;
                    468:                                        mach_msg_size_t         list_size;
                    469: 
                    470:                                        list_size = list->ikm_header.msgh_size;
                    471:                                        list->ikm_header.msgh_size =
                    472:                                                (mach_msg_size_t)kmsg;
                    473:                                        pr = ipc_kmsg_put(
                    474:                                                msg, list, list_size);
                    475:                                        if (pr != MACH_MSG_SUCCESS)
                    476:                                                mr = pr;
                    477:                                }
                    478:                                else                                    
                    479:                                if (copyout((char *) &kmsg,
                    480:                                               (char *) &msg->msgh_size,
                    481:                                               sizeof(mach_msg_size_t)))
                    482:                                        mr = MACH_RCV_INVALID_DATA;
                    483: 
                    484:                                thread_syscall_return(mr);
                    485:                                /*NOTREACHED*/
                    486:                        }
                    487:                        else {
                    488:                                mach_msg_return_t       pr;
                    489: 
                    490:                                pr = mach_msg_receive_error(kmsg, msg,
                    491:                                                        option, seqno, space);
                    492:                                if (pr != MACH_MSG_SUCCESS)
                    493:                                        mr = pr;
                    494:                        }
                    495:                }
                    496: 
                    497:                FREE_SCATTER_LIST(list);
                    498:                thread_syscall_return(mr);
                    499:                /*NOTREACHED*/
                    500:        }
                    501: 
                    502:        /*
                    503:         * Generate requested trailer.
                    504:         */
                    505:        trailer = (mach_msg_trailer_t *)
                    506:                        ((vm_offset_t)&kmsg->ikm_header +
                    507:                                        kmsg->ikm_header.msgh_size);
                    508: 
                    509:        if (option & MACH_RCV_NO_TRAILER) {
                    510:                trailer->msgh_trailer_size = 
                    511:                                trailer->msgh_trailer_type = 0;
                    512:                kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
                    513:        }
                    514:        else
                    515:        if (kmsg->ikm_delta > 0) {
                    516:                /* MACH_SEND_TRAILER */;
                    517:        }
                    518:        else {
                    519:                int     elements = GET_RCV_ELEMENTS(option);
                    520: #define trailer0       ((mach_msg_format_0_trailer_t *)trailer)
                    521:                
                    522:                if (elements == MACH_RCV_TRAILER_SENDER) {
                    523:                        trailer0->msgh_sender = kmsg->ikm_sender;
                    524:                        trailer0->msgh_seqno = seqno;
                    525:                }
                    526:                else
                    527:                if (elements == MACH_RCV_TRAILER_SEQNO)
                    528:                        trailer0->msgh_seqno = seqno;
                    529: 
                    530:                trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
                    531:                trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
                    532: #undef trailer0
                    533:        }
                    534: 
                    535:        if (option & MACH_RCV_NOTIFY) {
                    536:                if (self->ith_notify == MACH_PORT_NULL)
                    537:                        mr = MACH_RCV_INVALID_NOTIFY;
                    538:                else
                    539:                        mr = ipc_kmsg_copyout(
                    540:                                        kmsg, space, map,
                    541:                                        self->ith_notify, 
                    542:                                        self->ith_list);
                    543:        } else
                    544:                mr = ipc_kmsg_copyout(
                    545:                                kmsg, space, map,
                    546:                                MACH_PORT_NULL,
                    547:                                self->ith_list);
                    548:        if (mr != MACH_MSG_SUCCESS) {
                    549:                mach_msg_return_t       pr;
                    550: 
                    551:                if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
                    552:                        pr = ipc_kmsg_put(msg, kmsg,
                    553:                                        kmsg->ikm_header.msgh_size +
                    554:                                                trailer->msgh_trailer_size);
                    555:                        if (pr != MACH_MSG_SUCCESS)
                    556:                                mr = pr;
                    557:                                        
                    558:                } else {
                    559:                        pr = mach_msg_receive_error(kmsg, msg,
                    560:                                                option, seqno, space);
                    561:                        if (pr != MACH_MSG_SUCCESS)
                    562:                                mr = pr;
                    563:                }
                    564: 
                    565:                FREE_SCATTER_LIST(list);
                    566:                thread_syscall_return(mr);
                    567:                /*NOTREACHED*/
                    568:        }
                    569: 
                    570:        FREE_SCATTER_LIST(list);
                    571:        mr = ipc_kmsg_put(msg, kmsg,
                    572:                        kmsg->ikm_header.msgh_size +
                    573:                                trailer->msgh_trailer_size);
                    574:        thread_syscall_return(mr);
                    575:        /*NOTREACHED*/
                    576: }
                    577: 
                    578: /*
                    579:  *     Routine:        mach_msg_receive_error  [internal]
                    580:  *     Purpose:
                    581:  *             Builds a minimal header/trailer and copies it to
                    582:  *             the user message buffer.  Invoked when in the case of a
                    583:  *             MACH_RCV_TOO_LARGE or MACH_RCV_HEADER_ERROR error.
                    584:  *     Conditions:
                    585:  *             Nothing locked.
                    586:  *     Returns:
                    587:  *             MACH_MSG_SUCCESS        minimal headere/trailer copied
                    588:  *             MACH_RCV_INVALID_DATA   copyout to user buffer failed
                    589:  */
                    590:        
                    591: mach_msg_return_t
                    592: mach_msg_receive_error(
                    593:        ipc_kmsg_t              kmsg,
                    594:        mach_msg_header_t       *msg,
                    595:        mach_msg_option_t       option,
                    596:        mach_port_seqno_t       seqno,
                    597:        ipc_space_t             space)
                    598: {
                    599:        mach_msg_trailer_t *trailer;
                    600: 
                    601:        /*
                    602:         * Copy out the destination port in the message.
                    603:         * Destroy all other rights and memory in the message.
                    604:         */
                    605:        ipc_kmsg_copyout_dest(kmsg, space);
                    606: 
                    607:        /*
                    608:         * Build a minimal message with a null trailer.
                    609:         */
                    610:        kmsg->ikm_header.msgh_size = sizeof(mach_msg_header_t);
                    611:        trailer = (mach_msg_trailer_t *)
                    612:                                ((vm_offset_t)&kmsg->ikm_header +
                    613:                                                kmsg->ikm_header.msgh_size);
                    614: 
                    615:        if (option & MACH_RCV_NO_TRAILER) {
                    616:            trailer->msgh_trailer_size = trailer->msgh_trailer_type = 0;
                    617:            kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
                    618:        }
                    619:        else {
                    620:            trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
                    621:            trailer->msgh_trailer_size = sizeof (mach_msg_trailer_t);
                    622:        }
                    623: 
                    624:        /*
                    625:         * Copy the message to user space
                    626:         */
                    627:        return ipc_kmsg_put(msg, kmsg,
                    628:                        kmsg->ikm_header.msgh_size +
                    629:                                trailer->msgh_trailer_size);
                    630: }
                    631: 
                    632: /*
                    633:  *     Routine:        mach_msg_overwrite_trap [mach trap]
                    634:  *     Purpose:
                    635:  *             Possibly send a message; possibly receive a message.
                    636:  *     Conditions:
                    637:  *             Nothing locked.
                    638:  *     Returns:
                    639:  *             All of mach_msg_send and mach_msg_receive error codes.
                    640:  */
                    641: static __inline__
                    642: mach_msg_return_t
                    643: _mach_msg_overwrite(
                    644:        mach_msg_header_t       *msg,
                    645:        mach_msg_option_t       option,
                    646:        mach_msg_size_t         send_size,
                    647:        mach_msg_size_t         rcv_size,
                    648:        mach_port_t             rcv_name,
                    649:        mach_msg_timeout_t      timeout,
                    650:        mach_port_t             notify,
                    651:        mach_msg_header_t       *rcv_msg,
                    652:         mach_msg_size_t                list_size)
                    653: {
                    654:        mach_msg_return_t mr;
                    655: 
                    656:        if (option & MACH_SEND_MSG) {
                    657:                mr = mach_msg_send(msg, option, send_size,
                    658:                                   timeout, notify);
                    659:                if (mr != MACH_MSG_SUCCESS)
                    660:                        return mr;
                    661:        }
                    662: 
                    663:        if (option & MACH_RCV_MSG) {
                    664:                mach_msg_header_t *rcv;
                    665: 
                    666:                /*
                    667:                 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
                    668:                 *    and receive buffer
                    669:                 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
                    670:                 *    alternate receive buffer (separate send and receive buffers).
                    671:                 */
                    672:                if (option & MACH_RCV_OVERWRITE) 
                    673:                    rcv = rcv_msg;
                    674:                else if (rcv_msg != MACH_MSG_NULL)
                    675:                    rcv = rcv_msg;
                    676:                else
                    677:                    rcv = msg;
                    678:                mr = mach_msg_receive(rcv, option, rcv_size, rcv_name, 
                    679:                                      timeout, notify, list_size);
                    680:                if (mr != MACH_MSG_SUCCESS)
                    681:                        return mr;
                    682:        }
                    683: 
                    684:        return MACH_MSG_SUCCESS;
                    685: }
                    686: 
                    687: mach_msg_return_t
                    688: mach_msg_overwrite_trap(
                    689:        mach_msg_header_t       *msg,
                    690:        mach_msg_option_t       option,
                    691:        mach_msg_size_t         sndsiz,
                    692:        mach_msg_size_t         rcvsiz,
                    693:        mach_port_t             rcvnam,
                    694:        mach_msg_timeout_t      tout,
                    695:        mach_port_t             notify,
                    696:        mach_msg_header_t       *rmsg,
                    697:        mach_msg_size_t         rmsgsiz)
                    698: {
                    699:        return
                    700:        (
                    701:                _mach_msg_overwrite(
                    702:                                msg, option,
                    703:                                sndsiz,
                    704:                                rcvsiz, rcvnam,
                    705:                                tout, notify,
                    706:                                rmsg, rmsgsiz));
                    707: }
                    708: 
                    709: mach_msg_return_t
                    710: mach_msg_trap(
                    711:        mach_msg_header_t       *msg,
                    712:        mach_msg_option_t       option,
                    713:        mach_msg_size_t         sndsiz,
                    714:        mach_msg_size_t         rcvsiz,
                    715:        mach_port_t             rcvnam,
                    716:        mach_msg_timeout_t      tout,
                    717:        mach_port_t             notify)
                    718: {
                    719:        return
                    720:        (
                    721:                _mach_msg_overwrite(
                    722:                                msg, option,
                    723:                                sndsiz,
                    724:                                rcvsiz, rcvnam,
                    725:                                tout, notify,
                    726:                                MACH_MSG_NULL,  (mach_msg_size_t) 0));
                    727: }
                    728: 
                    729: mach_msg_return_t
                    730: mach_msg_simple_trap(
                    731:        mach_msg_header_t       *msg,
                    732:        mach_msg_option_t       option,
                    733:        mach_msg_size_t         sndsiz,
                    734:        mach_msg_size_t         rcvsiz,
                    735:        mach_port_t             rcvnam)
                    736: {
                    737:        return
                    738:        (
                    739:                _mach_msg_overwrite(
                    740:                                msg, option,
                    741:                                sndsiz,
                    742:                                rcvsiz, rcvnam,
                    743:                                MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
                    744:                                MACH_MSG_NULL,  (mach_msg_size_t) 0));
                    745: }
                    746: 
                    747: /*
                    748:  *     Routine:        mach_msg_interrupt
                    749:  *     Purpose:
                    750:  *             Attempts to force a thread waiting at mach_msg_continue or
                    751:  *             mach_msg_receive_continue into a clean point.  Returns TRUE
                    752:  *             if this was possible.
                    753:  *     Conditions:
                    754:  *             Nothing locked.  The thread must NOT be runnable.
                    755:  */
                    756: 
                    757: boolean_t
                    758: mach_msg_interrupt(
                    759:        thread_t thread)
                    760: {
                    761:        ipc_mqueue_t mqueue;
                    762: 
                    763:        assert((thread->swap_func == (void (*)()) mach_msg_continue) ||
                    764:               (thread->swap_func == (void (*)()) mach_msg_receive_continue));
                    765: 
                    766:        mqueue = thread->ith_mqueue;
                    767:        imq_lock(mqueue);
                    768:        if (thread->ith_state != MACH_RCV_IN_PROGRESS) {
                    769:                /*
                    770:                 *      The thread is no longer waiting for a message.
                    771:                 *      It may have a message sitting in ith_kmsg.
                    772:                 *      We can't clean this up.
                    773:                 */
                    774: 
                    775:                imq_unlock(mqueue);
                    776:                return FALSE;
                    777:        }
                    778:        ipc_thread_rmqueue(&mqueue->imq_threads, thread);
                    779:        imq_unlock(mqueue);
                    780: 
                    781:        ipc_object_release(thread->ith_object);
                    782: 
                    783:        thread_set_syscall_return(thread, MACH_RCV_INTERRUPTED);
                    784:        thread->swap_func = thread_exception_return;
                    785:        return TRUE;
                    786: }
                    787: 
                    788: #if    MACH_IPC_COMPAT
                    789: 
                    790: /*
                    791:  *     Routine:        msg_return_translate
                    792:  *     Purpose:
                    793:  *             Translate from new error code to old error code.
                    794:  */
                    795: 
                    796: msg_return_t
                    797: msg_return_translate(
                    798:        mach_msg_return_t mr)
                    799: {
                    800:        switch (mr &~ MACH_MSG_MASK) {
                    801:            case MACH_MSG_SUCCESS:
                    802:                return 0;       /* SEND_SUCCESS/RCV_SUCCESS/RPC_SUCCESS */
                    803: 
                    804:            case MACH_SEND_NO_BUFFER:
                    805:            case MACH_SEND_NO_NOTIFY:
                    806:                printf("msg_return_translate: %x -> interrupted\n", mr);
                    807:                return SEND_INTERRUPTED;
                    808: 
                    809:            case MACH_SEND_MSG_TOO_SMALL:
                    810:                return SEND_MSG_TOO_SMALL;
                    811:            case MACH_SEND_INVALID_DATA:
                    812:            case MACH_SEND_INVALID_MEMORY:
                    813:                return SEND_INVALID_MEMORY;
                    814:            case MACH_SEND_TIMED_OUT:
                    815:                return SEND_TIMED_OUT;
                    816:            case MACH_SEND_INTERRUPTED:
                    817:                return SEND_INTERRUPTED;
                    818:            case MACH_SEND_INVALID_DEST:
                    819:            case MACH_SEND_INVALID_REPLY:
                    820:            case MACH_SEND_INVALID_RIGHT:
                    821:            case MACH_SEND_INVALID_TYPE:
                    822:                return SEND_INVALID_PORT;
                    823:            case MACH_SEND_WILL_NOTIFY:
                    824:                return SEND_WILL_NOTIFY;
                    825:            case MACH_SEND_NOTIFY_IN_PROGRESS:
                    826:                return SEND_NOTIFY_IN_PROGRESS;
                    827: 
                    828:            case MACH_RCV_INVALID_NAME:
                    829:            case MACH_RCV_IN_SET:
                    830:            case MACH_RCV_PORT_DIED:
                    831:                return RCV_INVALID_PORT;
                    832:            case MACH_RCV_TOO_LARGE:
                    833:                return RCV_TOO_LARGE;
                    834:            case MACH_RCV_TIMED_OUT:
                    835:                return RCV_TIMED_OUT;
                    836:            case MACH_RCV_INTERRUPTED:
                    837:                return RCV_INTERRUPTED;
                    838:            case MACH_RCV_PORT_CHANGED:
                    839:                return RCV_PORT_CHANGE;
                    840:            case MACH_RCV_INVALID_DATA:
                    841:                return RCV_INVALID_MEMORY;
                    842: 
                    843:            case MACH_SEND_IN_PROGRESS:
                    844:            case MACH_SEND_INVALID_NOTIFY:
                    845:            case MACH_SEND_INVALID_HEADER:
                    846:            case MACH_RCV_IN_PROGRESS:
                    847:            case MACH_RCV_INVALID_NOTIFY:
                    848:            case MACH_RCV_HEADER_ERROR:
                    849:            case MACH_RCV_BODY_ERROR:
                    850:            default:
                    851:                panic("msg_return_translate");
                    852:        }
                    853: }
                    854: 
                    855: /*
                    856:  *     Routine:        msg_send_trap [mach trap]
                    857:  *     Purpose:
                    858:  *             Send a message.
                    859:  *     Conditions:
                    860:  *             Nothing locked.
                    861:  *     Returns:
                    862:  */
                    863: 
                    864: msg_return_t
                    865: msg_send_trap(
                    866:        msg_header_t *msg,
                    867:        msg_option_t option,
                    868:        msg_size_t send_size,
                    869:        msg_timeout_t timeout)
                    870: {
                    871:        ipc_space_t space = current_space();
                    872:        vm_map_t map = current_map();
                    873:        ipc_kmsg_t kmsg;
                    874:        integer_t send_delta = send_size;
                    875:        mach_msg_return_t mr;
                    876: 
                    877:        send_size = (send_size + 3) & ~3; /* round up */
                    878:        send_delta -= send_size;
                    879: 
                    880:        if (send_size > MSG_SIZE_MAX)
                    881:                return SEND_MSG_TOO_LARGE;
                    882: 
                    883:        mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE,
                    884:                          (mach_msg_size_t) send_size, send_delta,
                    885:                          &kmsg);
                    886:        if (mr != MACH_MSG_SUCCESS)
                    887:                return msg_return_translate(mr);
                    888: 
                    889:        mr = ipc_kmsg_copyin_compat(kmsg, space, map);
                    890:        if (mr != MACH_MSG_SUCCESS) {
                    891:                ikm_free(kmsg);
                    892:                return msg_return_translate(mr);
                    893:        }
                    894: 
                    895:        if (option & SEND_NOTIFY) {
                    896:                mr = ipc_mqueue_send(kmsg, 
                    897:                                     ((option & SEND_SWITCH) ?
                    898:                                      MACH_SEND_SWITCH :
                    899:                                      MACH_MSG_OPTION_NONE) |
                    900:                                      MACH_SEND_TIMEOUT,
                    901:                                     ((option & SEND_TIMEOUT) ?
                    902:                                      (mach_msg_timeout_t) timeout :
                    903:                                      MACH_MSG_TIMEOUT_NONE),
                    904:                                     IMQ_NULL_CONTINUE);
                    905:                if (mr == MACH_SEND_TIMED_OUT) {
                    906:                        ipc_port_t dest = (ipc_port_t)
                    907:                                kmsg->ikm_header.msgh_remote_port;
                    908: 
                    909:                        mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
                    910:                                                  &kmsg->ikm_marequest);
                    911:                        if (mr == MACH_MSG_SUCCESS) {
                    912:                                ipc_mqueue_send_always(kmsg);
                    913:                                return SEND_WILL_NOTIFY;
                    914:                        }
                    915:                }
                    916:        }
                    917:        else if (option & SEND_SWITCH)
                    918:                mr = ipc_mqueue_send(kmsg,
                    919:                                     ((option & SEND_TIMEOUT) ?
                    920:                                      MACH_SEND_TIMEOUT :
                    921:                                      MACH_MSG_OPTION_NONE) |
                    922:                                      MACH_SEND_SWITCH,
                    923:                                     (mach_msg_timeout_t) timeout,
                    924:                                     msg_send_switch_continue);
                    925:        else
                    926:                mr = ipc_mqueue_send(kmsg,
                    927:                                     ((option & SEND_TIMEOUT) ?
                    928:                                      MACH_SEND_TIMEOUT :
                    929:                                      MACH_MSG_OPTION_NONE),
                    930:                                     (mach_msg_timeout_t) timeout,
                    931:                                     IMQ_NULL_CONTINUE);
                    932: 
                    933:        if (mr != MACH_MSG_SUCCESS)
                    934:                ipc_kmsg_destroy(kmsg);
                    935: 
                    936:        return msg_return_translate(mr);
                    937: }
                    938: 
                    939: void
                    940: msg_send_switch_continue(void)
                    941: {
                    942:        thread_syscall_return(SEND_SUCCESS);
                    943:        /*NOTREACHED*/
                    944: }
                    945: 
                    946: mach_msg_return_t
                    947: msg_receive_error(
                    948:        ipc_kmsg_t      kmsg,
                    949:        msg_header_t    *msg,
                    950:        ipc_space_t     space);
                    951: 
                    952: /*
                    953:  *     Routine:        msg_receive_trap [mach trap]
                    954:  *     Purpose:
                    955:  *             Receive a message.
                    956:  *     Conditions:
                    957:  *             Nothing locked.
                    958:  *     Returns:
                    959:  */
                    960: 
                    961: msg_return_t
                    962: msg_receive_trap(
                    963:        msg_header_t *msg,
                    964:        msg_option_t option,
                    965:        msg_size_t rcv_size,
                    966:        port_name_t rcv_name,
                    967:        msg_timeout_t timeout)
                    968: {
                    969:        ipc_thread_t self;
                    970:        ipc_space_t space = current_space();
                    971:        vm_map_t map = current_map();
                    972:        ipc_object_t object;
                    973:        ipc_mqueue_t mqueue;
                    974:        ipc_kmsg_t kmsg;
                    975:        mach_port_seqno_t seqno;
                    976:        mach_msg_return_t mr;
                    977: 
                    978:        mr = ipc_mqueue_copyin(space, (mach_port_t) rcv_name,
                    979:                               &mqueue, &object);
                    980:        if (mr != MACH_MSG_SUCCESS)
                    981:                return msg_return_translate(mr);
                    982:        /* hold ref for object; mqueue is locked */
                    983: 
                    984:        /*
                    985:         *      ipc_mqueue_receive may not return, because if we block
                    986:         *      then our kernel stack may be discarded.  So we save
                    987:         *      state here for msg_receive_continue to pick up.
                    988:         */
                    989: 
                    990:        self = current_thread();
                    991:        self->ith_msg = (mach_msg_header_t *) msg;
                    992:        self->ith_option = (mach_msg_option_t) option;
                    993:        self->ith_rcv_size = (mach_msg_size_t) rcv_size;
                    994:        self->ith_timeout = (mach_msg_timeout_t) timeout;
                    995:        self->ith_object = object;
                    996:        self->ith_mqueue = mqueue;
                    997: 
                    998:        mr = ipc_mqueue_receive(mqueue,
                    999:                                ((option & RCV_TIMEOUT) ?
                   1000:                                MACH_RCV_TIMEOUT :
                   1001:                                MACH_MSG_OPTION_NONE) |
                   1002:                                MACH_RCV_OLD_FORMAT,
                   1003:                                (option & RCV_LARGE) ?
                   1004:                                (mach_msg_size_t) rcv_size :
                   1005:                                MACH_MSG_SIZE_MAX,
                   1006:                                (mach_msg_timeout_t) timeout,
                   1007:                                FALSE, msg_receive_continue,
                   1008:                                &kmsg, &seqno, 0);
                   1009:        /* mqueue is unlocked */
                   1010:        ipc_object_release(object);
                   1011: 
                   1012:        if (mr != MACH_MSG_SUCCESS) {
                   1013:                if (mr == MACH_RCV_HEADER_ERROR)
                   1014:                        mr = msg_receive_error(kmsg, msg, space);
                   1015:                else
                   1016:                if (mr == MACH_RCV_TOO_LARGE) {
                   1017:                        msg_size_t real_size =
                   1018:                                (msg_size_t) (mach_msg_size_t) kmsg;
                   1019: 
                   1020:                        assert(real_size > rcv_size);
                   1021: 
                   1022:                        (void) copyout((vm_offset_t) &real_size,
                   1023:                                       (vm_offset_t) &msg->msg_size,
                   1024:                                       sizeof(msg_size_t));
                   1025:                }
                   1026: 
                   1027:                return msg_return_translate(mr);
                   1028:        }
                   1029:        
                   1030:        if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
                   1031:                assert(!(option & RCV_LARGE));
                   1032:                
                   1033:                ipc_kmsg_destroy(kmsg);
                   1034:                return (RCV_TOO_LARGE);
                   1035:        }
                   1036: 
                   1037:        assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
                   1038: 
                   1039:        mr = ipc_kmsg_copyout_compat(kmsg, space, map);
                   1040:        assert(mr == MACH_MSG_SUCCESS);
                   1041: 
                   1042:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
                   1043:        mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
                   1044:                          kmsg->ikm_header.msgh_size);
                   1045:        return msg_return_translate(mr);
                   1046: }
                   1047: 
                   1048: /*
                   1049:  *     Routine:        msg_rpc_trap [mach trap]
                   1050:  *     Purpose:
                   1051:  *             Send and receive a message.
                   1052:  *     Conditions:
                   1053:  *             Nothing locked.
                   1054:  *     Returns:
                   1055:  */
                   1056: 
                   1057: msg_return_t
                   1058: msg_rpc_trap(
                   1059:        msg_header_t *msg,
                   1060:        msg_option_t option,
                   1061:        msg_size_t send_size,
                   1062:        msg_size_t rcv_size,
                   1063:        msg_timeout_t send_timeout,
                   1064:        msg_timeout_t rcv_timeout)
                   1065: {
                   1066:        ipc_thread_t self;
                   1067:        ipc_space_t space = current_space();
                   1068:        vm_map_t map = current_map();
                   1069:        ipc_port_t reply;
                   1070:        ipc_pset_t pset;
                   1071:        ipc_mqueue_t mqueue;
                   1072:        ipc_kmsg_t kmsg;
                   1073:        integer_t send_delta = send_size;
                   1074:        mach_port_seqno_t seqno;
                   1075:        mach_msg_return_t mr;
                   1076: 
                   1077:        /*
                   1078:         *      Instead of using msg_send_trap and msg_receive_trap,
                   1079:         *      we implement msg_rpc_trap directly.  The difference
                   1080:         *      is how the reply port is handled.  Instead of using
                   1081:         *      ipc_mqueue_copyin, we save a reference for the reply
                   1082:         *      port carried in the sent message.  For example,
                   1083:         *      consider a rename kernel call which changes the name
                   1084:         *      of the call's own reply port.  This is the behaviour
                   1085:         *      of the Mach 2.5 msg_rpc_trap.
                   1086:         */
                   1087: 
                   1088:        send_size = (send_size + 3) & ~3; /* round up */
                   1089:        send_delta -= send_size;
                   1090: 
                   1091:        if (send_size > MSG_SIZE_MAX)
                   1092:                return SEND_MSG_TOO_LARGE;
                   1093: 
                   1094:        mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE,
                   1095:                          (mach_msg_size_t) send_size, send_delta,
                   1096:                          &kmsg);
                   1097:        if (mr != MACH_MSG_SUCCESS)
                   1098:                return msg_return_translate(mr);
                   1099: 
                   1100:        mr = ipc_kmsg_copyin_compat(kmsg, space, map);
                   1101:        if (mr != MACH_MSG_SUCCESS) {
                   1102:                ikm_free(kmsg);
                   1103:                return msg_return_translate(mr);
                   1104:        }
                   1105: 
                   1106:        reply = (ipc_port_t) kmsg->ikm_header.msgh_local_port;
                   1107:        if (IP_VALID(reply)) {
                   1108:                ipc_port_t      dest = (ipc_port_t)
                   1109:                                        kmsg->ikm_header.msgh_remote_port;
                   1110:                
                   1111:                ipc_port_reference(reply);
                   1112:                assert(IP_VALID(dest));
                   1113:                
                   1114:                ip_lock(dest);
                   1115:                
                   1116:                if (dest->ip_receiver == ipc_space_kernel) {
                   1117:                        ipc_mqueue_t    mqueue;
                   1118: 
                   1119:                        assert(ip_active(dest));
                   1120:                        ip_unlock(dest);
                   1121:                        
                   1122:                        kmsg = ipc_kobject_server(kmsg);
                   1123:                        if (kmsg == IKM_NULL)
                   1124:                                goto receive_reply;
                   1125:                        
                   1126:                        ip_lock(reply);
                   1127:                        
                   1128:                        if ((!ip_active(reply)) ||
                   1129:                            (reply->ip_receiver != space) ||
                   1130:                            (reply->ip_pset != IPS_NULL) ||
                   1131:                            (rcv_size < (kmsg->ikm_header.msgh_size + 
                   1132:                                                        kmsg->ikm_delta)))
                   1133:                        {
                   1134:                                ip_unlock(reply);
                   1135:                                ipc_mqueue_send_always(kmsg);
                   1136:                                goto receive_reply;
                   1137:                        }
                   1138: 
                   1139:                        mqueue = &reply->ip_messages;
                   1140:                        imq_lock(mqueue);
                   1141:                        
                   1142:                        if ((ipc_thread_queue_first(&mqueue->imq_threads)
                   1143:                                != ITH_NULL) ||
                   1144:                            (ipc_kmsg_queue_first(&mqueue->imq_messages)
                   1145:                                != IKM_NULL))
                   1146:                        {
                   1147:                                imq_unlock(mqueue);
                   1148:                                ip_unlock(reply);
                   1149:                                ipc_mqueue_send_always(kmsg);
                   1150:                                goto receive_reply;
                   1151:                        }
                   1152: 
                   1153:                        assert(kmsg->ikm_marequest == IMAR_NULL);
                   1154:                        assert(ipc_thread_queue_first(&reply->ip_blocked)
                   1155:                                == ITH_NULL);
                   1156: 
                   1157:                        reply->ip_seqno++;
                   1158:                        imq_unlock(mqueue);
                   1159: 
                   1160:                        ip_release(reply);
                   1161:                        ip_unlock(reply);
                   1162:                        
                   1163:                        goto copyout_reply;
                   1164:                }
                   1165:                
                   1166:                ip_unlock(dest);
                   1167:        }
                   1168: 
                   1169:        if (option & SEND_NOTIFY) {
                   1170:                mr = ipc_mqueue_send(kmsg,
                   1171:                                     ((option & SEND_SWITCH) ?
                   1172:                                      MACH_SEND_SWITCH :
                   1173:                                      MACH_MSG_OPTION_NONE) |
                   1174:                                      MACH_SEND_TIMEOUT,
                   1175:                                     ((option & SEND_TIMEOUT) ?
                   1176:                                      (mach_msg_timeout_t) send_timeout :
                   1177:                                      MACH_MSG_TIMEOUT_NONE),
                   1178:                                     IMQ_NULL_CONTINUE);
                   1179:                if (mr == MACH_SEND_TIMED_OUT) {
                   1180:                        ipc_port_t dest = (ipc_port_t)
                   1181:                                kmsg->ikm_header.msgh_remote_port;
                   1182: 
                   1183:                        mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
                   1184:                                                  &kmsg->ikm_marequest);
                   1185:                        if (mr == MACH_MSG_SUCCESS) {
                   1186:                                ipc_mqueue_send_always(kmsg);
                   1187:                                if (IP_VALID(reply))
                   1188:                                        ipc_port_release(reply);
                   1189:                                return SEND_WILL_NOTIFY;
                   1190:                        }
                   1191:                }
                   1192:        }
                   1193:        else if (option & SEND_SWITCH)
                   1194:                mr = ipc_mqueue_send(kmsg,
                   1195:                                     ((option & SEND_TIMEOUT) ?
                   1196:                                      MACH_SEND_TIMEOUT :
                   1197:                                      MACH_MSG_OPTION_NONE) |
                   1198:                                      MACH_SEND_SWITCH,
                   1199:                                     (mach_msg_timeout_t) send_timeout,
                   1200:                                     IMQ_NULL_CONTINUE);
                   1201:        else
                   1202:                mr = ipc_mqueue_send(kmsg,
                   1203:                                     ((option & SEND_TIMEOUT) ?
                   1204:                                      MACH_SEND_TIMEOUT :
                   1205:                                      MACH_MSG_OPTION_NONE),
                   1206:                                     (mach_msg_timeout_t) send_timeout,
                   1207:                                     IMQ_NULL_CONTINUE);
                   1208: 
                   1209:        if (mr != MACH_MSG_SUCCESS) {
                   1210:                ipc_kmsg_destroy(kmsg);
                   1211:                if (IP_VALID(reply))
                   1212:                        ipc_port_release(reply);
                   1213:                return msg_return_translate(mr);
                   1214:        }
                   1215: 
                   1216: receive_reply:
                   1217:        if (!IP_VALID(reply))
                   1218:                return RCV_INVALID_PORT;
                   1219: 
                   1220:        ip_lock(reply);
                   1221:        if (reply->ip_receiver != space) {
                   1222:                ip_release(reply);
                   1223:                ip_check_unlock(reply);
                   1224:                return RCV_INVALID_PORT;
                   1225:        }
                   1226: 
                   1227:        assert(ip_active(reply));
                   1228:        pset = reply->ip_pset;
                   1229: 
                   1230:        if (pset != IPS_NULL) {
                   1231:                ips_lock(pset);
                   1232:                if (ips_active(pset)) {
                   1233:                        ips_unlock(pset);
                   1234:                        ip_release(reply);
                   1235:                        ip_unlock(reply);
                   1236:                        return RCV_INVALID_PORT;
                   1237:                }
                   1238: 
                   1239:                ipc_pset_remove(pset, reply);
                   1240:                ips_check_unlock(pset);
                   1241:                assert(reply->ip_pset == IPS_NULL);
                   1242:        }
                   1243: 
                   1244:        mqueue = &reply->ip_messages;
                   1245:        imq_lock(mqueue);
                   1246:        ip_unlock(reply);
                   1247: 
                   1248:        /*
                   1249:         *      ipc_mqueue_receive may not return, because if we block
                   1250:         *      then our kernel stack may be discarded.  So we save
                   1251:         *      state here for msg_receive_continue to pick up.
                   1252:         */
                   1253: 
                   1254:        self = current_thread();
                   1255:        self->ith_msg = (mach_msg_header_t *) msg;
                   1256:        self->ith_option = (mach_msg_option_t) option;
                   1257:        self->ith_rcv_size = (mach_msg_size_t) rcv_size;
                   1258:        self->ith_timeout = (mach_msg_timeout_t) rcv_timeout;
                   1259:        self->ith_object = (ipc_object_t) reply;
                   1260:        self->ith_mqueue = mqueue;
                   1261: 
                   1262:        mr = ipc_mqueue_receive(mqueue,
                   1263:                                ((option & RCV_TIMEOUT) ?
                   1264:                                MACH_RCV_TIMEOUT :
                   1265:                                MACH_MSG_OPTION_NONE) |
                   1266:                                MACH_RCV_OLD_FORMAT,
                   1267:                                (option & RCV_LARGE) ?
                   1268:                                (mach_msg_size_t) rcv_size :
                   1269:                                MACH_MSG_SIZE_MAX,
                   1270:                                (mach_msg_timeout_t) rcv_timeout,
                   1271:                                FALSE, msg_receive_continue,
                   1272:                                &kmsg, &seqno, 0);
                   1273:        /* mqueue is unlocked */
                   1274:        ipc_port_release(reply);
                   1275: 
                   1276:        if (mr != MACH_MSG_SUCCESS) {
                   1277:                if (mr == MACH_RCV_HEADER_ERROR)
                   1278:                        mr = msg_receive_error(kmsg, msg, space);
                   1279:                else
                   1280:                if (mr == MACH_RCV_TOO_LARGE) {
                   1281:                        msg_size_t real_size =
                   1282:                                (msg_size_t) (mach_msg_size_t) kmsg;
                   1283: 
                   1284:                        assert(real_size > rcv_size);
                   1285: 
                   1286:                        (void) copyout((vm_offset_t) &real_size,
                   1287:                                       (vm_offset_t) &msg->msg_size,
                   1288:                                       sizeof(msg_size_t));
                   1289:                }
                   1290: 
                   1291:                return msg_return_translate(mr);
                   1292:        }
                   1293:        
                   1294:        if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
                   1295:                assert(!(option & RCV_LARGE));
                   1296:                
                   1297:                ipc_kmsg_destroy(kmsg);
                   1298:                return (RCV_TOO_LARGE);
                   1299:        }
                   1300: 
                   1301: copyout_reply:
                   1302:        assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
                   1303: 
                   1304:        mr = ipc_kmsg_copyout_compat(kmsg, space, map);
                   1305:        assert(mr == MACH_MSG_SUCCESS);
                   1306: 
                   1307:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
                   1308:        mr = ipc_kmsg_put((mach_msg_header_t *) msg,
                   1309:                          kmsg, kmsg->ikm_header.msgh_size);
                   1310:        return msg_return_translate(mr);
                   1311: }
                   1312: 
                   1313: /*
                   1314:  *     Routine:        msg_receive_continue
                   1315:  *     Purpose:
                   1316:  *             Continue after blocking for a message.
                   1317:  *     Conditions:
                   1318:  *             Nothing locked.  We are running on a new kernel stack,
                   1319:  *             with the receive state saved in the thread.  From here
                   1320:  *             control goes back to user space.
                   1321:  */
                   1322: 
                   1323: void
                   1324: msg_receive_continue(void)
                   1325: {
                   1326:        ipc_thread_t self = current_thread();
                   1327:        msg_header_t *msg = (msg_header_t *) self->ith_msg;
                   1328:        msg_option_t option = (msg_option_t) self->ith_option;
                   1329:        ipc_kmsg_t kmsg;
                   1330:        mach_port_seqno_t seqno;
                   1331:        mach_msg_return_t mr;
                   1332: 
                   1333:        mr = ipc_mqueue_receive(self->ith_mqueue,
                   1334:                                ((option & RCV_TIMEOUT) ?
                   1335:                                MACH_RCV_TIMEOUT :
                   1336:                                MACH_MSG_OPTION_NONE) |
                   1337:                                MACH_RCV_OLD_FORMAT,
                   1338:                                (option & RCV_LARGE) ?
                   1339:                                self->ith_rcv_size :
                   1340:                                MACH_MSG_SIZE_MAX,
                   1341:                                self->ith_timeout,
                   1342:                                TRUE, msg_receive_continue,
                   1343:                                &kmsg, &seqno, 0);
                   1344:        /* mqueue is unlocked */
                   1345:        ipc_object_release(self->ith_object);
                   1346: 
                   1347:        if (mr != MACH_MSG_SUCCESS) {
                   1348:                if (mr == MACH_RCV_HEADER_ERROR)
                   1349:                        mr = msg_receive_error(kmsg, msg, current_space());
                   1350:                else
                   1351:                if (mr == MACH_RCV_TOO_LARGE) {
                   1352:                        msg_size_t real_size =
                   1353:                                (msg_size_t) (mach_msg_size_t) kmsg;
                   1354: 
                   1355:                        assert(real_size > rcv_size);
                   1356: 
                   1357:                        (void) copyout((vm_offset_t) &real_size,
                   1358:                                       (vm_offset_t) &msg->msg_size,
                   1359:                                       sizeof(msg_size_t));
                   1360:                }
                   1361: 
                   1362:                thread_syscall_return(msg_return_translate(mr));
                   1363:                /*NOTREACHED*/
                   1364:        }
                   1365:        
                   1366:        if (kmsg->ikm_header.msgh_size > self->ith_rcv_size) {
                   1367:                assert(!(option & RCV_LARGE));
                   1368:                
                   1369:                ipc_kmsg_destroy(kmsg);
                   1370:                thread_syscall_return(RCV_TOO_LARGE);
                   1371:                /*NOTREACHED*/
                   1372:        }
                   1373: 
                   1374:        assert(kmsg->ikm_header.msgh_size <= self->ith_rcv_size);
                   1375: 
                   1376:        mr = ipc_kmsg_copyout_compat(kmsg, current_space(), current_map());
                   1377:        assert(mr == MACH_MSG_SUCCESS);
                   1378: 
                   1379:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
                   1380:        mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
                   1381:                          kmsg->ikm_header.msgh_size);
                   1382:        thread_syscall_return(msg_return_translate(mr));
                   1383:        /*NOTREACHED*/
                   1384: }
                   1385: 
                   1386: mach_msg_return_t
                   1387: msg_receive_error(
                   1388:        ipc_kmsg_t      kmsg,
                   1389:        msg_header_t    *msg,
                   1390:        ipc_space_t     space)
                   1391: {
                   1392:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                   1393:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   1394:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                   1395:        mach_msg_return_t mr;
                   1396: 
                   1397:        if (IO_VALID(reply))
                   1398:                ipc_object_destroy(reply, reply_type);
                   1399:        (ipc_object_t)kmsg->ikm_header.msgh_local_port = IO_NULL;
                   1400: 
                   1401:        assert(!(mbits & MACH_MSGH_BITS_OLD_FORMAT));
                   1402:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                   1403:                mach_msg_body_t *body;
                   1404: 
                   1405:                body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
                   1406:                ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count);
                   1407:        }
                   1408: 
                   1409:        kmsg->ikm_header.msgh_size = sizeof (mach_msg_header_t);
                   1410:        kmsg->ikm_header.msgh_reserved = 0;     /* copied to msg_type */
                   1411:        mr = ipc_kmsg_copyout_compat(kmsg, space, VM_MAP_NULL);
                   1412:        assert(mr == MACH_MSG_SUCCESS);
                   1413: 
                   1414:        return ipc_kmsg_put((mach_msg_header_t *)msg, kmsg,
                   1415:                                        kmsg->ikm_header.msgh_size);
                   1416: }
                   1417: 
                   1418: #endif MACH_IPC_COMPAT

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.