static int fcopy_handle_handshake(u32 version) { u32 our_ver = FCOPY_CURRENT_VERSION; switch (version) { case FCOPY_VERSION_0: /* Daemon doesn't expect us to reply */ dm_reg_value = version; break; case FCOPY_VERSION_1: /* Daemon expects us to reply with our own version */ if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), fcopy_register_done)) return -EFAULT; dm_reg_value = version; break; default: /* * For now we will fail the registration. * If and when we have multiple versions to * deal with, we will be backward compatible. * We will add this code when needed. */ return -EINVAL; } pr_debug("FCP: userspace daemon ver. %d connected\n", version); return 0; }
static void vss_send_op(struct work_struct *dummy) { int op = vss_transaction.msg->vss_hdr.operation; int rc; struct hv_vss_msg *vss_msg; /* The transaction state is wrong. */ if (vss_transaction.state != HVUTIL_HOSTMSG_RECEIVED) return; vss_msg = kzalloc(sizeof(*vss_msg), GFP_KERNEL); if (!vss_msg) return; vss_msg->vss_hdr.operation = op; vss_transaction.state = HVUTIL_USERSPACE_REQ; rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg)); if (rc) { pr_warn("VSS: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&vss_timeout_work)) { vss_respond_to_host(HV_E_FAIL); vss_transaction.state = HVUTIL_READY; } } kfree(vss_msg); return; }
static void vss_send_op(void) { int op = vss_transaction.msg->vss_hdr.operation; int rc; struct hv_vss_msg *vss_msg; /* The transaction state is wrong. */ if (vss_transaction.state != HVUTIL_HOSTMSG_RECEIVED) { pr_debug("VSS: Unexpected attempt to send to daemon\n"); return; } vss_msg = kzalloc(sizeof(*vss_msg), GFP_KERNEL); if (!vss_msg) return; vss_msg->vss_hdr.operation = op; vss_transaction.state = HVUTIL_USERSPACE_REQ; schedule_delayed_work(&vss_timeout_work, op == VSS_OP_FREEZE ? VSS_FREEZE_TIMEOUT * HZ : HV_UTIL_TIMEOUT * HZ); rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg), NULL); if (rc) { pr_warn("VSS: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&vss_timeout_work)) { vss_respond_to_host(HV_E_FAIL); vss_transaction.state = HVUTIL_READY; } } kfree(vss_msg); }
static int fcopy_handle_handshake(u32 version) { u32 our_ver = FCOPY_CURRENT_VERSION; switch (version) { case FCOPY_VERSION_0: /* Daemon doesn't expect us to reply */ dm_reg_value = version; break; case FCOPY_VERSION_1: /* Daemon expects us to reply with our own version */ if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) return -EFAULT; dm_reg_value = version; break; default: /* * For now we will fail the registration. * If and when we have multiple versions to * deal with, we will be backward compatible. * We will add this code when needed. */ return -EINVAL; } pr_debug("FCP: userspace daemon ver. %d registered\n", version); /* Forward state for hv_fcopy_onchannelcallback */ fcopy_transaction.state = HVUTIL_READY; hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); return 0; }
static void fcopy_send_data(struct work_struct *dummy) { struct hv_start_fcopy *smsg_out = NULL; int operation = fcopy_transaction.fcopy_msg->operation; struct hv_start_fcopy *smsg_in; void *out_src; int rc, out_len; /* * The strings sent from the host are encoded in * in utf16; convert it to utf8 strings. * The host assures us that the utf16 strings will not exceed * the max lengths specified. We will however, reserve room * for the string terminating character - in the utf16s_utf8s() * function we limit the size of the buffer where the converted * string is placed to W_MAX_PATH -1 to guarantee * that the strings can be properly terminated! */ switch (operation) { case START_FILE_COPY: out_len = sizeof(struct hv_start_fcopy); smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL); if (!smsg_out) return; smsg_out->hdr.operation = operation; smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg; utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH, UTF16_LITTLE_ENDIAN, (__u8 *)&smsg_out->file_name, W_MAX_PATH - 1); utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH, UTF16_LITTLE_ENDIAN, (__u8 *)&smsg_out->path_name, W_MAX_PATH - 1); smsg_out->copy_flags = smsg_in->copy_flags; smsg_out->file_size = smsg_in->file_size; out_src = smsg_out; break; default: out_src = fcopy_transaction.fcopy_msg; out_len = fcopy_transaction.recv_len; break; } fcopy_transaction.state = HVUTIL_USERSPACE_REQ; rc = hvutil_transport_send(hvt, out_src, out_len, NULL); if (rc) { pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&fcopy_timeout_work)) { fcopy_respond_to_host(HV_E_FAIL); fcopy_transaction.state = HVUTIL_READY; } } kfree(smsg_out); }
static void kvp_register(int reg_value) { struct hv_kvp_msg *kvp_msg; char *version; kvp_msg = kzalloc(sizeof(*kvp_msg), GFP_KERNEL); if (kvp_msg) { version = kvp_msg->body.kvp_register.version; kvp_msg->kvp_hdr.operation = reg_value; strcpy(version, HV_DRV_VERSION); hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg)); kfree(kvp_msg); } }
static int vss_handle_handshake(struct hv_vss_msg *vss_msg) { u32 our_ver = VSS_OP_REGISTER1; switch (vss_msg->vss_hdr.operation) { case VSS_OP_REGISTER: /* Daemon doesn't expect us to reply */ dm_reg_value = VSS_OP_REGISTER; break; case VSS_OP_REGISTER1: /* Daemon expects us to reply with our own version*/ if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) return -EFAULT; dm_reg_value = VSS_OP_REGISTER1; break; default: return -EINVAL; } hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value); return 0; }
static void kvp_send_key(struct work_struct *dummy) { struct hv_kvp_msg *message; struct hv_kvp_msg *in_msg; __u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation; __u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool; __u32 val32; __u64 val64; int rc; /* The transaction state is wrong. */ if (kvp_transaction.state != HVUTIL_HOSTMSG_RECEIVED) return; message = kzalloc(sizeof(*message), GFP_KERNEL); if (!message) return; message->kvp_hdr.operation = operation; message->kvp_hdr.pool = pool; in_msg = kvp_transaction.kvp_msg; /* * The key/value strings sent from the host are encoded in * in utf16; convert it to utf8 strings. * The host assures us that the utf16 strings will not exceed * the max lengths specified. We will however, reserve room * for the string terminating character - in the utf16s_utf8s() * function we limit the size of the buffer where the converted * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee * that the strings can be properly terminated! */ switch (message->kvp_hdr.operation) { case KVP_OP_SET_IP_INFO: process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO); break; case KVP_OP_GET_IP_INFO: process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO); break; case KVP_OP_SET: switch (in_msg->body.kvp_set.data.value_type) { case REG_SZ: /* * The value is a string - utf16 encoding. */ message->body.kvp_set.data.value_size = utf16s_to_utf8s( (wchar_t *)in_msg->body.kvp_set.data.value, in_msg->body.kvp_set.data.value_size, UTF16_LITTLE_ENDIAN, message->body.kvp_set.data.value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1; break; case REG_U32: /* * The value is a 32 bit scalar. * We save this as a utf8 string. */ val32 = in_msg->body.kvp_set.data.value_u32; message->body.kvp_set.data.value_size = sprintf(message->body.kvp_set.data.value, "%d", val32) + 1; break; case REG_U64: /* * The value is a 64 bit scalar. * We save this as a utf8 string. */ val64 = in_msg->body.kvp_set.data.value_u64; message->body.kvp_set.data.value_size = sprintf(message->body.kvp_set.data.value, "%llu", val64) + 1; break; } case KVP_OP_GET: message->body.kvp_set.data.key_size = utf16s_to_utf8s( (wchar_t *)in_msg->body.kvp_set.data.key, in_msg->body.kvp_set.data.key_size, UTF16_LITTLE_ENDIAN, message->body.kvp_set.data.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; break; case KVP_OP_DELETE: message->body.kvp_delete.key_size = utf16s_to_utf8s( (wchar_t *)in_msg->body.kvp_delete.key, in_msg->body.kvp_delete.key_size, UTF16_LITTLE_ENDIAN, message->body.kvp_delete.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; break; case KVP_OP_ENUMERATE: message->body.kvp_enum_data.index = in_msg->body.kvp_enum_data.index; break; } kvp_transaction.state = HVUTIL_USERSPACE_REQ; rc = hvutil_transport_send(hvt, message, sizeof(*message)); if (rc) { pr_debug("KVP: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&kvp_timeout_work)) { kvp_respond_to_host(message, HV_E_FAIL); kvp_transaction.state = HVUTIL_READY; } } kfree(message); return; }