1/*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
49 *  School of Computer Science
50 *  Carnegie Mellon University
51 *  Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58
59#include <mach/boolean.h>
60#include <mach/port.h>
61#include <mach/mig.h>
62#include <mach/mig_errors.h>
63#include <mach/mach_types.h>
64#include <mach/mach_traps.h>
65
66#include <kern/ipc_tt.h>
67#include <kern/ipc_mig.h>
68#include <kern/kalloc.h>
69#include <kern/task.h>
70#include <kern/thread.h>
71#include <kern/ipc_kobject.h>
72#include <kern/misc_protos.h>
73
74#include <ipc/port.h>
75#include <ipc/ipc_kmsg.h>
76#include <ipc/ipc_entry.h>
77#include <ipc/ipc_object.h>
78#include <ipc/ipc_mqueue.h>
79#include <ipc/ipc_space.h>
80#include <ipc/ipc_port.h>
81#include <ipc/ipc_pset.h>
82#include <vm/vm_map.h>
83
84/*
85 *	Routine:	mach_msg_send_from_kernel
86 *	Purpose:
87 *		Send a message from the kernel.
88 *
89 *		This is used by the client side of KernelUser interfaces
90 *		to implement SimpleRoutines.  Currently, this includes
91 *		memory_object messages.
92 *	Conditions:
93 *		Nothing locked.
94 *	Returns:
95 *		MACH_MSG_SUCCESS	Sent the message.
96 *		MACH_SEND_INVALID_DEST	Bad destination port.
97 *		MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer
98 *		                        or destination is above kernel limit
99 */
100
101mach_msg_return_t
102mach_msg_send_from_kernel(
103	mach_msg_header_t	*msg,
104	mach_msg_size_t		send_size)
105{
106	ipc_kmsg_t kmsg;
107	mach_msg_return_t mr;
108
109	if (!MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port))
110		return MACH_SEND_INVALID_DEST;
111
112	mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
113	if (mr != MACH_MSG_SUCCESS)
114		return mr;
115
116	ipc_kmsg_copyin_from_kernel(kmsg);
117
118	mr = ipc_kmsg_send_always(kmsg);
119	if (mr != MACH_MSG_SUCCESS) {
120		ipc_kmsg_destroy(kmsg);
121	}
122
123	return mr;
124}
125
126mach_msg_return_t
127mach_msg_send_from_kernel_with_options(
128	mach_msg_header_t	*msg,
129	mach_msg_size_t		send_size,
130	mach_msg_option_t	option,
131	mach_msg_timeout_t	timeout_val)
132{
133	ipc_kmsg_t kmsg;
134	mach_msg_return_t mr;
135
136	if (!MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port))
137		return MACH_SEND_INVALID_DEST;
138
139	mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
140	if (mr != MACH_MSG_SUCCESS)
141		return mr;
142
143	ipc_kmsg_copyin_from_kernel(kmsg);
144	mr = ipc_kmsg_send(kmsg, option, timeout_val);
145	if (mr != MACH_MSG_SUCCESS) {
146		ipc_kmsg_destroy(kmsg);
147	}
148
149	return mr;
150}
151
152/*
153 *	Routine:	mach_msg_rpc_from_kernel
154 *	Purpose:
155 *		Send a message from the kernel and receive a reply.
156 *		Uses ith_rpc_reply for the reply port.
157 *
158 *		This is used by the client side of KernelUser interfaces
159 *		to implement Routines.
160 *	Conditions:
161 *		Nothing locked.
162 *	Returns:
163 *		MACH_MSG_SUCCESS	Sent the message.
164 *		MACH_RCV_PORT_DIED	The reply port was deallocated.
165 */
166
167mach_msg_return_t
168mach_msg_rpc_from_kernel(
169	mach_msg_header_t	*msg,
170	mach_msg_size_t		send_size,
171	mach_msg_size_t		rcv_size)
172{
173	thread_t self = current_thread();
174	ipc_port_t reply;
175	ipc_kmsg_t kmsg;
176	mach_port_seqno_t seqno;
177	mach_msg_return_t mr;
178
179	assert(MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port));
180	assert(msg->msgh_local_port == MACH_PORT_NULL);
181
182	mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
183	if (mr != MACH_MSG_SUCCESS)
184		return mr;
185
186	reply = self->ith_rpc_reply;
187	if (reply == IP_NULL) {
188		reply = ipc_port_alloc_reply();
189		if ((reply == IP_NULL) ||
190		    (self->ith_rpc_reply != IP_NULL))
191			panic("mach_msg_rpc_from_kernel");
192		self->ith_rpc_reply = reply;
193	}
194
195	/* insert send-once right for the reply port */
196	kmsg->ikm_header->msgh_local_port = reply;
197	kmsg->ikm_header->msgh_bits |=
198		MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE);
199
200	ipc_port_reference(reply);
201
202	ipc_kmsg_copyin_from_kernel(kmsg);
203
204	mr = ipc_kmsg_send_always(kmsg);
205	if (mr != MACH_MSG_SUCCESS) {
206		ipc_kmsg_destroy(kmsg);
207		return mr;
208	}
209
210	for (;;) {
211		ipc_mqueue_t mqueue;
212
213		ip_lock(reply);
214		if ( !ip_active(reply)) {
215			ip_unlock(reply);
216			ipc_port_release(reply);
217			return MACH_RCV_PORT_DIED;
218		}
219		if (!self->active) {
220			ip_unlock(reply);
221			ipc_port_release(reply);
222			return MACH_RCV_INTERRUPTED;
223		}
224
225		assert(reply->ip_pset_count == 0);
226		mqueue = &reply->ip_messages;
227		ip_unlock(reply);
228
229		self->ith_continuation = (void (*)(mach_msg_return_t))0;
230
231		ipc_mqueue_receive(mqueue,
232				   MACH_MSG_OPTION_NONE,
233				   MACH_MSG_SIZE_MAX,
234				   MACH_MSG_TIMEOUT_NONE,
235				   THREAD_INTERRUPTIBLE);
236
237		mr = self->ith_state;
238		kmsg = self->ith_kmsg;
239		seqno = self->ith_seqno;
240
241		if (mr == MACH_MSG_SUCCESS)
242		  {
243			break;
244		  }
245
246		assert(mr == MACH_RCV_INTERRUPTED);
247
248		if (self->handlers) {
249			ipc_port_release(reply);
250			return(mr);
251		}
252	}
253	ipc_port_release(reply);
254
255	/*
256	 * Check to see how much of the message/trailer can be received.
257	 * We chose the maximum trailer that will fit, since we don't
258	 * have options telling us which trailer elements the caller needed.
259	 */
260	if (rcv_size >= kmsg->ikm_header->msgh_size) {
261		mach_msg_format_0_trailer_t *trailer =  (mach_msg_format_0_trailer_t *)
262			((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size);
263
264		if (rcv_size >= kmsg->ikm_header->msgh_size + MAX_TRAILER_SIZE) {
265			/* Enough room for a maximum trailer */
266			trailer->msgh_trailer_size = MAX_TRAILER_SIZE;
267		}
268		else if (rcv_size < kmsg->ikm_header->msgh_size +
269			   trailer->msgh_trailer_size) {
270			/* no room for even the basic (default) trailer */
271			trailer->msgh_trailer_size = 0;
272		}
273		assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0);
274		rcv_size = kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size;
275		mr = MACH_MSG_SUCCESS;
276	} else {
277		mr = MACH_RCV_TOO_LARGE;
278	}
279
280
281	/*
282	 *	We want to preserve rights and memory in reply!
283	 *	We don't have to put them anywhere; just leave them
284	 *	as they are.
285	 */
286	ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
287	ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size);
288	return mr;
289}
290
291
292/************** These Calls are set up for kernel-loaded tasks/threads **************/
293
294/*
295 *	Routine:	mach_msg_overwrite
296 *	Purpose:
297 *		Like mach_msg_overwrite_trap except that message buffers
298 *		live in kernel space.  Doesn't handle any options.
299 *
300 *		This is used by in-kernel server threads to make
301 *		kernel calls, to receive request messages, and
302 *		to send reply messages.
303 *	Conditions:
304 *		Nothing locked.
305 *	Returns:
306 */
307
308mach_msg_return_t
309mach_msg_overwrite(
310	mach_msg_header_t		*msg,
311	mach_msg_option_t		option,
312	mach_msg_size_t		send_size,
313	mach_msg_size_t		rcv_size,
314	mach_port_name_t		rcv_name,
315	__unused mach_msg_timeout_t	msg_timeout,
316	__unused mach_port_name_t	notify,
317	__unused mach_msg_header_t	*rcv_msg,
318       __unused mach_msg_size_t	rcv_msg_size)
319{
320	ipc_space_t space = current_space();
321	vm_map_t map = current_map();
322	ipc_kmsg_t kmsg;
323	mach_port_seqno_t seqno;
324	mach_msg_return_t mr;
325	mach_msg_format_0_trailer_t *trailer;
326
327	if (option & MACH_SEND_MSG) {
328		mach_msg_size_t	msg_and_trailer_size;
329		mach_msg_max_trailer_t	*max_trailer;
330
331		if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3))
332			return MACH_SEND_MSG_TOO_SMALL;
333
334		if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE)
335			return MACH_SEND_TOO_LARGE;
336
337		msg_and_trailer_size = send_size + MAX_TRAILER_SIZE;
338		kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
339
340		if (kmsg == IKM_NULL)
341			return MACH_SEND_NO_BUFFER;
342
343		(void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size);
344
345		kmsg->ikm_header->msgh_size = send_size;
346
347		/*
348		 * Reserve for the trailer the largest space (MAX_TRAILER_SIZE)
349		 * However, the internal size field of the trailer (msgh_trailer_size)
350		 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
351		 * the cases where no implicit data is requested.
352		 */
353		max_trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size);
354		max_trailer->msgh_sender = current_thread()->task->sec_token;
355		max_trailer->msgh_audit = current_thread()->task->audit_token;
356		max_trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
357		max_trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
358
359		mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
360		if (mr != MACH_MSG_SUCCESS) {
361			ipc_kmsg_free(kmsg);
362			return mr;
363		}
364
365		do
366			mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE,
367					     MACH_MSG_TIMEOUT_NONE);
368		while (mr == MACH_SEND_INTERRUPTED);
369		assert(mr == MACH_MSG_SUCCESS);
370	}
371
372	if (option & MACH_RCV_MSG) {
373		thread_t self = current_thread();
374
375		do {
376			ipc_object_t object;
377			ipc_mqueue_t mqueue;
378
379			mr = ipc_mqueue_copyin(space, rcv_name,
380					       &mqueue, &object);
381			if (mr != MACH_MSG_SUCCESS)
382				return mr;
383			/* hold ref for object */
384
385			self->ith_continuation = (void (*)(mach_msg_return_t))0;
386			ipc_mqueue_receive(mqueue,
387					   MACH_MSG_OPTION_NONE,
388					   MACH_MSG_SIZE_MAX,
389					   MACH_MSG_TIMEOUT_NONE,
390					   THREAD_ABORTSAFE);
391			mr = self->ith_state;
392			kmsg = self->ith_kmsg;
393			seqno = self->ith_seqno;
394
395			ipc_object_release(object);
396
397		} while (mr == MACH_RCV_INTERRUPTED);
398		if (mr != MACH_MSG_SUCCESS)
399			return mr;
400
401		trailer = (mach_msg_format_0_trailer_t *)
402		    ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size);
403		if (option & MACH_RCV_TRAILER_MASK) {
404			trailer->msgh_seqno = seqno;
405			trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
406		}
407
408		if (rcv_size < (kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size)) {
409			ipc_kmsg_copyout_dest(kmsg, space);
410			(void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg);
411			ipc_kmsg_free(kmsg);
412			return MACH_RCV_TOO_LARGE;
413		}
414
415		mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL,
416				      MACH_MSG_BODY_NULL);
417		if (mr != MACH_MSG_SUCCESS) {
418			if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
419				ipc_kmsg_put_to_kernel(msg, kmsg,
420						kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size);
421			} else {
422				ipc_kmsg_copyout_dest(kmsg, space);
423				(void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg);
424				ipc_kmsg_free(kmsg);
425			}
426
427			return mr;
428		}
429
430		(void) memcpy((void *) msg, (const void *) kmsg->ikm_header,
431			      kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size);
432		ipc_kmsg_free(kmsg);
433	}
434
435	return MACH_MSG_SUCCESS;
436}
437
438/*
439 *	Routine:	mig_get_reply_port
440 *	Purpose:
441 *		Called by client side interfaces living in the kernel
442 *		to get a reply port.
443 */
444mach_port_t
445mig_get_reply_port(void)
446{
447	return (MACH_PORT_NULL);
448}
449
450/*
451 *	Routine:	mig_dealloc_reply_port
452 *	Purpose:
453 *		Called by client side interfaces to get rid of a reply port.
454 */
455
456void
457mig_dealloc_reply_port(
458	__unused mach_port_t reply_port)
459{
460	panic("mig_dealloc_reply_port");
461}
462
463/*
464 *	Routine:	mig_put_reply_port
465 *	Purpose:
466 *		Called by client side interfaces after each RPC to
467 *		let the client recycle the reply port if it wishes.
468 */
469void
470mig_put_reply_port(
471	__unused mach_port_t reply_port)
472{
473}
474
475/*
476 * mig_strncpy.c - by Joshua Block
477 *
478 * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
479 * OUGHT to do:  Copies the (null terminated) string in src into dest, a
480 * buffer of length len.  Assures that the copy is still null terminated
481 * and doesn't overflow the buffer, truncating the copy if necessary.
482 *
483 * Parameters:
484 *
485 *     dest - Pointer to destination buffer.
486 *
487 *     src - Pointer to source string.
488 *
489 *     len - Length of destination buffer.
490 */
491int
492mig_strncpy(
493	char		*dest,
494	const char	*src,
495	int		len)
496{
497    int i = 0;
498
499    if (len > 0)
500	if (dest != NULL) {
501	    if (src != NULL)
502		   for (i=1; i<len; i++)
503			if (! (*dest++ = *src++))
504			    return i;
505	        *dest = '\0';
506	}
507    return i;
508}
509
510char *
511mig_user_allocate(
512	vm_size_t	size)
513{
514	return (char *)kalloc(size);
515}
516
517void
518mig_user_deallocate(
519	char		*data,
520	vm_size_t	size)
521{
522	kfree(data, size);
523}
524
525/*
526 *	Routine:	mig_object_init
527 *	Purpose:
528 *		Initialize the base class portion of a MIG object.  We
529 *		will lazy init the port, so just clear it for now.
530 */
531kern_return_t
532mig_object_init(
533	mig_object_t		mig_object,
534	const IMIGObject	*interface)
535{
536	if (mig_object == MIG_OBJECT_NULL)
537		return KERN_INVALID_ARGUMENT;
538	mig_object->pVtbl = (const IMIGObjectVtbl *)interface;
539	mig_object->port = MACH_PORT_NULL;
540	return KERN_SUCCESS;
541}
542
543/*
544 *	Routine:	mig_object_destroy
545 *	Purpose:
546 *		The object is being freed.  This call lets us clean
547 *		up any state we have have built up over the object's
548 *		lifetime.
549 *	Conditions:
550 *		Since notifications and the port hold references on
551 *		on the object, neither can exist when this is called.
552 *		This is a good place to assert() that condition.
553 */
554void
555mig_object_destroy(
556	__assert_only mig_object_t	mig_object)
557{
558	assert(mig_object->port == MACH_PORT_NULL);
559	return;
560}
561
562/*
563 *	Routine:	mig_object_reference
564 *	Purpose:
565 *		Pure virtual helper to invoke the MIG object's AddRef
566 *		method.
567 *	Conditions:
568 *		MIG object port may be locked.
569 */
570void
571mig_object_reference(
572	mig_object_t	mig_object)
573{
574	assert(mig_object != MIG_OBJECT_NULL);
575	mig_object->pVtbl->AddRef((IMIGObject *)mig_object);
576}
577
578/*
579 *	Routine:	mig_object_deallocate
580 *	Purpose:
581 *		Pure virtual helper to invoke the MIG object's Release
582 *		method.
583 *	Conditions:
584 *		Nothing locked.
585 */
586void
587mig_object_deallocate(
588	mig_object_t	mig_object)
589{
590	assert(mig_object != MIG_OBJECT_NULL);
591	mig_object->pVtbl->Release((IMIGObject *)mig_object);
592}
593
594/*
595 *	Routine:	convert_mig_object_to_port [interface]
596 *	Purpose:
597 *		Base implementation of MIG outtrans routine to convert from
598 *		a mig object reference to a new send right on the object's
599 *		port.  The object reference is consumed.
600 *	Returns:
601 *		IP_NULL - Null MIG object supplied
602 *		Otherwise, a newly made send right for the port
603 *	Conditions:
604 *		Nothing locked.
605 */
606ipc_port_t
607convert_mig_object_to_port(
608	mig_object_t	mig_object)
609{
610	ipc_port_t	port;
611	boolean_t	deallocate = TRUE;
612
613	if (mig_object == MIG_OBJECT_NULL)
614		return IP_NULL;
615
616	port = mig_object->port;
617	while ((port == IP_NULL) ||
618	       ((port = ipc_port_make_send(port)) == IP_NULL)) {
619		ipc_port_t	previous;
620
621		/*
622		 * Either the port was never set up, or it was just
623		 * deallocated out from under us by the no-senders
624		 * processing.  In either case, we must:
625		 *	Attempt to make one
626		 * 	Arrange for no senders
627		 *	Try to atomically register it with the object
628		 *		Destroy it if we are raced.
629		 */
630		port = ipc_port_alloc_kernel();
631		ip_lock(port);
632		ipc_kobject_set_atomically(port,
633					   (ipc_kobject_t) mig_object,
634					   IKOT_MIG);
635
636		/* make a sonce right for the notification */
637		port->ip_sorights++;
638		ip_reference(port);
639
640		ipc_port_nsrequest(port, 1, port, &previous);
641		/* port unlocked */
642
643		assert(previous == IP_NULL);
644
645		if (hw_compare_and_store((uint32_t)IP_NULL, (uint32_t)port,
646											(uint32_t *)&mig_object->port)) {
647			deallocate = FALSE;
648		} else {
649			ipc_port_dealloc_kernel(port);
650			port = mig_object->port;
651		}
652	}
653
654	if (deallocate)
655		mig_object->pVtbl->Release((IMIGObject *)mig_object);
656
657	return (port);
658}
659
660
661/*
662 *	Routine:	convert_port_to_mig_object [interface]
663 *	Purpose:
664 *		Base implementation of MIG intrans routine to convert from
665 *		an incoming port reference to a new reference on the
666 *		underlying object. A new reference must be created, because
667 *		the port's reference could go away asynchronously.
668 *	Returns:
669 *		NULL - Not an active MIG object port or iid not supported
670 *		Otherwise, a reference to the underlying MIG interface
671 *	Conditions:
672 *		Nothing locked.
673 */
674mig_object_t
675convert_port_to_mig_object(
676	ipc_port_t	port,
677	const MIGIID	*iid)
678{
679	mig_object_t	mig_object;
680	void 		*ppv;
681
682	if (!IP_VALID(port))
683		return NULL;
684
685	ip_lock(port);
686	if (!ip_active(port) || (ip_kotype(port) != IKOT_MIG)) {
687		ip_unlock(port);
688		return NULL;
689	}
690
691	/*
692	 * Our port points to some MIG object interface.  Now
693	 * query it to get a reference to the desired interface.
694	 */
695	ppv = NULL;
696	mig_object = (mig_object_t)port->ip_kobject;
697	mig_object->pVtbl->QueryInterface((IMIGObject *)mig_object, iid, &ppv);
698	ip_unlock(port);
699	return (mig_object_t)ppv;
700}
701
702/*
703 *	Routine:	mig_object_no_senders [interface]
704 *	Purpose:
705 *		Base implementation of a no-senders notification handler
706 *		for MIG objects. If there truly are no more senders, must
707 *		destroy the port and drop its reference on the object.
708 *	Returns:
709 *		TRUE  - port deallocate and reference dropped
710 *		FALSE - more senders arrived, re-registered for notification
711 *	Conditions:
712 *		Nothing locked.
713 */
714
715boolean_t
716mig_object_no_senders(
717	ipc_port_t		port,
718	mach_port_mscount_t	mscount)
719{
720	mig_object_t		mig_object;
721
722	ip_lock(port);
723	if (port->ip_mscount > mscount) {
724		ipc_port_t 	previous;
725
726		/*
727		 * Somebody created new send rights while the
728		 * notification was in-flight.  Just create a
729		 * new send-once right and re-register with
730		 * the new (higher) mscount threshold.
731		 */
732		/* make a sonce right for the notification */
733		port->ip_sorights++;
734		ip_reference(port);
735		ipc_port_nsrequest(port, mscount, port, &previous);
736		/* port unlocked */
737
738		assert(previous == IP_NULL);
739		return (FALSE);
740	}
741
742	/*
743	 * Clear the port pointer while we have it locked.
744	 */
745	mig_object = (mig_object_t)port->ip_kobject;
746	mig_object->port = IP_NULL;
747
748	/*
749	 * Bring the sequence number and mscount in
750	 * line with ipc_port_destroy assertion.
751	 */
752	port->ip_mscount = 0;
753	port->ip_messages.imq_seqno = 0;
754	ipc_port_destroy(port); /* releases lock */
755
756	/*
757	 * Release the port's reference on the object.
758	 */
759	mig_object->pVtbl->Release((IMIGObject *)mig_object);
760	return (TRUE);
761}
762
763/*
764 * Kernel implementation of the notification chain for MIG object
765 * is kept separate from the actual objects, since there are expected
766 * to be much fewer of them than actual objects.
767 *
768 * The implementation of this part of MIG objects is coming
769 * "Real Soon Now"(TM).
770 */
771