-/*
- * Routine: ipc_kmsg_copyin_scatter
- * Purpose:
- * allocate and copyin a scatter list
- * Algorithm:
- * The gather (kmsg) is valid since it has been copied in.
- * Gather list descriptors are sequentially paired with scatter
- * list descriptors, with port descriptors in either list ignored.
- * Descriptors are consistent if the type fileds match and size
- * of the scatter descriptor is less than or equal to the
- * size of the gather descriptor. A MACH_MSG_ALLOCATE copy
- * strategy in a scatter descriptor matches any size in the
- * corresponding gather descriptor assuming they are the same type.
- * Either list may be larger than the other. During the
- * subsequent copy out, excess scatter descriptors are ignored
- * and excess gather descriptors default to dynamic allocation.
- *
- * In the case of a size error, the scatter list is released.
- * Conditions:
- * Nothing locked.
- * Returns:
- * the allocated message body containing the scatter list.
- */
-
-mach_msg_body_t *
-ipc_kmsg_get_scatter(
- mach_vm_address_t msg_addr,
- mach_msg_size_t slist_size,
- ipc_kmsg_t kmsg)
-{
- mach_msg_body_t *slist;
- mach_msg_body_t *body;
- mach_msg_descriptor_t *gstart, *gend;
- mach_msg_descriptor_t *sstart, *send;
-
-#if defined(__LP64__)
- panic("ipc_kmsg_get_scatter called!");
-#endif
-
- if (slist_size < sizeof(mach_msg_base_t))
- return MACH_MSG_BODY_NULL;
-
- slist_size -= (mach_msg_size_t)sizeof(mach_msg_header_t);
- slist = (mach_msg_body_t *)kalloc(slist_size);
- if (slist == MACH_MSG_BODY_NULL)
- return slist;
-
- if (copyin(msg_addr + sizeof(mach_msg_header_t), (char *)slist, slist_size)) {
- kfree(slist, slist_size);
- return MACH_MSG_BODY_NULL;
- }
-
- if ((slist->msgh_descriptor_count* sizeof(mach_msg_descriptor_t)
- + sizeof(mach_msg_size_t)) > slist_size) {
- kfree(slist, slist_size);
- return MACH_MSG_BODY_NULL;
- }
-
- body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
- gstart = (mach_msg_descriptor_t *) (body + 1);
- gend = gstart + body->msgh_descriptor_count;
-
- sstart = (mach_msg_descriptor_t *) (slist + 1);
- send = sstart + slist->msgh_descriptor_count;
-
- while (gstart < gend) {
- mach_msg_descriptor_type_t g_type;
-
- /*
- * Skip port descriptors in gather list.
- */
- g_type = gstart->type.type;
-
- if (g_type != MACH_MSG_PORT_DESCRIPTOR) {
-
- /*
- * A scatter list with a 0 descriptor count is treated as an
- * automatic size mismatch.
- */
- if (slist->msgh_descriptor_count == 0) {
- kfree(slist, slist_size);
- return MACH_MSG_BODY_NULL;
- }
-
- /*
- * Skip port descriptors in scatter list.
- */
- while (sstart < send) {
- if (sstart->type.type != MACH_MSG_PORT_DESCRIPTOR)
- break;
- sstart++;
- }
-
- /*
- * No more scatter descriptors, we're done
- */
- if (sstart >= send) {
- break;
- }
-
- /*
- * Check type, copy and size fields
- */
- if (g_type == MACH_MSG_OOL_DESCRIPTOR ||
- g_type == MACH_MSG_OOL_VOLATILE_DESCRIPTOR) {
- if (sstart->type.type != MACH_MSG_OOL_DESCRIPTOR &&
- sstart->type.type != MACH_MSG_OOL_VOLATILE_DESCRIPTOR) {
- kfree(slist, slist_size);
- return MACH_MSG_BODY_NULL;
- }
- if (sstart->out_of_line.copy == MACH_MSG_OVERWRITE &&
- gstart->out_of_line.size > sstart->out_of_line.size) {
- kfree(slist, slist_size);
- return MACH_MSG_BODY_NULL;
- }
- }
- else {
- if (sstart->type.type != MACH_MSG_OOL_PORTS_DESCRIPTOR) {
- kfree(slist, slist_size);
- return MACH_MSG_BODY_NULL;
- }
- if (sstart->ool_ports.copy == MACH_MSG_OVERWRITE &&
- gstart->ool_ports.count > sstart->ool_ports.count) {
- kfree(slist, slist_size);
- return MACH_MSG_BODY_NULL;
- }
- }
- sstart++;
- }
- gstart++;
- }
- return slist;
-}
-
-
-/*
- * Routine: ipc_kmsg_free_scatter
- * Purpose:
- * Deallocate a scatter list. Since we actually allocated
- * a body without a header, and since the header was originally
- * accounted for in slist_size, we have to ajust it down
- * before freeing the scatter list.
- */
-void
-ipc_kmsg_free_scatter(
- mach_msg_body_t *slist,
- mach_msg_size_t slist_size)
-{
-#if defined(__LP64__)
- panic("%s called; halting!", __func__);
-#endif
-
- slist_size -= (mach_msg_size_t)sizeof(mach_msg_header_t);
- kfree(slist, slist_size);
-}
-
-