--- Gnu-Mach/ipc/mach_port.c 2020/09/02 04:42:32 1.1.1.2 +++ Gnu-Mach/ipc/mach_port.c 2020/09/02 04:49:41 1.1.1.5 @@ -36,8 +36,8 @@ * Exported kernel calls. See mach/mach_port.defs. */ -#include - +#include +#include #include #include #include @@ -59,6 +59,7 @@ #include #include #include +#include @@ -102,11 +103,6 @@ mach_port_names_helper( ip_unlock(port); if (died) { -#if MACH_IPC_COMPAT - if (bits & IE_BITS_COMPAT) - return; -#endif /* MACH_IPC_COMPAT */ - /* pretend this is a dead-name entry */ bits &= ~(IE_BITS_TYPE_MASK|IE_BITS_MAREQUEST); @@ -118,11 +114,6 @@ mach_port_names_helper( } type = IE_BITS_TYPE(bits); -#if MACH_IPC_COMPAT - if (bits & IE_BITS_COMPAT) - type |= MACH_PORT_TYPE_COMPAT; - else -#endif /* MACH_IPC_COMPAT */ if (request != 0) type |= MACH_PORT_TYPE_DNREQUEST; if (bits & IE_BITS_MAREQUEST) @@ -159,10 +150,6 @@ mach_port_names( mach_port_type_t **typesp, mach_msg_type_number_t *typesCnt) { - ipc_tree_entry_t tentry; - ipc_entry_t table; - ipc_entry_num_t tsize; - mach_port_index_t index; ipc_entry_num_t actual; /* this many names */ ipc_port_timestamp_t timestamp; /* logical time of this operation */ mach_port_t *names; @@ -199,7 +186,7 @@ mach_port_names( /* upper bound on number of names in the space */ - bound = space->is_table_size + space->is_tree_total; + bound = space->is_size; size_needed = round_page(bound * sizeof(mach_port_t)); if (size_needed <= size) @@ -214,11 +201,14 @@ mach_port_names( size = size_needed; kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { + printf_once("no more room in ipc_kernel_map\n"); return KERN_RESOURCE_SHORTAGE; + } kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE); if (kr != KERN_SUCCESS) { + printf_once("no more room in ipc_kernel_map\n"); kmem_free(ipc_kernel_map, addr1, size); return KERN_RESOURCE_SHORTAGE; } @@ -241,33 +231,16 @@ mach_port_names( timestamp = ipc_port_timestamp(); - table = space->is_table; - tsize = space->is_table_size; - - for (index = 0; index < tsize; index++) { - ipc_entry_t entry = &table[index]; + ipc_entry_t entry; + struct rdxtree_iter iter; + rdxtree_for_each(&space->is_map, &iter, entry) { ipc_entry_bits_t bits = entry->ie_bits; if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) { - mach_port_t name = MACH_PORT_MAKEB(index, bits); - - mach_port_names_helper(timestamp, entry, name, + mach_port_names_helper(timestamp, entry, entry->ie_name, names, types, &actual); } } - - for (tentry = ipc_splay_traverse_start(&space->is_tree); - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) { - ipc_entry_t entry = &tentry->ite_entry; - mach_port_t name = tentry->ite_name; - - assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE); - - mach_port_names_helper(timestamp, entry, name, - names, types, &actual); - } - ipc_splay_traverse_finish(&space->is_tree); is_read_unlock(space); if (actual == 0) { @@ -440,10 +413,10 @@ mach_port_rename( */ kern_return_t -mach_port_allocate_name(space, right, name) - ipc_space_t space; - mach_port_right_t right; - mach_port_t name; +mach_port_allocate_name( + ipc_space_t space, + mach_port_right_t right, + mach_port_t name) { kern_return_t kr; @@ -503,10 +476,10 @@ mach_port_allocate_name(space, right, na */ kern_return_t -mach_port_allocate(space, right, namep) - ipc_space_t space; - mach_port_right_t right; - mach_port_t *namep; +mach_port_allocate( + ipc_space_t space, + mach_port_right_t right, + mach_port_t *namep) { kern_return_t kr; @@ -561,6 +534,8 @@ mach_port_allocate(space, right, namep) * KERN_INVALID_NAME The name doesn't denote a right. */ +static volatile boolean_t mach_port_deallocate_debug = FALSE; + kern_return_t mach_port_destroy( ipc_space_t space, @@ -573,8 +548,14 @@ mach_port_destroy( return KERN_INVALID_TASK; kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { + if (MACH_PORT_VALID (name) && space == current_space()) { + printf("task %.*s destroying a bogus port %lu, most probably a bug.\n", sizeof current_task()->name, current_task()->name, name); + if (mach_port_deallocate_debug) + SoftDebugger("mach_port_deallocate"); + } return kr; + } /* space is write-locked and active */ kr = ipc_right_destroy(space, name, entry); /* unlocks space */ @@ -611,8 +592,14 @@ mach_port_deallocate( return KERN_INVALID_TASK; kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { + if (MACH_PORT_VALID (name) && space == current_space()) { + printf("task %.*s deallocating a bogus port %lu, most probably a bug.\n", sizeof current_task()->name, current_task()->name, name); + if (mach_port_deallocate_debug) + SoftDebugger("mach_port_deallocate"); + } return kr; + } /* space is write-locked */ kr = ipc_right_dealloc(space, name, entry); /* unlocks space */ @@ -727,8 +714,19 @@ mach_port_mod_refs( return KERN_INVALID_VALUE; kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { + if (MACH_PORT_VALID (name) && space == current_space()) { + printf("task %.*s %screasing a bogus port " + "%lu by %d, most probably a bug.\n", + sizeof current_task()->name, + current_task()->name, + delta < 0 ? "de" : "in", name, + delta < 0 ? -delta : delta); + if (mach_port_deallocate_debug) + SoftDebugger("mach_port_mod_refs"); + } return kr; + } /* space is write-locked and active */ kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */ @@ -736,46 +734,6 @@ mach_port_mod_refs( } /* - * Routine: old_mach_port_get_receive_status [kernel call] - * Purpose: - * Compatibility for code written before sequence numbers. - * Retrieves mucho info about a receive right. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Retrieved status. - * KERN_INVALID_TASK The space is null. - * KERN_INVALID_TASK The space is dead. - * KERN_INVALID_NAME The name doesn't denote a right. - * KERN_INVALID_RIGHT Name doesn't denote receive rights. - */ - -kern_return_t -old_mach_port_get_receive_status(space, name, statusp) - ipc_space_t space; - mach_port_t name; - old_mach_port_status_t *statusp; -{ - mach_port_status_t status; - kern_return_t kr; - - kr = mach_port_get_receive_status(space, name, &status); - if (kr != KERN_SUCCESS) - return kr; - - statusp->mps_pset = status.mps_pset; - statusp->mps_mscount = status.mps_mscount; - statusp->mps_qlimit = status.mps_qlimit; - statusp->mps_msgcount = status.mps_msgcount; - statusp->mps_sorights = status.mps_sorights; - statusp->mps_srights = status.mps_srights; - statusp->mps_pdrequest = status.mps_pdrequest; - statusp->mps_nsrequest = status.mps_nsrequest; - - return KERN_SUCCESS; -} - -/* * Routine: mach_port_set_qlimit [kernel call] * Purpose: * Changes a receive right's queue limit. @@ -793,10 +751,10 @@ old_mach_port_get_receive_status(space, */ kern_return_t -mach_port_set_qlimit(space, name, qlimit) - ipc_space_t space; - mach_port_t name; - mach_port_msgcount_t qlimit; +mach_port_set_qlimit( + ipc_space_t space, + mach_port_t name, + mach_port_msgcount_t qlimit) { ipc_port_t port; kern_return_t kr; @@ -967,16 +925,15 @@ mach_port_get_set_status( size = PAGE_SIZE; /* initial guess */ for (;;) { - ipc_tree_entry_t tentry; - ipc_entry_t entry, table; - ipc_entry_num_t tsize; - mach_port_index_t index; + ipc_entry_t entry; mach_port_t *names; ipc_pset_t pset; kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { + printf_once("no more room in ipc_kernel_map\n"); return KERN_RESOURCE_SHORTAGE; + } /* can't fault while we hold locks */ @@ -1005,11 +962,9 @@ mach_port_get_set_status( maxnames = size / sizeof(mach_port_t); actual = 0; - table = space->is_table; - tsize = space->is_table_size; - - for (index = 0; index < tsize; index++) { - ipc_entry_t ientry = &table[index]; + ipc_entry_t ientry; + struct rdxtree_iter iter; + rdxtree_for_each(&space->is_map, &iter, ientry) { ipc_entry_bits_t bits = ientry->ie_bits; if (bits & MACH_PORT_TYPE_RECEIVE) { @@ -1021,22 +976,6 @@ mach_port_get_set_status( } } - for (tentry = ipc_splay_traverse_start(&space->is_tree); - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) { - ipc_entry_bits_t bits = tentry->ite_bits; - - assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); - - if (bits & MACH_PORT_TYPE_RECEIVE) { - ipc_port_t port = - (ipc_port_t) tentry->ite_object; - - mach_port_gst_helper(pset, port, maxnames, - names, &actual); - } - } - ipc_splay_traverse_finish(&space->is_tree); is_read_unlock(space); if (actual <= maxnames) @@ -1228,19 +1167,6 @@ mach_port_request_notification( ipc_port_pdrequest(port, notify, &previous); /* port is unlocked */ -#if MACH_IPC_COMPAT - /* - * If previous was a send right instead of a send-once - * right, we can't return it in the reply message. - * So destroy it instead. - */ - - if ((previous != IP_NULL) && ip_pdsendp(previous)) { - ipc_port_release_send(ip_pdsend(previous)); - previous = IP_NULL; - } -#endif /* MACH_IPC_COMPAT */ - *previousp = previous; break; } @@ -1307,10 +1233,11 @@ mach_port_insert_right( !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly)) return KERN_INVALID_VALUE; - if (!IO_VALID(poly)) + if (!IO_VALID((ipc_object_t)poly)) return KERN_INVALID_CAPABILITY; - return ipc_object_copyout_name(space, poly, polyPoly, FALSE, name); + return ipc_object_copyout_name(space, (ipc_object_t)poly, + polyPoly, FALSE, name); } /* @@ -1367,10 +1294,10 @@ mach_port_extract_right( */ kern_return_t -mach_port_get_receive_status(space, name, statusp) - ipc_space_t space; - mach_port_t name; - mach_port_status_t *statusp; +mach_port_get_receive_status( + ipc_space_t space, + mach_port_t name, + mach_port_status_t *statusp) { ipc_port_t port; kern_return_t kr; @@ -1421,11 +1348,11 @@ mach_port_get_receive_status(space, name #ifdef MIGRATING_THREADS kern_return_t -mach_port_set_rpcinfo(space, name, rpc_info, rpc_info_count) - ipc_space_t space; - mach_port_t name; - void *rpc_info; - unsigned int rpc_info_count; +mach_port_set_rpcinfo( + ipc_space_t space, + mach_port_t name, + void *rpc_info, + unsigned int rpc_info_count) { ipc_target_t target; ipc_object_t object; @@ -1459,19 +1386,19 @@ mach_port_set_rpcinfo(space, name, rpc_i int sacts, maxsacts; #endif -sact_count() +void sact_count(void) { printf("%d server activations in use, %d max\n", sacts, maxsacts); } kern_return_t -mach_port_create_act(task, name, user_stack, user_rbuf, user_rbuf_size, out_act) - task_t task; - mach_port_t name; - vm_offset_t user_stack; - vm_offset_t user_rbuf; - vm_size_t user_rbuf_size; - Act **out_act; +mach_port_create_act( + task_t task, + mach_port_t name, + vm_offset_t user_stack, + vm_offset_t user_rbuf, + vm_size_t user_rbuf_size, + Act **out_act) { ipc_target_t target; ipc_space_t space; @@ -1538,12 +1465,11 @@ mach_port_create_act(task, name, user_st #ifdef RPCKERNELSIG kern_return_t -mach_port_set_syscall_right(task, name) - task_t task; - mach_port_t name; +mach_port_set_syscall_right( + task_t task, + mach_port_t name) { ipc_entry_t entry; - ipc_port_t port; kern_return_t kr; if (task == IS_NULL) @@ -1568,938 +1494,75 @@ mach_port_set_syscall_right(task, name) #endif #endif /* MIGRATING_THREADS */ -#if MACH_IPC_COMPAT - -/* - * Routine: port_translate_compat - * Purpose: - * Converts a name to a receive right. - * Conditions: - * Nothing locked. If successful, the port - * is returned locked and active. - * Returns: - * KERN_SUCCESS Port is returned. - * KERN_INVALID_ARGUMENT The space is dead. - * KERN_INVALID_ARGUMENT Name doesn't denote port rights. - * KERN_NOT_RECEIVER Name denotes send, not receive, rights. - * KERN_NOT_RECEIVER Name denotes a send-once right. - * KERN_NOT_RECEIVER Name denotes a dead name. - */ - -kern_return_t -port_translate_compat(space, name, portp) - ipc_space_t space; - mach_port_t name; - ipc_port_t *portp; -{ - ipc_entry_t entry; - mach_port_type_t type; - mach_port_urefs_t urefs; - ipc_port_t port; - kern_return_t kr; - - kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; - /* space is write-locked and active */ - - kr = ipc_right_info(space, name, entry, &type, &urefs); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; /* space is unlocked */ - - if ((type & (MACH_PORT_TYPE_RECEIVE)) == 0) { - is_write_unlock(space); - if (type & MACH_PORT_TYPE_PORT_OR_DEAD) - return KERN_NOT_RECEIVER; - else - return KERN_INVALID_ARGUMENT; - } - - port = (ipc_port_t) entry->ie_object; - assert(port != IP_NULL); - - ip_lock(port); - is_write_unlock(space); - assert(ip_active(port)); - - *portp = port; - return KERN_SUCCESS; -} - -/* - * Routine: convert_port_type - * Purpose: - * Convert a new mach_port_type_t to an old value. - * Note send-once rights and dead names get - * represented as send rights. The extra info - * bits get dropped. - */ - -mach_port_type_t -convert_port_type(type) - mach_port_type_t type; -{ - switch (type & MACH_PORT_TYPE_ALL_RIGHTS) { - case MACH_PORT_TYPE_SEND: - case MACH_PORT_TYPE_SEND_ONCE: - case MACH_PORT_TYPE_DEAD_NAME: - return PORT_TYPE_SEND; - - case MACH_PORT_TYPE_RECEIVE: - case MACH_PORT_TYPE_SEND_RECEIVE: - return PORT_TYPE_RECEIVE_OWN; - - case MACH_PORT_TYPE_PORT_SET: - return PORT_TYPE_SET; - - default: -#if MACH_ASSERT - assert(!"convert_port_type: strange port type"); -#else - panic("convert_port_type: strange port type"); -#endif - } -} - -/* - * Routine: port_names [kernel call] - * Purpose: - * Retrieve all the names in the task's port name space. - * As a (major) convenience, return port type information. - * The port name space includes port sets. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Retrieved names. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * Additions: - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -port_names(space, namesp, namesCnt, typesp, typesCnt) - ipc_space_t space; - mach_port_t **namesp; - mach_msg_type_number_t *namesCnt; - mach_port_type_t **typesp; - mach_msg_type_number_t *typesCnt; -{ - kern_return_t kr; - - kr = mach_port_names(space, namesp, namesCnt, typesp, typesCnt); - if (kr == KERN_SUCCESS) { - ipc_entry_num_t actual = (ipc_entry_num_t) *typesCnt; - mach_port_type_t *types; - ipc_entry_num_t i; - - vm_map_copy_t copy = (vm_map_copy_t) *typesp; - vm_offset_t addr; - vm_size_t size = round_page(actual * sizeof(mach_port_type_t)); - - /* convert copy object back to something we can use */ - - kr = vm_map_copyout(ipc_kernel_map, &addr, copy); - if (kr != KERN_SUCCESS) { - vm_map_copy_discard((vm_map_copy_t) *typesp); - vm_map_copy_discard((vm_map_copy_t) *namesp); - return KERN_RESOURCE_SHORTAGE; - } - - types = (mach_port_type_t *) addr; - - for (i = 0; i < actual; i++) - types[i] = convert_port_type(types[i]); - - /* convert memory back into a copy object */ - - kr = vm_map_copyin(ipc_kernel_map, addr, size, - TRUE, ©); - assert(kr == KERN_SUCCESS); - - *typesp = (mach_port_type_t *) copy; - } else if (kr != KERN_RESOURCE_SHORTAGE) - kr = KERN_INVALID_ARGUMENT; - - return kr; -} - -/* - * Routine: port_type [kernel call] - * Purpose: - * Return type of the capability named. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Retrieved type. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT The name doesn't denote a right. - */ - -kern_return_t -port_type(space, name, typep) - ipc_space_t space; - mach_port_t name; - mach_port_type_t *typep; -{ - mach_port_type_t type; - kern_return_t kr; - - kr = mach_port_type(space, name, &type); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; - - *typep = convert_port_type(type); - return KERN_SUCCESS; -} - /* - * Routine: port_rename [kernel call] + * Routine: mach_port_set_protected_payload [kernel call] * Purpose: - * Change the name of a capability. - * The new name can't be in use. + * Changes a receive right's protected payload. * Conditions: * Nothing locked. * Returns: - * KERN_SUCCESS Retrieved type. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT The new name is reserved. - * KERN_NAME_EXISTS The new name already denotes a right. - * KERN_INVALID_ARGUMENT The old name doesn't denote a right. - */ - -kern_return_t -port_rename(space, old_name, new_name) - ipc_space_t space; - mach_port_t old_name; - mach_port_t new_name; -{ - kern_return_t kr; - - kr = mach_port_rename(space, old_name, new_name); - if ((kr != KERN_SUCCESS) && (kr != KERN_NAME_EXISTS)) - kr = KERN_INVALID_ARGUMENT; - - return kr; -} - -/* - * Routine: port_allocate [kernel call] - * Purpose: - * Allocate a new port, giving all rights to "task". - * - * Returns in "port_name" the task's local name for the port. - * Doesn't return a reference to the port. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Allocated a port. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. + * KERN_SUCCESS Set protected payload. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. */ kern_return_t -port_allocate(space, namep) - ipc_space_t space; - mach_port_t *namep; +mach_port_set_protected_payload( + ipc_space_t space, + mach_port_t name, + unsigned long payload) { ipc_port_t port; kern_return_t kr; if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_port_alloc_compat(space, namep, &port); - if (kr == KERN_SUCCESS) - ip_unlock(port); - else if (kr != KERN_RESOURCE_SHORTAGE) - kr = KERN_INVALID_ARGUMENT; - - return kr; -} - -/* - * Routine: port_deallocate [kernel call] - * Purpose: - * Delete port rights (send and receive) from a task. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Deallocated the port right. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote a port right. - * Additions: - * KERN_SUCCESS Deallocated a send-once right. - * KERN_SUCCESS Destroyed a dead name. - */ - -kern_return_t -port_deallocate(space, name) - ipc_space_t space; - mach_port_t name; -{ - ipc_entry_t entry; - mach_port_type_t type; - mach_port_urefs_t urefs; - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; - /* space is write-locked and active */ - - /* - * We serialize with port destruction with the - * ipc_right_info call, not ipc_right_destroy. - * After ipc_right_info, we pretend that the - * port doesn't get destroyed. - */ - - kr = ipc_right_info(space, name, entry, &type, &urefs); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; /* space is unlocked */ - - if ((type & (MACH_PORT_TYPE_PORT_OR_DEAD)) == 0) { - is_write_unlock(space); - return KERN_INVALID_ARGUMENT; - } - - (void) ipc_right_destroy(space, name, entry); - /* space is unlocked */ - - return KERN_SUCCESS; -} - -/* - * Routine: port_set_backlog [kernel call] - * Purpose: - * Change the queueing backlog on "port_name" to "backlog"; - * the specified "task" must be the current receiver. - * - * Valid backlog values are 0 < backlog <= PORT_BACKLOG_MAX. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Set the backlog. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote a port right. - * KERN_NOT_RECEIVER Name denotes send rights, not receive. - * KERN_INVALID_ARGUMENT Backlog value is invalid. - * Additions: - * KERN_NOT_RECEIVER Name denotes a send-once right. - * KERN_NOT_RECEIVER Name denotes a dead name. - */ - -kern_return_t -port_set_backlog(space, name, backlog) - ipc_space_t space; - mach_port_t name; - int backlog; -{ - ipc_port_t port; - kern_return_t kr; - - if ((space == IS_NULL) || - (backlog <= 0) || - (backlog > PORT_BACKLOG_MAX)) - return KERN_INVALID_ARGUMENT; + return KERN_INVALID_TASK; - kr = port_translate_compat(space, name, &port); + kr = ipc_port_translate_receive(space, name, &port); if (kr != KERN_SUCCESS) return kr; /* port is locked and active */ - ipc_port_set_qlimit(port, (mach_port_msgcount_t) backlog); + ipc_port_set_protected_payload(port, payload); ip_unlock(port); return KERN_SUCCESS; } /* - * Routine: port_set_backup [kernel call] + * Routine: mach_port_clear_protected_payload [kernel call] * Purpose: - * Changes the backup port for the the named port. - * The specified "task" must be the current receiver. - * Returns the old backup port, if any. + * Clears a receive right's protected payload. * Conditions: * Nothing locked. * Returns: - * KERN_SUCCESS Set the backup. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote a port right. - * KERN_NOT_RECEIVER Name denotes send rights, not receive. - * Additions: - * KERN_NOT_RECEIVER Name denotes a send-once right. - * KERN_NOT_RECEIVER Name denotes a dead name. + * KERN_SUCCESS Clear protected payload. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. */ kern_return_t -port_set_backup(space, name, backup, previousp) - ipc_space_t space; - mach_port_t name; - ipc_port_t backup; - ipc_port_t *previousp; +mach_port_clear_protected_payload( + ipc_space_t space, + mach_port_t name) { - ipc_port_t port, previous; + ipc_port_t port; kern_return_t kr; if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - if (backup == IP_DEAD) - backup = IP_NULL; - else if (backup != IP_NULL) - backup = ip_pdsendm(backup); + return KERN_INVALID_TASK; - kr = port_translate_compat(space, name, &port); + kr = ipc_port_translate_receive(space, name, &port); if (kr != KERN_SUCCESS) return kr; /* port is locked and active */ - ipc_port_pdrequest(port, backup, &previous); - /* port is unlocked */ - - /* - * If previous was a send-once right instead of a send - * right, we can't return it in the reply message. - * So get rid of it in a notification instead. - */ - - if (previous != IP_NULL) { - if (ip_pdsendp(previous)) - previous = ip_pdsend(previous); - else { - ipc_notify_send_once(previous); - previous = IP_NULL; - } - } - - *previousp = previous; - return KERN_SUCCESS; -} - -/* - * Routine: port_status [kernel call] - * Purpose: - * Returns statistics related to "port_name", as seen by "task". - * Only the receiver for a given port will see true message - * counts. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Retrieved status. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote a port right. - * Additions: - * KERN_SUCCESS Send-once right. - * KERN_SUCCESS Dead name. - */ - -kern_return_t -port_status(space, name, enabledp, num_msgs, backlog, - ownership, receive_rights) - ipc_space_t space; - mach_port_t name; - mach_port_t *enabledp; - int *num_msgs; - int *backlog; - boolean_t *ownership; - boolean_t *receive_rights; -{ - ipc_entry_t entry; - mach_port_type_t type; - mach_port_urefs_t urefs; - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; - /* space is write-locked and active */ - - kr = ipc_right_info(space, name, entry, &type, &urefs); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; /* space is unlocked */ - - if ((type & MACH_PORT_TYPE_PORT_OR_DEAD) == 0) { - is_write_unlock(space); - return KERN_INVALID_ARGUMENT; - } - - if (type & MACH_PORT_TYPE_RECEIVE) { - mach_port_t enabled; - mach_port_msgcount_t qlimit; - mach_port_msgcount_t msgcount; - ipc_port_t port; - - port = (ipc_port_t) entry->ie_object; - assert(port != IP_NULL); - - ip_lock(port); - is_write_unlock(space); - assert(ip_active(port)); - - if (port->ip_pset != IPS_NULL) { - ipc_pset_t pset = port->ip_pset; - - ips_lock(pset); - if (!ips_active(pset)) { - ipc_pset_remove(pset, port); - ips_check_unlock(pset); - enabled = MACH_PORT_NULL; - } else { - enabled = pset->ips_local_name; - ips_unlock(pset); - assert(MACH_PORT_VALID(enabled)); - } - } else - enabled = MACH_PORT_NULL; - - qlimit = port->ip_qlimit; - msgcount = port->ip_msgcount; - ip_unlock(port); - - *ownership = TRUE; - *receive_rights = TRUE; - *enabledp = enabled; - *num_msgs = (int) msgcount; - *backlog = (int) qlimit; - } else { - is_write_unlock(space); - - *ownership = FALSE; - *receive_rights = FALSE; - *enabledp = MACH_PORT_NULL; - *num_msgs = -1; - *backlog = 0; - } + ipc_port_clear_protected_payload(port); + ip_unlock(port); return KERN_SUCCESS; } - -/* - * Routine: port_set_allocate [kernel call] - * Purpose: - * Create a new port set, give rights to task, and - * return task's local name for the set. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Allocated a port set. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -port_set_allocate(space, namep) - ipc_space_t space; - mach_port_t *namep; -{ - ipc_pset_t pset; - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_pset_alloc(space, namep, &pset); - if (kr == KERN_SUCCESS) - ips_unlock(pset); - else if (kr != KERN_RESOURCE_SHORTAGE) - kr = KERN_INVALID_ARGUMENT; - - return kr; -} - -/* - * Routine: port_set_deallocate [kernel call] - * Purpose: - * Destroys the task's port set. If there are any - * receive rights in the set, they are removed. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Deallocated the port set. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote a port set. - */ - -kern_return_t -port_set_deallocate(space, name) - ipc_space_t space; - mach_port_t name; -{ - ipc_entry_t entry; - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) - return kr; - /* space is write-locked and active */ - - if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) { - is_write_unlock(space); - return KERN_INVALID_ARGUMENT; - } - - kr = ipc_right_destroy(space, name, entry); - /* space is unlocked */ - assert(kr == KERN_SUCCESS); - return kr; -} - -/* - * Routine: port_set_add [kernel call] - * Purpose: - * Moves receive rights into the port set. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Moved the receive right. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT port_name doesn't denote port rights. - * KERN_NOT_RECEIVER port_name doesn't denote receive right. - * KERN_INVALID_ARGUMENT set_name doesn't denote a port set. - * Additions: - * KERN_NOT_RECEIVER port_name denotes a send-once right. - * KERN_NOT_RECEIVER port_name denotes a dead name. - */ - -kern_return_t -port_set_add(space, set_name, port_name) - ipc_space_t space; - mach_port_t set_name; - mach_port_t port_name; -{ - ipc_entry_t entry; - mach_port_type_t type; - mach_port_urefs_t urefs; - ipc_port_t port; - ipc_pset_t pset; - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_right_lookup_write(space, port_name, &entry); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; - /* space is write-locked and active */ - - /* use ipc_right_info to check for dead compat entries */ - - kr = ipc_right_info(space, port_name, entry, &type, &urefs); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; /* space is unlocked */ - - if ((type & MACH_PORT_TYPE_RECEIVE) == 0) { - is_write_unlock(space); - if (type & MACH_PORT_TYPE_PORT_OR_DEAD) - return KERN_NOT_RECEIVER; - else - return KERN_INVALID_ARGUMENT; - } - - is_write_to_read_lock(space); - port = (ipc_port_t) entry->ie_object; - assert(port != IP_NULL); - - entry = ipc_entry_lookup(space, set_name); - if ((entry == IE_NULL) || - ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0)) { - is_read_unlock(space); - return KERN_INVALID_ARGUMENT; - } - - pset = (ipc_pset_t) entry->ie_object; - assert(pset != IPS_NULL); - - kr = ipc_pset_move(space, port, pset); - /* space is unlocked */ - assert(kr == KERN_SUCCESS); - return kr; -} - -/* - * Routine: port_set_remove [kernel call] - * Purpose: - * Removes the receive rights from the set they are in. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Removed the receive right. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote a port right. - * KERN_NOT_RECEIVER Name denotes send rights, not receive. - * KERN_NOT_IN_SET Port isn't in a port set. - * Additions: - * KERN_NOT_RECEIVER Name denotes a send-once right. - * KERN_NOT_RECEIVER Name denotes a dead name. - */ - -kern_return_t -port_set_remove(space, name) - ipc_space_t space; - mach_port_t name; -{ - ipc_entry_t entry; - mach_port_type_t type; - mach_port_urefs_t urefs; - ipc_port_t port; - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; - /* space is write-locked and active */ - - /* use ipc_right_info to check for dead compat entries */ - - kr = ipc_right_info(space, name, entry, &type, &urefs); - if (kr != KERN_SUCCESS) - return KERN_INVALID_ARGUMENT; /* space is unlocked */ - - if ((type & (MACH_PORT_TYPE_RECEIVE)) == 0) { - is_write_unlock(space); - if (type & MACH_PORT_TYPE_PORT_OR_DEAD) - return KERN_NOT_RECEIVER; - else - return KERN_INVALID_ARGUMENT; - } - - is_write_to_read_lock(space); - port = (ipc_port_t) entry->ie_object; - assert(port != IP_NULL); - - kr = ipc_pset_move(space, port, IPS_NULL); - /* space is unlocked */ - return kr; -} - -/* - * Routine: port_set_status [kernel call] - * Purpose: - * Retrieve list of members of a port set. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Retrieved port set status. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote a port set. - * Additions: - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -port_set_status(space, name, members, membersCnt) - ipc_space_t space; - mach_port_t name; - mach_port_t **members; - mach_msg_type_number_t *membersCnt; -{ - kern_return_t kr; - - kr = mach_port_get_set_status(space, name, members, membersCnt); - if ((kr != KERN_SUCCESS) && (kr != KERN_RESOURCE_SHORTAGE)) - kr = KERN_INVALID_ARGUMENT; - - return kr; -} - -/* - * Routine: port_insert_send [kernel call] - * Purpose: - * Inserts send rights to a port into a task, - * at a given name. The name must not be in use. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Inserted send right. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Port is null or dead. - * KERN_INVALID_ARGUMENT Name is reserved. - * KERN_NAME_EXISTS Name already denotes a right. - * KERN_FAILURE Task already has rights for the port. - * Additions: - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -port_insert_send(space, port, name) - ipc_space_t space; - ipc_port_t port; - mach_port_t name; -{ - kern_return_t kr; - - if ((space == IS_NULL) || - !MACH_PORT_VALID(name) || - !IP_VALID(port)) - return KERN_INVALID_ARGUMENT; - - kr = ipc_object_copyout_name_compat(space, (ipc_object_t) port, - MACH_MSG_TYPE_PORT_SEND, name); - switch (kr) { - case KERN_SUCCESS: - case KERN_NAME_EXISTS: - case KERN_RESOURCE_SHORTAGE: - break; - - case KERN_RIGHT_EXISTS: - kr = KERN_FAILURE; - break; - - default: - kr = KERN_INVALID_ARGUMENT; - break; - } - - return kr; -} - -/* - * Routine: port_extract_send [kernel call] - * Purpose: - * Extracts send rights from "task"'s "his_name" port. - * The task is left with no rights for the port. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Extracted send right. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote pure send rights. - */ - -kern_return_t -port_extract_send(space, name, portp) - ipc_space_t space; - mach_port_t name; - ipc_port_t *portp; -{ - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_object_copyin_compat(space, name, - MSG_TYPE_PORT, TRUE, - (ipc_object_t *) portp); - if (kr != KERN_SUCCESS) - kr = KERN_INVALID_ARGUMENT; - - return kr; -} - -/* - * Routine: port_insert_receive [kernel call] - * Purpose: - * Inserts receive/ownership rights to a port into a task, - * at a given name. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Inserted receive right. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Port is null. (Can't be dead.) - * KERN_INVALID_ARGUMENT Name is reserved. - * KERN_NAME_EXISTS Name already denotes a right. - * KERN_FAILURE Task already has rights for the port. - * Additions: - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -port_insert_receive(space, port, name) - ipc_space_t space; - ipc_port_t port; - mach_port_t name; -{ - kern_return_t kr; - - if ((space == IS_NULL) || - !MACH_PORT_VALID(name) || - !IP_VALID(port)) - return KERN_INVALID_ARGUMENT; - - kr = ipc_object_copyout_name_compat(space, (ipc_object_t) port, - MACH_MSG_TYPE_PORT_RECEIVE, name); - switch (kr) { - case KERN_SUCCESS: - case KERN_NAME_EXISTS: - case KERN_RESOURCE_SHORTAGE: - break; - - case KERN_RIGHT_EXISTS: - kr = KERN_FAILURE; - break; - - default: - kr = KERN_INVALID_ARGUMENT; - break; - } - - return kr; -} - -/* - * Routine: port_extract_receive [kernel call] - * Purpose: - * Extracts receive/ownership rights - * from "task"'s "his_name" port. - * - * The task is left with no rights for the port. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Extracted receive right. - * KERN_INVALID_ARGUMENT Task is null. - * KERN_INVALID_ARGUMENT Task is not active. - * KERN_INVALID_ARGUMENT Name doesn't denote receive rights. - */ - -kern_return_t -port_extract_receive(space, name, portp) - ipc_space_t space; - mach_port_t name; - ipc_port_t *portp; -{ - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_ARGUMENT; - - kr = ipc_object_copyin_compat(space, name, - MSG_TYPE_PORT_ALL, TRUE, - (ipc_object_t *) portp); - if (kr != KERN_SUCCESS) - kr = KERN_INVALID_ARGUMENT; - - return kr; -} - -#endif /* MACH_IPC_COMPAT */