+mach_msg_descriptor_t *
+ipc_kmsg_copyout_port_descriptor(mach_msg_descriptor_t *dsc,
+ mach_msg_descriptor_t *user_dsc,
+ ipc_space_t space,
+ kern_return_t *mr);
+mach_msg_descriptor_t *
+ipc_kmsg_copyout_port_descriptor(mach_msg_descriptor_t *dsc,
+ mach_msg_descriptor_t *dest_dsc,
+ ipc_space_t space,
+ kern_return_t *mr)
+{
+ mach_port_t port;
+ mach_port_name_t name;
+ mach_msg_type_name_t disp;
+
+
+ /* Copyout port right carried in the message */
+ port = dsc->port.name;
+ disp = dsc->port.disposition;
+ *mr |= ipc_kmsg_copyout_object(space,
+ (ipc_object_t)port,
+ disp,
+ &name);
+
+ if(current_task() == kernel_task)
+ {
+ mach_msg_port_descriptor_t *user_dsc = (typeof(user_dsc))dest_dsc;
+ user_dsc--; // point to the start of this port descriptor
+ bzero((void *)user_dsc, sizeof(*user_dsc));
+ user_dsc->name = CAST_MACH_NAME_TO_PORT(name);
+ user_dsc->disposition = disp;
+ user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
+ dest_dsc = (typeof(dest_dsc))user_dsc;
+ } else {
+ mach_msg_legacy_port_descriptor_t *user_dsc = (typeof(user_dsc))dest_dsc;
+ user_dsc--; // point to the start of this port descriptor
+ bzero((void *)user_dsc, sizeof(*user_dsc));
+ user_dsc->name = CAST_MACH_PORT_TO_NAME(name);
+ user_dsc->disposition = disp;
+ user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
+ dest_dsc = (typeof(dest_dsc))user_dsc;
+ }
+
+ return (mach_msg_descriptor_t *)dest_dsc;
+}
+
+mach_msg_descriptor_t *
+ipc_kmsg_copyout_ool_descriptor(mach_msg_ool_descriptor_t *dsc, mach_msg_descriptor_t *user_dsc, int is_64bit, vm_map_t map, mach_msg_return_t *mr);
+mach_msg_descriptor_t *
+ipc_kmsg_copyout_ool_descriptor(mach_msg_ool_descriptor_t *dsc, mach_msg_descriptor_t *user_dsc, int is_64bit, vm_map_t map, mach_msg_return_t *mr)
+{
+ vm_map_copy_t copy;
+ vm_map_address_t rcv_addr;
+ mach_msg_copy_options_t copy_options;
+ vm_map_size_t size;
+ mach_msg_descriptor_type_t dsc_type;
+
+ //SKIP_PORT_DESCRIPTORS(saddr, sdsc_count);
+
+ copy = (vm_map_copy_t)dsc->address;
+ size = (vm_map_size_t)dsc->size;
+ copy_options = dsc->copy;
+ assert(copy_options != MACH_MSG_KALLOC_COPY_T);
+ dsc_type = dsc->type;
+
+ if (copy != VM_MAP_COPY_NULL) {
+ kern_return_t kr;
+
+ rcv_addr = 0;
+ if (vm_map_copy_validate_size(map, copy, &size) == FALSE)
+ panic("Inconsistent OOL/copyout size on %p: expected %d, got %lld @%p",
+ dsc, dsc->size, (unsigned long long)copy->size, copy);
+ kr = vm_map_copyout_size(map, &rcv_addr, copy, size);
+ if (kr != KERN_SUCCESS) {
+ if (kr == KERN_RESOURCE_SHORTAGE)
+ *mr |= MACH_MSG_VM_KERNEL;
+ else
+ *mr |= MACH_MSG_VM_SPACE;
+ vm_map_copy_discard(copy);
+ rcv_addr = 0;
+ size = 0;
+ }
+ } else {
+ rcv_addr = 0;
+ size = 0;
+ }
+
+ /*
+ * Now update the descriptor as the user would see it.
+ * This may require expanding the descriptor to the user
+ * visible size. There is already space allocated for
+ * this in what naddr points to.
+ */
+ if(current_task() == kernel_task)
+ {
+ mach_msg_ool_descriptor_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
+ user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
+
+ user_ool_dsc->address = (void *)(uintptr_t)rcv_addr;
+ user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
+ TRUE : FALSE;
+ user_ool_dsc->copy = copy_options;
+ user_ool_dsc->type = dsc_type;
+ user_ool_dsc->size = (mach_msg_size_t)size;
+
+ user_dsc = (typeof(user_dsc))user_ool_dsc;
+ } else if (is_64bit) {
+ mach_msg_ool_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
+ user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
+
+ user_ool_dsc->address = rcv_addr;
+ user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
+ TRUE : FALSE;
+ user_ool_dsc->copy = copy_options;
+ user_ool_dsc->type = dsc_type;
+ user_ool_dsc->size = (mach_msg_size_t)size;
+
+ user_dsc = (typeof(user_dsc))user_ool_dsc;
+ } else {
+ mach_msg_ool_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
+ user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
+
+ user_ool_dsc->address = CAST_DOWN_EXPLICIT(uint32_t, rcv_addr);
+ user_ool_dsc->size = (mach_msg_size_t)size;
+ user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
+ TRUE : FALSE;
+ user_ool_dsc->copy = copy_options;
+ user_ool_dsc->type = dsc_type;
+
+ user_dsc = (typeof(user_dsc))user_ool_dsc;
+ }
+ return user_dsc;
+}
+
+mach_msg_descriptor_t *
+ipc_kmsg_copyout_ool_ports_descriptor(mach_msg_ool_ports_descriptor_t *dsc,
+ mach_msg_descriptor_t *user_dsc,
+ int is_64bit,
+ vm_map_t map,
+ ipc_space_t space,
+ ipc_kmsg_t kmsg,
+ mach_msg_return_t *mr);
+mach_msg_descriptor_t *
+ipc_kmsg_copyout_ool_ports_descriptor(mach_msg_ool_ports_descriptor_t *dsc,
+ mach_msg_descriptor_t *user_dsc,
+ int is_64bit,
+ vm_map_t map,
+ ipc_space_t space,
+ ipc_kmsg_t kmsg,
+ mach_msg_return_t *mr)
+{
+ mach_vm_offset_t rcv_addr = 0;
+ mach_msg_type_name_t disp;
+ mach_msg_type_number_t count, i;
+ vm_size_t ports_length, names_length;
+
+ mach_msg_copy_options_t copy_options = MACH_MSG_VIRTUAL_COPY;
+
+ //SKIP_PORT_DESCRIPTORS(saddr, sdsc_count);
+
+ count = dsc->count;
+ disp = dsc->disposition;
+ ports_length = count * sizeof(mach_port_t);
+ names_length = count * sizeof(mach_port_name_t);
+
+ if (ports_length != 0 && dsc->address != 0) {
+
+ /*
+ * Check to see if there is an overwrite descriptor
+ * specified in the scatter list for this ool data.
+ * The descriptor has already been verified.
+ */
+#if 0
+ if (saddr != MACH_MSG_DESCRIPTOR_NULL) {
+ if (differs) {
+ OTHER_OOL_DESCRIPTOR *scatter_dsc;
+
+ scatter_dsc = (OTHER_OOL_DESCRIPTOR *)saddr;
+ rcv_addr = (mach_vm_offset_t) scatter_dsc->address;
+ copy_options = scatter_dsc->copy;
+ } else {
+ mach_msg_ool_descriptor_t *scatter_dsc;
+
+ scatter_dsc = &saddr->out_of_line;
+ rcv_addr = CAST_USER_ADDR_T(scatter_dsc->address);
+ copy_options = scatter_dsc->copy;
+ }
+ INCREMENT_SCATTER(saddr, sdsc_count, differs);
+ }
+#endif
+
+ if (copy_options == MACH_MSG_VIRTUAL_COPY) {
+ /*
+ * Dynamically allocate the region
+ */
+ vm_tag_t tag;
+ if (vm_kernel_map_is_kernel(map)) tag = VM_KERN_MEMORY_IPC;
+ else tag = VM_MEMORY_MACH_MSG;
+
+ kern_return_t kr;
+ if ((kr = mach_vm_allocate_kernel(map, &rcv_addr,
+ (mach_vm_size_t)names_length,
+ VM_FLAGS_ANYWHERE, tag)) != KERN_SUCCESS) {
+ ipc_kmsg_clean_body(kmsg, 1, (mach_msg_descriptor_t *)dsc);
+ rcv_addr = 0;
+
+ if (kr == KERN_RESOURCE_SHORTAGE){
+ *mr |= MACH_MSG_VM_KERNEL;
+ } else {
+ *mr |= MACH_MSG_VM_SPACE;
+ }
+ }
+ }
+
+ /*
+ * Handle the port rights and copy out the names
+ * for those rights out to user-space.
+ */
+ if (rcv_addr != 0) {
+ mach_port_t *objects = (mach_port_t *) dsc->address;
+ mach_port_name_t *names = (mach_port_name_t *) dsc->address;
+
+ /* copyout port rights carried in the message */
+
+ for ( i = 0; i < count ; i++) {
+ ipc_object_t object = (ipc_object_t)objects[i];
+
+ *mr |= ipc_kmsg_copyout_object(space, object,
+ disp, &names[i]);
+ }
+
+ /* copyout to memory allocated above */
+ void *data = dsc->address;
+ if (copyoutmap(map, data, rcv_addr, names_length) != KERN_SUCCESS)
+ *mr |= MACH_MSG_VM_SPACE;
+ kfree(data, ports_length);
+ }
+ } else {
+ rcv_addr = 0;
+ }
+
+ /*
+ * Now update the descriptor based on the information
+ * calculated above.
+ */
+ if(current_task() == kernel_task) {
+ mach_msg_ool_ports_descriptor_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
+ user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
+
+ user_ool_dsc->address = (void *)(uintptr_t)rcv_addr;
+ user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
+ TRUE : FALSE;
+ user_ool_dsc->copy = copy_options;
+ user_ool_dsc->disposition = disp;
+ user_ool_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
+ user_ool_dsc->count = count;
+
+ user_dsc = (typeof(user_dsc))user_ool_dsc;
+ } if (is_64bit) {
+ mach_msg_ool_ports_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
+ user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
+
+ user_ool_dsc->address = rcv_addr;
+ user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
+ TRUE : FALSE;
+ user_ool_dsc->copy = copy_options;
+ user_ool_dsc->disposition = disp;
+ user_ool_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
+ user_ool_dsc->count = count;
+
+ user_dsc = (typeof(user_dsc))user_ool_dsc;
+ } else {
+ mach_msg_ool_ports_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
+ user_ool_dsc--;
+ bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
+
+ user_ool_dsc->address = CAST_DOWN_EXPLICIT(uint32_t, rcv_addr);
+ user_ool_dsc->count = count;
+ user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
+ TRUE : FALSE;
+ user_ool_dsc->copy = copy_options;
+ user_ool_dsc->disposition = disp;
+ user_ool_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
+
+ user_dsc = (typeof(user_dsc))user_ool_dsc;
+ }
+ return user_dsc;
+}
+