+/*
+ * Routine: ipc_object_insert_send_right
+ * Purpose:
+ * Insert a send right into an object already in the space.
+ * The specified name must already point to a valid object.
+ *
+ * Note: This really is a combined copyin()/copyout(),
+ * that avoids most of the overhead of being implemented that way.
+ *
+ * This is the fastpath for mach_port_insert_right.
+ *
+ * Conditions:
+ * Nothing locked.
+ *
+ * msgt_name must be MACH_MSG_TYPE_MAKE_SEND_ONCE or
+ * MACH_MSG_TYPE_MOVE_SEND_ONCE.
+ *
+ * Returns:
+ * KERN_SUCCESS Copied out object, consumed ref.
+ * KERN_INVALID_TASK The space is dead.
+ * KERN_INVALID_NAME Name doesn't exist in space.
+ * KERN_INVALID_CAPABILITY The object is dead.
+ * KERN_RIGHT_EXISTS Space has rights under another name.
+ */
+kern_return_t
+ipc_object_insert_send_right(
+ ipc_space_t space,
+ mach_port_name_t name,
+ mach_msg_type_name_t msgt_name)
+{
+ ipc_entry_bits_t bits;
+ ipc_object_t object;
+ ipc_entry_t entry;
+ kern_return_t kr;
+
+ assert(msgt_name == MACH_MSG_TYPE_MAKE_SEND ||
+ msgt_name == MACH_MSG_TYPE_COPY_SEND);
+
+ kr = ipc_right_lookup_write(space, name, &entry);
+ if (kr != KERN_SUCCESS) {
+ return kr;
+ }
+ /* space is write-locked and active */
+
+ if (!IO_VALID(entry->ie_object)) {
+ is_write_unlock(space);
+ return KERN_INVALID_CAPABILITY;
+ }
+
+ bits = entry->ie_bits;
+ object = entry->ie_object;
+
+ io_lock(object);
+ if (!io_active(object)) {
+ kr = KERN_INVALID_CAPABILITY;
+ } else if (msgt_name == MACH_MSG_TYPE_MAKE_SEND) {
+ if (bits & MACH_PORT_TYPE_RECEIVE) {
+ ipc_port_t port = ip_object_to_port(object);
+ port->ip_mscount++;
+ if ((bits & MACH_PORT_TYPE_SEND) == 0) {
+ port->ip_srights++;
+ bits |= MACH_PORT_TYPE_SEND;
+ }
+ /* leave urefs pegged to maximum if it overflowed */
+ if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
+ bits += 1; /* increment urefs */
+ }
+ entry->ie_bits = bits;
+ ipc_entry_modified(space, name, entry);
+ kr = KERN_SUCCESS;
+ } else {
+ kr = KERN_INVALID_RIGHT;
+ }
+ } else { // MACH_MSG_TYPE_COPY_SEND
+ if (bits & MACH_PORT_TYPE_SEND) {
+ /* leave urefs pegged to maximum if it overflowed */
+ if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) {
+ entry->ie_bits = bits + 1; /* increment urefs */
+ }
+ ipc_entry_modified(space, name, entry);
+ kr = KERN_SUCCESS;
+ } else {
+ kr = KERN_INVALID_RIGHT;
+ }
+ }
+
+ io_unlock(object);
+ is_write_unlock(space);
+
+ return kr;
+}
+