|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * File: ipc/ipc_kmsg.c
31: * Author: Rich Draves
32: * Date: 1989
33: *
34: * Operations on kernel messages.
35: */
36:
1.1.1.3 root 37: #include <kern/printf.h>
38: #include <string.h>
1.1 root 39:
40: #include <mach/boolean.h>
41: #include <mach/kern_return.h>
42: #include <mach/message.h>
43: #include <mach/port.h>
1.1.1.3 root 44: #include <machine/locore.h>
1.1 root 45: #include <kern/assert.h>
46: #include <kern/kalloc.h>
47: #include <vm/vm_map.h>
48: #include <vm/vm_object.h>
49: #include <vm/vm_kern.h>
1.1.1.3 root 50: #include <vm/vm_user.h>
1.1 root 51: #include <ipc/port.h>
52: #include <ipc/ipc_entry.h>
53: #include <ipc/ipc_kmsg.h>
54: #include <ipc/ipc_thread.h>
55: #include <ipc/ipc_marequest.h>
56: #include <ipc/ipc_notify.h>
57: #include <ipc/ipc_object.h>
58: #include <ipc/ipc_space.h>
59: #include <ipc/ipc_port.h>
60: #include <ipc/ipc_right.h>
61:
62: #include <ipc/ipc_machdep.h>
63:
1.1.1.3 root 64: #include <device/net_io.h>
65:
66: #if MACH_KDB
67: #include <ddb/db_output.h>
68: #include <ipc/ipc_print.h>
69: #endif
70:
1.1 root 71: #define is_misaligned(x) ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
72: #define ptr_align(x) \
73: ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
74:
75: ipc_kmsg_t ipc_kmsg_cache[NCPUS];
76:
77: /*
78: * Routine: ipc_kmsg_enqueue
79: * Purpose:
80: * Enqueue a kmsg.
81: */
82:
83: void
84: ipc_kmsg_enqueue(
85: ipc_kmsg_queue_t queue,
86: ipc_kmsg_t kmsg)
87: {
88: ipc_kmsg_enqueue_macro(queue, kmsg);
89: }
90:
91: /*
92: * Routine: ipc_kmsg_dequeue
93: * Purpose:
94: * Dequeue and return a kmsg.
95: */
96:
97: ipc_kmsg_t
98: ipc_kmsg_dequeue(
99: ipc_kmsg_queue_t queue)
100: {
101: ipc_kmsg_t first;
102:
103: first = ipc_kmsg_queue_first(queue);
104:
105: if (first != IKM_NULL)
106: ipc_kmsg_rmqueue_first_macro(queue, first);
107:
108: return first;
109: }
110:
111: /*
112: * Routine: ipc_kmsg_rmqueue
113: * Purpose:
114: * Pull a kmsg out of a queue.
115: */
116:
117: void
118: ipc_kmsg_rmqueue(
119: ipc_kmsg_queue_t queue,
120: ipc_kmsg_t kmsg)
121: {
122: ipc_kmsg_t next, prev;
123:
124: assert(queue->ikmq_base != IKM_NULL);
125:
126: next = kmsg->ikm_next;
127: prev = kmsg->ikm_prev;
128:
129: if (next == kmsg) {
130: assert(prev == kmsg);
131: assert(queue->ikmq_base == kmsg);
132:
133: queue->ikmq_base = IKM_NULL;
134: } else {
135: if (queue->ikmq_base == kmsg)
136: queue->ikmq_base = next;
137:
138: next->ikm_prev = prev;
139: prev->ikm_next = next;
140: }
1.1.1.4 root 141: ikm_mark_bogus (kmsg);
1.1 root 142: }
143:
144: /*
145: * Routine: ipc_kmsg_queue_next
146: * Purpose:
147: * Return the kmsg following the given kmsg.
148: * (Or IKM_NULL if it is the last one in the queue.)
149: */
150:
151: ipc_kmsg_t
152: ipc_kmsg_queue_next(
153: ipc_kmsg_queue_t queue,
154: ipc_kmsg_t kmsg)
155: {
156: ipc_kmsg_t next;
157:
158: assert(queue->ikmq_base != IKM_NULL);
159:
160: next = kmsg->ikm_next;
161: if (queue->ikmq_base == next)
162: next = IKM_NULL;
163:
164: return next;
165: }
166:
167: /*
168: * Routine: ipc_kmsg_destroy
169: * Purpose:
170: * Destroys a kernel message. Releases all rights,
171: * references, and memory held by the message.
172: * Frees the message.
173: * Conditions:
174: * No locks held.
175: */
176:
177: void
178: ipc_kmsg_destroy(
179: ipc_kmsg_t kmsg)
180: {
181: ipc_kmsg_queue_t queue;
182: boolean_t empty;
183:
184: /*
185: * ipc_kmsg_clean can cause more messages to be destroyed.
186: * Curtail recursion by queueing messages. If a message
187: * is already queued, then this is a recursive call.
188: */
189:
190: queue = ¤t_thread()->ith_messages;
191: empty = ipc_kmsg_queue_empty(queue);
192: ipc_kmsg_enqueue(queue, kmsg);
193:
194: if (empty) {
195: /* must leave kmsg in queue while cleaning it */
196:
197: while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
198: ipc_kmsg_clean(kmsg);
199: ipc_kmsg_rmqueue(queue, kmsg);
200: ikm_free(kmsg);
201: }
202: }
203: }
204:
205: /*
206: * Routine: ipc_kmsg_clean_body
207: * Purpose:
208: * Cleans the body of a kernel message.
209: * Releases all rights, references, and memory.
210: *
211: * The last type/data pair might stretch past eaddr.
212: * (See the usage in ipc_kmsg_copyout.)
213: * Conditions:
214: * No locks held.
215: */
216:
217: void
1.1.1.4 root 218: ipc_kmsg_clean_body(
219: vm_offset_t saddr,
220: vm_offset_t eaddr)
1.1 root 221: {
222: while (saddr < eaddr) {
223: mach_msg_type_long_t *type;
224: mach_msg_type_name_t name;
225: mach_msg_type_size_t size;
226: mach_msg_type_number_t number;
227: boolean_t is_inline, is_port;
228: vm_size_t length;
229:
230: type = (mach_msg_type_long_t *) saddr;
231: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
232: if (((mach_msg_type_t*)type)->msgt_longform) {
233: /* This must be aligned */
234: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
235: (is_misaligned(type))) {
236: saddr = ptr_align(saddr);
237: continue;
238: }
239: name = type->msgtl_name;
240: size = type->msgtl_size;
241: number = type->msgtl_number;
242: saddr += sizeof(mach_msg_type_long_t);
243: } else {
244: name = ((mach_msg_type_t*)type)->msgt_name;
245: size = ((mach_msg_type_t*)type)->msgt_size;
246: number = ((mach_msg_type_t*)type)->msgt_number;
247: saddr += sizeof(mach_msg_type_t);
248: }
249:
250: /* padding (ptrs and ports) ? */
251: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
252: ((size >> 3) == sizeof(natural_t)))
253: saddr = ptr_align(saddr);
254:
255: /* calculate length of data in bytes, rounding up */
256:
257: length = ((number * size) + 7) >> 3;
258:
259: is_port = MACH_MSG_TYPE_PORT_ANY(name);
260:
261: if (is_port) {
262: ipc_object_t *objects;
263: mach_msg_type_number_t i;
264:
265: if (is_inline) {
266: objects = (ipc_object_t *) saddr;
267: /* sanity check */
268: while (eaddr < (vm_offset_t)&objects[number]) number--;
269: } else {
270: objects = (ipc_object_t *)
271: * (vm_offset_t *) saddr;
272: }
273:
274: /* destroy port rights carried in the message */
275:
276: for (i = 0; i < number; i++) {
277: ipc_object_t object = objects[i];
278:
279: if (!IO_VALID(object))
280: continue;
281:
282: ipc_object_destroy(object, name);
283: }
284: }
285:
286: if (is_inline) {
287: /* inline data sizes round up to int boundaries */
288:
289: saddr += (length + 3) &~ 3;
290: } else {
291: vm_offset_t data = * (vm_offset_t *) saddr;
292:
293: /* destroy memory carried in the message */
294:
295: if (length == 0)
296: assert(data == 0);
297: else if (is_port)
298: kfree(data, length);
299: else
300: vm_map_copy_discard((vm_map_copy_t) data);
301:
302: saddr += sizeof(vm_offset_t);
303: }
304: }
305: }
306:
307: /*
308: * Routine: ipc_kmsg_clean
309: * Purpose:
310: * Cleans a kernel message. Releases all rights,
311: * references, and memory held by the message.
312: * Conditions:
313: * No locks held.
314: */
315:
316: void
1.1.1.4 root 317: ipc_kmsg_clean(ipc_kmsg_t kmsg)
1.1 root 318: {
319: ipc_marequest_t marequest;
320: ipc_object_t object;
321: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
322:
323: marequest = kmsg->ikm_marequest;
324: if (marequest != IMAR_NULL)
325: ipc_marequest_destroy(marequest);
326:
327: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
328: if (IO_VALID(object))
329: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
330:
331: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
332: if (IO_VALID(object))
333: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
334:
335: if (mbits & MACH_MSGH_BITS_COMPLEX) {
336: vm_offset_t saddr, eaddr;
337:
338: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
339: eaddr = (vm_offset_t) &kmsg->ikm_header +
340: kmsg->ikm_header.msgh_size;
341:
342: ipc_kmsg_clean_body(saddr, eaddr);
343: }
344: }
345:
346: /*
347: * Routine: ipc_kmsg_clean_partial
348: * Purpose:
349: * Cleans a partially-acquired kernel message.
350: * eaddr is the address of the type specification
351: * in the body of the message that contained the error.
352: * If dolast, the memory and port rights in this last
353: * type spec are also cleaned. In that case, number
354: * specifies the number of port rights to clean.
355: * Conditions:
356: * Nothing locked.
357: */
358:
359: void
1.1.1.4 root 360: ipc_kmsg_clean_partial(
361: ipc_kmsg_t kmsg,
362: vm_offset_t eaddr,
363: boolean_t dolast,
364: mach_msg_type_number_t number)
1.1 root 365: {
366: ipc_object_t object;
367: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
368: vm_offset_t saddr;
369:
370: assert(kmsg->ikm_marequest == IMAR_NULL);
371:
372: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
373: assert(IO_VALID(object));
374: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
375:
376: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
377: if (IO_VALID(object))
378: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
379:
380: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
381: ipc_kmsg_clean_body(saddr, eaddr);
382:
383: if (dolast) {
384: mach_msg_type_long_t *type;
385: mach_msg_type_name_t name;
386: mach_msg_type_size_t size;
387: mach_msg_type_number_t rnumber;
388: boolean_t is_inline, is_port;
389: vm_size_t length;
390:
391: xxx: type = (mach_msg_type_long_t *) eaddr;
392: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
393: if (((mach_msg_type_t*)type)->msgt_longform) {
394: /* This must be aligned */
395: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
396: (is_misaligned(type))) {
397: eaddr = ptr_align(eaddr);
398: goto xxx;
399: }
400: name = type->msgtl_name;
401: size = type->msgtl_size;
402: rnumber = type->msgtl_number;
403: eaddr += sizeof(mach_msg_type_long_t);
404: } else {
405: name = ((mach_msg_type_t*)type)->msgt_name;
406: size = ((mach_msg_type_t*)type)->msgt_size;
407: rnumber = ((mach_msg_type_t*)type)->msgt_number;
408: eaddr += sizeof(mach_msg_type_t);
409: }
410:
411: /* padding (ptrs and ports) ? */
412: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
413: ((size >> 3) == sizeof(natural_t)))
414: eaddr = ptr_align(eaddr);
415:
416: /* calculate length of data in bytes, rounding up */
417:
418: length = ((rnumber * size) + 7) >> 3;
419:
420: is_port = MACH_MSG_TYPE_PORT_ANY(name);
421:
422: if (is_port) {
423: ipc_object_t *objects;
424: mach_msg_type_number_t i;
425:
426: objects = (ipc_object_t *)
427: (is_inline ? eaddr : * (vm_offset_t *) eaddr);
428:
429: /* destroy port rights carried in the message */
430:
431: for (i = 0; i < number; i++) {
432: ipc_object_t obj = objects[i];
433:
434: if (!IO_VALID(obj))
435: continue;
436:
437: ipc_object_destroy(obj, name);
438: }
439: }
440:
441: if (!is_inline) {
442: vm_offset_t data = * (vm_offset_t *) eaddr;
443:
444: /* destroy memory carried in the message */
445:
446: if (length == 0)
447: assert(data == 0);
448: else if (is_port)
449: kfree(data, length);
450: else
451: vm_map_copy_discard((vm_map_copy_t) data);
452: }
453: }
454: }
455:
456: /*
457: * Routine: ipc_kmsg_free
458: * Purpose:
459: * Free a kernel message buffer.
460: * Conditions:
461: * Nothing locked.
462: */
463:
464: void
1.1.1.4 root 465: ipc_kmsg_free(ipc_kmsg_t kmsg)
1.1 root 466: {
467: vm_size_t size = kmsg->ikm_size;
468:
469: switch (size) {
470:
471: case IKM_SIZE_NETWORK:
472: /* return it to the network code */
473: net_kmsg_put(kmsg);
474: break;
475:
476: default:
477: kfree((vm_offset_t) kmsg, size);
478: break;
479: }
480: }
481:
482: /*
483: * Routine: ipc_kmsg_get
484: * Purpose:
485: * Allocates a kernel message buffer.
486: * Copies a user message to the message buffer.
487: * Conditions:
488: * Nothing locked.
489: * Returns:
490: * MACH_MSG_SUCCESS Acquired a message buffer.
491: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
492: * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
493: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
494: * MACH_SEND_INVALID_DATA Couldn't copy message data.
495: */
496:
497: mach_msg_return_t
1.1.1.4 root 498: ipc_kmsg_get(
499: mach_msg_header_t *msg,
500: mach_msg_size_t size,
501: ipc_kmsg_t *kmsgp)
1.1 root 502: {
503: ipc_kmsg_t kmsg;
504:
505: if ((size < sizeof(mach_msg_header_t)) || (size & 3))
506: return MACH_SEND_MSG_TOO_SMALL;
507:
508: if (size <= IKM_SAVED_MSG_SIZE) {
509: kmsg = ikm_cache();
510: if (kmsg != IKM_NULL) {
511: ikm_cache() = IKM_NULL;
512: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
513: } else {
514: kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
515: if (kmsg == IKM_NULL)
516: return MACH_SEND_NO_BUFFER;
517: ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
518: }
519: } else {
520: kmsg = ikm_alloc(size);
521: if (kmsg == IKM_NULL)
522: return MACH_SEND_NO_BUFFER;
523: ikm_init(kmsg, size);
524: }
525:
1.1.1.3 root 526: if (copyinmsg(msg, &kmsg->ikm_header, size)) {
1.1 root 527: ikm_free(kmsg);
528: return MACH_SEND_INVALID_DATA;
529: }
530:
531: kmsg->ikm_header.msgh_size = size;
532: *kmsgp = kmsg;
533: return MACH_MSG_SUCCESS;
534: }
535:
536: /*
537: * Routine: ipc_kmsg_get_from_kernel
538: * Purpose:
539: * Allocates a kernel message buffer.
540: * Copies a kernel message to the message buffer.
541: * Only resource errors are allowed.
542: * Conditions:
543: * Nothing locked.
544: * Returns:
545: * MACH_MSG_SUCCESS Acquired a message buffer.
546: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
547: */
548:
549: extern mach_msg_return_t
1.1.1.4 root 550: ipc_kmsg_get_from_kernel(
551: mach_msg_header_t *msg,
552: mach_msg_size_t size,
553: ipc_kmsg_t *kmsgp)
1.1 root 554: {
555: ipc_kmsg_t kmsg;
556:
557: assert(size >= sizeof(mach_msg_header_t));
558: assert((size & 3) == 0);
559:
560: kmsg = ikm_alloc(size);
561: if (kmsg == IKM_NULL)
562: return MACH_SEND_NO_BUFFER;
563: ikm_init(kmsg, size);
564:
1.1.1.3 root 565: memcpy(&kmsg->ikm_header, msg, size);
1.1 root 566:
567: kmsg->ikm_header.msgh_size = size;
568: *kmsgp = kmsg;
569: return MACH_MSG_SUCCESS;
570: }
571:
572: /*
573: * Routine: ipc_kmsg_put
574: * Purpose:
575: * Copies a message buffer to a user message.
576: * Copies only the specified number of bytes.
577: * Frees the message buffer.
578: * Conditions:
579: * Nothing locked. The message buffer must have clean
580: * header (ikm_marequest) fields.
581: * Returns:
582: * MACH_MSG_SUCCESS Copied data out of message buffer.
583: * MACH_RCV_INVALID_DATA Couldn't copy to user message.
584: */
585:
586: mach_msg_return_t
1.1.1.4 root 587: ipc_kmsg_put(
588: mach_msg_header_t *msg,
589: ipc_kmsg_t kmsg,
590: mach_msg_size_t size)
1.1 root 591: {
592: mach_msg_return_t mr;
593:
594: ikm_check_initialized(kmsg, kmsg->ikm_size);
595:
1.1.1.3 root 596: if (copyoutmsg(&kmsg->ikm_header, msg, size))
1.1 root 597: mr = MACH_RCV_INVALID_DATA;
598: else
599: mr = MACH_MSG_SUCCESS;
600:
601: if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
602: (ikm_cache() == IKM_NULL))
603: ikm_cache() = kmsg;
604: else
605: ikm_free(kmsg);
606:
607: return mr;
608: }
609:
610: /*
611: * Routine: ipc_kmsg_put_to_kernel
612: * Purpose:
613: * Copies a message buffer to a kernel message.
614: * Frees the message buffer.
615: * No errors allowed.
616: * Conditions:
617: * Nothing locked.
618: */
619:
620: void
621: ipc_kmsg_put_to_kernel(
622: mach_msg_header_t *msg,
623: ipc_kmsg_t kmsg,
624: mach_msg_size_t size)
625: {
626: #if DIPC
627: assert(!KMSG_IN_DIPC(kmsg));
628: #endif /* DIPC */
629:
1.1.1.3 root 630: memcpy(msg, &kmsg->ikm_header, size);
1.1 root 631:
632: ikm_free(kmsg);
633: }
634:
635: /*
636: * Routine: ipc_kmsg_copyin_header
637: * Purpose:
638: * "Copy-in" port rights in the header of a message.
639: * Operates atomically; if it doesn't succeed the
640: * message header and the space are left untouched.
641: * If it does succeed the remote/local port fields
642: * contain object pointers instead of port names,
643: * and the bits field is updated. The destination port
644: * will be a valid port pointer.
645: *
646: * The notify argument implements the MACH_SEND_CANCEL option.
647: * If it is not MACH_PORT_NULL, it should name a receive right.
648: * If the processing of the destination port would generate
649: * a port-deleted notification (because the right for the
650: * destination port is destroyed and it had a request for
651: * a dead-name notification registered), and the port-deleted
652: * notification would be sent to the named receive right,
653: * then it isn't sent and the send-once right for the notify
654: * port is quietly destroyed.
655: * Conditions:
656: * Nothing locked.
657: * Returns:
658: * MACH_MSG_SUCCESS Successful copyin.
659: * MACH_SEND_INVALID_HEADER
660: * Illegal value in the message header bits.
661: * MACH_SEND_INVALID_DEST The space is dead.
662: * MACH_SEND_INVALID_NOTIFY
663: * Notify is non-null and doesn't name a receive right.
664: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
665: * MACH_SEND_INVALID_DEST Can't copyin destination port.
666: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
667: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
668: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
669: */
670:
671: mach_msg_return_t
1.1.1.4 root 672: ipc_kmsg_copyin_header(
673: mach_msg_header_t *msg,
674: ipc_space_t space,
675: mach_port_t notify)
1.1 root 676: {
677: mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
678: mach_port_t dest_name = msg->msgh_remote_port;
679: mach_port_t reply_name = msg->msgh_local_port;
680: kern_return_t kr;
681:
682: #ifndef MIGRATING_THREADS
683: /* first check for common cases */
684:
685: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
686: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): {
687: ipc_entry_t entry;
688: ipc_entry_bits_t bits;
689: ipc_port_t dest_port;
690:
691: /* sending an asynchronous message */
692:
693: if (reply_name != MACH_PORT_NULL)
694: break;
695:
696: is_read_lock(space);
697: if (!space->is_active)
698: goto abort_async;
699:
1.1.1.5 root 700: entry = ipc_entry_lookup (space, dest_name);
701: if (entry == IE_NULL)
1.1 root 702: goto abort_async;
703: bits = entry->ie_bits;
704:
1.1.1.5 root 705: /* check type bits */
706: if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND)
1.1 root 707: goto abort_async;
708:
709: /* optimized ipc_right_copyin */
710:
711: assert(IE_BITS_UREFS(bits) > 0);
712:
713: dest_port = (ipc_port_t) entry->ie_object;
714: assert(dest_port != IP_NULL);
715:
716: ip_lock(dest_port);
717: /* can unlock space now without compromising atomicity */
718: is_read_unlock(space);
719:
720: if (!ip_active(dest_port)) {
721: ip_unlock(dest_port);
722: break;
723: }
724:
725: assert(dest_port->ip_srights > 0);
726: dest_port->ip_srights++;
727: ip_reference(dest_port);
728: ip_unlock(dest_port);
729:
730: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
731: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
732: msg->msgh_remote_port = (mach_port_t) dest_port;
733: return MACH_MSG_SUCCESS;
734:
735: abort_async:
736: is_read_unlock(space);
737: break;
738: }
739:
740: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
741: MACH_MSG_TYPE_MAKE_SEND_ONCE): {
742: ipc_entry_t entry;
743: ipc_entry_bits_t bits;
744: ipc_port_t dest_port, reply_port;
745:
746: /* sending a request message */
747:
748: is_read_lock(space);
749: if (!space->is_active)
750: goto abort_request;
751:
1.1.1.5 root 752: entry = ipc_entry_lookup (space, dest_name);
753: if (entry == IE_NULL)
1.1 root 754: goto abort_request;
755: bits = entry->ie_bits;
756:
1.1.1.5 root 757: /* check type bits */
758: if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND)
1.1 root 759: goto abort_request;
760:
761: assert(IE_BITS_UREFS(bits) > 0);
762:
763: dest_port = (ipc_port_t) entry->ie_object;
764: assert(dest_port != IP_NULL);
765:
1.1.1.5 root 766: entry = ipc_entry_lookup (space, reply_name);
767: if (entry == IE_NULL)
1.1 root 768: goto abort_request;
769: bits = entry->ie_bits;
770:
1.1.1.5 root 771: /* check type bits */
772: if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_RECEIVE)
1.1 root 773: goto abort_request;
774:
775: reply_port = (ipc_port_t) entry->ie_object;
776: assert(reply_port != IP_NULL);
777:
778: /*
779: * To do an atomic copyin, need simultaneous
780: * locks on both ports and the space. If
781: * dest_port == reply_port, and simple locking is
782: * enabled, then we will abort. Otherwise it's
783: * OK to unlock twice.
784: */
785:
786: ip_lock(dest_port);
787: if (!ip_active(dest_port) || !ip_lock_try(reply_port)) {
788: ip_unlock(dest_port);
789: goto abort_request;
790: }
791: /* can unlock space now without compromising atomicity */
792: is_read_unlock(space);
793:
794: assert(dest_port->ip_srights > 0);
795: dest_port->ip_srights++;
796: ip_reference(dest_port);
797: ip_unlock(dest_port);
798:
799: assert(ip_active(reply_port));
800: assert(reply_port->ip_receiver_name == reply_name);
801: assert(reply_port->ip_receiver == space);
802:
803: reply_port->ip_sorights++;
804: ip_reference(reply_port);
805: ip_unlock(reply_port);
806:
807: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
808: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
809: MACH_MSG_TYPE_PORT_SEND_ONCE));
810: msg->msgh_remote_port = (mach_port_t) dest_port;
811: msg->msgh_local_port = (mach_port_t) reply_port;
812: return MACH_MSG_SUCCESS;
813:
814: abort_request:
815: is_read_unlock(space);
816: break;
817: }
818:
819: case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
820: ipc_entry_t entry;
821: ipc_entry_bits_t bits;
822: ipc_port_t dest_port;
823:
824: /* sending a reply message */
825:
826: if (reply_name != MACH_PORT_NULL)
827: break;
828:
829: is_write_lock(space);
830: if (!space->is_active)
831: goto abort_reply;
832:
1.1.1.5 root 833: entry = ipc_entry_lookup (space, dest_name);
834: if (entry == IE_NULL)
1.1 root 835: goto abort_reply;
836: bits = entry->ie_bits;
837:
1.1.1.5 root 838: /* check and type bits */
839: if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND_ONCE)
1.1 root 840: goto abort_reply;
841:
842: /* optimized ipc_right_copyin */
843:
844: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
845: assert(IE_BITS_UREFS(bits) == 1);
846: assert((bits & IE_BITS_MAREQUEST) == 0);
847:
848: if (entry->ie_request != 0)
849: goto abort_reply;
850:
851: dest_port = (ipc_port_t) entry->ie_object;
852: assert(dest_port != IP_NULL);
853:
854: ip_lock(dest_port);
855: if (!ip_active(dest_port)) {
856: ip_unlock(dest_port);
857: goto abort_reply;
858: }
859:
860: assert(dest_port->ip_sorights > 0);
861: ip_unlock(dest_port);
862:
863: entry->ie_object = IO_NULL;
1.1.1.5 root 864: ipc_entry_dealloc (space, dest_name, entry);
1.1 root 865: is_write_unlock(space);
866:
867: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
868: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
869: 0));
870: msg->msgh_remote_port = (mach_port_t) dest_port;
871: return MACH_MSG_SUCCESS;
872:
873: abort_reply:
874: is_write_unlock(space);
875: break;
876: }
877:
878: default:
879: /* don't bother optimizing */
880: break;
881: }
882: #endif /* MIGRATING_THREADS */
883:
884: {
885: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
886: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
887: ipc_object_t dest_port, reply_port;
888: ipc_port_t dest_soright, reply_soright;
889: ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */
890:
891: if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
892: return MACH_SEND_INVALID_HEADER;
893:
894: if ((reply_type == 0) ?
895: (reply_name != MACH_PORT_NULL) :
896: !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
897: return MACH_SEND_INVALID_HEADER;
898:
899: is_write_lock(space);
900: if (!space->is_active)
901: goto invalid_dest;
902:
903: if (notify != MACH_PORT_NULL) {
904: ipc_entry_t entry;
905:
906: if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
907: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
908: is_write_unlock(space);
909: return MACH_SEND_INVALID_NOTIFY;
910: }
911:
912: notify_port = (ipc_port_t) entry->ie_object;
913: }
914:
915: if (dest_name == reply_name) {
916: ipc_entry_t entry;
917: mach_port_t name = dest_name;
918:
919: /*
920: * Destination and reply ports are the same!
921: * This is a little tedious to make atomic, because
922: * there are 25 combinations of dest_type/reply_type.
923: * However, most are easy. If either is move-sonce,
924: * then there must be an error. If either are
925: * make-send or make-sonce, then we must be looking
926: * at a receive right so the port can't die.
927: * The hard cases are the combinations of
928: * copy-send and make-send.
929: */
930:
931: entry = ipc_entry_lookup(space, name);
932: if (entry == IE_NULL)
933: goto invalid_dest;
934:
935: assert(reply_type != 0); /* because name not null */
936:
937: if (!ipc_right_copyin_check(space, name, entry, reply_type))
938: goto invalid_reply;
939:
940: if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
941: (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
942: /*
943: * Why must there be an error? To get a valid
944: * destination, this entry must name a live
945: * port (not a dead name or dead port). However
946: * a successful move-sonce will destroy a
947: * live entry. Therefore the other copyin,
948: * whatever it is, would fail. We've already
949: * checked for reply port errors above,
950: * so report a destination error.
951: */
952:
953: goto invalid_dest;
954: } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
955: (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
956: (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
957: (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
958: kr = ipc_right_copyin(space, name, entry,
959: dest_type, FALSE,
960: &dest_port, &dest_soright);
961: if (kr != KERN_SUCCESS)
962: goto invalid_dest;
963:
964: /*
965: * Either dest or reply needs a receive right.
966: * We know the receive right is there, because
967: * of the copyin_check and copyin calls. Hence
968: * the port is not in danger of dying. If dest
969: * used the receive right, then the right needed
970: * by reply (and verified by copyin_check) will
971: * still be there.
972: */
973:
974: assert(IO_VALID(dest_port));
975: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
976: assert(dest_soright == IP_NULL);
977:
978: kr = ipc_right_copyin(space, name, entry,
979: reply_type, TRUE,
980: &reply_port, &reply_soright);
981:
982: assert(kr == KERN_SUCCESS);
983: assert(reply_port == dest_port);
984: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
985: assert(reply_soright == IP_NULL);
986: } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
987: (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
988: /*
989: * To make this atomic, just do one copy-send,
990: * and dup the send right we get out.
991: */
992:
993: kr = ipc_right_copyin(space, name, entry,
994: dest_type, FALSE,
995: &dest_port, &dest_soright);
996: if (kr != KERN_SUCCESS)
997: goto invalid_dest;
998:
999: assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
1000: assert(dest_soright == IP_NULL);
1001:
1002: /*
1003: * It's OK if the port we got is dead now,
1004: * so reply_port is IP_DEAD, because the msg
1005: * won't go anywhere anyway.
1006: */
1007:
1008: reply_port = (ipc_object_t)
1009: ipc_port_copy_send((ipc_port_t) dest_port);
1010: reply_soright = IP_NULL;
1011: } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1012: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
1013: /*
1014: * This is an easy case. Just use our
1015: * handy-dandy special-purpose copyin call
1016: * to get two send rights for the price of one.
1017: */
1018:
1019: kr = ipc_right_copyin_two(space, name, entry,
1020: &dest_port, &dest_soright);
1021: if (kr != KERN_SUCCESS)
1022: goto invalid_dest;
1023:
1024: /* the entry might need to be deallocated */
1025:
1026: if (IE_BITS_TYPE(entry->ie_bits)
1027: == MACH_PORT_TYPE_NONE)
1028: ipc_entry_dealloc(space, name, entry);
1029:
1030: reply_port = dest_port;
1031: reply_soright = IP_NULL;
1032: } else {
1033: ipc_port_t soright;
1034:
1035: assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
1036: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
1037: ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1038: (reply_type == MACH_MSG_TYPE_COPY_SEND)));
1039:
1040: /*
1041: * To make this atomic, just do a move-send,
1042: * and dup the send right we get out.
1043: */
1044:
1045: kr = ipc_right_copyin(space, name, entry,
1046: MACH_MSG_TYPE_MOVE_SEND, FALSE,
1047: &dest_port, &soright);
1048: if (kr != KERN_SUCCESS)
1049: goto invalid_dest;
1050:
1051: /* the entry might need to be deallocated */
1052:
1053: if (IE_BITS_TYPE(entry->ie_bits)
1054: == MACH_PORT_TYPE_NONE)
1055: ipc_entry_dealloc(space, name, entry);
1056:
1057: /*
1058: * It's OK if the port we got is dead now,
1059: * so reply_port is IP_DEAD, because the msg
1060: * won't go anywhere anyway.
1061: */
1062:
1063: reply_port = (ipc_object_t)
1064: ipc_port_copy_send((ipc_port_t) dest_port);
1065:
1066: if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
1067: dest_soright = soright;
1068: reply_soright = IP_NULL;
1069: } else {
1070: dest_soright = IP_NULL;
1071: reply_soright = soright;
1072: }
1073: }
1074: } else if (!MACH_PORT_VALID(reply_name)) {
1075: ipc_entry_t entry;
1076:
1077: /*
1078: * No reply port! This is an easy case
1079: * to make atomic. Just copyin the destination.
1080: */
1081:
1082: entry = ipc_entry_lookup(space, dest_name);
1083: if (entry == IE_NULL)
1084: goto invalid_dest;
1085:
1086: kr = ipc_right_copyin(space, dest_name, entry,
1087: dest_type, FALSE,
1088: &dest_port, &dest_soright);
1089: if (kr != KERN_SUCCESS)
1090: goto invalid_dest;
1091:
1092: /* the entry might need to be deallocated */
1093:
1094: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
1095: ipc_entry_dealloc(space, dest_name, entry);
1096:
1097: reply_port = (ipc_object_t) reply_name;
1098: reply_soright = IP_NULL;
1099: } else {
1100: ipc_entry_t dest_entry, reply_entry;
1101: ipc_port_t saved_reply;
1102:
1103: /*
1104: * This is the tough case to make atomic.
1105: * The difficult problem is serializing with port death.
1106: * At the time we copyin dest_port, it must be alive.
1107: * If reply_port is alive when we copyin it, then
1108: * we are OK, because we serialize before the death
1109: * of both ports. Assume reply_port is dead at copyin.
1110: * Then if dest_port dies/died after reply_port died,
1111: * we are OK, because we serialize between the death
1112: * of the two ports. So the bad case is when dest_port
1113: * dies after its copyin, reply_port dies before its
1114: * copyin, and dest_port dies before reply_port. Then
1115: * the copyins operated as if dest_port was alive
1116: * and reply_port was dead, which shouldn't have happened
1117: * because they died in the other order.
1118: *
1119: * We handle the bad case by undoing the copyins
1120: * (which is only possible because the ports are dead)
1121: * and failing with MACH_SEND_INVALID_DEST, serializing
1122: * after the death of the ports.
1123: *
1124: * Note that it is easy for a user task to tell if
1125: * a copyin happened before or after a port died.
1126: * For example, suppose both dest and reply are
1127: * send-once rights (types are both move-sonce) and
1128: * both rights have dead-name requests registered.
1129: * If a port dies before copyin, a dead-name notification
1130: * is generated and the dead name's urefs are incremented,
1131: * and if the copyin happens first, a port-deleted
1132: * notification is generated.
1133: *
1134: * Note that although the entries are different,
1135: * dest_port and reply_port might still be the same.
1136: */
1137:
1138: dest_entry = ipc_entry_lookup(space, dest_name);
1139: if (dest_entry == IE_NULL)
1140: goto invalid_dest;
1141:
1142: reply_entry = ipc_entry_lookup(space, reply_name);
1143: if (reply_entry == IE_NULL)
1144: goto invalid_reply;
1145:
1146: assert(dest_entry != reply_entry); /* names are not equal */
1147: assert(reply_type != 0); /* because reply_name not null */
1148:
1149: if (!ipc_right_copyin_check(space, reply_name, reply_entry,
1150: reply_type))
1151: goto invalid_reply;
1152:
1153: kr = ipc_right_copyin(space, dest_name, dest_entry,
1154: dest_type, FALSE,
1155: &dest_port, &dest_soright);
1156: if (kr != KERN_SUCCESS)
1157: goto invalid_dest;
1158:
1159: assert(IO_VALID(dest_port));
1160:
1161: saved_reply = (ipc_port_t) reply_entry->ie_object;
1162: /* might be IP_NULL, if this is a dead name */
1163: if (saved_reply != IP_NULL)
1164: ipc_port_reference(saved_reply);
1165:
1166: kr = ipc_right_copyin(space, reply_name, reply_entry,
1167: reply_type, TRUE,
1168: &reply_port, &reply_soright);
1169: assert(kr == KERN_SUCCESS);
1170:
1171: if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) {
1172: ipc_port_t dest = (ipc_port_t) dest_port;
1173: ipc_port_timestamp_t timestamp;
1174: boolean_t must_undo;
1175:
1176: /*
1177: * The reply port died before copyin.
1178: * Check if dest port died before reply.
1179: */
1180:
1181: ip_lock(saved_reply);
1182: assert(!ip_active(saved_reply));
1183: timestamp = saved_reply->ip_timestamp;
1184: ip_unlock(saved_reply);
1185:
1186: ip_lock(dest);
1187: must_undo = (!ip_active(dest) &&
1188: IP_TIMESTAMP_ORDER(dest->ip_timestamp,
1189: timestamp));
1190: ip_unlock(dest);
1191:
1192: if (must_undo) {
1193: /*
1194: * Our worst nightmares are realized.
1195: * Both destination and reply ports
1196: * are dead, but in the wrong order,
1197: * so we must undo the copyins and
1198: * possibly generate a dead-name notif.
1199: */
1200:
1201: ipc_right_copyin_undo(
1202: space, dest_name, dest_entry,
1203: dest_type, dest_port,
1204: dest_soright);
1205: /* dest_entry may be deallocated now */
1206:
1207: ipc_right_copyin_undo(
1208: space, reply_name, reply_entry,
1209: reply_type, reply_port,
1210: reply_soright);
1211: /* reply_entry may be deallocated now */
1212:
1213: is_write_unlock(space);
1214:
1215: if (dest_soright != IP_NULL)
1216: ipc_notify_dead_name(dest_soright,
1217: dest_name);
1218: assert(reply_soright == IP_NULL);
1219:
1220: ipc_port_release(saved_reply);
1221: return MACH_SEND_INVALID_DEST;
1222: }
1223: }
1224:
1225: /* the entries might need to be deallocated */
1226:
1227: if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1228: ipc_entry_dealloc(space, reply_name, reply_entry);
1229:
1230: if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1231: ipc_entry_dealloc(space, dest_name, dest_entry);
1232:
1233: if (saved_reply != IP_NULL)
1234: ipc_port_release(saved_reply);
1235: }
1236:
1237: /*
1238: * At this point, dest_port, reply_port,
1239: * dest_soright, reply_soright are all initialized.
1240: * Any defunct entries have been deallocated.
1241: * The space is still write-locked, and we need to
1242: * make the MACH_SEND_CANCEL check. The notify_port pointer
1243: * is still usable, because the copyin code above won't ever
1244: * deallocate a receive right, so its entry still exists
1245: * and holds a ref. Note notify_port might even equal
1246: * dest_port or reply_port.
1247: */
1248:
1249: if ((notify != MACH_PORT_NULL) &&
1250: (dest_soright == notify_port)) {
1251: ipc_port_release_sonce(dest_soright);
1252: dest_soright = IP_NULL;
1253: }
1254:
1255: is_write_unlock(space);
1256:
1257: if (dest_soright != IP_NULL)
1258: ipc_notify_port_deleted(dest_soright, dest_name);
1259:
1260: if (reply_soright != IP_NULL)
1261: ipc_notify_port_deleted(reply_soright, reply_name);
1262:
1263: dest_type = ipc_object_copyin_type(dest_type);
1264: reply_type = ipc_object_copyin_type(reply_type);
1265:
1266: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1267: MACH_MSGH_BITS(dest_type, reply_type));
1268: msg->msgh_remote_port = (mach_port_t) dest_port;
1269: msg->msgh_local_port = (mach_port_t) reply_port;
1270: }
1271:
1272: return MACH_MSG_SUCCESS;
1273:
1274: invalid_dest:
1275: is_write_unlock(space);
1276: return MACH_SEND_INVALID_DEST;
1277:
1278: invalid_reply:
1279: is_write_unlock(space);
1280: return MACH_SEND_INVALID_REPLY;
1281: }
1282:
1283: mach_msg_return_t
1.1.1.4 root 1284: ipc_kmsg_copyin_body(
1285: ipc_kmsg_t kmsg,
1286: ipc_space_t space,
1287: vm_map_t map)
1.1 root 1288: {
1289: ipc_object_t dest;
1290: vm_offset_t saddr, eaddr;
1291: boolean_t complex;
1292: boolean_t use_page_lists, steal_pages;
1293:
1294: dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
1295: complex = FALSE;
1296: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
1297: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
1298:
1299: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
1300: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
1301:
1302: while (saddr < eaddr) {
1303: vm_offset_t taddr = saddr;
1304: mach_msg_type_long_t *type;
1305: mach_msg_type_name_t name;
1306: mach_msg_type_size_t size;
1307: mach_msg_type_number_t number;
1308: boolean_t is_inline, longform, dealloc, is_port;
1309: vm_offset_t data;
1.1.1.6 ! root 1310: uint64_t length;
1.1 root 1311: kern_return_t kr;
1312:
1313: type = (mach_msg_type_long_t *) saddr;
1314:
1315: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
1316: ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
1317: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
1318: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1319: return MACH_SEND_MSG_TOO_SMALL;
1320: }
1321:
1322: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
1323: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
1324: if (longform) {
1325: /* This must be aligned */
1326: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1327: (is_misaligned(type))) {
1328: saddr = ptr_align(saddr);
1329: continue;
1330: }
1331: name = type->msgtl_name;
1332: size = type->msgtl_size;
1333: number = type->msgtl_number;
1334: saddr += sizeof(mach_msg_type_long_t);
1335: } else {
1336: name = ((mach_msg_type_t*)type)->msgt_name;
1337: size = ((mach_msg_type_t*)type)->msgt_size;
1338: number = ((mach_msg_type_t*)type)->msgt_number;
1339: saddr += sizeof(mach_msg_type_t);
1340: }
1341:
1342: is_port = MACH_MSG_TYPE_PORT_ANY(name);
1343:
1344: if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
1345: (longform && ((type->msgtl_header.msgt_name != 0) ||
1346: (type->msgtl_header.msgt_size != 0) ||
1347: (type->msgtl_header.msgt_number != 0))) ||
1348: (((mach_msg_type_t*)type)->msgt_unused != 0) ||
1349: (dealloc && is_inline)) {
1350: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1351: return MACH_SEND_INVALID_TYPE;
1352: }
1353:
1354: /* padding (ptrs and ports) ? */
1355: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1356: ((size >> 3) == sizeof(natural_t)))
1357: saddr = ptr_align(saddr);
1358:
1359: /* calculate length of data in bytes, rounding up */
1360:
1.1.1.6 ! root 1361: length = (((uint64_t) number * size) + 7) >> 3;
1.1 root 1362:
1363: if (is_inline) {
1364: vm_size_t amount;
1365:
1366: /* inline data sizes round up to int boundaries */
1367:
1368: amount = (length + 3) &~ 3;
1369: if ((eaddr - saddr) < amount) {
1370: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1371: return MACH_SEND_MSG_TOO_SMALL;
1372: }
1373:
1374: data = saddr;
1375: saddr += amount;
1376: } else {
1377: vm_offset_t addr;
1378:
1379: if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
1380: saddr = ptr_align(saddr);
1.1.1.2 root 1381:
1.1 root 1382: if ((eaddr - saddr) < sizeof(vm_offset_t)) {
1383: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1384: return MACH_SEND_MSG_TOO_SMALL;
1385: }
1386:
1387: /* grab the out-of-line data */
1388:
1389: addr = * (vm_offset_t *) saddr;
1390:
1391: if (length == 0)
1392: data = 0;
1393: else if (is_port) {
1394: data = kalloc(length);
1395: if (data == 0)
1396: goto invalid_memory;
1397:
1398: if (copyinmap(map, (char *) addr,
1399: (char *) data, length) ||
1400: (dealloc &&
1401: (vm_deallocate(map, addr, length) !=
1402: KERN_SUCCESS))) {
1403: kfree(data, length);
1404: goto invalid_memory;
1405: }
1406: } else {
1407: vm_map_copy_t copy;
1408:
1409: if (use_page_lists) {
1410: kr = vm_map_copyin_page_list(map,
1411: addr, length, dealloc,
1412: steal_pages, ©, FALSE);
1413: } else {
1414: kr = vm_map_copyin(map, addr, length,
1415: dealloc, ©);
1416: }
1417: if (kr != KERN_SUCCESS) {
1418: invalid_memory:
1419: ipc_kmsg_clean_partial(kmsg, taddr,
1420: FALSE, 0);
1421: return MACH_SEND_INVALID_MEMORY;
1422: }
1423:
1424: data = (vm_offset_t) copy;
1425: }
1426:
1427: * (vm_offset_t *) saddr = data;
1428: saddr += sizeof(vm_offset_t);
1429: complex = TRUE;
1430: }
1431:
1432: if (is_port) {
1433: mach_msg_type_name_t newname =
1434: ipc_object_copyin_type(name);
1435: ipc_object_t *objects = (ipc_object_t *) data;
1436: mach_msg_type_number_t i;
1437:
1438: if (longform)
1439: type->msgtl_name = newname;
1440: else
1441: ((mach_msg_type_t*)type)->msgt_name = newname;
1442:
1443: for (i = 0; i < number; i++) {
1444: mach_port_t port = (mach_port_t) objects[i];
1445: ipc_object_t object;
1446:
1447: if (!MACH_PORT_VALID(port))
1448: continue;
1449:
1450: kr = ipc_object_copyin(space, port,
1451: name, &object);
1452: if (kr != KERN_SUCCESS) {
1453: ipc_kmsg_clean_partial(kmsg, taddr,
1454: TRUE, i);
1455: return MACH_SEND_INVALID_RIGHT;
1456: }
1457:
1458: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
1459: ipc_port_check_circularity(
1460: (ipc_port_t) object,
1461: (ipc_port_t) dest))
1462: kmsg->ikm_header.msgh_bits |=
1463: MACH_MSGH_BITS_CIRCULAR;
1464:
1465: objects[i] = object;
1466: }
1467:
1468: complex = TRUE;
1469: }
1470: }
1471:
1472: if (!complex)
1473: kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
1474:
1475: return MACH_MSG_SUCCESS;
1476: }
1477:
1478: /*
1479: * Routine: ipc_kmsg_copyin
1480: * Purpose:
1481: * "Copy-in" port rights and out-of-line memory
1482: * in the message.
1483: *
1484: * In all failure cases, the message is left holding
1485: * no rights or memory. However, the message buffer
1486: * is not deallocated. If successful, the message
1487: * contains a valid destination port.
1488: * Conditions:
1489: * Nothing locked.
1490: * Returns:
1491: * MACH_MSG_SUCCESS Successful copyin.
1492: * MACH_SEND_INVALID_HEADER
1493: * Illegal value in the message header bits.
1494: * MACH_SEND_INVALID_NOTIFY Bad notify port.
1495: * MACH_SEND_INVALID_DEST Can't copyin destination port.
1496: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
1497: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
1498: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
1499: * MACH_SEND_INVALID_TYPE Bad type specification.
1500: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
1501: */
1502:
1503: mach_msg_return_t
1.1.1.4 root 1504: ipc_kmsg_copyin(
1505: ipc_kmsg_t kmsg,
1506: ipc_space_t space,
1507: vm_map_t map,
1508: mach_port_t notify)
1.1 root 1509: {
1510: mach_msg_return_t mr;
1511:
1512: mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
1513: if (mr != MACH_MSG_SUCCESS)
1514: return mr;
1515:
1516: if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
1517: return MACH_MSG_SUCCESS;
1518:
1519: return ipc_kmsg_copyin_body(kmsg, space, map);
1520: }
1521:
1522: /*
1523: * Routine: ipc_kmsg_copyin_from_kernel
1524: * Purpose:
1525: * "Copy-in" port rights and out-of-line memory
1526: * in a message sent from the kernel.
1527: *
1528: * Because the message comes from the kernel,
1529: * the implementation assumes there are no errors
1530: * or peculiarities in the message.
1531: *
1532: * Returns TRUE if queueing the message
1533: * would result in a circularity.
1534: * Conditions:
1535: * Nothing locked.
1536: */
1537:
1538: void
1.1.1.4 root 1539: ipc_kmsg_copyin_from_kernel(ipc_kmsg_t kmsg)
1.1 root 1540: {
1541: mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits;
1542: mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
1543: mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
1544: ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
1545: ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
1546: vm_offset_t saddr, eaddr;
1547:
1548: /* translate the destination and reply ports */
1549:
1550: ipc_object_copyin_from_kernel(remote, rname);
1551: if (IO_VALID(local))
1552: ipc_object_copyin_from_kernel(local, lname);
1553:
1554: /*
1555: * The common case is a complex message with no reply port,
1556: * because that is what the memory_object interface uses.
1557: */
1558:
1559: if (bits == (MACH_MSGH_BITS_COMPLEX |
1560: MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
1561: bits = (MACH_MSGH_BITS_COMPLEX |
1562: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
1563:
1564: kmsg->ikm_header.msgh_bits = bits;
1565: } else {
1566: bits = (MACH_MSGH_BITS_OTHER(bits) |
1567: MACH_MSGH_BITS(ipc_object_copyin_type(rname),
1568: ipc_object_copyin_type(lname)));
1569:
1570: kmsg->ikm_header.msgh_bits = bits;
1571: if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
1572: return;
1573: }
1574:
1575: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
1576: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
1577:
1578: while (saddr < eaddr) {
1579: mach_msg_type_long_t *type;
1580: mach_msg_type_name_t name;
1581: mach_msg_type_size_t size;
1582: mach_msg_type_number_t number;
1583: boolean_t is_inline, longform, is_port;
1584: vm_offset_t data;
1585: vm_size_t length;
1586:
1587: type = (mach_msg_type_long_t *) saddr;
1588: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
1589: longform = ((mach_msg_type_t*)type)->msgt_longform;
1590: /* type->msgtl_header.msgt_deallocate not used */
1591: if (longform) {
1592: /* This must be aligned */
1593: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1594: (is_misaligned(type))) {
1595: saddr = ptr_align(saddr);
1596: continue;
1597: }
1598: name = type->msgtl_name;
1599: size = type->msgtl_size;
1600: number = type->msgtl_number;
1601: saddr += sizeof(mach_msg_type_long_t);
1602: } else {
1603: name = ((mach_msg_type_t*)type)->msgt_name;
1604: size = ((mach_msg_type_t*)type)->msgt_size;
1605: number = ((mach_msg_type_t*)type)->msgt_number;
1606: saddr += sizeof(mach_msg_type_t);
1607: }
1608:
1609: /* padding (ptrs and ports) ? */
1610: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1611: ((size >> 3) == sizeof(natural_t)))
1612: saddr = ptr_align(saddr);
1613:
1614: /* calculate length of data in bytes, rounding up */
1615:
1616: length = ((number * size) + 7) >> 3;
1617:
1618: is_port = MACH_MSG_TYPE_PORT_ANY(name);
1619:
1620: if (is_inline) {
1621: /* inline data sizes round up to int boundaries */
1622:
1623: data = saddr;
1624: saddr += (length + 3) &~ 3;
1625: } else {
1626: /*
1627: * The sender should supply ready-made memory
1628: * for us, so we don't need to do anything.
1629: */
1630:
1631: data = * (vm_offset_t *) saddr;
1632: saddr += sizeof(vm_offset_t);
1633: }
1634:
1635: if (is_port) {
1636: mach_msg_type_name_t newname =
1637: ipc_object_copyin_type(name);
1638: ipc_object_t *objects = (ipc_object_t *) data;
1639: mach_msg_type_number_t i;
1640:
1641: if (longform)
1642: type->msgtl_name = newname;
1643: else
1644: ((mach_msg_type_t*)type)->msgt_name = newname;
1645: for (i = 0; i < number; i++) {
1646: ipc_object_t object = objects[i];
1647:
1648: if (!IO_VALID(object))
1649: continue;
1650:
1651: ipc_object_copyin_from_kernel(object, name);
1652:
1653: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
1654: ipc_port_check_circularity(
1655: (ipc_port_t) object,
1656: (ipc_port_t) remote))
1657: kmsg->ikm_header.msgh_bits |=
1658: MACH_MSGH_BITS_CIRCULAR;
1659: }
1660: }
1661: }
1662: }
1663:
1664: /*
1665: * Routine: ipc_kmsg_copyout_header
1666: * Purpose:
1667: * "Copy-out" port rights in the header of a message.
1668: * Operates atomically; if it doesn't succeed the
1669: * message header and the space are left untouched.
1670: * If it does succeed the remote/local port fields
1671: * contain port names instead of object pointers,
1672: * and the bits field is updated.
1673: *
1674: * The notify argument implements the MACH_RCV_NOTIFY option.
1675: * If it is not MACH_PORT_NULL, it should name a receive right.
1676: * If the process of receiving the reply port creates a
1677: * new right in the receiving task, then the new right is
1678: * automatically registered for a dead-name notification,
1679: * with the notify port supplying the send-once right.
1680: * Conditions:
1681: * Nothing locked.
1682: * Returns:
1683: * MACH_MSG_SUCCESS Copied out port rights.
1.1.1.2 root 1684: * MACH_RCV_INVALID_NOTIFY
1.1 root 1685: * Notify is non-null and doesn't name a receive right.
1686: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
1687: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
1688: * The space is dead.
1689: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
1690: * No room in space for another name.
1691: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
1692: * Couldn't allocate memory for the reply port.
1693: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
1694: * Couldn't allocate memory for the dead-name request.
1695: */
1696:
1697: mach_msg_return_t
1.1.1.4 root 1698: ipc_kmsg_copyout_header(
1699: mach_msg_header_t *msg,
1700: ipc_space_t space,
1701: mach_port_t notify)
1.1 root 1702: {
1703: mach_msg_bits_t mbits = msg->msgh_bits;
1704: ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
1705:
1706: assert(IP_VALID(dest));
1707:
1708: #ifndef MIGRATING_THREADS
1709: /* first check for common cases */
1710:
1711: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
1712: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
1713: mach_port_t dest_name;
1714: ipc_port_t nsrequest;
1.1.1.5 root 1715: unsigned long payload;
1.1 root 1716:
1717: /* receiving an asynchronous message */
1718:
1719: ip_lock(dest);
1720: if (!ip_active(dest)) {
1721: ip_unlock(dest);
1722: break;
1723: }
1724:
1725: /* optimized ipc_object_copyout_dest */
1726:
1727: assert(dest->ip_srights > 0);
1728: ip_release(dest);
1729:
1730: if (dest->ip_receiver == space)
1731: dest_name = dest->ip_receiver_name;
1732: else
1733: dest_name = MACH_PORT_NULL;
1.1.1.5 root 1734: payload = dest->ip_protected_payload;
1.1 root 1735:
1736: if ((--dest->ip_srights == 0) &&
1737: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
1738: mach_port_mscount_t mscount;
1739:
1740: dest->ip_nsrequest = IP_NULL;
1741: mscount = dest->ip_mscount;
1742: ip_unlock(dest);
1743:
1744: ipc_notify_no_senders(nsrequest, mscount);
1745: } else
1746: ip_unlock(dest);
1747:
1.1.1.4 root 1748: if (! ipc_port_flag_protected_payload(dest)) {
1749: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1750: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
1751: msg->msgh_local_port = dest_name;
1752: } else {
1753: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1754: MACH_MSGH_BITS(
1755: 0, MACH_MSG_TYPE_PROTECTED_PAYLOAD));
1.1.1.5 root 1756: msg->msgh_protected_payload = payload;
1.1.1.4 root 1757: }
1.1 root 1758: msg->msgh_remote_port = MACH_PORT_NULL;
1759: return MACH_MSG_SUCCESS;
1760: }
1761:
1762: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
1763: MACH_MSG_TYPE_PORT_SEND_ONCE): {
1764: ipc_entry_t entry;
1765: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
1766: mach_port_t dest_name, reply_name;
1767: ipc_port_t nsrequest;
1.1.1.5 root 1768: unsigned long payload;
1.1 root 1769:
1770: /* receiving a request message */
1771:
1772: if (!IP_VALID(reply))
1773: break;
1774:
1775: is_write_lock(space);
1.1.1.5 root 1776: if (!space->is_active || space->is_free_list == NULL) {
1.1 root 1777: is_write_unlock(space);
1778: break;
1779: }
1780:
1781: /*
1782: * To do an atomic copyout, need simultaneous
1783: * locks on both ports and the space. If
1784: * dest == reply, and simple locking is
1785: * enabled, then we will abort. Otherwise it's
1786: * OK to unlock twice.
1787: */
1788:
1789: ip_lock(dest);
1790: if (!ip_active(dest) || !ip_lock_try(reply)) {
1791: ip_unlock(dest);
1792: is_write_unlock(space);
1793: break;
1794: }
1795:
1796: if (!ip_active(reply)) {
1797: ip_unlock(reply);
1798: ip_unlock(dest);
1799: is_write_unlock(space);
1800: break;
1801: }
1802:
1803: assert(reply->ip_sorights > 0);
1804: ip_unlock(reply);
1805:
1.1.1.5 root 1806: kern_return_t kr;
1807: kr = ipc_entry_get (space, &reply_name, &entry);
1808: if (kr) {
1809: ip_unlock(reply);
1810: ip_unlock(dest);
1811: is_write_unlock(space);
1812: break;
1813: }
1.1 root 1814:
1815: {
1816: mach_port_gen_t gen;
1817:
1818: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
1819: gen = entry->ie_bits + IE_BITS_GEN_ONE;
1820:
1821: /* optimized ipc_right_copyout */
1822:
1823: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
1824: }
1825:
1826: assert(MACH_PORT_VALID(reply_name));
1827: entry->ie_object = (ipc_object_t) reply;
1828: is_write_unlock(space);
1829:
1830: /* optimized ipc_object_copyout_dest */
1831:
1832: assert(dest->ip_srights > 0);
1833: ip_release(dest);
1834:
1835: if (dest->ip_receiver == space)
1836: dest_name = dest->ip_receiver_name;
1837: else
1838: dest_name = MACH_PORT_NULL;
1.1.1.5 root 1839: payload = dest->ip_protected_payload;
1.1 root 1840:
1841: if ((--dest->ip_srights == 0) &&
1842: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
1843: mach_port_mscount_t mscount;
1844:
1845: dest->ip_nsrequest = IP_NULL;
1846: mscount = dest->ip_mscount;
1847: ip_unlock(dest);
1848:
1849: ipc_notify_no_senders(nsrequest, mscount);
1850: } else
1851: ip_unlock(dest);
1852:
1.1.1.4 root 1853: if (! ipc_port_flag_protected_payload(dest)) {
1854: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1855: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
1856: MACH_MSG_TYPE_PORT_SEND));
1857: msg->msgh_local_port = dest_name;
1858: } else {
1859: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1860: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
1861: MACH_MSG_TYPE_PROTECTED_PAYLOAD));
1.1.1.5 root 1862: msg->msgh_protected_payload = payload;
1.1.1.4 root 1863: }
1.1 root 1864: msg->msgh_remote_port = reply_name;
1865: return MACH_MSG_SUCCESS;
1866: }
1867:
1868: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1869: mach_port_t dest_name;
1.1.1.5 root 1870: unsigned long payload;
1.1 root 1871:
1872: /* receiving a reply message */
1873:
1874: ip_lock(dest);
1875: if (!ip_active(dest)) {
1876: ip_unlock(dest);
1877: break;
1878: }
1879:
1880: /* optimized ipc_object_copyout_dest */
1881:
1882: assert(dest->ip_sorights > 0);
1883:
1.1.1.5 root 1884: payload = dest->ip_protected_payload;
1885:
1.1 root 1886: if (dest->ip_receiver == space) {
1887: ip_release(dest);
1888: dest->ip_sorights--;
1889: dest_name = dest->ip_receiver_name;
1890: ip_unlock(dest);
1891: } else {
1892: ip_unlock(dest);
1893:
1894: ipc_notify_send_once(dest);
1895: dest_name = MACH_PORT_NULL;
1896: }
1897:
1.1.1.4 root 1898: if (! ipc_port_flag_protected_payload(dest)) {
1899: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1900: MACH_MSGH_BITS(0,
1901: MACH_MSG_TYPE_PORT_SEND_ONCE));
1902: msg->msgh_local_port = dest_name;
1903: } else {
1904: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1905: MACH_MSGH_BITS(0,
1906: MACH_MSG_TYPE_PROTECTED_PAYLOAD));
1.1.1.5 root 1907: msg->msgh_protected_payload = payload;
1.1.1.4 root 1908: }
1.1 root 1909: msg->msgh_remote_port = MACH_PORT_NULL;
1910: return MACH_MSG_SUCCESS;
1911: }
1912:
1913: default:
1914: /* don't bother optimizing */
1915: break;
1916: }
1917: #endif /* MIGRATING_THREADS */
1918:
1919: {
1920: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
1921: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
1922: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
1923: mach_port_t dest_name, reply_name;
1.1.1.5 root 1924: unsigned long payload;
1.1 root 1925:
1926: if (IP_VALID(reply)) {
1927: ipc_port_t notify_port;
1928: ipc_entry_t entry;
1929: kern_return_t kr;
1930:
1931: /*
1932: * Handling notify (for MACH_RCV_NOTIFY) is tricky.
1933: * The problem is atomically making a send-once right
1934: * from the notify port and installing it for a
1935: * dead-name request in the new entry, because this
1936: * requires two port locks (on the notify port and
1937: * the reply port). However, we can safely make
1938: * and consume send-once rights for the notify port
1939: * as long as we hold the space locked. This isn't
1940: * an atomicity problem, because the only way
1941: * to detect that a send-once right has been created
1942: * and then consumed if it wasn't needed is by getting
1943: * at the receive right to look at ip_sorights, and
1944: * because the space is write-locked status calls can't
1945: * lookup the notify port receive right. When we make
1946: * the send-once right, we lock the notify port,
1947: * so any status calls in progress will be done.
1948: */
1949:
1950: is_write_lock(space);
1951:
1952: for (;;) {
1953: ipc_port_request_index_t request;
1954:
1955: if (!space->is_active) {
1956: is_write_unlock(space);
1957: return (MACH_RCV_HEADER_ERROR|
1958: MACH_MSG_IPC_SPACE);
1959: }
1960:
1961: if (notify != MACH_PORT_NULL) {
1962: notify_port = ipc_port_lookup_notify(space,
1963: notify);
1964: if (notify_port == IP_NULL) {
1965: is_write_unlock(space);
1966: return MACH_RCV_INVALID_NOTIFY;
1967: }
1968: } else
1969: notify_port = IP_NULL;
1970:
1971: if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
1972: ipc_right_reverse(space, (ipc_object_t) reply,
1973: &reply_name, &entry)) {
1974: /* reply port is locked and active */
1975:
1976: /*
1977: * We don't need the notify_port
1978: * send-once right, but we can't release
1979: * it here because reply port is locked.
1980: * Wait until after the copyout to
1981: * release the notify port right.
1982: */
1983:
1984: assert(entry->ie_bits &
1985: MACH_PORT_TYPE_SEND_RECEIVE);
1986: break;
1987: }
1988:
1989: ip_lock(reply);
1990: if (!ip_active(reply)) {
1991: ip_release(reply);
1992: ip_check_unlock(reply);
1993:
1994: if (notify_port != IP_NULL)
1995: ipc_port_release_sonce(notify_port);
1996:
1997: ip_lock(dest);
1998: is_write_unlock(space);
1999:
2000: reply = IP_DEAD;
2001: reply_name = MACH_PORT_DEAD;
2002: goto copyout_dest;
2003: }
2004:
1.1.1.5 root 2005: kr = ipc_entry_alloc(space, &reply_name, &entry);
1.1 root 2006: if (kr != KERN_SUCCESS) {
2007: ip_unlock(reply);
2008:
2009: if (notify_port != IP_NULL)
2010: ipc_port_release_sonce(notify_port);
2011:
1.1.1.5 root 2012: is_write_unlock(space);
2013: if (kr == KERN_RESOURCE_SHORTAGE)
2014: return (MACH_RCV_HEADER_ERROR|
2015: MACH_MSG_IPC_KERNEL);
2016: else
2017: return (MACH_RCV_HEADER_ERROR|
2018: MACH_MSG_IPC_SPACE);
1.1 root 2019: }
2020:
2021: assert(IE_BITS_TYPE(entry->ie_bits)
2022: == MACH_PORT_TYPE_NONE);
2023: assert(entry->ie_object == IO_NULL);
2024:
2025: if (notify_port == IP_NULL) {
2026: /* not making a dead-name request */
2027:
2028: entry->ie_object = (ipc_object_t) reply;
2029: break;
2030: }
2031:
2032: kr = ipc_port_dnrequest(reply, reply_name,
2033: notify_port, &request);
2034: if (kr != KERN_SUCCESS) {
2035: ip_unlock(reply);
2036:
2037: ipc_port_release_sonce(notify_port);
2038:
2039: ipc_entry_dealloc(space, reply_name, entry);
2040: is_write_unlock(space);
2041:
2042: ip_lock(reply);
2043: if (!ip_active(reply)) {
2044: /* will fail next time around loop */
2045:
2046: ip_unlock(reply);
2047: is_write_lock(space);
2048: continue;
2049: }
2050:
2051: kr = ipc_port_dngrow(reply);
2052: /* port is unlocked */
2053: if (kr != KERN_SUCCESS)
2054: return (MACH_RCV_HEADER_ERROR|
2055: MACH_MSG_IPC_KERNEL);
2056:
2057: is_write_lock(space);
2058: continue;
2059: }
2060:
2061: notify_port = IP_NULL; /* don't release right below */
2062:
2063: entry->ie_object = (ipc_object_t) reply;
2064: entry->ie_request = request;
2065: break;
2066: }
2067:
2068: /* space and reply port are locked and active */
2069:
2070: ip_reference(reply); /* hold onto the reply port */
2071:
2072: kr = ipc_right_copyout(space, reply_name, entry,
2073: reply_type, TRUE, (ipc_object_t) reply);
2074: /* reply port is unlocked */
2075: assert(kr == KERN_SUCCESS);
2076:
2077: if (notify_port != IP_NULL)
2078: ipc_port_release_sonce(notify_port);
2079:
2080: ip_lock(dest);
2081: is_write_unlock(space);
2082: } else {
2083: /*
2084: * No reply port! This is an easy case.
2085: * We only need to have the space locked
2086: * when checking notify and when locking
2087: * the destination (to ensure atomicity).
2088: */
2089:
2090: is_read_lock(space);
2091: if (!space->is_active) {
2092: is_read_unlock(space);
2093: return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
2094: }
2095:
2096: if (notify != MACH_PORT_NULL) {
2097: ipc_entry_t entry;
2098:
2099: /* must check notify even though it won't be used */
2100:
2101: if (((entry = ipc_entry_lookup(space, notify))
2102: == IE_NULL) ||
2103: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
2104: is_read_unlock(space);
2105: return MACH_RCV_INVALID_NOTIFY;
2106: }
2107: }
2108:
2109: ip_lock(dest);
2110: is_read_unlock(space);
2111:
2112: reply_name = (mach_port_t) reply;
2113: }
2114:
2115: /*
2116: * At this point, the space is unlocked and the destination
2117: * port is locked. (Lock taken while space was locked.)
2118: * reply_name is taken care of; we still need dest_name.
2119: * We still hold a ref for reply (if it is valid).
2120: *
2121: * If the space holds receive rights for the destination,
2122: * we return its name for the right. Otherwise the task
2123: * managed to destroy or give away the receive right between
2124: * receiving the message and this copyout. If the destination
2125: * is dead, return MACH_PORT_DEAD, and if the receive right
2126: * exists somewhere else (another space, in transit)
2127: * return MACH_PORT_NULL.
2128: *
2129: * Making this copyout operation atomic with the previous
2130: * copyout of the reply port is a bit tricky. If there was
2131: * no real reply port (it wasn't IP_VALID) then this isn't
2132: * an issue. If the reply port was dead at copyout time,
2133: * then we are OK, because if dest is dead we serialize
2134: * after the death of both ports and if dest is alive
2135: * we serialize after reply died but before dest's (later) death.
2136: * So assume reply was alive when we copied it out. If dest
2137: * is alive, then we are OK because we serialize before
2138: * the ports' deaths. So assume dest is dead when we look at it.
2139: * If reply dies/died after dest, then we are OK because
2140: * we serialize after dest died but before reply dies.
2141: * So the hard case is when reply is alive at copyout,
2142: * dest is dead at copyout, and reply died before dest died.
2143: * In this case pretend that dest is still alive, so
2144: * we serialize while both ports are alive.
2145: *
2146: * Because the space lock is held across the copyout of reply
2147: * and locking dest, the receive right for dest can't move
2148: * in or out of the space while the copyouts happen, so
2149: * that isn't an atomicity problem. In the last hard case
2150: * above, this implies that when dest is dead that the
2151: * space couldn't have had receive rights for dest at
2152: * the time reply was copied-out, so when we pretend
2153: * that dest is still alive, we can return MACH_PORT_NULL.
2154: *
2155: * If dest == reply, then we have to make it look like
2156: * either both copyouts happened before the port died,
2157: * or both happened after the port died. This special
2158: * case works naturally if the timestamp comparison
2159: * is done correctly.
2160: */
2161:
2162: copyout_dest:
1.1.1.5 root 2163: payload = dest->ip_protected_payload;
1.1 root 2164:
2165: if (ip_active(dest)) {
2166: ipc_object_copyout_dest(space, (ipc_object_t) dest,
2167: dest_type, &dest_name);
2168: /* dest is unlocked */
2169: } else {
2170: ipc_port_timestamp_t timestamp;
2171:
2172: timestamp = dest->ip_timestamp;
2173: ip_release(dest);
2174: ip_check_unlock(dest);
2175:
2176: if (IP_VALID(reply)) {
2177: ip_lock(reply);
2178: if (ip_active(reply) ||
2179: IP_TIMESTAMP_ORDER(timestamp,
2180: reply->ip_timestamp))
2181: dest_name = MACH_PORT_DEAD;
2182: else
2183: dest_name = MACH_PORT_NULL;
2184: ip_unlock(reply);
2185: } else
2186: dest_name = MACH_PORT_DEAD;
2187: }
2188:
2189: if (IP_VALID(reply))
2190: ipc_port_release(reply);
2191:
1.1.1.4 root 2192: if (! ipc_port_flag_protected_payload(dest)) {
2193: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2194: MACH_MSGH_BITS(reply_type, dest_type));
2195: msg->msgh_local_port = dest_name;
2196: } else {
2197: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2198: MACH_MSGH_BITS(reply_type,
2199: MACH_MSG_TYPE_PROTECTED_PAYLOAD));
1.1.1.5 root 2200: msg->msgh_protected_payload = payload;
1.1.1.4 root 2201: }
1.1.1.5 root 2202:
1.1 root 2203: msg->msgh_remote_port = reply_name;
2204: }
2205:
2206: return MACH_MSG_SUCCESS;
2207: }
2208:
2209: /*
2210: * Routine: ipc_kmsg_copyout_object
2211: * Purpose:
2212: * Copy-out a port right. Always returns a name,
2213: * even for unsuccessful return codes. Always
2214: * consumes the supplied object.
2215: * Conditions:
2216: * Nothing locked.
2217: * Returns:
2218: * MACH_MSG_SUCCESS The space acquired the right
2219: * (name is valid) or the object is dead (MACH_PORT_DEAD).
2220: * MACH_MSG_IPC_SPACE No room in space for the right,
2221: * or the space is dead. (Name is MACH_PORT_NULL.)
2222: * MACH_MSG_IPC_KERNEL Kernel resource shortage.
2223: * (Name is MACH_PORT_NULL.)
2224: */
2225:
2226: mach_msg_return_t
1.1.1.4 root 2227: ipc_kmsg_copyout_object(
2228: ipc_space_t space,
2229: ipc_object_t object,
2230: mach_msg_type_name_t msgt_name,
2231: mach_port_t *namep)
1.1 root 2232: {
2233: if (!IO_VALID(object)) {
2234: *namep = (mach_port_t) object;
2235: return MACH_MSG_SUCCESS;
2236: }
2237:
2238: #ifndef MIGRATING_THREADS
2239: /*
2240: * Attempt quick copyout of send rights. We optimize for a
2241: * live port for which the receiver holds send (and not
2242: * receive) rights in his local table.
2243: */
2244:
2245: if (msgt_name != MACH_MSG_TYPE_PORT_SEND)
2246: goto slow_copyout;
2247:
2248: {
1.1.1.4 root 2249: ipc_port_t port = (ipc_port_t) object;
1.1 root 2250: ipc_entry_t entry;
2251:
2252: is_write_lock(space);
2253: if (!space->is_active) {
2254: is_write_unlock(space);
2255: goto slow_copyout;
2256: }
2257:
2258: ip_lock(port);
2259: if (!ip_active(port) ||
1.1.1.5 root 2260: (entry = ipc_reverse_lookup(space,
2261: (ipc_object_t) port)) == NULL) {
1.1 root 2262: ip_unlock(port);
2263: is_write_unlock(space);
2264: goto slow_copyout;
2265: }
1.1.1.5 root 2266: *namep = entry->ie_name;
1.1 root 2267:
2268: /*
2269: * Copyout the send right, incrementing urefs
2270: * unless it would overflow, and consume the right.
2271: */
2272:
2273: assert(port->ip_srights > 1);
2274: port->ip_srights--;
2275: ip_release(port);
2276: ip_unlock(port);
2277:
2278: assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
2279: assert(IE_BITS_UREFS(entry->ie_bits) > 0);
2280: assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX);
2281:
2282: {
1.1.1.4 root 2283: ipc_entry_bits_t bits = entry->ie_bits + 1;
1.1 root 2284:
2285: if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2286: entry->ie_bits = bits;
2287: }
2288:
2289: is_write_unlock(space);
2290: return MACH_MSG_SUCCESS;
2291: }
2292:
2293: slow_copyout:
2294: #endif /* MIGRATING_THREADS */
2295:
2296: {
2297: kern_return_t kr;
2298:
2299: kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
2300: if (kr != KERN_SUCCESS) {
2301: ipc_object_destroy(object, msgt_name);
2302:
2303: if (kr == KERN_INVALID_CAPABILITY)
2304: *namep = MACH_PORT_DEAD;
2305: else {
2306: *namep = MACH_PORT_NULL;
2307:
2308: if (kr == KERN_RESOURCE_SHORTAGE)
2309: return MACH_MSG_IPC_KERNEL;
2310: else
2311: return MACH_MSG_IPC_SPACE;
2312: }
2313: }
2314:
2315: return MACH_MSG_SUCCESS;
2316: }
2317: }
2318:
2319: /*
2320: * Routine: ipc_kmsg_copyout_body
2321: * Purpose:
2322: * "Copy-out" port rights and out-of-line memory
2323: * in the body of a message.
2324: *
2325: * The error codes are a combination of special bits.
2326: * The copyout proceeds despite errors.
2327: * Conditions:
2328: * Nothing locked.
2329: * Returns:
2330: * MACH_MSG_SUCCESS Successful copyout.
2331: * MACH_MSG_IPC_SPACE No room for port right in name space.
2332: * MACH_MSG_VM_SPACE No room for memory in address space.
2333: * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2334: * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2335: */
2336:
2337: mach_msg_return_t
1.1.1.4 root 2338: ipc_kmsg_copyout_body(
2339: vm_offset_t saddr,
2340: vm_offset_t eaddr,
2341: ipc_space_t space,
2342: vm_map_t map)
1.1 root 2343: {
2344: mach_msg_return_t mr = MACH_MSG_SUCCESS;
2345: kern_return_t kr;
2346:
2347: while (saddr < eaddr) {
2348: vm_offset_t taddr = saddr;
2349: mach_msg_type_long_t *type;
2350: mach_msg_type_name_t name;
2351: mach_msg_type_size_t size;
2352: mach_msg_type_number_t number;
2353: boolean_t is_inline, longform, is_port;
1.1.1.6 ! root 2354: uint64_t length;
1.1 root 2355: vm_offset_t addr;
2356:
2357: type = (mach_msg_type_long_t *) saddr;
2358: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
2359: longform = ((mach_msg_type_t*)type)->msgt_longform;
2360: if (longform) {
2361: /* This must be aligned */
2362: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2363: (is_misaligned(type))) {
2364: saddr = ptr_align(saddr);
2365: continue;
2366: }
2367: name = type->msgtl_name;
2368: size = type->msgtl_size;
2369: number = type->msgtl_number;
2370: saddr += sizeof(mach_msg_type_long_t);
2371: } else {
2372: name = ((mach_msg_type_t*)type)->msgt_name;
2373: size = ((mach_msg_type_t*)type)->msgt_size;
2374: number = ((mach_msg_type_t*)type)->msgt_number;
2375: saddr += sizeof(mach_msg_type_t);
2376: }
2377:
2378: /* padding (ptrs and ports) ? */
2379: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2380: ((size >> 3) == sizeof(natural_t)))
2381: saddr = ptr_align(saddr);
2382:
2383: /* calculate length of data in bytes, rounding up */
2384:
1.1.1.6 ! root 2385: length = (((uint64_t) number * size) + 7) >> 3;
1.1 root 2386:
2387: is_port = MACH_MSG_TYPE_PORT_ANY(name);
2388:
2389: if (is_port) {
2390: mach_port_t *objects;
2391: mach_msg_type_number_t i;
2392:
2393: if (!is_inline && (length != 0)) {
2394: /* first allocate memory in the map */
2395:
2396: kr = vm_allocate(map, &addr, length, TRUE);
2397: if (kr != KERN_SUCCESS) {
2398: ipc_kmsg_clean_body(taddr, saddr);
2399: goto vm_copyout_failure;
2400: }
2401: }
2402:
2403: objects = (mach_port_t *)
2404: (is_inline ? saddr : * (vm_offset_t *) saddr);
2405:
2406: /* copyout port rights carried in the message */
2407:
2408: for (i = 0; i < number; i++) {
2409: ipc_object_t object =
2410: (ipc_object_t) objects[i];
2411:
2412: mr |= ipc_kmsg_copyout_object(space, object,
2413: name, &objects[i]);
2414: }
2415: }
2416:
2417: if (is_inline) {
2418: /* inline data sizes round up to int boundaries */
2419:
2420: ((mach_msg_type_t*)type)->msgt_deallocate = FALSE;
2421: saddr += (length + 3) &~ 3;
2422: } else {
2423: vm_offset_t data;
2424:
2425: if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
2426: saddr = ptr_align(saddr);
2427:
2428: data = * (vm_offset_t *) saddr;
2429:
2430: /* copyout memory carried in the message */
2431:
2432: if (length == 0) {
2433: assert(data == 0);
2434: addr = 0;
2435: } else if (is_port) {
2436: /* copyout to memory allocated above */
2437:
2438: (void) copyoutmap(map, (char *) data,
2439: (char *) addr, length);
2440: kfree(data, length);
2441: } else {
2442: vm_map_copy_t copy = (vm_map_copy_t) data;
2443:
2444: kr = vm_map_copyout(map, &addr, copy);
2445: if (kr != KERN_SUCCESS) {
2446: vm_map_copy_discard(copy);
2447:
2448: vm_copyout_failure:
2449:
2450: addr = 0;
2451: if (longform)
2452: type->msgtl_size = 0;
2453: else
2454: ((mach_msg_type_t*)type)->msgt_size = 0;
2455:
2456: if (kr == KERN_RESOURCE_SHORTAGE)
2457: mr |= MACH_MSG_VM_KERNEL;
2458: else
2459: mr |= MACH_MSG_VM_SPACE;
2460: }
2461: }
2462:
2463: ((mach_msg_type_t*)type)->msgt_deallocate = TRUE;
2464: * (vm_offset_t *) saddr = addr;
2465: saddr += sizeof(vm_offset_t);
2466: }
2467: }
2468:
2469: return mr;
2470: }
2471:
2472: /*
2473: * Routine: ipc_kmsg_copyout
2474: * Purpose:
2475: * "Copy-out" port rights and out-of-line memory
2476: * in the message.
2477: * Conditions:
2478: * Nothing locked.
2479: * Returns:
2480: * MACH_MSG_SUCCESS Copied out all rights and memory.
2481: * MACH_RCV_INVALID_NOTIFY Bad notify port.
2482: * Rights and memory in the message are intact.
2483: * MACH_RCV_HEADER_ERROR + special bits
2484: * Rights and memory in the message are intact.
2485: * MACH_RCV_BODY_ERROR + special bits
2486: * The message header was successfully copied out.
2487: * As much of the body was handled as possible.
2488: */
2489:
2490: mach_msg_return_t
1.1.1.4 root 2491: ipc_kmsg_copyout(
2492: ipc_kmsg_t kmsg,
2493: ipc_space_t space,
2494: vm_map_t map,
2495: mach_port_t notify)
1.1 root 2496: {
2497: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2498: mach_msg_return_t mr;
2499:
2500: mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
2501: if (mr != MACH_MSG_SUCCESS)
2502: return mr;
2503:
2504: if (mbits & MACH_MSGH_BITS_COMPLEX) {
2505: vm_offset_t saddr, eaddr;
2506:
2507: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2508: eaddr = (vm_offset_t) &kmsg->ikm_header +
2509: kmsg->ikm_header.msgh_size;
2510:
2511: mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map);
2512: if (mr != MACH_MSG_SUCCESS)
2513: mr |= MACH_RCV_BODY_ERROR;
2514: }
2515:
2516: return mr;
2517: }
2518:
2519: /*
2520: * Routine: ipc_kmsg_copyout_pseudo
2521: * Purpose:
2522: * Does a pseudo-copyout of the message.
2523: * This is like a regular copyout, except
2524: * that the ports in the header are handled
2525: * as if they are in the body. They aren't reversed.
2526: *
2527: * The error codes are a combination of special bits.
2528: * The copyout proceeds despite errors.
2529: * Conditions:
2530: * Nothing locked.
2531: * Returns:
2532: * MACH_MSG_SUCCESS Successful copyout.
2533: * MACH_MSG_IPC_SPACE No room for port right in name space.
2534: * MACH_MSG_VM_SPACE No room for memory in address space.
2535: * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2536: * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2537: */
2538:
2539: mach_msg_return_t
2540: ipc_kmsg_copyout_pseudo(
2541: ipc_kmsg_t kmsg,
2542: ipc_space_t space,
2543: vm_map_t map)
2544: {
2545: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2546: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2547: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2548: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2549: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2550: mach_port_t dest_name, reply_name;
2551: mach_msg_return_t mr;
2552:
2553: assert(IO_VALID(dest));
2554:
2555: mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
2556: ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
2557:
2558: kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
2559: kmsg->ikm_header.msgh_remote_port = dest_name;
2560: kmsg->ikm_header.msgh_local_port = reply_name;
2561:
2562: if (mbits & MACH_MSGH_BITS_COMPLEX) {
2563: vm_offset_t saddr, eaddr;
2564:
2565: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2566: eaddr = (vm_offset_t) &kmsg->ikm_header +
2567: kmsg->ikm_header.msgh_size;
2568:
2569: mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map);
2570: }
2571:
2572: return mr;
2573: }
2574:
2575: /*
2576: * Routine: ipc_kmsg_copyout_dest
2577: * Purpose:
2578: * Copies out the destination port in the message.
2579: * Destroys all other rights and memory in the message.
2580: * Conditions:
2581: * Nothing locked.
2582: */
2583:
2584: void
1.1.1.4 root 2585: ipc_kmsg_copyout_dest(
2586: ipc_kmsg_t kmsg,
2587: ipc_space_t space)
1.1 root 2588: {
2589: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2590: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2591: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2592: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2593: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2594: mach_port_t dest_name, reply_name;
2595:
2596: assert(IO_VALID(dest));
2597:
2598: io_lock(dest);
2599: if (io_active(dest)) {
2600: ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
2601: /* dest is unlocked */
2602: } else {
2603: io_release(dest);
2604: io_check_unlock(dest);
2605: dest_name = MACH_PORT_DEAD;
2606: }
2607:
2608: if (IO_VALID(reply)) {
2609: ipc_object_destroy(reply, reply_type);
2610: reply_name = MACH_PORT_NULL;
2611: } else
2612: reply_name = (mach_port_t) reply;
2613:
2614: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2615: MACH_MSGH_BITS(reply_type, dest_type));
2616: kmsg->ikm_header.msgh_local_port = dest_name;
2617: kmsg->ikm_header.msgh_remote_port = reply_name;
2618:
2619: if (mbits & MACH_MSGH_BITS_COMPLEX) {
2620: vm_offset_t saddr, eaddr;
2621:
2622: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2623: eaddr = (vm_offset_t) &kmsg->ikm_header +
2624: kmsg->ikm_header.msgh_size;
2625:
2626: ipc_kmsg_clean_body(saddr, eaddr);
2627: }
2628: }
2629:
2630: #if MACH_KDB
2631:
2632: char *
1.1.1.4 root 2633: ipc_type_name(
2634: int type_name,
2635: boolean_t received)
1.1 root 2636: {
2637: switch (type_name) {
2638: case MACH_MSG_TYPE_BOOLEAN:
2639: return "boolean";
1.1.1.2 root 2640:
1.1 root 2641: case MACH_MSG_TYPE_INTEGER_16:
2642: return "short";
1.1.1.2 root 2643:
1.1 root 2644: case MACH_MSG_TYPE_INTEGER_32:
2645: return "int32";
2646:
2647: case MACH_MSG_TYPE_INTEGER_64:
2648: return "int64";
1.1.1.2 root 2649:
1.1 root 2650: case MACH_MSG_TYPE_CHAR:
2651: return "char";
1.1.1.2 root 2652:
1.1 root 2653: case MACH_MSG_TYPE_BYTE:
2654: return "byte";
1.1.1.2 root 2655:
1.1 root 2656: case MACH_MSG_TYPE_REAL:
2657: return "real";
1.1.1.2 root 2658:
1.1 root 2659: case MACH_MSG_TYPE_STRING:
2660: return "string";
1.1.1.2 root 2661:
1.1 root 2662: case MACH_MSG_TYPE_PORT_NAME:
2663: return "port_name";
1.1.1.2 root 2664:
1.1 root 2665: case MACH_MSG_TYPE_MOVE_RECEIVE:
2666: if (received) {
2667: return "port_receive";
2668: } else {
2669: return "move_receive";
2670: }
1.1.1.2 root 2671:
1.1 root 2672: case MACH_MSG_TYPE_MOVE_SEND:
2673: if (received) {
2674: return "port_send";
2675: } else {
2676: return "move_send";
2677: }
1.1.1.2 root 2678:
1.1 root 2679: case MACH_MSG_TYPE_MOVE_SEND_ONCE:
2680: if (received) {
2681: return "port_send_once";
2682: } else {
2683: return "move_send_once";
2684: }
1.1.1.2 root 2685:
1.1 root 2686: case MACH_MSG_TYPE_COPY_SEND:
2687: return "copy_send";
1.1.1.2 root 2688:
1.1 root 2689: case MACH_MSG_TYPE_MAKE_SEND:
2690: return "make_send";
1.1.1.2 root 2691:
1.1 root 2692: case MACH_MSG_TYPE_MAKE_SEND_ONCE:
2693: return "make_send_once";
1.1.1.2 root 2694:
1.1 root 2695: default:
2696: return (char *) 0;
2697: }
2698: }
1.1.1.2 root 2699:
1.1 root 2700: void
2701: ipc_print_type_name(
2702: int type_name)
2703: {
2704: char *name = ipc_type_name(type_name, TRUE);
2705: if (name) {
2706: printf("%s", name);
2707: } else {
2708: printf("type%d", type_name);
2709: }
2710: }
2711:
2712: /*
2713: * ipc_kmsg_print [ debug ]
2714: */
2715: void
1.1.1.4 root 2716: ipc_kmsg_print(ipc_kmsg_t kmsg)
1.1 root 2717: {
2718: db_printf("kmsg=0x%x\n", kmsg);
2719: db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x",
2720: kmsg->ikm_next,
2721: kmsg->ikm_prev,
2722: kmsg->ikm_size,
2723: kmsg->ikm_marequest);
2724: db_printf("\n");
2725: ipc_msg_print(&kmsg->ikm_header);
2726: }
2727:
2728: /*
2729: * ipc_msg_print [ debug ]
2730: */
2731: void
1.1.1.4 root 2732: ipc_msg_print(mach_msg_header_t *msgh)
1.1 root 2733: {
2734: vm_offset_t saddr, eaddr;
2735:
2736: db_printf("msgh_bits=0x%x: ", msgh->msgh_bits);
2737: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
2738: db_printf("complex,");
2739: }
2740: if (msgh->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
2741: db_printf("circular,");
2742: }
2743: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_PORTS) {
2744: db_printf("complex_ports,");
2745: }
2746: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_DATA) {
2747: db_printf("complex_data,");
2748: }
2749: if (msgh->msgh_bits & MACH_MSGH_BITS_MIGRATED) {
2750: db_printf("migrated,");
2751: }
2752: if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) {
2753: db_printf("unused=0x%x,",
2754: msgh->msgh_bits & MACH_MSGH_BITS_UNUSED);
2755: }
2756: db_printf("l=0x%x,r=0x%x\n",
2757: MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
2758: MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
2759:
2760: db_printf("msgh_id=%d,size=%d,seqno=%d,",
2761: msgh->msgh_id,
2762: msgh->msgh_size,
2763: msgh->msgh_seqno);
2764:
2765: if (msgh->msgh_remote_port) {
2766: db_printf("remote=0x%x(", msgh->msgh_remote_port);
2767: ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
2768: db_printf("),");
2769: } else {
2770: db_printf("remote=null,\n");
2771: }
2772:
2773: if (msgh->msgh_local_port) {
2774: db_printf("local=0x%x(", msgh->msgh_local_port);
2775: ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
2776: db_printf(")\n");
2777: } else {
2778: db_printf("local=null\n");
2779: }
2780:
2781: saddr = (vm_offset_t) (msgh + 1);
2782: eaddr = (vm_offset_t) msgh + msgh->msgh_size;
2783:
2784: while (saddr < eaddr) {
2785: mach_msg_type_long_t *type;
2786: mach_msg_type_name_t name;
2787: mach_msg_type_size_t size;
2788: mach_msg_type_number_t number;
2789: boolean_t is_inline, longform, dealloc, is_port;
2790: vm_size_t length;
2791:
2792: type = (mach_msg_type_long_t *) saddr;
2793:
2794: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
2795: ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
2796: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
2797: db_printf("*** msg too small\n");
2798: return;
2799: }
2800:
2801: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
2802: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
2803: if (longform) {
2804: /* This must be aligned */
2805: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2806: (is_misaligned(type))) {
2807: saddr = ptr_align(saddr);
2808: continue;
2809: }
2810: name = type->msgtl_name;
2811: size = type->msgtl_size;
2812: number = type->msgtl_number;
2813: saddr += sizeof(mach_msg_type_long_t);
2814: } else {
2815: name = ((mach_msg_type_t*)type)->msgt_name;
2816: size = ((mach_msg_type_t*)type)->msgt_size;
2817: number = ((mach_msg_type_t*)type)->msgt_number;
2818: saddr += sizeof(mach_msg_type_t);
2819: }
2820:
2821: db_printf("-- type=");
2822: ipc_print_type_name(name);
2823: if (! is_inline) {
2824: db_printf(",ool");
2825: }
2826: if (dealloc) {
2827: db_printf(",dealloc");
2828: }
2829: if (longform) {
2830: db_printf(",longform");
2831: }
2832: db_printf(",size=%d,number=%d,addr=0x%x\n",
2833: size,
2834: number,
2835: saddr);
2836:
2837: is_port = MACH_MSG_TYPE_PORT_ANY(name);
2838:
2839: if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
2840: (longform && ((type->msgtl_header.msgt_name != 0) ||
2841: (type->msgtl_header.msgt_size != 0) ||
2842: (type->msgtl_header.msgt_number != 0))) ||
2843: (((mach_msg_type_t*)type)->msgt_unused != 0) ||
2844: (dealloc && is_inline)) {
2845: db_printf("*** invalid type\n");
2846: return;
2847: }
2848:
2849: /* padding (ptrs and ports) ? */
2850: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2851: ((size >> 3) == sizeof(natural_t)))
2852: saddr = ptr_align(saddr);
2853:
2854: /* calculate length of data in bytes, rounding up */
2855:
2856: length = ((number * size) + 7) >> 3;
2857:
2858: if (is_inline) {
2859: vm_size_t amount;
1.1.1.6 ! root 2860: unsigned i, numwords;
1.1 root 2861:
2862: /* inline data sizes round up to int boundaries */
2863: amount = (length + 3) &~ 3;
2864: if ((eaddr - saddr) < amount) {
2865: db_printf("*** too small\n");
2866: return;
2867: }
2868: numwords = amount / sizeof(int);
2869: if (numwords > 8) {
2870: numwords = 8;
2871: }
2872: for (i = 0; i < numwords; i++) {
2873: db_printf("0x%x\n", ((int *) saddr)[i]);
2874: }
2875: if (numwords < amount / sizeof(int)) {
2876: db_printf("...\n");
2877: }
2878: saddr += amount;
2879: } else {
2880: if ((eaddr - saddr) < sizeof(vm_offset_t)) {
2881: db_printf("*** too small\n");
2882: return;
2883: }
2884: db_printf("0x%x\n", * (vm_offset_t *) saddr);
2885: saddr += sizeof(vm_offset_t);
2886: }
2887: }
2888: }
1.1.1.2 root 2889: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.