aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hv/hv_kvp.c114
1 files changed, 91 insertions, 23 deletions
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 0012eed6d872..eb4d0730f44d 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 */
56static bool in_hand_shake = true;
57
58/*
59 * This state maintains the version number registered by the daemon.
60 */
61static int dm_reg_value;
62
51static void kvp_send_key(struct work_struct *dummy); 63static void kvp_send_key(struct work_struct *dummy);
52 64
53#define TIMEOUT_FIRED 1
54 65
55static void kvp_respond_to_host(char *key, char *value, int error); 66static void kvp_respond_to_host(char *key, char *value, int error);
56static void kvp_work_func(struct work_struct *dummy); 67static void kvp_work_func(struct work_struct *dummy);
57static void kvp_register(void); 68static void kvp_register(int);
58 69
59static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func); 70static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func);
60static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); 71static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
@@ -68,7 +79,7 @@ static u8 *recv_buffer;
68 */ 79 */
69 80
70static void 81static void
71kvp_register(void) 82kvp_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
114static 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
135static void 205static 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)];