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 <ipc/ipc_notify.h> 83#include <vm/vm_map.h> 84 85#include <libkern/OSAtomic.h> 86 87/* 88 * Routine: mach_msg_send_from_kernel 89 * Purpose: 90 * Send a message from the kernel. 91 * 92 * This is used by the client side of KernelUser interfaces 93 * to implement SimpleRoutines. Currently, this includes 94 * memory_object messages. 95 * Conditions: 96 * Nothing locked. 97 * Returns: 98 * MACH_MSG_SUCCESS Sent the message. 99 * MACH_SEND_INVALID_DEST Bad destination port. 100 * MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer 101 * or destination is above kernel limit 102 */ 103 104#if IKM_SUPPORT_LEGACY 105 106#undef mach_msg_send_from_kernel 107mach_msg_return_t mach_msg_send_from_kernel( 108 mach_msg_header_t *msg, 109 mach_msg_size_t send_size); 110 111mach_msg_return_t 112mach_msg_send_from_kernel( 113 mach_msg_header_t *msg, 114 mach_msg_size_t send_size) 115{ 116 ipc_kmsg_t kmsg; 117 mach_msg_return_t mr; 118 119 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 120 if (mr != MACH_MSG_SUCCESS) 121 return mr; 122 123 mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); 124 if (mr != MACH_MSG_SUCCESS) { 125 ipc_kmsg_free(kmsg); 126 return mr; 127 } 128 129 mr = ipc_kmsg_send_always(kmsg); 130 if (mr != MACH_MSG_SUCCESS) { 131 ipc_kmsg_destroy(kmsg); 132 } 133 134 return mr; 135} 136 137#endif /* IKM_SUPPORT_LEGACY */ 138 139mach_msg_return_t 140mach_msg_send_from_kernel_proper( 141 mach_msg_header_t *msg, 142 mach_msg_size_t send_size) 143{ 144 ipc_kmsg_t kmsg; 145 mach_msg_return_t mr; 146 147 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 148 if (mr != MACH_MSG_SUCCESS) 149 return mr; 150 151 mr = ipc_kmsg_copyin_from_kernel(kmsg); 152 if (mr != MACH_MSG_SUCCESS) { 153 ipc_kmsg_free(kmsg); 154 return mr; 155 } 156 157 mr = ipc_kmsg_send_always(kmsg); 158 if (mr != MACH_MSG_SUCCESS) { 159 ipc_kmsg_destroy(kmsg); 160 } 161 162 return mr; 163} 164 165#if IKM_SUPPORT_LEGACY 166 167mach_msg_return_t 168mach_msg_send_from_kernel_with_options( 169 mach_msg_header_t *msg, 170 mach_msg_size_t send_size, 171 mach_msg_option_t option, 172 mach_msg_timeout_t timeout_val) 173{ 174 ipc_kmsg_t kmsg; 175 mach_msg_return_t mr; 176 177 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 178 if (mr != MACH_MSG_SUCCESS) 179 return mr; 180 181 mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); 182 if (mr != MACH_MSG_SUCCESS) { 183 ipc_kmsg_free(kmsg); 184 return mr; 185 } 186 187 mr = ipc_kmsg_send(kmsg, option, timeout_val); 188 if (mr != MACH_MSG_SUCCESS) { 189 ipc_kmsg_destroy(kmsg); 190 } 191 192 return mr; 193} 194 195#endif /* IKM_SUPPORT_LEGACY */ 196 197/* 198 * Routine: mach_msg_rpc_from_kernel 199 * Purpose: 200 * Send a message from the kernel and receive a reply. 201 * Uses ith_rpc_reply for the reply port. 202 * 203 * This is used by the client side of KernelUser interfaces 204 * to implement Routines. 205 * Conditions: 206 * Nothing locked. 207 * Returns: 208 * MACH_MSG_SUCCESS Sent the message. 209 * MACH_RCV_PORT_DIED The reply port was deallocated. 210 */ 211 212mach_msg_return_t mach_msg_rpc_from_kernel_body(mach_msg_header_t *msg, 213 mach_msg_size_t send_size, mach_msg_size_t rcv_size, boolean_t legacy); 214 215#if IKM_SUPPORT_LEGACY 216 217#undef mach_msg_rpc_from_kernel 218mach_msg_return_t 219mach_msg_rpc_from_kernel( 220 mach_msg_header_t *msg, 221 mach_msg_size_t send_size, 222 mach_msg_size_t rcv_size); 223 224mach_msg_return_t 225mach_msg_rpc_from_kernel( 226 mach_msg_header_t *msg, 227 mach_msg_size_t send_size, 228 mach_msg_size_t rcv_size) 229{ 230 return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, TRUE); 231} 232 233#endif /* IKM_SUPPORT_LEGACY */ 234 235mach_msg_return_t 236mach_msg_rpc_from_kernel_proper( 237 mach_msg_header_t *msg, 238 mach_msg_size_t send_size, 239 mach_msg_size_t rcv_size) 240{ 241 return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, FALSE); 242} 243 244mach_msg_return_t 245mach_msg_rpc_from_kernel_body( 246 mach_msg_header_t *msg, 247 mach_msg_size_t send_size, 248 mach_msg_size_t rcv_size, 249#if !IKM_SUPPORT_LEGACY 250 __unused 251#endif 252 boolean_t legacy) 253{ 254 thread_t self = current_thread(); 255 ipc_port_t reply; 256 ipc_kmsg_t kmsg; 257 mach_port_seqno_t seqno; 258 mach_msg_return_t mr; 259 260 assert(msg->msgh_local_port == MACH_PORT_NULL); 261 262 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 263 if (mr != MACH_MSG_SUCCESS) 264 return mr; 265 266 reply = self->ith_rpc_reply; 267 if (reply == IP_NULL) { 268 reply = ipc_port_alloc_reply(); 269 if ((reply == IP_NULL) || 270 (self->ith_rpc_reply != IP_NULL)) 271 panic("mach_msg_rpc_from_kernel"); 272 self->ith_rpc_reply = reply; 273 } 274 275 /* insert send-once right for the reply port */ 276 kmsg->ikm_header->msgh_local_port = reply; 277 kmsg->ikm_header->msgh_bits |= 278 MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); 279 280 ip_reference(reply); 281 282#if IKM_SUPPORT_LEGACY 283 if(legacy) 284 mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); 285 else 286 mr = ipc_kmsg_copyin_from_kernel(kmsg); 287#else 288 mr = ipc_kmsg_copyin_from_kernel(kmsg); 289#endif 290 if (mr != MACH_MSG_SUCCESS) { 291 ipc_kmsg_free(kmsg); 292 return mr; 293 } 294 mr = ipc_kmsg_send_always(kmsg); 295 if (mr != MACH_MSG_SUCCESS) { 296 ipc_kmsg_destroy(kmsg); 297 return mr; 298 } 299 300 for (;;) { 301 ipc_mqueue_t mqueue; 302 303 ip_lock(reply); 304 if ( !ip_active(reply)) { 305 ip_unlock(reply); 306 ip_release(reply); 307 return MACH_RCV_PORT_DIED; 308 } 309 if (!self->active) { 310 ip_unlock(reply); 311 ip_release(reply); 312 return MACH_RCV_INTERRUPTED; 313 } 314 315 assert(reply->ip_pset_count == 0); 316 mqueue = &reply->ip_messages; 317 ip_unlock(reply); 318 319 self->ith_continuation = (void (*)(mach_msg_return_t))0; 320 321 ipc_mqueue_receive(mqueue, 322 MACH_MSG_OPTION_NONE, 323 MACH_MSG_SIZE_MAX, 324 MACH_MSG_TIMEOUT_NONE, 325 THREAD_INTERRUPTIBLE); 326 327 mr = self->ith_state; 328 kmsg = self->ith_kmsg; 329 seqno = self->ith_seqno; 330 331 if (mr == MACH_MSG_SUCCESS) 332 { 333 break; 334 } 335 336 assert(mr == MACH_RCV_INTERRUPTED); 337 338 if (self->handlers) { 339 ip_release(reply); 340 return(mr); 341 } 342 } 343 ip_release(reply); 344 345 /* 346 * Check to see how much of the message/trailer can be received. 347 * We chose the maximum trailer that will fit, since we don't 348 * have options telling us which trailer elements the caller needed. 349 */ 350 if (rcv_size >= kmsg->ikm_header->msgh_size) { 351 mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *) 352 ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size); 353 354 if (rcv_size >= kmsg->ikm_header->msgh_size + MAX_TRAILER_SIZE) { 355 /* Enough room for a maximum trailer */ 356 trailer->msgh_trailer_size = MAX_TRAILER_SIZE; 357 } 358 else if (rcv_size < kmsg->ikm_header->msgh_size + 359 trailer->msgh_trailer_size) { 360 /* no room for even the basic (default) trailer */ 361 trailer->msgh_trailer_size = 0; 362 } 363 assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0); 364 rcv_size = kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size; 365 mr = MACH_MSG_SUCCESS; 366 } else { 367 mr = MACH_RCV_TOO_LARGE; 368 } 369 370 371 /* 372 * We want to preserve rights and memory in reply! 373 * We don't have to put them anywhere; just leave them 374 * as they are. 375 */ 376#if IKM_SUPPORT_LEGACY 377 if(legacy) 378 ipc_kmsg_copyout_to_kernel_legacy(kmsg, ipc_space_reply); 379 else 380 ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); 381#else 382 ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); 383#endif 384 ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size); 385 return mr; 386} 387 388 389/************** These Calls are set up for kernel-loaded tasks/threads **************/ 390 391/* 392 * Routine: mach_msg_overwrite 393 * Purpose: 394 * Like mach_msg_overwrite_trap except that message buffers 395 * live in kernel space. Doesn't handle any options. 396 * 397 * This is used by in-kernel server threads to make 398 * kernel calls, to receive request messages, and 399 * to send reply messages. 400 * Conditions: 401 * Nothing locked. 402 * Returns: 403 */ 404 405mach_msg_return_t 406mach_msg_overwrite( 407 mach_msg_header_t *msg, 408 mach_msg_option_t option, 409 mach_msg_size_t send_size, 410 mach_msg_size_t rcv_size, 411 mach_port_name_t rcv_name, 412 __unused mach_msg_timeout_t msg_timeout, 413 __unused mach_port_name_t notify, 414 __unused mach_msg_header_t *rcv_msg, 415 __unused mach_msg_size_t rcv_msg_size) 416{ 417 ipc_space_t space = current_space(); 418 vm_map_t map = current_map(); 419 ipc_kmsg_t kmsg; 420 mach_port_seqno_t seqno; 421 mach_msg_return_t mr; 422 mach_msg_trailer_size_t trailer_size; 423 424 if (option & MACH_SEND_MSG) { 425 mach_msg_size_t msg_and_trailer_size; 426 mach_msg_max_trailer_t *max_trailer; 427 428 if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3)) 429 return MACH_SEND_MSG_TOO_SMALL; 430 431 if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) 432 return MACH_SEND_TOO_LARGE; 433 434 msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; 435 kmsg = ipc_kmsg_alloc(msg_and_trailer_size); 436 437 if (kmsg == IKM_NULL) 438 return MACH_SEND_NO_BUFFER; 439 440 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); 441 442 kmsg->ikm_header->msgh_size = send_size; 443 444 /* 445 * Reserve for the trailer the largest space (MAX_TRAILER_SIZE) 446 * However, the internal size field of the trailer (msgh_trailer_size) 447 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize 448 * the cases where no implicit data is requested. 449 */ 450 max_trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size); 451 max_trailer->msgh_sender = current_thread()->task->sec_token; 452 max_trailer->msgh_audit = current_thread()->task->audit_token; 453 max_trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; 454 max_trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; 455 456 mr = ipc_kmsg_copyin(kmsg, space, map, FALSE); 457 if (mr != MACH_MSG_SUCCESS) { 458 ipc_kmsg_free(kmsg); 459 return mr; 460 } 461 462 do 463 mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE, 464 MACH_MSG_TIMEOUT_NONE); 465 while (mr == MACH_SEND_INTERRUPTED); 466 assert(mr == MACH_MSG_SUCCESS); 467 } 468 469 if (option & MACH_RCV_MSG) { 470 thread_t self = current_thread(); 471 472 do { 473 ipc_object_t object; 474 ipc_mqueue_t mqueue; 475 476 mr = ipc_mqueue_copyin(space, rcv_name, 477 &mqueue, &object); 478 if (mr != MACH_MSG_SUCCESS) 479 return mr; 480 /* hold ref for object */ 481 482 self->ith_continuation = (void (*)(mach_msg_return_t))0; 483 ipc_mqueue_receive(mqueue, 484 MACH_MSG_OPTION_NONE, 485 MACH_MSG_SIZE_MAX, 486 MACH_MSG_TIMEOUT_NONE, 487 THREAD_ABORTSAFE); 488 mr = self->ith_state; 489 kmsg = self->ith_kmsg; 490 seqno = self->ith_seqno; 491 492 io_release(object); 493 494 } while (mr == MACH_RCV_INTERRUPTED); 495 if (mr != MACH_MSG_SUCCESS) 496 return mr; 497 498 499 trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, current_thread(), seqno, TRUE, 500 kmsg->ikm_header->msgh_remote_port->ip_context); 501 502 if (rcv_size < (kmsg->ikm_header->msgh_size + trailer_size)) { 503 ipc_kmsg_copyout_dest(kmsg, space); 504 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); 505 ipc_kmsg_free(kmsg); 506 return MACH_RCV_TOO_LARGE; 507 } 508 509 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL); 510 if (mr != MACH_MSG_SUCCESS) { 511 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { 512 ipc_kmsg_put_to_kernel(msg, kmsg, 513 kmsg->ikm_header->msgh_size + trailer_size); 514 } else { 515 ipc_kmsg_copyout_dest(kmsg, space); 516 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); 517 ipc_kmsg_free(kmsg); 518 } 519 520 return mr; 521 } 522 523 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, 524 kmsg->ikm_header->msgh_size + trailer_size); 525 ipc_kmsg_free(kmsg); 526 } 527 528 return MACH_MSG_SUCCESS; 529} 530 531/* 532 * Routine: mig_get_reply_port 533 * Purpose: 534 * Called by client side interfaces living in the kernel 535 * to get a reply port. 536 */ 537mach_port_t 538mig_get_reply_port(void) 539{ 540 return (MACH_PORT_NULL); 541} 542 543/* 544 * Routine: mig_dealloc_reply_port 545 * Purpose: 546 * Called by client side interfaces to get rid of a reply port. 547 */ 548 549void 550mig_dealloc_reply_port( 551 __unused mach_port_t reply_port) 552{ 553} 554 555/* 556 * Routine: mig_put_reply_port 557 * Purpose: 558 * Called by client side interfaces after each RPC to 559 * let the client recycle the reply port if it wishes. 560 */ 561void 562mig_put_reply_port( 563 __unused mach_port_t reply_port) 564{ 565} 566 567/* 568 * mig_strncpy.c - by Joshua Block 569 * 570 * mig_strncp -- Bounded string copy. Does what the library routine strncpy 571 * OUGHT to do: Copies the (null terminated) string in src into dest, a 572 * buffer of length len. Assures that the copy is still null terminated 573 * and doesn't overflow the buffer, truncating the copy if necessary. 574 * 575 * Parameters: 576 * 577 * dest - Pointer to destination buffer. 578 * 579 * src - Pointer to source string. 580 * 581 * len - Length of destination buffer. 582 */ 583int 584mig_strncpy( 585 char *dest, 586 const char *src, 587 int len) 588{ 589 int i = 0; 590 591 if (len > 0) 592 if (dest != NULL) { 593 if (src != NULL) 594 for (i=1; i<len; i++) 595 if (! (*dest++ = *src++)) 596 return i; 597 *dest = '\0'; 598 } 599 return i; 600} 601 602char * 603mig_user_allocate( 604 vm_size_t size) 605{ 606 return (char *)kalloc(size); 607} 608 609void 610mig_user_deallocate( 611 char *data, 612 vm_size_t size) 613{ 614 kfree(data, size); 615} 616 617/* 618 * Routine: mig_object_init 619 * Purpose: 620 * Initialize the base class portion of a MIG object. We 621 * will lazy init the port, so just clear it for now. 622 */ 623kern_return_t 624mig_object_init( 625 mig_object_t mig_object, 626 const IMIGObject *interface) 627{ 628 if (mig_object == MIG_OBJECT_NULL) 629 return KERN_INVALID_ARGUMENT; 630 mig_object->pVtbl = (const IMIGObjectVtbl *)interface; 631 mig_object->port = MACH_PORT_NULL; 632 return KERN_SUCCESS; 633} 634 635/* 636 * Routine: mig_object_destroy 637 * Purpose: 638 * The object is being freed. This call lets us clean 639 * up any state we have have built up over the object's 640 * lifetime. 641 * Conditions: 642 * Since notifications and the port hold references on 643 * on the object, neither can exist when this is called. 644 * This is a good place to assert() that condition. 645 */ 646void 647mig_object_destroy( 648 __assert_only mig_object_t mig_object) 649{ 650 assert(mig_object->port == MACH_PORT_NULL); 651 return; 652} 653 654/* 655 * Routine: mig_object_reference 656 * Purpose: 657 * Pure virtual helper to invoke the MIG object's AddRef 658 * method. 659 * Conditions: 660 * MIG object port may be locked. 661 */ 662void 663mig_object_reference( 664 mig_object_t mig_object) 665{ 666 assert(mig_object != MIG_OBJECT_NULL); 667 mig_object->pVtbl->AddRef((IMIGObject *)mig_object); 668} 669 670/* 671 * Routine: mig_object_deallocate 672 * Purpose: 673 * Pure virtual helper to invoke the MIG object's Release 674 * method. 675 * Conditions: 676 * Nothing locked. 677 */ 678void 679mig_object_deallocate( 680 mig_object_t mig_object) 681{ 682 assert(mig_object != MIG_OBJECT_NULL); 683 mig_object->pVtbl->Release((IMIGObject *)mig_object); 684} 685 686/* 687 * Routine: convert_mig_object_to_port [interface] 688 * Purpose: 689 * Base implementation of MIG outtrans routine to convert from 690 * a mig object reference to a new send right on the object's 691 * port. The object reference is consumed. 692 * Returns: 693 * IP_NULL - Null MIG object supplied 694 * Otherwise, a newly made send right for the port 695 * Conditions: 696 * Nothing locked. 697 */ 698ipc_port_t 699convert_mig_object_to_port( 700 mig_object_t mig_object) 701{ 702 ipc_port_t port; 703 boolean_t deallocate = TRUE; 704 705 if (mig_object == MIG_OBJECT_NULL) 706 return IP_NULL; 707 708 port = mig_object->port; 709 while ((port == IP_NULL) || 710 ((port = ipc_port_make_send(port)) == IP_NULL)) { 711 ipc_port_t previous; 712 713 /* 714 * Either the port was never set up, or it was just 715 * deallocated out from under us by the no-senders 716 * processing. In either case, we must: 717 * Attempt to make one 718 * Arrange for no senders 719 * Try to atomically register it with the object 720 * Destroy it if we are raced. 721 */ 722 port = ipc_port_alloc_kernel(); 723 ip_lock(port); 724 ipc_kobject_set_atomically(port, 725 (ipc_kobject_t) mig_object, 726 IKOT_MIG); 727 728 /* make a sonce right for the notification */ 729 port->ip_sorights++; 730 ip_reference(port); 731 732 ipc_port_nsrequest(port, 1, port, &previous); 733 /* port unlocked */ 734 735 assert(previous == IP_NULL); 736 737 if (OSCompareAndSwapPtr((void *)IP_NULL, (void *)port, 738 (void * volatile *)&mig_object->port)) { 739 deallocate = FALSE; 740 } else { 741 ipc_port_dealloc_kernel(port); 742 port = mig_object->port; 743 } 744 } 745 746 if (deallocate) 747 mig_object->pVtbl->Release((IMIGObject *)mig_object); 748 749 return (port); 750} 751 752 753/* 754 * Routine: convert_port_to_mig_object [interface] 755 * Purpose: 756 * Base implementation of MIG intrans routine to convert from 757 * an incoming port reference to a new reference on the 758 * underlying object. A new reference must be created, because 759 * the port's reference could go away asynchronously. 760 * Returns: 761 * NULL - Not an active MIG object port or iid not supported 762 * Otherwise, a reference to the underlying MIG interface 763 * Conditions: 764 * Nothing locked. 765 */ 766mig_object_t 767convert_port_to_mig_object( 768 ipc_port_t port, 769 const MIGIID *iid) 770{ 771 mig_object_t mig_object; 772 void *ppv; 773 774 if (!IP_VALID(port)) 775 return NULL; 776 777 ip_lock(port); 778 if (!ip_active(port) || (ip_kotype(port) != IKOT_MIG)) { 779 ip_unlock(port); 780 return NULL; 781 } 782 783 /* 784 * Our port points to some MIG object interface. Now 785 * query it to get a reference to the desired interface. 786 */ 787 ppv = NULL; 788 mig_object = (mig_object_t)port->ip_kobject; 789 mig_object->pVtbl->QueryInterface((IMIGObject *)mig_object, iid, &ppv); 790 ip_unlock(port); 791 return (mig_object_t)ppv; 792} 793 794/* 795 * Routine: mig_object_no_senders [interface] 796 * Purpose: 797 * Base implementation of a no-senders notification handler 798 * for MIG objects. If there truly are no more senders, must 799 * destroy the port and drop its reference on the object. 800 * Returns: 801 * TRUE - port deallocate and reference dropped 802 * FALSE - more senders arrived, re-registered for notification 803 * Conditions: 804 * Nothing locked. 805 */ 806 807boolean_t 808mig_object_no_senders( 809 ipc_port_t port, 810 mach_port_mscount_t mscount) 811{ 812 mig_object_t mig_object; 813 814 ip_lock(port); 815 if (port->ip_mscount > mscount) { 816 ipc_port_t previous; 817 818 /* 819 * Somebody created new send rights while the 820 * notification was in-flight. Just create a 821 * new send-once right and re-register with 822 * the new (higher) mscount threshold. 823 */ 824 /* make a sonce right for the notification */ 825 port->ip_sorights++; 826 ip_reference(port); 827 ipc_port_nsrequest(port, mscount, port, &previous); 828 /* port unlocked */ 829 830 assert(previous == IP_NULL); 831 return (FALSE); 832 } 833 834 /* 835 * Clear the port pointer while we have it locked. 836 */ 837 mig_object = (mig_object_t)port->ip_kobject; 838 mig_object->port = IP_NULL; 839 840 /* 841 * Bring the sequence number and mscount in 842 * line with ipc_port_destroy assertion. 843 */ 844 port->ip_mscount = 0; 845 port->ip_messages.imq_seqno = 0; 846 ipc_port_destroy(port); /* releases lock */ 847 848 /* 849 * Release the port's reference on the object. 850 */ 851 mig_object->pVtbl->Release((IMIGObject *)mig_object); 852 return (TRUE); 853} 854 855/* 856 * Kernel implementation of the notification chain for MIG object 857 * is kept separate from the actual objects, since there are expected 858 * to be much fewer of them than actual objects. 859 * 860 * The implementation of this part of MIG objects is coming 861 * "Real Soon Now"(TM). 862 */ 863