diff options
-rw-r--r-- | drivers/hv/hv_kvp.c | 114 | ||||
-rw-r--r-- | include/linux/hyperv.h | 17 | ||||
-rw-r--r-- | tools/hv/hv_kvp_daemon.c | 66 |
3 files changed, 135 insertions, 62 deletions
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 0012eed6d87..eb4d0730f44 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -48,13 +48,24 @@ static struct { | |||
48 | void *kvp_context; /* for the channel callback */ | 48 | void *kvp_context; /* for the channel callback */ |
49 | } kvp_transaction; | 49 | } kvp_transaction; |
50 | 50 | ||
51 | /* | ||
52 | * Before we can accept KVP messages from the host, we need | ||
53 | * to handshake with the user level daemon. This state tracks | ||
54 | * if we are in the handshake phase. | ||
55 | */ | ||
56 | static bool in_hand_shake = true; | ||
57 | |||
58 | /* | ||
59 | * This state maintains the version number registered by the daemon. | ||
60 | */ | ||
61 | static int dm_reg_value; | ||
62 | |||
51 | static void kvp_send_key(struct work_struct *dummy); | 63 | static void kvp_send_key(struct work_struct *dummy); |
52 | 64 | ||
53 | #define TIMEOUT_FIRED 1 | ||
54 | 65 | ||
55 | static void kvp_respond_to_host(char *key, char *value, int error); | 66 | static void kvp_respond_to_host(char *key, char *value, int error); |
56 | static void kvp_work_func(struct work_struct *dummy); | 67 | static void kvp_work_func(struct work_struct *dummy); |
57 | static void kvp_register(void); | 68 | static void kvp_register(int); |
58 | 69 | ||
59 | static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func); | 70 | static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func); |
60 | static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); | 71 | static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); |
@@ -68,7 +79,7 @@ static u8 *recv_buffer; | |||
68 | */ | 79 | */ |
69 | 80 | ||
70 | static void | 81 | static void |
71 | kvp_register(void) | 82 | kvp_register(int reg_value) |
72 | { | 83 | { |
73 | 84 | ||
74 | struct cn_msg *msg; | 85 | struct cn_msg *msg; |
@@ -83,7 +94,7 @@ kvp_register(void) | |||
83 | msg->id.idx = CN_KVP_IDX; | 94 | msg->id.idx = CN_KVP_IDX; |
84 | msg->id.val = CN_KVP_VAL; | 95 | msg->id.val = CN_KVP_VAL; |
85 | 96 | ||
86 | kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER; | 97 | kvp_msg->kvp_hdr.operation = reg_value; |
87 | strcpy(version, HV_DRV_VERSION); | 98 | strcpy(version, HV_DRV_VERSION); |
88 | msg->len = sizeof(struct hv_kvp_msg); | 99 | msg->len = sizeof(struct hv_kvp_msg); |
89 | cn_netlink_send(msg, 0, GFP_ATOMIC); | 100 | cn_netlink_send(msg, 0, GFP_ATOMIC); |
@@ -97,9 +108,43 @@ kvp_work_func(struct work_struct *dummy) | |||
97 | * If the timer fires, the user-mode component has not responded; | 108 | * If the timer fires, the user-mode component has not responded; |
98 | * process the pending transaction. | 109 | * process the pending transaction. |
99 | */ | 110 | */ |
100 | kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED); | 111 | kvp_respond_to_host("Unknown key", "Guest timed out", HV_E_FAIL); |
112 | } | ||
113 | |||
114 | static int kvp_handle_handshake(struct hv_kvp_msg *msg) | ||
115 | { | ||
116 | int ret = 1; | ||
117 | |||
118 | switch (msg->kvp_hdr.operation) { | ||
119 | case KVP_OP_REGISTER: | ||
120 | dm_reg_value = KVP_OP_REGISTER; | ||
121 | pr_info("KVP: IP injection functionality not available\n"); | ||
122 | pr_info("KVP: Upgrade the KVP daemon\n"); | ||
123 | break; | ||
124 | case KVP_OP_REGISTER1: | ||
125 | dm_reg_value = KVP_OP_REGISTER1; | ||
126 | break; | ||
127 | default: | ||
128 | pr_info("KVP: incompatible daemon\n"); | ||
129 | pr_info("KVP: KVP version: %d, Daemon version: %d\n", | ||
130 | KVP_OP_REGISTER1, msg->kvp_hdr.operation); | ||
131 | ret = 0; | ||
132 | } | ||
133 | |||
134 | if (ret) { | ||
135 | /* | ||
136 | * We have a compatible daemon; complete the handshake. | ||
137 | */ | ||
138 | pr_info("KVP: user-mode registering done.\n"); | ||
139 | kvp_register(dm_reg_value); | ||
140 | kvp_transaction.active = false; | ||
141 | if (kvp_transaction.kvp_context) | ||
142 | hv_kvp_onchannelcallback(kvp_transaction.kvp_context); | ||
143 | } | ||
144 | return ret; | ||
101 | } | 145 | } |
102 | 146 | ||
147 | |||
103 | /* | 148 | /* |
104 | * Callback when data is received from user mode. | 149 | * Callback when data is received from user mode. |
105 | */ | 150 | */ |
@@ -109,27 +154,52 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
109 | { | 154 | { |
110 | struct hv_kvp_msg *message; | 155 | struct hv_kvp_msg *message; |
111 | struct hv_kvp_msg_enumerate *data; | 156 | struct hv_kvp_msg_enumerate *data; |
157 | int error = 0; | ||
112 | 158 | ||
113 | message = (struct hv_kvp_msg *)msg->data; | 159 | message = (struct hv_kvp_msg *)msg->data; |
114 | switch (message->kvp_hdr.operation) { | 160 | |
161 | /* | ||
162 | * If we are negotiating the version information | ||
163 | * with the daemon; handle that first. | ||
164 | */ | ||
165 | |||
166 | if (in_hand_shake) { | ||
167 | if (kvp_handle_handshake(message)) | ||
168 | in_hand_shake = false; | ||
169 | return; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Based on the version of the daemon, we propagate errors from the | ||
174 | * daemon differently. | ||
175 | */ | ||
176 | |||
177 | data = &message->body.kvp_enum_data; | ||
178 | |||
179 | switch (dm_reg_value) { | ||
115 | case KVP_OP_REGISTER: | 180 | case KVP_OP_REGISTER: |
116 | pr_info("KVP: user-mode registering done.\n"); | 181 | /* |
117 | kvp_register(); | 182 | * Null string is used to pass back error condition. |
118 | kvp_transaction.active = false; | 183 | */ |
119 | hv_kvp_onchannelcallback(kvp_transaction.kvp_context); | 184 | if (data->data.key[0] == 0) |
185 | error = HV_S_CONT; | ||
120 | break; | 186 | break; |
121 | 187 | ||
122 | default: | 188 | case KVP_OP_REGISTER1: |
123 | data = &message->body.kvp_enum_data; | ||
124 | /* | 189 | /* |
125 | * Complete the transaction by forwarding the key value | 190 | * We use the message header information from |
126 | * to the host. But first, cancel the timeout. | 191 | * the user level daemon to transmit errors. |
127 | */ | 192 | */ |
128 | if (cancel_delayed_work_sync(&kvp_work)) | 193 | error = message->error; |
129 | kvp_respond_to_host(data->data.key, | 194 | break; |
130 | data->data.value, | ||
131 | !strlen(data->data.key)); | ||
132 | } | 195 | } |
196 | |||
197 | /* | ||
198 | * Complete the transaction by forwarding the key value | ||
199 | * to the host. But first, cancel the timeout. | ||
200 | */ | ||
201 | if (cancel_delayed_work_sync(&kvp_work)) | ||
202 | kvp_respond_to_host(data->data.key, data->data.value, error); | ||
133 | } | 203 | } |
134 | 204 | ||
135 | static void | 205 | static void |
@@ -287,6 +357,7 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
287 | */ | 357 | */ |
288 | return; | 358 | return; |
289 | 359 | ||
360 | icmsghdrp->status = error; | ||
290 | 361 | ||
291 | /* | 362 | /* |
292 | * If the error parameter is set, terminate the host's enumeration | 363 | * If the error parameter is set, terminate the host's enumeration |
@@ -294,15 +365,12 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
294 | */ | 365 | */ |
295 | if (error) { | 366 | if (error) { |
296 | /* | 367 | /* |
297 | * Something failed or the we have timedout; | 368 | * Something failed or we have timedout; |
298 | * terminate the current host-side iteration. | 369 | * terminate the current host-side iteration. |
299 | */ | 370 | */ |
300 | icmsghdrp->status = HV_S_CONT; | ||
301 | goto response_done; | 371 | goto response_done; |
302 | } | 372 | } |
303 | 373 | ||
304 | icmsghdrp->status = HV_S_OK; | ||
305 | |||
306 | kvp_msg = (struct hv_kvp_msg *) | 374 | kvp_msg = (struct hv_kvp_msg *) |
307 | &recv_buffer[sizeof(struct vmbuspipe_hdr) + | 375 | &recv_buffer[sizeof(struct vmbuspipe_hdr) + |
308 | sizeof(struct icmsg_hdr)]; | 376 | sizeof(struct icmsg_hdr)]; |
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 11afc4e0849..b587c448e8a 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h | |||
@@ -181,6 +181,17 @@ enum hv_kvp_exchg_pool { | |||
181 | KVP_POOL_COUNT /* Number of pools, must be last. */ | 181 | KVP_POOL_COUNT /* Number of pools, must be last. */ |
182 | }; | 182 | }; |
183 | 183 | ||
184 | /* | ||
185 | * Some Hyper-V status codes. | ||
186 | */ | ||
187 | |||
188 | #define HV_S_OK 0x00000000 | ||
189 | #define HV_E_FAIL 0x80004005 | ||
190 | #define HV_S_CONT 0x80070103 | ||
191 | #define HV_ERROR_NOT_SUPPORTED 0x80070032 | ||
192 | #define HV_ERROR_MACHINE_LOCKED 0x800704F7 | ||
193 | #define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F | ||
194 | |||
184 | #define ADDR_FAMILY_NONE 0x00 | 195 | #define ADDR_FAMILY_NONE 0x00 |
185 | #define ADDR_FAMILY_IPV4 0x01 | 196 | #define ADDR_FAMILY_IPV4 0x01 |
186 | #define ADDR_FAMILY_IPV6 0x02 | 197 | #define ADDR_FAMILY_IPV6 0x02 |
@@ -1048,12 +1059,6 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver); | |||
1048 | #define ICMSGHDRFLAG_REQUEST 2 | 1059 | #define ICMSGHDRFLAG_REQUEST 2 |
1049 | #define ICMSGHDRFLAG_RESPONSE 4 | 1060 | #define ICMSGHDRFLAG_RESPONSE 4 |
1050 | 1061 | ||
1051 | #define HV_S_OK 0x00000000 | ||
1052 | #define HV_E_FAIL 0x80004005 | ||
1053 | #define HV_S_CONT 0x80070103 | ||
1054 | #define HV_ERROR_NOT_SUPPORTED 0x80070032 | ||
1055 | #define HV_ERROR_MACHINE_LOCKED 0x800704F7 | ||
1056 | #define HV_ERROR_DEVICE_NOT_CONNECTED 0x8007048F | ||
1057 | 1062 | ||
1058 | /* | 1063 | /* |
1059 | * While we want to handle util services as regular devices, | 1064 | * While we want to handle util services as regular devices, |
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 8fbcf7b3c69..069e2b38dec 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -71,13 +71,14 @@ enum key_index { | |||
71 | static char kvp_send_buffer[4096]; | 71 | static char kvp_send_buffer[4096]; |
72 | static char kvp_recv_buffer[4096 * 2]; | 72 | static char kvp_recv_buffer[4096 * 2]; |
73 | static struct sockaddr_nl addr; | 73 | static struct sockaddr_nl addr; |
74 | static int in_hand_shake = 1; | ||
74 | 75 | ||
75 | static char *os_name = ""; | 76 | static char *os_name = ""; |
76 | static char *os_major = ""; | 77 | static char *os_major = ""; |
77 | static char *os_minor = ""; | 78 | static char *os_minor = ""; |
78 | static char *processor_arch; | 79 | static char *processor_arch; |
79 | static char *os_build; | 80 | static char *os_build; |
80 | static char *lic_version; | 81 | static char *lic_version = "Unknown version"; |
81 | static struct utsname uts_buf; | 82 | static struct utsname uts_buf; |
82 | 83 | ||
83 | 84 | ||
@@ -394,7 +395,7 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, | |||
394 | return 1; | 395 | return 1; |
395 | } | 396 | } |
396 | 397 | ||
397 | static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, | 398 | static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, |
398 | __u8 *value, int value_size) | 399 | __u8 *value, int value_size) |
399 | { | 400 | { |
400 | struct kvp_record *record; | 401 | struct kvp_record *record; |
@@ -406,16 +407,12 @@ static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, | |||
406 | record = kvp_file_info[pool].records; | 407 | record = kvp_file_info[pool].records; |
407 | 408 | ||
408 | if (index >= kvp_file_info[pool].num_records) { | 409 | if (index >= kvp_file_info[pool].num_records) { |
409 | /* | 410 | return 1; |
410 | * This is an invalid index; terminate enumeration; | ||
411 | * - a NULL value will do the trick. | ||
412 | */ | ||
413 | strcpy(value, ""); | ||
414 | return; | ||
415 | } | 411 | } |
416 | 412 | ||
417 | memcpy(key, record[index].key, key_size); | 413 | memcpy(key, record[index].key, key_size); |
418 | memcpy(value, record[index].value, value_size); | 414 | memcpy(value, record[index].value, value_size); |
415 | return 0; | ||
419 | } | 416 | } |
420 | 417 | ||
421 | 418 | ||
@@ -646,6 +643,8 @@ int main(void) | |||
646 | char *p; | 643 | char *p; |
647 | char *key_value; | 644 | char *key_value; |
648 | char *key_name; | 645 | char *key_name; |
646 | int op; | ||
647 | int pool; | ||
649 | 648 | ||
650 | daemon(1, 0); | 649 | daemon(1, 0); |
651 | openlog("KVP", 0, LOG_USER); | 650 | openlog("KVP", 0, LOG_USER); |
@@ -687,7 +686,7 @@ int main(void) | |||
687 | message->id.val = CN_KVP_VAL; | 686 | message->id.val = CN_KVP_VAL; |
688 | 687 | ||
689 | hv_msg = (struct hv_kvp_msg *)message->data; | 688 | hv_msg = (struct hv_kvp_msg *)message->data; |
690 | hv_msg->kvp_hdr.operation = KVP_OP_REGISTER; | 689 | hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1; |
691 | message->ack = 0; | 690 | message->ack = 0; |
692 | message->len = sizeof(struct hv_kvp_msg); | 691 | message->len = sizeof(struct hv_kvp_msg); |
693 | 692 | ||
@@ -721,12 +720,21 @@ int main(void) | |||
721 | incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); | 720 | incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); |
722 | hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; | 721 | hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; |
723 | 722 | ||
724 | switch (hv_msg->kvp_hdr.operation) { | 723 | /* |
725 | case KVP_OP_REGISTER: | 724 | * We will use the KVP header information to pass back |
725 | * the error from this daemon. So, first copy the state | ||
726 | * and set the error code to success. | ||
727 | */ | ||
728 | op = hv_msg->kvp_hdr.operation; | ||
729 | pool = hv_msg->kvp_hdr.pool; | ||
730 | hv_msg->error = HV_S_OK; | ||
731 | |||
732 | if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) { | ||
726 | /* | 733 | /* |
727 | * Driver is registering with us; stash away the version | 734 | * Driver is registering with us; stash away the version |
728 | * information. | 735 | * information. |
729 | */ | 736 | */ |
737 | in_hand_shake = 0; | ||
730 | p = (char *)hv_msg->body.kvp_register.version; | 738 | p = (char *)hv_msg->body.kvp_register.version; |
731 | lic_version = malloc(strlen(p) + 1); | 739 | lic_version = malloc(strlen(p) + 1); |
732 | if (lic_version) { | 740 | if (lic_version) { |
@@ -737,44 +745,39 @@ int main(void) | |||
737 | syslog(LOG_ERR, "malloc failed"); | 745 | syslog(LOG_ERR, "malloc failed"); |
738 | } | 746 | } |
739 | continue; | 747 | continue; |
748 | } | ||
740 | 749 | ||
741 | /* | 750 | switch (op) { |
742 | * The current protocol with the kernel component uses a | ||
743 | * NULL key name to pass an error condition. | ||
744 | * For the SET, GET and DELETE operations, | ||
745 | * use the existing protocol to pass back error. | ||
746 | */ | ||
747 | |||
748 | case KVP_OP_SET: | 751 | case KVP_OP_SET: |
749 | if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool, | 752 | if (kvp_key_add_or_modify(pool, |
750 | hv_msg->body.kvp_set.data.key, | 753 | hv_msg->body.kvp_set.data.key, |
751 | hv_msg->body.kvp_set.data.key_size, | 754 | hv_msg->body.kvp_set.data.key_size, |
752 | hv_msg->body.kvp_set.data.value, | 755 | hv_msg->body.kvp_set.data.value, |
753 | hv_msg->body.kvp_set.data.value_size)) | 756 | hv_msg->body.kvp_set.data.value_size)) |
754 | strcpy(hv_msg->body.kvp_set.data.key, ""); | 757 | hv_msg->error = HV_S_CONT; |
755 | break; | 758 | break; |
756 | 759 | ||
757 | case KVP_OP_GET: | 760 | case KVP_OP_GET: |
758 | if (kvp_get_value(hv_msg->kvp_hdr.pool, | 761 | if (kvp_get_value(pool, |
759 | hv_msg->body.kvp_set.data.key, | 762 | hv_msg->body.kvp_set.data.key, |
760 | hv_msg->body.kvp_set.data.key_size, | 763 | hv_msg->body.kvp_set.data.key_size, |
761 | hv_msg->body.kvp_set.data.value, | 764 | hv_msg->body.kvp_set.data.value, |
762 | hv_msg->body.kvp_set.data.value_size)) | 765 | hv_msg->body.kvp_set.data.value_size)) |
763 | strcpy(hv_msg->body.kvp_set.data.key, ""); | 766 | hv_msg->error = HV_S_CONT; |
764 | break; | 767 | break; |
765 | 768 | ||
766 | case KVP_OP_DELETE: | 769 | case KVP_OP_DELETE: |
767 | if (kvp_key_delete(hv_msg->kvp_hdr.pool, | 770 | if (kvp_key_delete(pool, |
768 | hv_msg->body.kvp_delete.key, | 771 | hv_msg->body.kvp_delete.key, |
769 | hv_msg->body.kvp_delete.key_size)) | 772 | hv_msg->body.kvp_delete.key_size)) |
770 | strcpy(hv_msg->body.kvp_delete.key, ""); | 773 | hv_msg->error = HV_S_CONT; |
771 | break; | 774 | break; |
772 | 775 | ||
773 | default: | 776 | default: |
774 | break; | 777 | break; |
775 | } | 778 | } |
776 | 779 | ||
777 | if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE) | 780 | if (op != KVP_OP_ENUMERATE) |
778 | goto kvp_done; | 781 | goto kvp_done; |
779 | 782 | ||
780 | /* | 783 | /* |
@@ -782,13 +785,14 @@ int main(void) | |||
782 | * both the key and the value; if not read from the | 785 | * both the key and the value; if not read from the |
783 | * appropriate pool. | 786 | * appropriate pool. |
784 | */ | 787 | */ |
785 | if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) { | 788 | if (pool != KVP_POOL_AUTO) { |
786 | kvp_pool_enumerate(hv_msg->kvp_hdr.pool, | 789 | if (kvp_pool_enumerate(pool, |
787 | hv_msg->body.kvp_enum_data.index, | 790 | hv_msg->body.kvp_enum_data.index, |
788 | hv_msg->body.kvp_enum_data.data.key, | 791 | hv_msg->body.kvp_enum_data.data.key, |
789 | HV_KVP_EXCHANGE_MAX_KEY_SIZE, | 792 | HV_KVP_EXCHANGE_MAX_KEY_SIZE, |
790 | hv_msg->body.kvp_enum_data.data.value, | 793 | hv_msg->body.kvp_enum_data.data.value, |
791 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE); | 794 | HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) |
795 | hv_msg->error = HV_S_CONT; | ||
792 | goto kvp_done; | 796 | goto kvp_done; |
793 | } | 797 | } |
794 | 798 | ||
@@ -841,11 +845,7 @@ int main(void) | |||
841 | strcpy(key_name, "ProcessorArchitecture"); | 845 | strcpy(key_name, "ProcessorArchitecture"); |
842 | break; | 846 | break; |
843 | default: | 847 | default: |
844 | strcpy(key_value, "Unknown Key"); | 848 | hv_msg->error = HV_S_CONT; |
845 | /* | ||
846 | * We use a null key name to terminate enumeration. | ||
847 | */ | ||
848 | strcpy(key_name, ""); | ||
849 | break; | 849 | break; |
850 | } | 850 | } |
851 | /* | 851 | /* |