/* * fileport_alloc * * Description: Obtain a send right for the given fileglob, which must be * referenced. * * Parameters: fg A fileglob. * * Returns: Port of type IKOT_FILEPORT with fileglob set as its kobject. * Port is returned with a send right. */ ipc_port_t fileport_alloc(struct fileglob *fg) { ipc_port_t fileport; ipc_port_t sendport; ipc_port_t notifyport; fileport = ipc_port_alloc_kernel(); if (fileport == IP_NULL) { goto out; } ipc_kobject_set(fileport, (ipc_kobject_t)fg, IKOT_FILEPORT); notifyport = ipc_port_make_sonce(fileport); ip_lock(fileport); /* unlocked by ipc_port_nsrequest */ ipc_port_nsrequest(fileport, 1, notifyport, ¬ifyport); sendport = ipc_port_make_send(fileport); if (!IP_VALID(sendport)) { panic("Couldn't allocate send right for fileport!\n"); } out: return fileport; }
EXTERN ipc_port_t iokit_alloc_object_port( io_object_t obj, ipc_kobject_type_t type ) { ipc_port_t notify; ipc_port_t port; do { /* Allocate port, keeping a reference for it. */ port = ipc_port_alloc_kernel(); if( port == IP_NULL) continue; /* set kobject & type */ // iokit_add_reference( obj ); ipc_kobject_set( port, (ipc_kobject_t) obj, type); /* Request no-senders notifications on the port. */ ip_lock( port); notify = ipc_port_make_sonce_locked( port); ipc_port_nsrequest( port, 1, notify, ¬ify); /* port unlocked */ assert( notify == IP_NULL); gIOKitPortCount++; } while( FALSE); return( port ); }
/* * Routine: convert_mig_object_to_port [interface] * Purpose: * Base implementation of MIG outtrans routine to convert from * a mig object reference to a new send right on the object's * port. The object reference is consumed. * Returns: * IP_NULL - Null MIG object supplied * Otherwise, a newly made send right for the port * Conditions: * Nothing locked. */ ipc_port_t convert_mig_object_to_port( mig_object_t mig_object) { ipc_port_t port; boolean_t deallocate = TRUE; if (mig_object == MIG_OBJECT_NULL) return IP_NULL; port = mig_object->port; while ((port == IP_NULL) || ((port = ipc_port_make_send(port)) == IP_NULL)) { ipc_port_t previous; /* * Either the port was never set up, or it was just * deallocated out from under us by the no-senders * processing. In either case, we must: * Attempt to make one * Arrange for no senders * Try to atomically register it with the object * Destroy it if we are raced. */ port = ipc_port_alloc_kernel(); ip_lock(port); ipc_kobject_set_atomically(port, (ipc_kobject_t) mig_object, IKOT_MIG); /* make a sonce right for the notification */ port->ip_sorights++; ip_reference(port); ipc_port_nsrequest(port, 1, port, &previous); /* port unlocked */ assert(previous == IP_NULL); if (OSCompareAndSwapPtr((void *)IP_NULL, (void *)port, (void * volatile *)&mig_object->port)) { deallocate = FALSE; } else { ipc_port_dealloc_kernel(port); port = mig_object->port; } } if (deallocate) mig_object->pVtbl->Release((IMIGObject *)mig_object); return (port); }
boolean_t mig_object_no_senders( ipc_port_t port, mach_port_mscount_t mscount) { mig_object_t mig_object; ip_lock(port); if (port->ip_mscount > mscount) { ipc_port_t previous; /* * Somebody created new send rights while the * notification was in-flight. Just create a * new send-once right and re-register with * the new (higher) mscount threshold. */ /* make a sonce right for the notification */ port->ip_sorights++; ip_reference(port); ipc_port_nsrequest(port, mscount, port, &previous); /* port unlocked */ assert(previous == IP_NULL); return (FALSE); } /* * Clear the port pointer while we have it locked. */ mig_object = (mig_object_t)port->ip_kobject; mig_object->port = IP_NULL; /* * Bring the sequence number and mscount in * line with ipc_port_destroy assertion. */ port->ip_mscount = 0; port->ip_messages.imq_seqno = 0; ipc_port_destroy(port); /* releases lock */ /* * Release the port's reference on the object. */ mig_object->pVtbl->Release((IMIGObject *)mig_object); return (TRUE); }
static void iokit_no_senders( mach_no_senders_notification_t * notification ) { ipc_port_t port; io_object_t obj = NULL; ipc_kobject_type_t type = IKOT_NONE; ipc_port_t notify; port = (ipc_port_t) notification->not_header.msgh_remote_port; // convert a port to io_object_t. if( IP_VALID(port)) { iokit_lock_port(port); if( ip_active(port)) { obj = (io_object_t) port->ip_kobject; type = ip_kotype( port ); if( (IKOT_IOKIT_OBJECT == type) || (IKOT_IOKIT_CONNECT == type)) iokit_add_reference( obj ); else obj = NULL; } iokit_unlock_port(port); if( obj ) { mach_port_mscount_t mscount = notification->not_count; if( KERN_SUCCESS != iokit_client_died( obj, port, type, &mscount )) { /* Re-request no-senders notifications on the port (if still active) */ ip_lock(port); if (ip_active(port)) { notify = ipc_port_make_sonce_locked(port); ipc_port_nsrequest( port, mscount + 1, notify, ¬ify); /* port unlocked */ if ( notify != IP_NULL) ipc_port_release_sonce(notify); } else { ip_unlock(port); } } iokit_remove_reference( obj ); } } }
/* * Routine: convert_semaphore_to_port * Purpose: * Convert a semaphore reference to a send right to a * semaphore port. * * Consumes the semaphore reference. If the semaphore * port currently has no send rights (or doesn't exist * yet), the reference is donated to the port to represent * all extant send rights collectively. */ ipc_port_t convert_semaphore_to_port (semaphore_t semaphore) { ipc_port_t port, send; if (semaphore == SEMAPHORE_NULL) return (IP_NULL); /* caller is donating a reference */ port = semaphore->port; if (!IP_VALID(port)) { port = ipc_port_alloc_kernel(); assert(IP_VALID(port)); ipc_kobject_set_atomically(port, (ipc_kobject_t) semaphore, IKOT_SEMAPHORE); /* If we lose the race, deallocate and pick up the other guy's port */ if (!OSCompareAndSwapPtr(IP_NULL, port, &semaphore->port)) { ipc_port_dealloc_kernel(port); port = semaphore->port; assert(ip_kotype(port) == IKOT_SEMAPHORE); assert(port->ip_kobject == (ipc_kobject_t)semaphore); } } ip_lock(port); assert(ip_active(port)); send = ipc_port_make_send_locked(port); if (1 == port->ip_srights) { ipc_port_t old_notify; /* transfer our ref to the port, and arm the no-senders notification */ assert(IP_NULL == port->ip_nsrequest); ipc_port_nsrequest(port, port->ip_mscount, ipc_port_make_sonce_locked(port), &old_notify); /* port unlocked */ assert(IP_NULL == old_notify); } else { /* piggyback on the existing port reference, so consume ours */ ip_unlock(port); semaphore_dereference(semaphore); } return (send); }
kern_return_t mach_port_request_notification( ipc_space_t space, mach_port_name_t name, mach_msg_id_t id, mach_port_mscount_t sync, ipc_port_t notify, ipc_port_t *previousp) { kern_return_t kr; ipc_entry_t entry; ipc_port_t port; if (space == IS_NULL) return KERN_INVALID_TASK; if (notify == IP_DEAD) return KERN_INVALID_CAPABILITY; #if NOTYET /* * Requesting notifications on RPC ports is an error. */ kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; port = (ipc_port_t) entry->ie_object; if (port->ip_subsystem != NULL) { is_write_unlock(space); panic("mach_port_request_notification: on RPC port!!"); return KERN_INVALID_CAPABILITY; } is_write_unlock(space); #endif /* NOTYET */ switch (id) { case MACH_NOTIFY_PORT_DESTROYED: { ipc_port_t port, previous; if (sync != 0) return KERN_INVALID_VALUE; if (!MACH_PORT_VALID(name)) return KERN_INVALID_RIGHT; kr = ipc_port_translate_receive(space, name, &port); if (kr != KERN_SUCCESS) return kr; /* port is locked and active */ ipc_port_pdrequest(port, notify, &previous); /* port is unlocked */ *previousp = previous; break; } case MACH_NOTIFY_NO_SENDERS: { ipc_port_t port; if (!MACH_PORT_VALID(name)) return KERN_INVALID_RIGHT; kr = ipc_port_translate_receive(space, name, &port); if (kr != KERN_SUCCESS) return kr; /* port is locked and active */ ipc_port_nsrequest(port, sync, notify, previousp); /* port is unlocked */ break; } case MACH_NOTIFY_DEAD_NAME: if (!MACH_PORT_VALID(name)) { /* * Already dead. * Should do immediate delivery check - * will do that in the near future. */ return KERN_INVALID_ARGUMENT; } kr = ipc_right_dnrequest(space, name, sync != 0, notify, previousp); if (kr != KERN_SUCCESS) return kr; break; default: return KERN_INVALID_VALUE; } return KERN_SUCCESS; }
static io_return_t device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type, dev_mode_t mode, char *name, device_t *devp) { io_return_t err = D_SUCCESS; ipc_port_t notify; struct ifnet *ifp; struct linux_device *dev; struct net_data *nd; /* Search for the device. */ for (dev = dev_base; dev; dev = dev->next) if (dev->base_addr && dev->base_addr != 0xffe0 && !strcmp (name, dev->name)) break; if (!dev) return D_NO_SUCH_DEVICE; /* Allocate and initialize device data if this is the first open. */ nd = dev->net_data; if (!nd) { dev->net_data = nd = ((struct net_data *) kalloc (sizeof (struct net_data))); if (!nd) { err = D_NO_MEMORY; goto out; } nd->dev = dev; nd->device.emul_data = nd; nd->device.emul_ops = &linux_net_emulation_ops; nd->port = ipc_port_alloc_kernel (); if (nd->port == IP_NULL) { err = KERN_RESOURCE_SHORTAGE; goto out; } ipc_kobject_set (nd->port, (ipc_kobject_t) & nd->device, IKOT_DEVICE); notify = ipc_port_make_sonce (nd->port); ip_lock (nd->port); ipc_port_nsrequest (nd->port, 1, notify, ¬ify); assert (notify == IP_NULL); ifp = &nd->ifnet; ifp->if_unit = dev->name[strlen (dev->name) - 1] - '0'; ifp->if_flags = IFF_UP | IFF_RUNNING; ifp->if_mtu = dev->mtu; ifp->if_header_size = dev->hard_header_len; ifp->if_header_format = dev->type; ifp->if_address_size = dev->addr_len; ifp->if_address = dev->dev_addr; if_init_queues (ifp); if (dev->open) { linux_intr_pri = SPL6; if ((*dev->open) (dev)) err = D_NO_SUCH_DEVICE; } out: if (err) { if (nd) { if (nd->port != IP_NULL) { ipc_kobject_set (nd->port, IKO_NULL, IKOT_NONE); ipc_port_dealloc_kernel (nd->port); } kfree ((vm_offset_t) nd, sizeof (struct net_data)); nd = NULL; dev->net_data = NULL; } } else { /* IPv6 heavily relies on multicasting (especially router and neighbor solicits and advertisements), so enable reception of those multicast packets by setting `LINUX_IFF_ALLMULTI'. */ dev->flags |= LINUX_IFF_UP | LINUX_IFF_RUNNING | LINUX_IFF_ALLMULTI; skb_queue_head_init (&dev->buffs[0]); if (dev->set_multicast_list) dev->set_multicast_list (dev); } if (IP_VALID (reply_port)) ds_device_open_reply (reply_port, reply_port_type, err, dev_to_port (nd)); return MIG_NO_REPLY; } *devp = &nd->device; return D_SUCCESS; }