EXTERN io_object_t iokit_lookup_connect_ref(io_object_t connectRef, ipc_space_t space) { io_object_t obj = NULL; if (connectRef && MACH_PORT_VALID(CAST_MACH_PORT_TO_NAME(connectRef))) { ipc_port_t port; kern_return_t kr; kr = ipc_object_translate(space, CAST_MACH_PORT_TO_NAME(connectRef), MACH_PORT_RIGHT_SEND, (ipc_object_t *)&port); if (kr == KERN_SUCCESS) { assert(IP_VALID(port)); ip_reference(port); ip_unlock(port); iokit_lock_port(port); if (ip_active(port) && (ip_kotype(port) == IKOT_IOKIT_CONNECT)) { obj = (io_object_t) port->ip_kobject; iokit_add_connect_reference(obj); } iokit_unlock_port(port); ip_release(port); } } return obj; }
/* * Routine: port_name_to_semaphore * Purpose: * Convert from a port name in the current space to a semaphore. * Produces a semaphore ref, which may be null. * Conditions: * Nothing locked. */ kern_return_t port_name_to_semaphore( mach_port_name_t name, semaphore_t *semaphorep) { ipc_port_t kern_port; kern_return_t kr; if (!MACH_PORT_VALID(name)) { *semaphorep = SEMAPHORE_NULL; return KERN_INVALID_NAME; } kr = ipc_object_translate(current_space(), name, MACH_PORT_RIGHT_SEND, (ipc_object_t *) &kern_port); if (kr != KERN_SUCCESS) { *semaphorep = SEMAPHORE_NULL; return kr; } /* have the port locked */ assert(IP_VALID(kern_port)); *semaphorep = convert_port_to_semaphore(kern_port); ip_unlock(kern_port); return KERN_SUCCESS; }
static int filt_machportattach( struct knote *kn) { mach_port_name_t name = (mach_port_name_t)kn->kn_kevent.ident; uint64_t wq_link_id = waitq_link_reserve(NULL); ipc_pset_t pset = IPS_NULL; int result = ENOSYS; kern_return_t kr; kr = ipc_object_translate(current_space(), name, MACH_PORT_RIGHT_PORT_SET, (ipc_object_t *)&pset); if (kr != KERN_SUCCESS) { waitq_link_release(wq_link_id); return (kr == KERN_INVALID_NAME ? ENOENT : ENOTSUP); } /* We've got a lock on pset */ /* * Bind the portset wait queue directly to knote/kqueue. * This allows us to just use wait_queue foo to effect a wakeup, * rather than having to call knote() from the Mach code on each * message. */ result = knote_link_waitq(kn, &pset->ips_messages.imq_wait_queue, &wq_link_id); if (result == 0) { waitq_link_release(wq_link_id); /* keep a reference for the knote */ kn->kn_ptr.p_pset = pset; ips_reference(pset); ips_unlock(pset); return 0; } ips_unlock(pset); waitq_link_release(wq_link_id); return result; }
static int filt_machport( struct knote *kn, __unused long hint) { mach_port_name_t name = (mach_port_name_t)kn->kn_kevent.ident; ipc_pset_t pset = IPS_NULL; wait_result_t wresult; thread_t self = current_thread(); kern_return_t kr; mach_msg_option_t option; mach_msg_size_t size; /* never called from below */ assert(hint == 0); /* * called from user context. Have to validate the * name. If it changed, we have an EOF situation. */ kr = ipc_object_translate(current_space(), name, MACH_PORT_RIGHT_PORT_SET, (ipc_object_t *)&pset); if (kr != KERN_SUCCESS || pset != kn->kn_ptr.p_pset || !ips_active(pset)) { kn->kn_data = 0; kn->kn_flags |= (EV_EOF | EV_ONESHOT); if (pset != IPS_NULL) { ips_unlock(pset); } return(1); } /* just use the reference from here on out */ ips_reference(pset); ips_unlock(pset); /* * Only honor supported receive options. If no options are * provided, just force a MACH_RCV_TOO_LARGE to detect the * name of the port and sizeof the waiting message. */ option = kn->kn_sfflags & (MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_LARGE_IDENTITY| MACH_RCV_TRAILER_MASK|MACH_RCV_VOUCHER); if (option & MACH_RCV_MSG) { self->ith_msg_addr = (mach_vm_address_t) kn->kn_ext[0]; size = (mach_msg_size_t)kn->kn_ext[1]; } else { option = MACH_RCV_LARGE; self->ith_msg_addr = 0; size = 0; } /* * Set up to receive a message or the notification of a * too large message. But never allow this call to wait. * If the user provided aditional options, like trailer * options, pass those through here. But we don't support * scatter lists through this interface. */ self->ith_object = (ipc_object_t)pset; self->ith_msize = size; self->ith_option = option; self->ith_receiver_name = MACH_PORT_NULL; self->ith_continuation = NULL; option |= MACH_RCV_TIMEOUT; // never wait self->ith_state = MACH_RCV_IN_PROGRESS; wresult = ipc_mqueue_receive_on_thread( &pset->ips_messages, option, size, /* max_size */ 0, /* immediate timeout */ THREAD_INTERRUPTIBLE, self); assert(wresult == THREAD_NOT_WAITING); assert(self->ith_state != MACH_RCV_IN_PROGRESS); /* * If we timed out, just release the reference on the * portset and return zero. */ if (self->ith_state == MACH_RCV_TIMED_OUT) { ips_release(pset); return 0; } /* * If we weren't attempting to receive a message * directly, we need to return the port name in * the kevent structure. */ if ((option & MACH_RCV_MSG) != MACH_RCV_MSG) { assert(self->ith_state == MACH_RCV_TOO_LARGE); assert(self->ith_kmsg == IKM_NULL); kn->kn_data = self->ith_receiver_name; ips_release(pset); return 1; } /* * Attempt to receive the message directly, returning * the results in the fflags field. */ assert(option & MACH_RCV_MSG); kn->kn_ext[1] = self->ith_msize; kn->kn_data = MACH_PORT_NULL; kn->kn_fflags = mach_msg_receive_results(); /* kmsg and pset reference consumed */ /* * if the user asked for the identity of ports containing a * a too-large message, return it in the data field (as we * do for messages we didn't try to receive). */ if ((kn->kn_fflags == MACH_RCV_TOO_LARGE) && (option & MACH_RCV_LARGE_IDENTITY)) kn->kn_data = self->ith_receiver_name; return 1; }