static void kvp_send_key(struct work_struct *dummy) { struct cn_msg *msg; 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; msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC); if (!msg) return; msg->id.idx = CN_KVP_IDX; msg->id.val = CN_KVP_VAL; message = (struct hv_kvp_msg *)msg->data; 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; } msg->len = sizeof(struct hv_kvp_msg); cn_netlink_send(msg, 0, GFP_ATOMIC); kfree(msg); return; }
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; }