162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * An implementation of key value pair (KVP) functionality for Linux.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010, Novell, Inc.
662306a36Sopenharmony_ci * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it
962306a36Sopenharmony_ci * under the terms of the GNU General Public License version 2 as published
1062306a36Sopenharmony_ci * by the Free Software Foundation.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
1362306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
1462306a36Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
1562306a36Sopenharmony_ci * NON INFRINGEMENT.  See the GNU General Public License for more
1662306a36Sopenharmony_ci * details.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License
1962306a36Sopenharmony_ci * along with this program; if not, write to the Free Software
2062306a36Sopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/net.h>
2662306a36Sopenharmony_ci#include <linux/nls.h>
2762306a36Sopenharmony_ci#include <linux/connector.h>
2862306a36Sopenharmony_ci#include <linux/workqueue.h>
2962306a36Sopenharmony_ci#include <linux/hyperv.h>
3062306a36Sopenharmony_ci#include <asm/hyperv-tlfs.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "hyperv_vmbus.h"
3362306a36Sopenharmony_ci#include "hv_utils_transport.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci#define WS2008_SRV_MAJOR	1
3962306a36Sopenharmony_ci#define WS2008_SRV_MINOR	0
4062306a36Sopenharmony_ci#define WS2008_SRV_VERSION     (WS2008_SRV_MAJOR << 16 | WS2008_SRV_MINOR)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define WIN7_SRV_MAJOR   3
4362306a36Sopenharmony_ci#define WIN7_SRV_MINOR   0
4462306a36Sopenharmony_ci#define WIN7_SRV_VERSION     (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define WIN8_SRV_MAJOR   4
4762306a36Sopenharmony_ci#define WIN8_SRV_MINOR   0
4862306a36Sopenharmony_ci#define WIN8_SRV_VERSION     (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define KVP_VER_COUNT 3
5162306a36Sopenharmony_cistatic const int kvp_versions[] = {
5262306a36Sopenharmony_ci	WIN8_SRV_VERSION,
5362306a36Sopenharmony_ci	WIN7_SRV_VERSION,
5462306a36Sopenharmony_ci	WS2008_SRV_VERSION
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define FW_VER_COUNT 2
5862306a36Sopenharmony_cistatic const int fw_versions[] = {
5962306a36Sopenharmony_ci	UTIL_FW_VERSION,
6062306a36Sopenharmony_ci	UTIL_WS2K8_FW_VERSION
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * Global state maintained for transaction that is being processed. For a class
6562306a36Sopenharmony_ci * of integration services, including the "KVP service", the specified protocol
6662306a36Sopenharmony_ci * is a "request/response" protocol which means that there can only be single
6762306a36Sopenharmony_ci * outstanding transaction from the host at any given point in time. We use
6862306a36Sopenharmony_ci * this to simplify memory management in this driver - we cache and process
6962306a36Sopenharmony_ci * only one message at a time.
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * While the request/response protocol is guaranteed by the host, we further
7262306a36Sopenharmony_ci * ensure this by serializing packet processing in this driver - we do not
7362306a36Sopenharmony_ci * read additional packets from the VMBUS until the current packet is fully
7462306a36Sopenharmony_ci * handled.
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic struct {
7862306a36Sopenharmony_ci	int state;   /* hvutil_device_state */
7962306a36Sopenharmony_ci	int recv_len; /* number of bytes received. */
8062306a36Sopenharmony_ci	struct hv_kvp_msg  *kvp_msg; /* current message */
8162306a36Sopenharmony_ci	struct vmbus_channel *recv_channel; /* chn we got the request */
8262306a36Sopenharmony_ci	u64 recv_req_id; /* request ID. */
8362306a36Sopenharmony_ci} kvp_transaction;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci * This state maintains the version number registered by the daemon.
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistatic int dm_reg_value;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic void kvp_send_key(struct work_struct *dummy);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void kvp_respond_to_host(struct hv_kvp_msg *msg, int error);
9462306a36Sopenharmony_cistatic void kvp_timeout_func(struct work_struct *dummy);
9562306a36Sopenharmony_cistatic void kvp_host_handshake_func(struct work_struct *dummy);
9662306a36Sopenharmony_cistatic void kvp_register(int);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic DECLARE_DELAYED_WORK(kvp_timeout_work, kvp_timeout_func);
9962306a36Sopenharmony_cistatic DECLARE_DELAYED_WORK(kvp_host_handshake_work, kvp_host_handshake_func);
10062306a36Sopenharmony_cistatic DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic const char kvp_devname[] = "vmbus/hv_kvp";
10362306a36Sopenharmony_cistatic u8 *recv_buffer;
10462306a36Sopenharmony_cistatic struct hvutil_transport *hvt;
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci * Register the kernel component with the user-level daemon.
10762306a36Sopenharmony_ci * As part of this registration, pass the LIC version number.
10862306a36Sopenharmony_ci * This number has no meaning, it satisfies the registration protocol.
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_ci#define HV_DRV_VERSION           "3.1"
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void kvp_poll_wrapper(void *channel)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	/* Transaction is finished, reset the state here to avoid races. */
11562306a36Sopenharmony_ci	kvp_transaction.state = HVUTIL_READY;
11662306a36Sopenharmony_ci	tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void kvp_register_done(void)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	/*
12262306a36Sopenharmony_ci	 * If we're still negotiating with the host cancel the timeout
12362306a36Sopenharmony_ci	 * work to not poll the channel twice.
12462306a36Sopenharmony_ci	 */
12562306a36Sopenharmony_ci	pr_debug("KVP: userspace daemon registered\n");
12662306a36Sopenharmony_ci	cancel_delayed_work_sync(&kvp_host_handshake_work);
12762306a36Sopenharmony_ci	hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void
13162306a36Sopenharmony_cikvp_register(int reg_value)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	struct hv_kvp_msg *kvp_msg;
13562306a36Sopenharmony_ci	char *version;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	kvp_msg = kzalloc(sizeof(*kvp_msg), GFP_KERNEL);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (kvp_msg) {
14062306a36Sopenharmony_ci		version = kvp_msg->body.kvp_register.version;
14162306a36Sopenharmony_ci		kvp_msg->kvp_hdr.operation = reg_value;
14262306a36Sopenharmony_ci		strcpy(version, HV_DRV_VERSION);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
14562306a36Sopenharmony_ci				      kvp_register_done);
14662306a36Sopenharmony_ci		kfree(kvp_msg);
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void kvp_timeout_func(struct work_struct *dummy)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	/*
15362306a36Sopenharmony_ci	 * If the timer fires, the user-mode component has not responded;
15462306a36Sopenharmony_ci	 * process the pending transaction.
15562306a36Sopenharmony_ci	 */
15662306a36Sopenharmony_ci	kvp_respond_to_host(NULL, HV_E_FAIL);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic void kvp_host_handshake_func(struct work_struct *dummy)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	tasklet_schedule(&kvp_transaction.recv_channel->callback_event);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int kvp_handle_handshake(struct hv_kvp_msg *msg)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	switch (msg->kvp_hdr.operation) {
16962306a36Sopenharmony_ci	case KVP_OP_REGISTER:
17062306a36Sopenharmony_ci		dm_reg_value = KVP_OP_REGISTER;
17162306a36Sopenharmony_ci		pr_info("KVP: IP injection functionality not available\n");
17262306a36Sopenharmony_ci		pr_info("KVP: Upgrade the KVP daemon\n");
17362306a36Sopenharmony_ci		break;
17462306a36Sopenharmony_ci	case KVP_OP_REGISTER1:
17562306a36Sopenharmony_ci		dm_reg_value = KVP_OP_REGISTER1;
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	default:
17862306a36Sopenharmony_ci		pr_info("KVP: incompatible daemon\n");
17962306a36Sopenharmony_ci		pr_info("KVP: KVP version: %d, Daemon version: %d\n",
18062306a36Sopenharmony_ci			KVP_OP_REGISTER1, msg->kvp_hdr.operation);
18162306a36Sopenharmony_ci		return -EINVAL;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/*
18562306a36Sopenharmony_ci	 * We have a compatible daemon; complete the handshake.
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci	pr_debug("KVP: userspace daemon ver. %d connected\n",
18862306a36Sopenharmony_ci		 msg->kvp_hdr.operation);
18962306a36Sopenharmony_ci	kvp_register(dm_reg_value);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return 0;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/*
19662306a36Sopenharmony_ci * Callback when data is received from user mode.
19762306a36Sopenharmony_ci */
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int kvp_on_msg(void *msg, int len)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct hv_kvp_msg *message = (struct hv_kvp_msg *)msg;
20262306a36Sopenharmony_ci	struct hv_kvp_msg_enumerate *data;
20362306a36Sopenharmony_ci	int	error = 0;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	if (len < sizeof(*message))
20662306a36Sopenharmony_ci		return -EINVAL;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/*
20962306a36Sopenharmony_ci	 * If we are negotiating the version information
21062306a36Sopenharmony_ci	 * with the daemon; handle that first.
21162306a36Sopenharmony_ci	 */
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (kvp_transaction.state < HVUTIL_READY) {
21462306a36Sopenharmony_ci		return kvp_handle_handshake(message);
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/* We didn't send anything to userspace so the reply is spurious */
21862306a36Sopenharmony_ci	if (kvp_transaction.state < HVUTIL_USERSPACE_REQ)
21962306a36Sopenharmony_ci		return -EINVAL;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	kvp_transaction.state = HVUTIL_USERSPACE_RECV;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/*
22462306a36Sopenharmony_ci	 * Based on the version of the daemon, we propagate errors from the
22562306a36Sopenharmony_ci	 * daemon differently.
22662306a36Sopenharmony_ci	 */
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	data = &message->body.kvp_enum_data;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	switch (dm_reg_value) {
23162306a36Sopenharmony_ci	case KVP_OP_REGISTER:
23262306a36Sopenharmony_ci		/*
23362306a36Sopenharmony_ci		 * Null string is used to pass back error condition.
23462306a36Sopenharmony_ci		 */
23562306a36Sopenharmony_ci		if (data->data.key[0] == 0)
23662306a36Sopenharmony_ci			error = HV_S_CONT;
23762306a36Sopenharmony_ci		break;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	case KVP_OP_REGISTER1:
24062306a36Sopenharmony_ci		/*
24162306a36Sopenharmony_ci		 * We use the message header information from
24262306a36Sopenharmony_ci		 * the user level daemon to transmit errors.
24362306a36Sopenharmony_ci		 */
24462306a36Sopenharmony_ci		error = message->error;
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * Complete the transaction by forwarding the key value
25062306a36Sopenharmony_ci	 * to the host. But first, cancel the timeout.
25162306a36Sopenharmony_ci	 */
25262306a36Sopenharmony_ci	if (cancel_delayed_work_sync(&kvp_timeout_work)) {
25362306a36Sopenharmony_ci		kvp_respond_to_host(message, error);
25462306a36Sopenharmony_ci		hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic int process_ob_ipinfo(void *in_msg, void *out_msg, int op)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct hv_kvp_msg *in = in_msg;
26462306a36Sopenharmony_ci	struct hv_kvp_ip_msg *out = out_msg;
26562306a36Sopenharmony_ci	int len;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	switch (op) {
26862306a36Sopenharmony_ci	case KVP_OP_GET_IP_INFO:
26962306a36Sopenharmony_ci		/*
27062306a36Sopenharmony_ci		 * Transform all parameters into utf16 encoding.
27162306a36Sopenharmony_ci		 */
27262306a36Sopenharmony_ci		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.ip_addr,
27362306a36Sopenharmony_ci				strlen((char *)in->body.kvp_ip_val.ip_addr),
27462306a36Sopenharmony_ci				UTF16_HOST_ENDIAN,
27562306a36Sopenharmony_ci				(wchar_t *)out->kvp_ip_val.ip_addr,
27662306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE);
27762306a36Sopenharmony_ci		if (len < 0)
27862306a36Sopenharmony_ci			return len;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.sub_net,
28162306a36Sopenharmony_ci				strlen((char *)in->body.kvp_ip_val.sub_net),
28262306a36Sopenharmony_ci				UTF16_HOST_ENDIAN,
28362306a36Sopenharmony_ci				(wchar_t *)out->kvp_ip_val.sub_net,
28462306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE);
28562306a36Sopenharmony_ci		if (len < 0)
28662306a36Sopenharmony_ci			return len;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.gate_way,
28962306a36Sopenharmony_ci				strlen((char *)in->body.kvp_ip_val.gate_way),
29062306a36Sopenharmony_ci				UTF16_HOST_ENDIAN,
29162306a36Sopenharmony_ci				(wchar_t *)out->kvp_ip_val.gate_way,
29262306a36Sopenharmony_ci				MAX_GATEWAY_SIZE);
29362306a36Sopenharmony_ci		if (len < 0)
29462306a36Sopenharmony_ci			return len;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.dns_addr,
29762306a36Sopenharmony_ci				strlen((char *)in->body.kvp_ip_val.dns_addr),
29862306a36Sopenharmony_ci				UTF16_HOST_ENDIAN,
29962306a36Sopenharmony_ci				(wchar_t *)out->kvp_ip_val.dns_addr,
30062306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE);
30162306a36Sopenharmony_ci		if (len < 0)
30262306a36Sopenharmony_ci			return len;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.adapter_id,
30562306a36Sopenharmony_ci				strlen((char *)in->body.kvp_ip_val.adapter_id),
30662306a36Sopenharmony_ci				UTF16_HOST_ENDIAN,
30762306a36Sopenharmony_ci				(wchar_t *)out->kvp_ip_val.adapter_id,
30862306a36Sopenharmony_ci				MAX_ADAPTER_ID_SIZE);
30962306a36Sopenharmony_ci		if (len < 0)
31062306a36Sopenharmony_ci			return len;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		out->kvp_ip_val.dhcp_enabled =
31362306a36Sopenharmony_ci			in->body.kvp_ip_val.dhcp_enabled;
31462306a36Sopenharmony_ci		out->kvp_ip_val.addr_family =
31562306a36Sopenharmony_ci			in->body.kvp_ip_val.addr_family;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return 0;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void process_ib_ipinfo(void *in_msg, void *out_msg, int op)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct hv_kvp_ip_msg *in = in_msg;
32462306a36Sopenharmony_ci	struct hv_kvp_msg *out = out_msg;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	switch (op) {
32762306a36Sopenharmony_ci	case KVP_OP_SET_IP_INFO:
32862306a36Sopenharmony_ci		/*
32962306a36Sopenharmony_ci		 * Transform all parameters into utf8 encoding.
33062306a36Sopenharmony_ci		 */
33162306a36Sopenharmony_ci		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.ip_addr,
33262306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE,
33362306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
33462306a36Sopenharmony_ci				(__u8 *)out->body.kvp_ip_val.ip_addr,
33562306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.sub_net,
33862306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE,
33962306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
34062306a36Sopenharmony_ci				(__u8 *)out->body.kvp_ip_val.sub_net,
34162306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.gate_way,
34462306a36Sopenharmony_ci				MAX_GATEWAY_SIZE,
34562306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
34662306a36Sopenharmony_ci				(__u8 *)out->body.kvp_ip_val.gate_way,
34762306a36Sopenharmony_ci				MAX_GATEWAY_SIZE);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.dns_addr,
35062306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE,
35162306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
35262306a36Sopenharmony_ci				(__u8 *)out->body.kvp_ip_val.dns_addr,
35362306a36Sopenharmony_ci				MAX_IP_ADDR_SIZE);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		fallthrough;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	case KVP_OP_GET_IP_INFO:
36062306a36Sopenharmony_ci		utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id,
36162306a36Sopenharmony_ci				MAX_ADAPTER_ID_SIZE,
36262306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
36362306a36Sopenharmony_ci				(__u8 *)out->body.kvp_ip_val.adapter_id,
36462306a36Sopenharmony_ci				MAX_ADAPTER_ID_SIZE);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		out->body.kvp_ip_val.addr_family = in->kvp_ip_val.addr_family;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void
37462306a36Sopenharmony_cikvp_send_key(struct work_struct *dummy)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct hv_kvp_msg *message;
37762306a36Sopenharmony_ci	struct hv_kvp_msg *in_msg;
37862306a36Sopenharmony_ci	__u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation;
37962306a36Sopenharmony_ci	__u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool;
38062306a36Sopenharmony_ci	__u32 val32;
38162306a36Sopenharmony_ci	__u64 val64;
38262306a36Sopenharmony_ci	int rc;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/* The transaction state is wrong. */
38562306a36Sopenharmony_ci	if (kvp_transaction.state != HVUTIL_HOSTMSG_RECEIVED)
38662306a36Sopenharmony_ci		return;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	message = kzalloc(sizeof(*message), GFP_KERNEL);
38962306a36Sopenharmony_ci	if (!message)
39062306a36Sopenharmony_ci		return;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	message->kvp_hdr.operation = operation;
39362306a36Sopenharmony_ci	message->kvp_hdr.pool = pool;
39462306a36Sopenharmony_ci	in_msg = kvp_transaction.kvp_msg;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/*
39762306a36Sopenharmony_ci	 * The key/value strings sent from the host are encoded
39862306a36Sopenharmony_ci	 * in utf16; convert it to utf8 strings.
39962306a36Sopenharmony_ci	 * The host assures us that the utf16 strings will not exceed
40062306a36Sopenharmony_ci	 * the max lengths specified. We will however, reserve room
40162306a36Sopenharmony_ci	 * for the string terminating character - in the utf16s_utf8s()
40262306a36Sopenharmony_ci	 * function we limit the size of the buffer where the converted
40362306a36Sopenharmony_ci	 * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to guarantee
40462306a36Sopenharmony_ci	 * that the strings can be properly terminated!
40562306a36Sopenharmony_ci	 */
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	switch (message->kvp_hdr.operation) {
40862306a36Sopenharmony_ci	case KVP_OP_SET_IP_INFO:
40962306a36Sopenharmony_ci		process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO);
41062306a36Sopenharmony_ci		break;
41162306a36Sopenharmony_ci	case KVP_OP_GET_IP_INFO:
41262306a36Sopenharmony_ci		/*
41362306a36Sopenharmony_ci		 * We only need to pass on the info of operation, adapter_id
41462306a36Sopenharmony_ci		 * and addr_family to the userland kvp daemon.
41562306a36Sopenharmony_ci		 */
41662306a36Sopenharmony_ci		process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO);
41762306a36Sopenharmony_ci		break;
41862306a36Sopenharmony_ci	case KVP_OP_SET:
41962306a36Sopenharmony_ci		switch (in_msg->body.kvp_set.data.value_type) {
42062306a36Sopenharmony_ci		case REG_SZ:
42162306a36Sopenharmony_ci			/*
42262306a36Sopenharmony_ci			 * The value is a string - utf16 encoding.
42362306a36Sopenharmony_ci			 */
42462306a36Sopenharmony_ci			message->body.kvp_set.data.value_size =
42562306a36Sopenharmony_ci				utf16s_to_utf8s(
42662306a36Sopenharmony_ci				(wchar_t *)in_msg->body.kvp_set.data.value,
42762306a36Sopenharmony_ci				in_msg->body.kvp_set.data.value_size,
42862306a36Sopenharmony_ci				UTF16_LITTLE_ENDIAN,
42962306a36Sopenharmony_ci				message->body.kvp_set.data.value,
43062306a36Sopenharmony_ci				HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1;
43162306a36Sopenharmony_ci			break;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		case REG_U32:
43462306a36Sopenharmony_ci			/*
43562306a36Sopenharmony_ci			 * The value is a 32 bit scalar.
43662306a36Sopenharmony_ci			 * We save this as a utf8 string.
43762306a36Sopenharmony_ci			 */
43862306a36Sopenharmony_ci			val32 = in_msg->body.kvp_set.data.value_u32;
43962306a36Sopenharmony_ci			message->body.kvp_set.data.value_size =
44062306a36Sopenharmony_ci				sprintf(message->body.kvp_set.data.value,
44162306a36Sopenharmony_ci					"%u", val32) + 1;
44262306a36Sopenharmony_ci			break;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		case REG_U64:
44562306a36Sopenharmony_ci			/*
44662306a36Sopenharmony_ci			 * The value is a 64 bit scalar.
44762306a36Sopenharmony_ci			 * We save this as a utf8 string.
44862306a36Sopenharmony_ci			 */
44962306a36Sopenharmony_ci			val64 = in_msg->body.kvp_set.data.value_u64;
45062306a36Sopenharmony_ci			message->body.kvp_set.data.value_size =
45162306a36Sopenharmony_ci				sprintf(message->body.kvp_set.data.value,
45262306a36Sopenharmony_ci					"%llu", val64) + 1;
45362306a36Sopenharmony_ci			break;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		/*
45862306a36Sopenharmony_ci		 * The key is always a string - utf16 encoding.
45962306a36Sopenharmony_ci		 */
46062306a36Sopenharmony_ci		message->body.kvp_set.data.key_size =
46162306a36Sopenharmony_ci			utf16s_to_utf8s(
46262306a36Sopenharmony_ci			(wchar_t *)in_msg->body.kvp_set.data.key,
46362306a36Sopenharmony_ci			in_msg->body.kvp_set.data.key_size,
46462306a36Sopenharmony_ci			UTF16_LITTLE_ENDIAN,
46562306a36Sopenharmony_ci			message->body.kvp_set.data.key,
46662306a36Sopenharmony_ci			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		break;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	case KVP_OP_GET:
47162306a36Sopenharmony_ci		message->body.kvp_get.data.key_size =
47262306a36Sopenharmony_ci			utf16s_to_utf8s(
47362306a36Sopenharmony_ci			(wchar_t *)in_msg->body.kvp_get.data.key,
47462306a36Sopenharmony_ci			in_msg->body.kvp_get.data.key_size,
47562306a36Sopenharmony_ci			UTF16_LITTLE_ENDIAN,
47662306a36Sopenharmony_ci			message->body.kvp_get.data.key,
47762306a36Sopenharmony_ci			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
47862306a36Sopenharmony_ci		break;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	case KVP_OP_DELETE:
48162306a36Sopenharmony_ci		message->body.kvp_delete.key_size =
48262306a36Sopenharmony_ci			utf16s_to_utf8s(
48362306a36Sopenharmony_ci			(wchar_t *)in_msg->body.kvp_delete.key,
48462306a36Sopenharmony_ci			in_msg->body.kvp_delete.key_size,
48562306a36Sopenharmony_ci			UTF16_LITTLE_ENDIAN,
48662306a36Sopenharmony_ci			message->body.kvp_delete.key,
48762306a36Sopenharmony_ci			HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1;
48862306a36Sopenharmony_ci		break;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	case KVP_OP_ENUMERATE:
49162306a36Sopenharmony_ci		message->body.kvp_enum_data.index =
49262306a36Sopenharmony_ci			in_msg->body.kvp_enum_data.index;
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	kvp_transaction.state = HVUTIL_USERSPACE_REQ;
49762306a36Sopenharmony_ci	rc = hvutil_transport_send(hvt, message, sizeof(*message), NULL);
49862306a36Sopenharmony_ci	if (rc) {
49962306a36Sopenharmony_ci		pr_debug("KVP: failed to communicate to the daemon: %d\n", rc);
50062306a36Sopenharmony_ci		if (cancel_delayed_work_sync(&kvp_timeout_work)) {
50162306a36Sopenharmony_ci			kvp_respond_to_host(message, HV_E_FAIL);
50262306a36Sopenharmony_ci			kvp_transaction.state = HVUTIL_READY;
50362306a36Sopenharmony_ci		}
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	kfree(message);
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/*
51062306a36Sopenharmony_ci * Send a response back to the host.
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic void
51462306a36Sopenharmony_cikvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct hv_kvp_msg  *kvp_msg;
51762306a36Sopenharmony_ci	struct hv_kvp_exchg_msg_value  *kvp_data;
51862306a36Sopenharmony_ci	char	*key_name;
51962306a36Sopenharmony_ci	char	*value;
52062306a36Sopenharmony_ci	struct icmsg_hdr *icmsghdrp;
52162306a36Sopenharmony_ci	int	keylen = 0;
52262306a36Sopenharmony_ci	int	valuelen = 0;
52362306a36Sopenharmony_ci	u32	buf_len;
52462306a36Sopenharmony_ci	struct vmbus_channel *channel;
52562306a36Sopenharmony_ci	u64	req_id;
52662306a36Sopenharmony_ci	int ret;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/*
52962306a36Sopenharmony_ci	 * Copy the global state for completing the transaction. Note that
53062306a36Sopenharmony_ci	 * only one transaction can be active at a time.
53162306a36Sopenharmony_ci	 */
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	buf_len = kvp_transaction.recv_len;
53462306a36Sopenharmony_ci	channel = kvp_transaction.recv_channel;
53562306a36Sopenharmony_ci	req_id = kvp_transaction.recv_req_id;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	icmsghdrp = (struct icmsg_hdr *)
53862306a36Sopenharmony_ci			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (channel->onchannel_callback == NULL)
54162306a36Sopenharmony_ci		/*
54262306a36Sopenharmony_ci		 * We have raced with util driver being unloaded;
54362306a36Sopenharmony_ci		 * silently return.
54462306a36Sopenharmony_ci		 */
54562306a36Sopenharmony_ci		return;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	icmsghdrp->status = error;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/*
55062306a36Sopenharmony_ci	 * If the error parameter is set, terminate the host's enumeration
55162306a36Sopenharmony_ci	 * on this pool.
55262306a36Sopenharmony_ci	 */
55362306a36Sopenharmony_ci	if (error) {
55462306a36Sopenharmony_ci		/*
55562306a36Sopenharmony_ci		 * Something failed or we have timed out;
55662306a36Sopenharmony_ci		 * terminate the current host-side iteration.
55762306a36Sopenharmony_ci		 */
55862306a36Sopenharmony_ci		goto response_done;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	kvp_msg = (struct hv_kvp_msg *)
56262306a36Sopenharmony_ci			&recv_buffer[sizeof(struct vmbuspipe_hdr) +
56362306a36Sopenharmony_ci			sizeof(struct icmsg_hdr)];
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	switch (kvp_transaction.kvp_msg->kvp_hdr.operation) {
56662306a36Sopenharmony_ci	case KVP_OP_GET_IP_INFO:
56762306a36Sopenharmony_ci		ret = process_ob_ipinfo(msg_to_host,
56862306a36Sopenharmony_ci				 (struct hv_kvp_ip_msg *)kvp_msg,
56962306a36Sopenharmony_ci				 KVP_OP_GET_IP_INFO);
57062306a36Sopenharmony_ci		if (ret < 0)
57162306a36Sopenharmony_ci			icmsghdrp->status = HV_E_FAIL;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		goto response_done;
57462306a36Sopenharmony_ci	case KVP_OP_SET_IP_INFO:
57562306a36Sopenharmony_ci		goto response_done;
57662306a36Sopenharmony_ci	case KVP_OP_GET:
57762306a36Sopenharmony_ci		kvp_data = &kvp_msg->body.kvp_get.data;
57862306a36Sopenharmony_ci		goto copy_value;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	case KVP_OP_SET:
58162306a36Sopenharmony_ci	case KVP_OP_DELETE:
58262306a36Sopenharmony_ci		goto response_done;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	default:
58562306a36Sopenharmony_ci		break;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	kvp_data = &kvp_msg->body.kvp_enum_data.data;
58962306a36Sopenharmony_ci	key_name = msg_to_host->body.kvp_enum_data.data.key;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/*
59262306a36Sopenharmony_ci	 * The windows host expects the key/value pair to be encoded
59362306a36Sopenharmony_ci	 * in utf16. Ensure that the key/value size reported to the host
59462306a36Sopenharmony_ci	 * will be less than or equal to the MAX size (including the
59562306a36Sopenharmony_ci	 * terminating character).
59662306a36Sopenharmony_ci	 */
59762306a36Sopenharmony_ci	keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
59862306a36Sopenharmony_ci				(wchar_t *) kvp_data->key,
59962306a36Sopenharmony_ci				(HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2);
60062306a36Sopenharmony_ci	kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cicopy_value:
60362306a36Sopenharmony_ci	value = msg_to_host->body.kvp_enum_data.data.value;
60462306a36Sopenharmony_ci	valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
60562306a36Sopenharmony_ci				(wchar_t *) kvp_data->value,
60662306a36Sopenharmony_ci				(HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2);
60762306a36Sopenharmony_ci	kvp_data->value_size = 2*(valuelen + 1); /* utf16 encoding */
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/*
61062306a36Sopenharmony_ci	 * If the utf8s to utf16s conversion failed; notify host
61162306a36Sopenharmony_ci	 * of the error.
61262306a36Sopenharmony_ci	 */
61362306a36Sopenharmony_ci	if ((keylen < 0) || (valuelen < 0))
61462306a36Sopenharmony_ci		icmsghdrp->status = HV_E_FAIL;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	kvp_data->value_type = REG_SZ; /* all our values are strings */
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ciresponse_done:
61962306a36Sopenharmony_ci	icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
62262306a36Sopenharmony_ci				VM_PKT_DATA_INBAND, 0);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/*
62662306a36Sopenharmony_ci * This callback is invoked when we get a KVP message from the host.
62762306a36Sopenharmony_ci * The host ensures that only one KVP transaction can be active at a time.
62862306a36Sopenharmony_ci * KVP implementation in Linux needs to forward the key to a user-mde
62962306a36Sopenharmony_ci * component to retrieve the corresponding value. Consequently, we cannot
63062306a36Sopenharmony_ci * respond to the host in the context of this callback. Since the host
63162306a36Sopenharmony_ci * guarantees that at most only one transaction can be active at a time,
63262306a36Sopenharmony_ci * we stash away the transaction state in a set of global variables.
63362306a36Sopenharmony_ci */
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_civoid hv_kvp_onchannelcallback(void *context)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct vmbus_channel *channel = context;
63862306a36Sopenharmony_ci	u32 recvlen;
63962306a36Sopenharmony_ci	u64 requestid;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	struct hv_kvp_msg *kvp_msg;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	struct icmsg_hdr *icmsghdrp;
64462306a36Sopenharmony_ci	int kvp_srv_version;
64562306a36Sopenharmony_ci	static enum {NEGO_NOT_STARTED,
64662306a36Sopenharmony_ci		     NEGO_IN_PROGRESS,
64762306a36Sopenharmony_ci		     NEGO_FINISHED} host_negotiatied = NEGO_NOT_STARTED;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (kvp_transaction.state < HVUTIL_READY) {
65062306a36Sopenharmony_ci		/*
65162306a36Sopenharmony_ci		 * If userspace daemon is not connected and host is asking
65262306a36Sopenharmony_ci		 * us to negotiate we need to delay to not lose messages.
65362306a36Sopenharmony_ci		 * This is important for Failover IP setting.
65462306a36Sopenharmony_ci		 */
65562306a36Sopenharmony_ci		if (host_negotiatied == NEGO_NOT_STARTED) {
65662306a36Sopenharmony_ci			host_negotiatied = NEGO_IN_PROGRESS;
65762306a36Sopenharmony_ci			schedule_delayed_work(&kvp_host_handshake_work,
65862306a36Sopenharmony_ci				      HV_UTIL_NEGO_TIMEOUT * HZ);
65962306a36Sopenharmony_ci		}
66062306a36Sopenharmony_ci		return;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci	if (kvp_transaction.state > HVUTIL_READY)
66362306a36Sopenharmony_ci		return;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 4, &recvlen, &requestid)) {
66662306a36Sopenharmony_ci		pr_err_ratelimited("KVP request received. Could not read into recv buf\n");
66762306a36Sopenharmony_ci		return;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	if (!recvlen)
67162306a36Sopenharmony_ci		return;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* Ensure recvlen is big enough to read header data */
67462306a36Sopenharmony_ci	if (recvlen < ICMSG_HDR) {
67562306a36Sopenharmony_ci		pr_err_ratelimited("KVP request received. Packet length too small: %d\n",
67662306a36Sopenharmony_ci				   recvlen);
67762306a36Sopenharmony_ci		return;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	icmsghdrp = (struct icmsg_hdr *)&recv_buffer[sizeof(struct vmbuspipe_hdr)];
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
68362306a36Sopenharmony_ci		if (vmbus_prep_negotiate_resp(icmsghdrp,
68462306a36Sopenharmony_ci				recv_buffer, recvlen,
68562306a36Sopenharmony_ci				fw_versions, FW_VER_COUNT,
68662306a36Sopenharmony_ci				kvp_versions, KVP_VER_COUNT,
68762306a36Sopenharmony_ci				NULL, &kvp_srv_version)) {
68862306a36Sopenharmony_ci			pr_info("KVP IC version %d.%d\n",
68962306a36Sopenharmony_ci				kvp_srv_version >> 16,
69062306a36Sopenharmony_ci				kvp_srv_version & 0xFFFF);
69162306a36Sopenharmony_ci		}
69262306a36Sopenharmony_ci	} else if (icmsghdrp->icmsgtype == ICMSGTYPE_KVPEXCHANGE) {
69362306a36Sopenharmony_ci		/*
69462306a36Sopenharmony_ci		 * recvlen is not checked against sizeof(struct kvp_msg) because kvp_msg contains
69562306a36Sopenharmony_ci		 * a union of structs and the msg type received is not known. Code using this
69662306a36Sopenharmony_ci		 * struct should provide validation when accessing its fields.
69762306a36Sopenharmony_ci		 */
69862306a36Sopenharmony_ci		kvp_msg = (struct hv_kvp_msg *)&recv_buffer[ICMSG_HDR];
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		/*
70162306a36Sopenharmony_ci		 * Stash away this global state for completing the
70262306a36Sopenharmony_ci		 * transaction; note transactions are serialized.
70362306a36Sopenharmony_ci		 */
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		kvp_transaction.recv_len = recvlen;
70662306a36Sopenharmony_ci		kvp_transaction.recv_req_id = requestid;
70762306a36Sopenharmony_ci		kvp_transaction.kvp_msg = kvp_msg;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		if (kvp_transaction.state < HVUTIL_READY) {
71062306a36Sopenharmony_ci			/* Userspace is not registered yet */
71162306a36Sopenharmony_ci			kvp_respond_to_host(NULL, HV_E_FAIL);
71262306a36Sopenharmony_ci			return;
71362306a36Sopenharmony_ci		}
71462306a36Sopenharmony_ci		kvp_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		/*
71762306a36Sopenharmony_ci		 * Get the information from the
71862306a36Sopenharmony_ci		 * user-mode component.
71962306a36Sopenharmony_ci		 * component. This transaction will be
72062306a36Sopenharmony_ci		 * completed when we get the value from
72162306a36Sopenharmony_ci		 * the user-mode component.
72262306a36Sopenharmony_ci		 * Set a timeout to deal with
72362306a36Sopenharmony_ci		 * user-mode not responding.
72462306a36Sopenharmony_ci		 */
72562306a36Sopenharmony_ci		schedule_work(&kvp_sendkey_work);
72662306a36Sopenharmony_ci		schedule_delayed_work(&kvp_timeout_work,
72762306a36Sopenharmony_ci					HV_UTIL_TIMEOUT * HZ);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		return;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	} else {
73262306a36Sopenharmony_ci		pr_err_ratelimited("KVP request received. Invalid msg type: %d\n",
73362306a36Sopenharmony_ci				   icmsghdrp->icmsgtype);
73462306a36Sopenharmony_ci		return;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
73862306a36Sopenharmony_ci		| ICMSGHDRFLAG_RESPONSE;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	vmbus_sendpacket(channel, recv_buffer,
74162306a36Sopenharmony_ci			 recvlen, requestid,
74262306a36Sopenharmony_ci			 VM_PKT_DATA_INBAND, 0);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	host_negotiatied = NEGO_FINISHED;
74562306a36Sopenharmony_ci	hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic void kvp_on_reset(void)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	if (cancel_delayed_work_sync(&kvp_timeout_work))
75162306a36Sopenharmony_ci		kvp_respond_to_host(NULL, HV_E_FAIL);
75262306a36Sopenharmony_ci	kvp_transaction.state = HVUTIL_DEVICE_INIT;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ciint
75662306a36Sopenharmony_cihv_kvp_init(struct hv_util_service *srv)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	recv_buffer = srv->recv_buffer;
75962306a36Sopenharmony_ci	kvp_transaction.recv_channel = srv->channel;
76062306a36Sopenharmony_ci	kvp_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 4;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/*
76362306a36Sopenharmony_ci	 * When this driver loads, the user level daemon that
76462306a36Sopenharmony_ci	 * processes the host requests may not yet be running.
76562306a36Sopenharmony_ci	 * Defer processing channel callbacks until the daemon
76662306a36Sopenharmony_ci	 * has registered.
76762306a36Sopenharmony_ci	 */
76862306a36Sopenharmony_ci	kvp_transaction.state = HVUTIL_DEVICE_INIT;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	hvt = hvutil_transport_init(kvp_devname, CN_KVP_IDX, CN_KVP_VAL,
77162306a36Sopenharmony_ci				    kvp_on_msg, kvp_on_reset);
77262306a36Sopenharmony_ci	if (!hvt)
77362306a36Sopenharmony_ci		return -EFAULT;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return 0;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic void hv_kvp_cancel_work(void)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	cancel_delayed_work_sync(&kvp_host_handshake_work);
78162306a36Sopenharmony_ci	cancel_delayed_work_sync(&kvp_timeout_work);
78262306a36Sopenharmony_ci	cancel_work_sync(&kvp_sendkey_work);
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ciint hv_kvp_pre_suspend(void)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	struct vmbus_channel *channel = kvp_transaction.recv_channel;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	tasklet_disable(&channel->callback_event);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/*
79262306a36Sopenharmony_ci	 * If there is a pending transtion, it's unnecessary to tell the host
79362306a36Sopenharmony_ci	 * that the transaction will fail, because that is implied when
79462306a36Sopenharmony_ci	 * util_suspend() calls vmbus_close() later.
79562306a36Sopenharmony_ci	 */
79662306a36Sopenharmony_ci	hv_kvp_cancel_work();
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	/*
79962306a36Sopenharmony_ci	 * Forece the state to READY to handle the ICMSGTYPE_NEGOTIATE message
80062306a36Sopenharmony_ci	 * later. The user space daemon may go out of order and its write()
80162306a36Sopenharmony_ci	 * may fail with EINVAL: this doesn't matter since the daemon will
80262306a36Sopenharmony_ci	 * reset the device by closing and re-opening it.
80362306a36Sopenharmony_ci	 */
80462306a36Sopenharmony_ci	kvp_transaction.state = HVUTIL_READY;
80562306a36Sopenharmony_ci	return 0;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ciint hv_kvp_pre_resume(void)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	struct vmbus_channel *channel = kvp_transaction.recv_channel;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	tasklet_enable(&channel->callback_event);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return 0;
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_civoid hv_kvp_deinit(void)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	kvp_transaction.state = HVUTIL_DEVICE_DYING;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	hv_kvp_cancel_work();
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	hvutil_transport_destroy(hvt);
82462306a36Sopenharmony_ci}
825