]>
Commit | Line | Data |
---|---|---|
245ba56a KS |
1 | /* |
2 | * An implementation of key value pair (KVP) functionality for Linux. | |
3 | * | |
4 | * | |
5 | * Copyright (C) 2010, Novell, Inc. | |
6 | * Author : K. Y. Srinivasan <ksrinivasan@novell.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License version 2 as published | |
10 | * by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
15 | * NON INFRINGEMENT. See the GNU General Public License for more | |
16 | * details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | * | |
22 | */ | |
af7a5b6e | 23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
245ba56a KS |
24 | |
25 | #include <linux/net.h> | |
26 | #include <linux/nls.h> | |
27 | #include <linux/connector.h> | |
28 | #include <linux/workqueue.h> | |
46a97191 | 29 | #include <linux/hyperv.h> |
245ba56a | 30 | |
245ba56a KS |
31 | |
32 | ||
33 | /* | |
34 | * Global state maintained for transaction that is being processed. | |
35 | * Note that only one transaction can be active at any point in time. | |
36 | * | |
37 | * This state is set when we receive a request from the host; we | |
38 | * cleanup this state when the transaction is completed - when we respond | |
39 | * to the host with the key value. | |
40 | */ | |
41 | ||
42 | static struct { | |
43 | bool active; /* transaction status - active or not */ | |
44 | int recv_len; /* number of bytes received. */ | |
fa3d5b85 | 45 | struct hv_kvp_msg *kvp_msg; /* current message */ |
245ba56a KS |
46 | struct vmbus_channel *recv_channel; /* chn we got the request */ |
47 | u64 recv_req_id; /* request ID. */ | |
fa3d5b85 | 48 | void *kvp_context; /* for the channel callback */ |
245ba56a KS |
49 | } kvp_transaction; |
50 | ||
e2bb6537 | 51 | static void kvp_send_key(struct work_struct *dummy); |
245ba56a | 52 | |
76e5f813 S |
53 | #define TIMEOUT_FIRED 1 |
54 | ||
245ba56a KS |
55 | static void kvp_respond_to_host(char *key, char *value, int error); |
56 | static void kvp_work_func(struct work_struct *dummy); | |
57 | static void kvp_register(void); | |
58 | ||
59 | static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func); | |
e2bb6537 | 60 | static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); |
245ba56a KS |
61 | |
62 | static struct cb_id kvp_id = { CN_KVP_IDX, CN_KVP_VAL }; | |
63 | static const char kvp_name[] = "kvp_kernel_module"; | |
245ba56a KS |
64 | static u8 *recv_buffer; |
65 | /* | |
66 | * Register the kernel component with the user-level daemon. | |
67 | * As part of this registration, pass the LIC version number. | |
68 | */ | |
69 | ||
70 | static void | |
71 | kvp_register(void) | |
72 | { | |
73 | ||
74 | struct cn_msg *msg; | |
26403354 S |
75 | struct hv_kvp_msg *kvp_msg; |
76 | char *version; | |
245ba56a | 77 | |
26403354 | 78 | msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC); |
245ba56a KS |
79 | |
80 | if (msg) { | |
26403354 | 81 | kvp_msg = (struct hv_kvp_msg *)msg->data; |
e485ceac | 82 | version = kvp_msg->body.kvp_register.version; |
245ba56a KS |
83 | msg->id.idx = CN_KVP_IDX; |
84 | msg->id.val = CN_KVP_VAL; | |
26403354 S |
85 | |
86 | kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER; | |
87 | strcpy(version, HV_DRV_VERSION); | |
88 | msg->len = sizeof(struct hv_kvp_msg); | |
245ba56a KS |
89 | cn_netlink_send(msg, 0, GFP_ATOMIC); |
90 | kfree(msg); | |
91 | } | |
92 | } | |
93 | static void | |
94 | kvp_work_func(struct work_struct *dummy) | |
95 | { | |
96 | /* | |
97 | * If the timer fires, the user-mode component has not responded; | |
98 | * process the pending transaction. | |
99 | */ | |
76e5f813 | 100 | kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED); |
245ba56a KS |
101 | } |
102 | ||
103 | /* | |
104 | * Callback when data is received from user mode. | |
105 | */ | |
106 | ||
107 | static void | |
108 | kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |
109 | { | |
26403354 S |
110 | struct hv_kvp_msg *message; |
111 | struct hv_kvp_msg_enumerate *data; | |
245ba56a | 112 | |
26403354 | 113 | message = (struct hv_kvp_msg *)msg->data; |
fa3d5b85 S |
114 | switch (message->kvp_hdr.operation) { |
115 | case KVP_OP_REGISTER: | |
af7a5b6e | 116 | pr_info("KVP: user-mode registering done.\n"); |
245ba56a | 117 | kvp_register(); |
fa3d5b85 S |
118 | kvp_transaction.active = false; |
119 | hv_kvp_onchannelcallback(kvp_transaction.kvp_context); | |
120 | break; | |
245ba56a | 121 | |
fa3d5b85 | 122 | default: |
26403354 | 123 | data = &message->body.kvp_enum_data; |
245ba56a KS |
124 | /* |
125 | * Complete the transaction by forwarding the key value | |
126 | * to the host. But first, cancel the timeout. | |
127 | */ | |
128 | if (cancel_delayed_work_sync(&kvp_work)) | |
e485ceac S |
129 | kvp_respond_to_host(data->data.key, |
130 | data->data.value, | |
26403354 | 131 | !strlen(data->data.key)); |
245ba56a KS |
132 | } |
133 | } | |
134 | ||
e2bb6537 S |
135 | static void |
136 | kvp_send_key(struct work_struct *dummy) | |
245ba56a KS |
137 | { |
138 | struct cn_msg *msg; | |
26403354 | 139 | struct hv_kvp_msg *message; |
fa3d5b85 S |
140 | struct hv_kvp_msg *in_msg; |
141 | __u8 operation = kvp_transaction.kvp_msg->kvp_hdr.operation; | |
142 | __u8 pool = kvp_transaction.kvp_msg->kvp_hdr.pool; | |
143 | __u32 val32; | |
144 | __u64 val64; | |
245ba56a KS |
145 | |
146 | msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC); | |
fa3d5b85 S |
147 | if (!msg) |
148 | return; | |
245ba56a | 149 | |
fa3d5b85 S |
150 | msg->id.idx = CN_KVP_IDX; |
151 | msg->id.val = CN_KVP_VAL; | |
26403354 | 152 | |
fa3d5b85 S |
153 | message = (struct hv_kvp_msg *)msg->data; |
154 | message->kvp_hdr.operation = operation; | |
155 | message->kvp_hdr.pool = pool; | |
156 | in_msg = kvp_transaction.kvp_msg; | |
157 | ||
158 | /* | |
159 | * The key/value strings sent from the host are encoded in | |
160 | * in utf16; convert it to utf8 strings. | |
161 | * The host assures us that the utf16 strings will not exceed | |
162 | * the max lengths specified. We will however, reserve room | |
163 | * for the string terminating character - in the utf16s_utf8s() | |
164 | * function we limit the size of the buffer where the converted | |
165 | * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee | |
166 | * that the strings can be properly terminated! | |
167 | */ | |
168 | ||
169 | switch (message->kvp_hdr.operation) { | |
170 | case KVP_OP_SET: | |
171 | switch (in_msg->body.kvp_set.data.value_type) { | |
172 | case REG_SZ: | |
173 | /* | |
174 | * The value is a string - utf16 encoding. | |
175 | */ | |
176 | message->body.kvp_set.data.value_size = | |
177 | utf16s_to_utf8s( | |
178 | (wchar_t *)in_msg->body.kvp_set.data.value, | |
179 | in_msg->body.kvp_set.data.value_size, | |
180 | UTF16_LITTLE_ENDIAN, | |
181 | message->body.kvp_set.data.value, | |
182 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE - 1) + 1; | |
183 | break; | |
184 | ||
185 | case REG_U32: | |
186 | /* | |
187 | * The value is a 32 bit scalar. | |
188 | * We save this as a utf8 string. | |
189 | */ | |
190 | val32 = in_msg->body.kvp_set.data.value_u32; | |
191 | message->body.kvp_set.data.value_size = | |
192 | sprintf(message->body.kvp_set.data.value, | |
193 | "%d", val32) + 1; | |
194 | break; | |
195 | ||
196 | case REG_U64: | |
197 | /* | |
198 | * The value is a 64 bit scalar. | |
199 | * We save this as a utf8 string. | |
200 | */ | |
201 | val64 = in_msg->body.kvp_set.data.value_u64; | |
202 | message->body.kvp_set.data.value_size = | |
203 | sprintf(message->body.kvp_set.data.value, | |
204 | "%llu", val64) + 1; | |
205 | break; | |
206 | ||
207 | } | |
208 | case KVP_OP_GET: | |
209 | message->body.kvp_set.data.key_size = | |
210 | utf16s_to_utf8s( | |
211 | (wchar_t *)in_msg->body.kvp_set.data.key, | |
212 | in_msg->body.kvp_set.data.key_size, | |
213 | UTF16_LITTLE_ENDIAN, | |
214 | message->body.kvp_set.data.key, | |
215 | HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; | |
216 | break; | |
217 | ||
218 | case KVP_OP_DELETE: | |
219 | message->body.kvp_delete.key_size = | |
220 | utf16s_to_utf8s( | |
221 | (wchar_t *)in_msg->body.kvp_delete.key, | |
222 | in_msg->body.kvp_delete.key_size, | |
223 | UTF16_LITTLE_ENDIAN, | |
224 | message->body.kvp_delete.key, | |
225 | HV_KVP_EXCHANGE_MAX_KEY_SIZE - 1) + 1; | |
226 | break; | |
227 | ||
228 | case KVP_OP_ENUMERATE: | |
229 | message->body.kvp_enum_data.index = | |
230 | in_msg->body.kvp_enum_data.index; | |
231 | break; | |
245ba56a | 232 | } |
fa3d5b85 S |
233 | |
234 | msg->len = sizeof(struct hv_kvp_msg); | |
235 | cn_netlink_send(msg, 0, GFP_ATOMIC); | |
236 | kfree(msg); | |
237 | ||
e2bb6537 | 238 | return; |
245ba56a KS |
239 | } |
240 | ||
241 | /* | |
242 | * Send a response back to the host. | |
243 | */ | |
244 | ||
245 | static void | |
246 | kvp_respond_to_host(char *key, char *value, int error) | |
247 | { | |
248 | struct hv_kvp_msg *kvp_msg; | |
fa3d5b85 | 249 | struct hv_kvp_exchg_msg_value *kvp_data; |
245ba56a KS |
250 | char *key_name; |
251 | struct icmsg_hdr *icmsghdrp; | |
fa3d5b85 S |
252 | int keylen = 0; |
253 | int valuelen = 0; | |
245ba56a KS |
254 | u32 buf_len; |
255 | struct vmbus_channel *channel; | |
256 | u64 req_id; | |
257 | ||
258 | /* | |
259 | * If a transaction is not active; log and return. | |
260 | */ | |
261 | ||
262 | if (!kvp_transaction.active) { | |
263 | /* | |
264 | * This is a spurious call! | |
265 | */ | |
af7a5b6e | 266 | pr_warn("KVP: Transaction not active\n"); |
245ba56a KS |
267 | return; |
268 | } | |
269 | /* | |
270 | * Copy the global state for completing the transaction. Note that | |
271 | * only one transaction can be active at a time. | |
272 | */ | |
273 | ||
274 | buf_len = kvp_transaction.recv_len; | |
275 | channel = kvp_transaction.recv_channel; | |
276 | req_id = kvp_transaction.recv_req_id; | |
277 | ||
76e5f813 S |
278 | kvp_transaction.active = false; |
279 | ||
fa3d5b85 S |
280 | icmsghdrp = (struct icmsg_hdr *) |
281 | &recv_buffer[sizeof(struct vmbuspipe_hdr)]; | |
282 | ||
4e65f6e8 S |
283 | if (channel->onchannel_callback == NULL) |
284 | /* | |
285 | * We have raced with util driver being unloaded; | |
286 | * silently return. | |
287 | */ | |
288 | return; | |
289 | ||
245ba56a KS |
290 | |
291 | /* | |
292 | * If the error parameter is set, terminate the host's enumeration. | |
293 | */ | |
294 | if (error) { | |
295 | /* | |
fa3d5b85 | 296 | * Something failed or the we have timedout; |
245ba56a KS |
297 | * terminate the host-side iteration by returning an error. |
298 | */ | |
299 | icmsghdrp->status = HV_E_FAIL; | |
300 | goto response_done; | |
301 | } | |
302 | ||
fa3d5b85 S |
303 | icmsghdrp->status = HV_S_OK; |
304 | ||
305 | kvp_msg = (struct hv_kvp_msg *) | |
306 | &recv_buffer[sizeof(struct vmbuspipe_hdr) + | |
307 | sizeof(struct icmsg_hdr)]; | |
308 | ||
309 | switch (kvp_transaction.kvp_msg->kvp_hdr.operation) { | |
310 | case KVP_OP_GET: | |
311 | kvp_data = &kvp_msg->body.kvp_get.data; | |
312 | goto copy_value; | |
313 | ||
314 | case KVP_OP_SET: | |
315 | case KVP_OP_DELETE: | |
316 | goto response_done; | |
317 | ||
318 | default: | |
319 | break; | |
320 | } | |
321 | ||
322 | kvp_data = &kvp_msg->body.kvp_enum_data.data; | |
323 | key_name = key; | |
324 | ||
245ba56a KS |
325 | /* |
326 | * The windows host expects the key/value pair to be encoded | |
fa3d5b85 S |
327 | * in utf16. Ensure that the key/value size reported to the host |
328 | * will be less than or equal to the MAX size (including the | |
329 | * terminating character). | |
245ba56a | 330 | */ |
0720a06a | 331 | keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN, |
fa3d5b85 S |
332 | (wchar_t *) kvp_data->key, |
333 | (HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2) - 2); | |
334 | kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */ | |
335 | ||
336 | copy_value: | |
0720a06a | 337 | valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, |
fa3d5b85 S |
338 | (wchar_t *) kvp_data->value, |
339 | (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2); | |
340 | kvp_data->value_size = 2*(valuelen + 1); /* utf16 encoding */ | |
245ba56a | 341 | |
fa3d5b85 S |
342 | /* |
343 | * If the utf8s to utf16s conversion failed; notify host | |
344 | * of the error. | |
345 | */ | |
346 | if ((keylen < 0) || (valuelen < 0)) | |
347 | icmsghdrp->status = HV_E_FAIL; | |
348 | ||
349 | kvp_data->value_type = REG_SZ; /* all our values are strings */ | |
245ba56a KS |
350 | |
351 | response_done: | |
352 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; | |
353 | ||
354 | vmbus_sendpacket(channel, recv_buffer, buf_len, req_id, | |
415f2287 | 355 | VM_PKT_DATA_INBAND, 0); |
245ba56a | 356 | |
245ba56a KS |
357 | } |
358 | ||
359 | /* | |
360 | * This callback is invoked when we get a KVP message from the host. | |
361 | * The host ensures that only one KVP transaction can be active at a time. | |
362 | * KVP implementation in Linux needs to forward the key to a user-mde | |
363 | * component to retrive the corresponding value. Consequently, we cannot | |
364 | * respond to the host in the conext of this callback. Since the host | |
365 | * guarantees that at most only one transaction can be active at a time, | |
366 | * we stash away the transaction state in a set of global variables. | |
367 | */ | |
368 | ||
369 | void hv_kvp_onchannelcallback(void *context) | |
370 | { | |
371 | struct vmbus_channel *channel = context; | |
372 | u32 recvlen; | |
373 | u64 requestid; | |
374 | ||
375 | struct hv_kvp_msg *kvp_msg; | |
245ba56a KS |
376 | |
377 | struct icmsg_hdr *icmsghdrp; | |
378 | struct icmsg_negotiate *negop = NULL; | |
379 | ||
fa3d5b85 S |
380 | if (kvp_transaction.active) { |
381 | /* | |
382 | * We will defer processing this callback once | |
383 | * the current transaction is complete. | |
384 | */ | |
385 | kvp_transaction.kvp_context = context; | |
386 | return; | |
387 | } | |
245ba56a | 388 | |
245ba56a KS |
389 | vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid); |
390 | ||
391 | if (recvlen > 0) { | |
245ba56a KS |
392 | icmsghdrp = (struct icmsg_hdr *)&recv_buffer[ |
393 | sizeof(struct vmbuspipe_hdr)]; | |
394 | ||
395 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { | |
da0e9631 | 396 | vmbus_prep_negotiate_resp(icmsghdrp, negop, recv_buffer); |
245ba56a KS |
397 | } else { |
398 | kvp_msg = (struct hv_kvp_msg *)&recv_buffer[ | |
399 | sizeof(struct vmbuspipe_hdr) + | |
400 | sizeof(struct icmsg_hdr)]; | |
401 | ||
245ba56a KS |
402 | /* |
403 | * Stash away this global state for completing the | |
404 | * transaction; note transactions are serialized. | |
405 | */ | |
fa3d5b85 | 406 | |
245ba56a KS |
407 | kvp_transaction.recv_len = recvlen; |
408 | kvp_transaction.recv_channel = channel; | |
409 | kvp_transaction.recv_req_id = requestid; | |
410 | kvp_transaction.active = true; | |
fa3d5b85 | 411 | kvp_transaction.kvp_msg = kvp_msg; |
245ba56a KS |
412 | |
413 | /* | |
414 | * Get the information from the | |
415 | * user-mode component. | |
416 | * component. This transaction will be | |
417 | * completed when we get the value from | |
418 | * the user-mode component. | |
419 | * Set a timeout to deal with | |
420 | * user-mode not responding. | |
421 | */ | |
e2bb6537 S |
422 | schedule_work(&kvp_sendkey_work); |
423 | schedule_delayed_work(&kvp_work, 5*HZ); | |
245ba56a KS |
424 | |
425 | return; | |
426 | ||
427 | } | |
428 | ||
245ba56a KS |
429 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
430 | | ICMSGHDRFLAG_RESPONSE; | |
431 | ||
432 | vmbus_sendpacket(channel, recv_buffer, | |
433 | recvlen, requestid, | |
415f2287 | 434 | VM_PKT_DATA_INBAND, 0); |
245ba56a KS |
435 | } |
436 | ||
437 | } | |
438 | ||
439 | int | |
a29b643c | 440 | hv_kvp_init(struct hv_util_service *srv) |
245ba56a KS |
441 | { |
442 | int err; | |
443 | ||
444 | err = cn_add_callback(&kvp_id, kvp_name, kvp_cn_callback); | |
445 | if (err) | |
446 | return err; | |
a29b643c | 447 | recv_buffer = srv->recv_buffer; |
245ba56a | 448 | |
fa3d5b85 S |
449 | /* |
450 | * When this driver loads, the user level daemon that | |
451 | * processes the host requests may not yet be running. | |
452 | * Defer processing channel callbacks until the daemon | |
453 | * has registered. | |
454 | */ | |
455 | kvp_transaction.active = true; | |
456 | ||
245ba56a KS |
457 | return 0; |
458 | } | |
459 | ||
460 | void hv_kvp_deinit(void) | |
461 | { | |
462 | cn_del_callback(&kvp_id); | |
463 | cancel_delayed_work_sync(&kvp_work); | |
e2bb6537 | 464 | cancel_work_sync(&kvp_sendkey_work); |
245ba56a | 465 | } |