xref: /openbmc/linux/drivers/hv/hv_kvp.c (revision 46a971913611a23478283931460a95be962ce329)
1*46a97191SGreg Kroah-Hartman /*
2*46a97191SGreg Kroah-Hartman  * An implementation of key value pair (KVP) functionality for Linux.
3*46a97191SGreg Kroah-Hartman  *
4*46a97191SGreg Kroah-Hartman  *
5*46a97191SGreg Kroah-Hartman  * Copyright (C) 2010, Novell, Inc.
6*46a97191SGreg Kroah-Hartman  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7*46a97191SGreg Kroah-Hartman  *
8*46a97191SGreg Kroah-Hartman  * This program is free software; you can redistribute it and/or modify it
9*46a97191SGreg Kroah-Hartman  * under the terms of the GNU General Public License version 2 as published
10*46a97191SGreg Kroah-Hartman  * by the Free Software Foundation.
11*46a97191SGreg Kroah-Hartman  *
12*46a97191SGreg Kroah-Hartman  * This program is distributed in the hope that it will be useful, but
13*46a97191SGreg Kroah-Hartman  * WITHOUT ANY WARRANTY; without even the implied warranty of
14*46a97191SGreg Kroah-Hartman  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15*46a97191SGreg Kroah-Hartman  * NON INFRINGEMENT.  See the GNU General Public License for more
16*46a97191SGreg Kroah-Hartman  * details.
17*46a97191SGreg Kroah-Hartman  *
18*46a97191SGreg Kroah-Hartman  * You should have received a copy of the GNU General Public License
19*46a97191SGreg Kroah-Hartman  * along with this program; if not, write to the Free Software
20*46a97191SGreg Kroah-Hartman  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21*46a97191SGreg Kroah-Hartman  *
22*46a97191SGreg Kroah-Hartman  */
23*46a97191SGreg Kroah-Hartman #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24*46a97191SGreg Kroah-Hartman 
25*46a97191SGreg Kroah-Hartman #include <linux/net.h>
26*46a97191SGreg Kroah-Hartman #include <linux/nls.h>
27*46a97191SGreg Kroah-Hartman #include <linux/connector.h>
28*46a97191SGreg Kroah-Hartman #include <linux/workqueue.h>
29*46a97191SGreg Kroah-Hartman #include <linux/hyperv.h>
30*46a97191SGreg Kroah-Hartman 
31*46a97191SGreg Kroah-Hartman #include "hv_kvp.h"
32*46a97191SGreg Kroah-Hartman 
33*46a97191SGreg Kroah-Hartman 
34*46a97191SGreg Kroah-Hartman 
35*46a97191SGreg Kroah-Hartman /*
36*46a97191SGreg Kroah-Hartman  * Global state maintained for transaction that is being processed.
37*46a97191SGreg Kroah-Hartman  * Note that only one transaction can be active at any point in time.
38*46a97191SGreg Kroah-Hartman  *
39*46a97191SGreg Kroah-Hartman  * This state is set when we receive a request from the host; we
40*46a97191SGreg Kroah-Hartman  * cleanup this state when the transaction is completed - when we respond
41*46a97191SGreg Kroah-Hartman  * to the host with the key value.
42*46a97191SGreg Kroah-Hartman  */
43*46a97191SGreg Kroah-Hartman 
44*46a97191SGreg Kroah-Hartman static struct {
45*46a97191SGreg Kroah-Hartman 	bool active; /* transaction status - active or not */
46*46a97191SGreg Kroah-Hartman 	int recv_len; /* number of bytes received. */
47*46a97191SGreg Kroah-Hartman 	int index; /* current index */
48*46a97191SGreg Kroah-Hartman 	struct vmbus_channel *recv_channel; /* chn we got the request */
49*46a97191SGreg Kroah-Hartman 	u64 recv_req_id; /* request ID. */
50*46a97191SGreg Kroah-Hartman } kvp_transaction;
51*46a97191SGreg Kroah-Hartman 
52*46a97191SGreg Kroah-Hartman static void kvp_send_key(struct work_struct *dummy);
53*46a97191SGreg Kroah-Hartman 
54*46a97191SGreg Kroah-Hartman #define TIMEOUT_FIRED 1
55*46a97191SGreg Kroah-Hartman 
56*46a97191SGreg Kroah-Hartman static void kvp_respond_to_host(char *key, char *value, int error);
57*46a97191SGreg Kroah-Hartman static void kvp_work_func(struct work_struct *dummy);
58*46a97191SGreg Kroah-Hartman static void kvp_register(void);
59*46a97191SGreg Kroah-Hartman 
60*46a97191SGreg Kroah-Hartman static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
61*46a97191SGreg Kroah-Hartman static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
62*46a97191SGreg Kroah-Hartman 
63*46a97191SGreg Kroah-Hartman static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL };
64*46a97191SGreg Kroah-Hartman static const char kvp_name[] = "kvp_kernel_module";
65*46a97191SGreg Kroah-Hartman static u8 *recv_buffer;
66*46a97191SGreg Kroah-Hartman /*
67*46a97191SGreg Kroah-Hartman  * Register the kernel component with the user-level daemon.
68*46a97191SGreg Kroah-Hartman  * As part of this registration, pass the LIC version number.
69*46a97191SGreg Kroah-Hartman  */
70*46a97191SGreg Kroah-Hartman 
71*46a97191SGreg Kroah-Hartman static void
72*46a97191SGreg Kroah-Hartman kvp_register(void)
73*46a97191SGreg Kroah-Hartman {
74*46a97191SGreg Kroah-Hartman 
75*46a97191SGreg Kroah-Hartman 	struct cn_msg *msg;
76*46a97191SGreg Kroah-Hartman 
77*46a97191SGreg Kroah-Hartman 	msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC);
78*46a97191SGreg Kroah-Hartman 
79*46a97191SGreg Kroah-Hartman 	if (msg) {
80*46a97191SGreg Kroah-Hartman 		msg->id.idx =  CN_KVP_IDX;
81*46a97191SGreg Kroah-Hartman 		msg->id.val = CN_KVP_VAL;
82*46a97191SGreg Kroah-Hartman 		msg->seq = KVP_REGISTER;
83*46a97191SGreg Kroah-Hartman 		strcpy(msg->data, HV_DRV_VERSION);
84*46a97191SGreg Kroah-Hartman 		msg->len = strlen(HV_DRV_VERSION) + 1;
85*46a97191SGreg Kroah-Hartman 		cn_netlink_send(msg, 0, GFP_ATOMIC);
86*46a97191SGreg Kroah-Hartman 		kfree(msg);
87*46a97191SGreg Kroah-Hartman 	}
88*46a97191SGreg Kroah-Hartman }
89*46a97191SGreg Kroah-Hartman static void
90*46a97191SGreg Kroah-Hartman kvp_work_func(struct work_struct *dummy)
91*46a97191SGreg Kroah-Hartman {
92*46a97191SGreg Kroah-Hartman 	/*
93*46a97191SGreg Kroah-Hartman 	 * If the timer fires, the user-mode component has not responded;
94*46a97191SGreg Kroah-Hartman 	 * process the pending transaction.
95*46a97191SGreg Kroah-Hartman 	 */
96*46a97191SGreg Kroah-Hartman 	kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED);
97*46a97191SGreg Kroah-Hartman }
98*46a97191SGreg Kroah-Hartman 
99*46a97191SGreg Kroah-Hartman /*
100*46a97191SGreg Kroah-Hartman  * Callback when data is received from user mode.
101*46a97191SGreg Kroah-Hartman  */
102*46a97191SGreg Kroah-Hartman 
103*46a97191SGreg Kroah-Hartman static void
104*46a97191SGreg Kroah-Hartman kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
105*46a97191SGreg Kroah-Hartman {
106*46a97191SGreg Kroah-Hartman 	struct hv_ku_msg *message;
107*46a97191SGreg Kroah-Hartman 
108*46a97191SGreg Kroah-Hartman 	message = (struct hv_ku_msg *)msg->data;
109*46a97191SGreg Kroah-Hartman 	if (msg->seq == KVP_REGISTER) {
110*46a97191SGreg Kroah-Hartman 		pr_info("KVP: user-mode registering done.\n");
111*46a97191SGreg Kroah-Hartman 		kvp_register();
112*46a97191SGreg Kroah-Hartman 	}
113*46a97191SGreg Kroah-Hartman 
114*46a97191SGreg Kroah-Hartman 	if (msg->seq == KVP_USER_SET) {
115*46a97191SGreg Kroah-Hartman 		/*
116*46a97191SGreg Kroah-Hartman 		 * Complete the transaction by forwarding the key value
117*46a97191SGreg Kroah-Hartman 		 * to the host. But first, cancel the timeout.
118*46a97191SGreg Kroah-Hartman 		 */
119*46a97191SGreg Kroah-Hartman 		if (cancel_delayed_work_sync(&kvp_work))
120*46a97191SGreg Kroah-Hartman 			kvp_respond_to_host(message->kvp_key,
121*46a97191SGreg Kroah-Hartman 						message->kvp_value,
122*46a97191SGreg Kroah-Hartman 						!strlen(message->kvp_key));
123*46a97191SGreg Kroah-Hartman 	}
124*46a97191SGreg Kroah-Hartman }
125*46a97191SGreg Kroah-Hartman 
126*46a97191SGreg Kroah-Hartman static void
127*46a97191SGreg Kroah-Hartman kvp_send_key(struct work_struct *dummy)
128*46a97191SGreg Kroah-Hartman {
129*46a97191SGreg Kroah-Hartman 	struct cn_msg *msg;
130*46a97191SGreg Kroah-Hartman 	int index = kvp_transaction.index;
131*46a97191SGreg Kroah-Hartman 
132*46a97191SGreg Kroah-Hartman 	msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
133*46a97191SGreg Kroah-Hartman 
134*46a97191SGreg Kroah-Hartman 	if (msg) {
135*46a97191SGreg Kroah-Hartman 		msg->id.idx =  CN_KVP_IDX;
136*46a97191SGreg Kroah-Hartman 		msg->id.val = CN_KVP_VAL;
137*46a97191SGreg Kroah-Hartman 		msg->seq = KVP_KERNEL_GET;
138*46a97191SGreg Kroah-Hartman 		((struct hv_ku_msg *)msg->data)->kvp_index = index;
139*46a97191SGreg Kroah-Hartman 		msg->len = sizeof(struct hv_ku_msg);
140*46a97191SGreg Kroah-Hartman 		cn_netlink_send(msg, 0, GFP_ATOMIC);
141*46a97191SGreg Kroah-Hartman 		kfree(msg);
142*46a97191SGreg Kroah-Hartman 	}
143*46a97191SGreg Kroah-Hartman 	return;
144*46a97191SGreg Kroah-Hartman }
145*46a97191SGreg Kroah-Hartman 
146*46a97191SGreg Kroah-Hartman /*
147*46a97191SGreg Kroah-Hartman  * Send a response back to the host.
148*46a97191SGreg Kroah-Hartman  */
149*46a97191SGreg Kroah-Hartman 
150*46a97191SGreg Kroah-Hartman static void
151*46a97191SGreg Kroah-Hartman kvp_respond_to_host(char *key, char *value, int error)
152*46a97191SGreg Kroah-Hartman {
153*46a97191SGreg Kroah-Hartman 	struct hv_kvp_msg  *kvp_msg;
154*46a97191SGreg Kroah-Hartman 	struct hv_kvp_msg_enumerate  *kvp_data;
155*46a97191SGreg Kroah-Hartman 	char	*key_name;
156*46a97191SGreg Kroah-Hartman 	struct icmsg_hdr *icmsghdrp;
157*46a97191SGreg Kroah-Hartman 	int	keylen, valuelen;
158*46a97191SGreg Kroah-Hartman 	u32	buf_len;
159*46a97191SGreg Kroah-Hartman 	struct vmbus_channel *channel;
160*46a97191SGreg Kroah-Hartman 	u64	req_id;
161*46a97191SGreg Kroah-Hartman 
162*46a97191SGreg Kroah-Hartman 	/*
163*46a97191SGreg Kroah-Hartman 	 * If a transaction is not active; log and return.
164*46a97191SGreg Kroah-Hartman 	 */
165*46a97191SGreg Kroah-Hartman 
166*46a97191SGreg Kroah-Hartman 	if (!kvp_transaction.active) {
167*46a97191SGreg Kroah-Hartman 		/*
168*46a97191SGreg Kroah-Hartman 		 * This is a spurious call!
169*46a97191SGreg Kroah-Hartman 		 */
170*46a97191SGreg Kroah-Hartman 		pr_warn("KVP: Transaction not active\n");
171*46a97191SGreg Kroah-Hartman 		return;
172*46a97191SGreg Kroah-Hartman 	}
173*46a97191SGreg Kroah-Hartman 	/*
174*46a97191SGreg Kroah-Hartman 	 * Copy the global state for completing the transaction. Note that
175*46a97191SGreg Kroah-Hartman 	 * only one transaction can be active at a time.
176*46a97191SGreg Kroah-Hartman 	 */
177*46a97191SGreg Kroah-Hartman 
178*46a97191SGreg Kroah-Hartman 	buf_len = kvp_transaction.recv_len;
179*46a97191SGreg Kroah-Hartman 	channel = kvp_transaction.recv_channel;
180*46a97191SGreg Kroah-Hartman 	req_id = kvp_transaction.recv_req_id;
181*46a97191SGreg Kroah-Hartman 
182*46a97191SGreg Kroah-Hartman 	kvp_transaction.active = false;
183*46a97191SGreg Kroah-Hartman 
184*46a97191SGreg Kroah-Hartman 	if (channel->onchannel_callback == NULL)
185*46a97191SGreg Kroah-Hartman 		/*
186*46a97191SGreg Kroah-Hartman 		 * We have raced with util driver being unloaded;
187*46a97191SGreg Kroah-Hartman 		 * silently return.
188*46a97191SGreg Kroah-Hartman 		 */
189*46a97191SGreg Kroah-Hartman 		return;
190*46a97191SGreg Kroah-Hartman 
191*46a97191SGreg Kroah-Hartman 	icmsghdrp = (struct icmsg_hdr *)
192*46a97191SGreg Kroah-Hartman 			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
193*46a97191SGreg Kroah-Hartman 	kvp_msg = (struct hv_kvp_msg *)
194*46a97191SGreg Kroah-Hartman 			&recv_buffer[sizeof(struct vmbuspipe_hdr) +
195*46a97191SGreg Kroah-Hartman 			sizeof(struct icmsg_hdr)];
196*46a97191SGreg Kroah-Hartman 	kvp_data = &kvp_msg->kvp_data;
197*46a97191SGreg Kroah-Hartman 	key_name = key;
198*46a97191SGreg Kroah-Hartman 
199*46a97191SGreg Kroah-Hartman 	/*
200*46a97191SGreg Kroah-Hartman 	 * If the error parameter is set, terminate the host's enumeration.
201*46a97191SGreg Kroah-Hartman 	 */
202*46a97191SGreg Kroah-Hartman 	if (error) {
203*46a97191SGreg Kroah-Hartman 		/*
204*46a97191SGreg Kroah-Hartman 		 * We don't support this index or the we have timedout;
205*46a97191SGreg Kroah-Hartman 		 * terminate the host-side iteration by returning an error.
206*46a97191SGreg Kroah-Hartman 		 */
207*46a97191SGreg Kroah-Hartman 		icmsghdrp->status = HV_E_FAIL;
208*46a97191SGreg Kroah-Hartman 		goto response_done;
209*46a97191SGreg Kroah-Hartman 	}
210*46a97191SGreg Kroah-Hartman 
211*46a97191SGreg Kroah-Hartman 	/*
212*46a97191SGreg Kroah-Hartman 	 * The windows host expects the key/value pair to be encoded
213*46a97191SGreg Kroah-Hartman 	 * in utf16.
214*46a97191SGreg Kroah-Hartman 	 */
215*46a97191SGreg Kroah-Hartman 	keylen = utf8s_to_utf16s(key_name, strlen(key_name),
216*46a97191SGreg Kroah-Hartman 				(wchar_t *)kvp_data->data.key);
217*46a97191SGreg Kroah-Hartman 	kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
218*46a97191SGreg Kroah-Hartman 	valuelen = utf8s_to_utf16s(value, strlen(value),
219*46a97191SGreg Kroah-Hartman 				(wchar_t *)kvp_data->data.value);
220*46a97191SGreg Kroah-Hartman 	kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
221*46a97191SGreg Kroah-Hartman 
222*46a97191SGreg Kroah-Hartman 	kvp_data->data.value_type = REG_SZ; /* all our values are strings */
223*46a97191SGreg Kroah-Hartman 	icmsghdrp->status = HV_S_OK;
224*46a97191SGreg Kroah-Hartman 
225*46a97191SGreg Kroah-Hartman response_done:
226*46a97191SGreg Kroah-Hartman 	icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
227*46a97191SGreg Kroah-Hartman 
228*46a97191SGreg Kroah-Hartman 	vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
229*46a97191SGreg Kroah-Hartman 				VM_PKT_DATA_INBAND, 0);
230*46a97191SGreg Kroah-Hartman 
231*46a97191SGreg Kroah-Hartman }
232*46a97191SGreg Kroah-Hartman 
233*46a97191SGreg Kroah-Hartman /*
234*46a97191SGreg Kroah-Hartman  * This callback is invoked when we get a KVP message from the host.
235*46a97191SGreg Kroah-Hartman  * The host ensures that only one KVP transaction can be active at a time.
236*46a97191SGreg Kroah-Hartman  * KVP implementation in Linux needs to forward the key to a user-mde
237*46a97191SGreg Kroah-Hartman  * component to retrive the corresponding value. Consequently, we cannot
238*46a97191SGreg Kroah-Hartman  * respond to the host in the conext of this callback. Since the host
239*46a97191SGreg Kroah-Hartman  * guarantees that at most only one transaction can be active at a time,
240*46a97191SGreg Kroah-Hartman  * we stash away the transaction state in a set of global variables.
241*46a97191SGreg Kroah-Hartman  */
242*46a97191SGreg Kroah-Hartman 
243*46a97191SGreg Kroah-Hartman void hv_kvp_onchannelcallback(void *context)
244*46a97191SGreg Kroah-Hartman {
245*46a97191SGreg Kroah-Hartman 	struct vmbus_channel *channel = context;
246*46a97191SGreg Kroah-Hartman 	u32 recvlen;
247*46a97191SGreg Kroah-Hartman 	u64 requestid;
248*46a97191SGreg Kroah-Hartman 
249*46a97191SGreg Kroah-Hartman 	struct hv_kvp_msg *kvp_msg;
250*46a97191SGreg Kroah-Hartman 	struct hv_kvp_msg_enumerate *kvp_data;
251*46a97191SGreg Kroah-Hartman 
252*46a97191SGreg Kroah-Hartman 	struct icmsg_hdr *icmsghdrp;
253*46a97191SGreg Kroah-Hartman 	struct icmsg_negotiate *negop = NULL;
254*46a97191SGreg Kroah-Hartman 
255*46a97191SGreg Kroah-Hartman 
256*46a97191SGreg Kroah-Hartman 	vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid);
257*46a97191SGreg Kroah-Hartman 
258*46a97191SGreg Kroah-Hartman 	if (recvlen > 0) {
259*46a97191SGreg Kroah-Hartman 		icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
260*46a97191SGreg Kroah-Hartman 			sizeof(struct vmbuspipe_hdr)];
261*46a97191SGreg Kroah-Hartman 
262*46a97191SGreg Kroah-Hartman 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
263*46a97191SGreg Kroah-Hartman 			prep_negotiate_resp(icmsghdrp, negop, recv_buffer);
264*46a97191SGreg Kroah-Hartman 		} else {
265*46a97191SGreg Kroah-Hartman 			kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
266*46a97191SGreg Kroah-Hartman 				sizeof(struct vmbuspipe_hdr) +
267*46a97191SGreg Kroah-Hartman 				sizeof(struct icmsg_hdr)];
268*46a97191SGreg Kroah-Hartman 
269*46a97191SGreg Kroah-Hartman 			kvp_data = &kvp_msg->kvp_data;
270*46a97191SGreg Kroah-Hartman 
271*46a97191SGreg Kroah-Hartman 			/*
272*46a97191SGreg Kroah-Hartman 			 * We only support the "get" operation on
273*46a97191SGreg Kroah-Hartman 			 * "KVP_POOL_AUTO" pool.
274*46a97191SGreg Kroah-Hartman 			 */
275*46a97191SGreg Kroah-Hartman 
276*46a97191SGreg Kroah-Hartman 			if ((kvp_msg->kvp_hdr.pool != KVP_POOL_AUTO) ||
277*46a97191SGreg Kroah-Hartman 				(kvp_msg->kvp_hdr.operation !=
278*46a97191SGreg Kroah-Hartman 				KVP_OP_ENUMERATE)) {
279*46a97191SGreg Kroah-Hartman 				icmsghdrp->status = HV_E_FAIL;
280*46a97191SGreg Kroah-Hartman 				goto callback_done;
281*46a97191SGreg Kroah-Hartman 			}
282*46a97191SGreg Kroah-Hartman 
283*46a97191SGreg Kroah-Hartman 			/*
284*46a97191SGreg Kroah-Hartman 			 * Stash away this global state for completing the
285*46a97191SGreg Kroah-Hartman 			 * transaction; note transactions are serialized.
286*46a97191SGreg Kroah-Hartman 			 */
287*46a97191SGreg Kroah-Hartman 			kvp_transaction.recv_len = recvlen;
288*46a97191SGreg Kroah-Hartman 			kvp_transaction.recv_channel = channel;
289*46a97191SGreg Kroah-Hartman 			kvp_transaction.recv_req_id = requestid;
290*46a97191SGreg Kroah-Hartman 			kvp_transaction.active = true;
291*46a97191SGreg Kroah-Hartman 			kvp_transaction.index = kvp_data->index;
292*46a97191SGreg Kroah-Hartman 
293*46a97191SGreg Kroah-Hartman 			/*
294*46a97191SGreg Kroah-Hartman 			 * Get the information from the
295*46a97191SGreg Kroah-Hartman 			 * user-mode component.
296*46a97191SGreg Kroah-Hartman 			 * component. This transaction will be
297*46a97191SGreg Kroah-Hartman 			 * completed when we get the value from
298*46a97191SGreg Kroah-Hartman 			 * the user-mode component.
299*46a97191SGreg Kroah-Hartman 			 * Set a timeout to deal with
300*46a97191SGreg Kroah-Hartman 			 * user-mode not responding.
301*46a97191SGreg Kroah-Hartman 			 */
302*46a97191SGreg Kroah-Hartman 			schedule_work(&kvp_sendkey_work);
303*46a97191SGreg Kroah-Hartman 			schedule_delayed_work(&kvp_work, 5*HZ);
304*46a97191SGreg Kroah-Hartman 
305*46a97191SGreg Kroah-Hartman 			return;
306*46a97191SGreg Kroah-Hartman 
307*46a97191SGreg Kroah-Hartman 		}
308*46a97191SGreg Kroah-Hartman 
309*46a97191SGreg Kroah-Hartman callback_done:
310*46a97191SGreg Kroah-Hartman 
311*46a97191SGreg Kroah-Hartman 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
312*46a97191SGreg Kroah-Hartman 			| ICMSGHDRFLAG_RESPONSE;
313*46a97191SGreg Kroah-Hartman 
314*46a97191SGreg Kroah-Hartman 		vmbus_sendpacket(channel, recv_buffer,
315*46a97191SGreg Kroah-Hartman 				       recvlen, requestid,
316*46a97191SGreg Kroah-Hartman 				       VM_PKT_DATA_INBAND, 0);
317*46a97191SGreg Kroah-Hartman 	}
318*46a97191SGreg Kroah-Hartman 
319*46a97191SGreg Kroah-Hartman }
320*46a97191SGreg Kroah-Hartman 
321*46a97191SGreg Kroah-Hartman int
322*46a97191SGreg Kroah-Hartman hv_kvp_init(struct hv_util_service *srv)
323*46a97191SGreg Kroah-Hartman {
324*46a97191SGreg Kroah-Hartman 	int err;
325*46a97191SGreg Kroah-Hartman 
326*46a97191SGreg Kroah-Hartman 	err = cn_add_callback(&kvp_id, kvp_name, kvp_cn_callback);
327*46a97191SGreg Kroah-Hartman 	if (err)
328*46a97191SGreg Kroah-Hartman 		return err;
329*46a97191SGreg Kroah-Hartman 	recv_buffer = srv->recv_buffer;
330*46a97191SGreg Kroah-Hartman 
331*46a97191SGreg Kroah-Hartman 	return 0;
332*46a97191SGreg Kroah-Hartman }
333*46a97191SGreg Kroah-Hartman 
334*46a97191SGreg Kroah-Hartman void hv_kvp_deinit(void)
335*46a97191SGreg Kroah-Hartman {
336*46a97191SGreg Kroah-Hartman 	cn_del_callback(&kvp_id);
337*46a97191SGreg Kroah-Hartman 	cancel_delayed_work_sync(&kvp_work);
338*46a97191SGreg Kroah-Hartman 	cancel_work_sync(&kvp_sendkey_work);
339*46a97191SGreg Kroah-Hartman }
340