diff options
author | K. Y. Srinivasan <kys@microsoft.com> | 2012-08-16 21:32:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-17 11:23:57 -0400 |
commit | 03db7724af1315f644ddc26e9539789eac4a016a (patch) | |
tree | ce3c2a6a641af101c514d6e24d379927136f12ae /drivers/hv/hv_kvp.c | |
parent | ab6dd8e5ecf8c1a38ee1b9b9dfa9ab129dc3e200 (diff) |
Drivers: hv: kvp: Support the new IP injection messages
Implement support for the new IP injection messages in the driver code.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/hv_kvp.c')
-rw-r--r-- | drivers/hv/hv_kvp.c | 141 |
1 files changed, 135 insertions, 6 deletions
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index eb4d0730f44d..d9060502b073 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -63,7 +63,7 @@ static int dm_reg_value; | |||
63 | static void kvp_send_key(struct work_struct *dummy); | 63 | static void kvp_send_key(struct work_struct *dummy); |
64 | 64 | ||
65 | 65 | ||
66 | static void kvp_respond_to_host(char *key, char *value, int error); | 66 | static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error); |
67 | static void kvp_work_func(struct work_struct *dummy); | 67 | static void kvp_work_func(struct work_struct *dummy); |
68 | static void kvp_register(int); | 68 | static void kvp_register(int); |
69 | 69 | ||
@@ -108,7 +108,7 @@ kvp_work_func(struct work_struct *dummy) | |||
108 | * If the timer fires, the user-mode component has not responded; | 108 | * If the timer fires, the user-mode component has not responded; |
109 | * process the pending transaction. | 109 | * process the pending transaction. |
110 | */ | 110 | */ |
111 | kvp_respond_to_host("Unknown key", "Guest timed out", HV_E_FAIL); | 111 | kvp_respond_to_host(NULL, HV_E_FAIL); |
112 | } | 112 | } |
113 | 113 | ||
114 | static int kvp_handle_handshake(struct hv_kvp_msg *msg) | 114 | static int kvp_handle_handshake(struct hv_kvp_msg *msg) |
@@ -199,9 +199,118 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
199 | * to the host. But first, cancel the timeout. | 199 | * to the host. But first, cancel the timeout. |
200 | */ | 200 | */ |
201 | if (cancel_delayed_work_sync(&kvp_work)) | 201 | if (cancel_delayed_work_sync(&kvp_work)) |
202 | kvp_respond_to_host(data->data.key, data->data.value, error); | 202 | kvp_respond_to_host(message, error); |
203 | } | 203 | } |
204 | 204 | ||
205 | |||
206 | static int process_ob_ipinfo(void *in_msg, void *out_msg, int op) | ||
207 | { | ||
208 | struct hv_kvp_msg *in = in_msg; | ||
209 | struct hv_kvp_ip_msg *out = out_msg; | ||
210 | int len; | ||
211 | |||
212 | switch (op) { | ||
213 | case KVP_OP_GET_IP_INFO: | ||
214 | /* | ||
215 | * Transform all parameters into utf16 encoding. | ||
216 | */ | ||
217 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.ip_addr, | ||
218 | strlen((char *)in->body.kvp_ip_val.ip_addr), | ||
219 | UTF16_HOST_ENDIAN, | ||
220 | (wchar_t *)out->kvp_ip_val.ip_addr, | ||
221 | MAX_IP_ADDR_SIZE); | ||
222 | if (len < 0) | ||
223 | return len; | ||
224 | |||
225 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.sub_net, | ||
226 | strlen((char *)in->body.kvp_ip_val.sub_net), | ||
227 | UTF16_HOST_ENDIAN, | ||
228 | (wchar_t *)out->kvp_ip_val.sub_net, | ||
229 | MAX_IP_ADDR_SIZE); | ||
230 | if (len < 0) | ||
231 | return len; | ||
232 | |||
233 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.gate_way, | ||
234 | strlen((char *)in->body.kvp_ip_val.gate_way), | ||
235 | UTF16_HOST_ENDIAN, | ||
236 | (wchar_t *)out->kvp_ip_val.gate_way, | ||
237 | MAX_GATEWAY_SIZE); | ||
238 | if (len < 0) | ||
239 | return len; | ||
240 | |||
241 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.dns_addr, | ||
242 | strlen((char *)in->body.kvp_ip_val.dns_addr), | ||
243 | UTF16_HOST_ENDIAN, | ||
244 | (wchar_t *)out->kvp_ip_val.dns_addr, | ||
245 | MAX_IP_ADDR_SIZE); | ||
246 | if (len < 0) | ||
247 | return len; | ||
248 | |||
249 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.adapter_id, | ||
250 | strlen((char *)in->body.kvp_ip_val.adapter_id), | ||
251 | UTF16_HOST_ENDIAN, | ||
252 | (wchar_t *)out->kvp_ip_val.adapter_id, | ||
253 | MAX_IP_ADDR_SIZE); | ||
254 | if (len < 0) | ||
255 | return len; | ||
256 | |||
257 | out->kvp_ip_val.dhcp_enabled = | ||
258 | in->body.kvp_ip_val.dhcp_enabled; | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static void process_ib_ipinfo(void *in_msg, void *out_msg, int op) | ||
265 | { | ||
266 | struct hv_kvp_ip_msg *in = in_msg; | ||
267 | struct hv_kvp_msg *out = out_msg; | ||
268 | |||
269 | switch (op) { | ||
270 | case KVP_OP_SET_IP_INFO: | ||
271 | /* | ||
272 | * Transform all parameters into utf8 encoding. | ||
273 | */ | ||
274 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.ip_addr, | ||
275 | MAX_IP_ADDR_SIZE, | ||
276 | UTF16_LITTLE_ENDIAN, | ||
277 | (__u8 *)out->body.kvp_ip_val.ip_addr, | ||
278 | MAX_IP_ADDR_SIZE); | ||
279 | |||
280 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.sub_net, | ||
281 | MAX_IP_ADDR_SIZE, | ||
282 | UTF16_LITTLE_ENDIAN, | ||
283 | (__u8 *)out->body.kvp_ip_val.sub_net, | ||
284 | MAX_IP_ADDR_SIZE); | ||
285 | |||
286 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.gate_way, | ||
287 | MAX_GATEWAY_SIZE, | ||
288 | UTF16_LITTLE_ENDIAN, | ||
289 | (__u8 *)out->body.kvp_ip_val.gate_way, | ||
290 | MAX_GATEWAY_SIZE); | ||
291 | |||
292 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.dns_addr, | ||
293 | MAX_IP_ADDR_SIZE, | ||
294 | UTF16_LITTLE_ENDIAN, | ||
295 | (__u8 *)out->body.kvp_ip_val.dns_addr, | ||
296 | MAX_IP_ADDR_SIZE); | ||
297 | |||
298 | out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled; | ||
299 | |||
300 | default: | ||
301 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id, | ||
302 | MAX_ADAPTER_ID_SIZE, | ||
303 | UTF16_LITTLE_ENDIAN, | ||
304 | (__u8 *)out->body.kvp_ip_val.adapter_id, | ||
305 | MAX_ADAPTER_ID_SIZE); | ||
306 | |||
307 | out->body.kvp_ip_val.addr_family = in->kvp_ip_val.addr_family; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | |||
312 | |||
313 | |||
205 | static void | 314 | static void |
206 | kvp_send_key(struct work_struct *dummy) | 315 | kvp_send_key(struct work_struct *dummy) |
207 | { | 316 | { |
@@ -237,6 +346,12 @@ kvp_send_key(struct work_struct *dummy) | |||
237 | */ | 346 | */ |
238 | 347 | ||
239 | switch (message->kvp_hdr.operation) { | 348 | switch (message->kvp_hdr.operation) { |
349 | case KVP_OP_SET_IP_INFO: | ||
350 | process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO); | ||
351 | break; | ||
352 | case KVP_OP_GET_IP_INFO: | ||
353 | process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO); | ||
354 | break; | ||
240 | case KVP_OP_SET: | 355 | case KVP_OP_SET: |
241 | switch (in_msg->body.kvp_set.data.value_type) { | 356 | switch (in_msg->body.kvp_set.data.value_type) { |
242 | case REG_SZ: | 357 | case REG_SZ: |
@@ -313,17 +428,19 @@ kvp_send_key(struct work_struct *dummy) | |||
313 | */ | 428 | */ |
314 | 429 | ||
315 | static void | 430 | static void |
316 | kvp_respond_to_host(char *key, char *value, int error) | 431 | kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error) |
317 | { | 432 | { |
318 | struct hv_kvp_msg *kvp_msg; | 433 | struct hv_kvp_msg *kvp_msg; |
319 | struct hv_kvp_exchg_msg_value *kvp_data; | 434 | struct hv_kvp_exchg_msg_value *kvp_data; |
320 | char *key_name; | 435 | char *key_name; |
436 | char *value; | ||
321 | struct icmsg_hdr *icmsghdrp; | 437 | struct icmsg_hdr *icmsghdrp; |
322 | int keylen = 0; | 438 | int keylen = 0; |
323 | int valuelen = 0; | 439 | int valuelen = 0; |
324 | u32 buf_len; | 440 | u32 buf_len; |
325 | struct vmbus_channel *channel; | 441 | struct vmbus_channel *channel; |
326 | u64 req_id; | 442 | u64 req_id; |
443 | int ret; | ||
327 | 444 | ||
328 | /* | 445 | /* |
329 | * If a transaction is not active; log and return. | 446 | * If a transaction is not active; log and return. |
@@ -376,6 +493,16 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
376 | sizeof(struct icmsg_hdr)]; | 493 | sizeof(struct icmsg_hdr)]; |
377 | 494 | ||
378 | switch (kvp_transaction.kvp_msg->kvp_hdr.operation) { | 495 | switch (kvp_transaction.kvp_msg->kvp_hdr.operation) { |
496 | case KVP_OP_GET_IP_INFO: | ||
497 | ret = process_ob_ipinfo(msg_to_host, | ||
498 | (struct hv_kvp_ip_msg *)kvp_msg, | ||
499 | KVP_OP_GET_IP_INFO); | ||
500 | if (ret < 0) | ||
501 | icmsghdrp->status = HV_E_FAIL; | ||
502 | |||
503 | goto response_done; | ||
504 | case KVP_OP_SET_IP_INFO: | ||
505 | goto response_done; | ||
379 | case KVP_OP_GET: | 506 | case KVP_OP_GET: |
380 | kvp_data = &kvp_msg->body.kvp_get.data; | 507 | kvp_data = &kvp_msg->body.kvp_get.data; |
381 | goto copy_value; | 508 | goto copy_value; |
@@ -389,7 +516,7 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
389 | } | 516 | } |
390 | 517 | ||
391 | kvp_data = &kvp_msg->body.kvp_enum_data.data; | 518 | kvp_data = &kvp_msg->body.kvp_enum_data.data; |
392 | key_name = key; | 519 | key_name = msg_to_host->body.kvp_enum_data.data.key; |
393 | 520 | ||
394 | /* | 521 | /* |
395 | * The windows host expects the key/value pair to be encoded | 522 | * The windows host expects the key/value pair to be encoded |
@@ -403,6 +530,7 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
403 | kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */ | 530 | kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */ |
404 | 531 | ||
405 | copy_value: | 532 | copy_value: |
533 | value = msg_to_host->body.kvp_enum_data.data.value; | ||
406 | valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, | 534 | valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, |
407 | (wchar_t *) kvp_data->value, | 535 | (wchar_t *) kvp_data->value, |
408 | (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2); | 536 | (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2); |
@@ -455,7 +583,8 @@ void hv_kvp_onchannelcallback(void *context) | |||
455 | return; | 583 | return; |
456 | } | 584 | } |
457 | 585 | ||
458 | vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid); | 586 | vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, |
587 | &requestid); | ||
459 | 588 | ||
460 | if (recvlen > 0) { | 589 | if (recvlen > 0) { |
461 | icmsghdrp = (struct icmsg_hdr *)&recv_buffer[ | 590 | icmsghdrp = (struct icmsg_hdr *)&recv_buffer[ |