1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21
22#include <linux/nls.h>
23#include <linux/workqueue.h>
24#include <linux/hyperv.h>
25#include <linux/sched.h>
26
27#include "hyperv_vmbus.h"
28#include "hv_utils_transport.h"
29
30#define WIN8_SRV_MAJOR 1
31#define WIN8_SRV_MINOR 1
32#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
33
34#define FCOPY_VER_COUNT 1
35static const int fcopy_versions[] = {
36 WIN8_SRV_VERSION
37};
38
39#define FW_VER_COUNT 1
40static const int fw_versions[] = {
41 UTIL_FW_VERSION
42};
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58static struct {
59 int state;
60 int recv_len;
61 struct hv_fcopy_hdr *fcopy_msg;
62 struct vmbus_channel *recv_channel;
63 u64 recv_req_id;
64} fcopy_transaction;
65
66static void fcopy_respond_to_host(int error);
67static void fcopy_send_data(struct work_struct *dummy);
68static void fcopy_timeout_func(struct work_struct *dummy);
69static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
70static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
71static const char fcopy_devname[] = "vmbus/hv_fcopy";
72static u8 *recv_buffer;
73static struct hvutil_transport *hvt;
74
75
76
77static int dm_reg_value;
78
79static void fcopy_poll_wrapper(void *channel)
80{
81
82 fcopy_transaction.state = HVUTIL_READY;
83 hv_fcopy_onchannelcallback(channel);
84}
85
86static void fcopy_timeout_func(struct work_struct *dummy)
87{
88
89
90
91
92 fcopy_respond_to_host(HV_E_FAIL);
93 hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
94}
95
96static void fcopy_register_done(void)
97{
98 pr_debug("FCP: userspace daemon registered\n");
99 hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
100}
101
102static int fcopy_handle_handshake(u32 version)
103{
104 u32 our_ver = FCOPY_CURRENT_VERSION;
105
106 switch (version) {
107 case FCOPY_VERSION_0:
108
109 dm_reg_value = version;
110 break;
111 case FCOPY_VERSION_1:
112
113 if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
114 fcopy_register_done))
115 return -EFAULT;
116 dm_reg_value = version;
117 break;
118 default:
119
120
121
122
123
124
125 return -EINVAL;
126 }
127 pr_debug("FCP: userspace daemon ver. %d connected\n", version);
128 return 0;
129}
130
131static void fcopy_send_data(struct work_struct *dummy)
132{
133 struct hv_start_fcopy *smsg_out = NULL;
134 int operation = fcopy_transaction.fcopy_msg->operation;
135 struct hv_start_fcopy *smsg_in;
136 void *out_src;
137 int rc, out_len;
138
139
140
141
142
143
144
145
146
147
148
149
150 switch (operation) {
151 case START_FILE_COPY:
152 out_len = sizeof(struct hv_start_fcopy);
153 smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL);
154 if (!smsg_out)
155 return;
156
157 smsg_out->hdr.operation = operation;
158 smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
159
160 utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
161 UTF16_LITTLE_ENDIAN,
162 (__u8 *)&smsg_out->file_name, W_MAX_PATH - 1);
163
164 utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
165 UTF16_LITTLE_ENDIAN,
166 (__u8 *)&smsg_out->path_name, W_MAX_PATH - 1);
167
168 smsg_out->copy_flags = smsg_in->copy_flags;
169 smsg_out->file_size = smsg_in->file_size;
170 out_src = smsg_out;
171 break;
172
173 default:
174 out_src = fcopy_transaction.fcopy_msg;
175 out_len = fcopy_transaction.recv_len;
176 break;
177 }
178
179 fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
180 rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
181 if (rc) {
182 pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
183 if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
184 fcopy_respond_to_host(HV_E_FAIL);
185 fcopy_transaction.state = HVUTIL_READY;
186 }
187 }
188 kfree(smsg_out);
189
190 return;
191}
192
193
194
195
196
197static void
198fcopy_respond_to_host(int error)
199{
200 struct icmsg_hdr *icmsghdr;
201 u32 buf_len;
202 struct vmbus_channel *channel;
203 u64 req_id;
204
205
206
207
208
209
210
211
212
213 buf_len = fcopy_transaction.recv_len;
214 channel = fcopy_transaction.recv_channel;
215 req_id = fcopy_transaction.recv_req_id;
216
217 icmsghdr = (struct icmsg_hdr *)
218 &recv_buffer[sizeof(struct vmbuspipe_hdr)];
219
220 if (channel->onchannel_callback == NULL)
221
222
223
224
225 return;
226
227 icmsghdr->status = error;
228 icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
229 vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
230 VM_PKT_DATA_INBAND, 0);
231}
232
233void hv_fcopy_onchannelcallback(void *context)
234{
235 struct vmbus_channel *channel = context;
236 u32 recvlen;
237 u64 requestid;
238 struct hv_fcopy_hdr *fcopy_msg;
239 struct icmsg_hdr *icmsghdr;
240 int fcopy_srv_version;
241
242 if (fcopy_transaction.state > HVUTIL_READY)
243 return;
244
245 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
246 &requestid);
247 if (recvlen <= 0)
248 return;
249
250 icmsghdr = (struct icmsg_hdr *)&recv_buffer[
251 sizeof(struct vmbuspipe_hdr)];
252 if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
253 if (vmbus_prep_negotiate_resp(icmsghdr, recv_buffer,
254 fw_versions, FW_VER_COUNT,
255 fcopy_versions, FCOPY_VER_COUNT,
256 NULL, &fcopy_srv_version)) {
257
258 pr_info("FCopy IC version %d.%d\n",
259 fcopy_srv_version >> 16,
260 fcopy_srv_version & 0xFFFF);
261 }
262 } else {
263 fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[
264 sizeof(struct vmbuspipe_hdr) +
265 sizeof(struct icmsg_hdr)];
266
267
268
269
270
271
272 fcopy_transaction.recv_len = recvlen;
273 fcopy_transaction.recv_req_id = requestid;
274 fcopy_transaction.fcopy_msg = fcopy_msg;
275
276 if (fcopy_transaction.state < HVUTIL_READY) {
277
278 fcopy_respond_to_host(HV_E_FAIL);
279 return;
280 }
281 fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
282
283
284
285
286 schedule_work(&fcopy_send_work);
287 schedule_delayed_work(&fcopy_timeout_work,
288 HV_UTIL_TIMEOUT * HZ);
289 return;
290 }
291 icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
292 vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
293 VM_PKT_DATA_INBAND, 0);
294}
295
296
297static int fcopy_on_msg(void *msg, int len)
298{
299 int *val = (int *)msg;
300
301 if (len != sizeof(int))
302 return -EINVAL;
303
304 if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
305 return fcopy_handle_handshake(*val);
306
307 if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
308 return -EINVAL;
309
310
311
312
313
314 if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
315 fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
316 fcopy_respond_to_host(*val);
317 hv_poll_channel(fcopy_transaction.recv_channel,
318 fcopy_poll_wrapper);
319 }
320
321 return 0;
322}
323
324static void fcopy_on_reset(void)
325{
326
327
328
329 fcopy_transaction.state = HVUTIL_DEVICE_INIT;
330
331 if (cancel_delayed_work_sync(&fcopy_timeout_work))
332 fcopy_respond_to_host(HV_E_FAIL);
333}
334
335int hv_fcopy_init(struct hv_util_service *srv)
336{
337 recv_buffer = srv->recv_buffer;
338 fcopy_transaction.recv_channel = srv->channel;
339
340
341
342
343
344
345
346 fcopy_transaction.state = HVUTIL_DEVICE_INIT;
347
348 hvt = hvutil_transport_init(fcopy_devname, 0, 0,
349 fcopy_on_msg, fcopy_on_reset);
350 if (!hvt)
351 return -EFAULT;
352
353 return 0;
354}
355
356void hv_fcopy_deinit(void)
357{
358 fcopy_transaction.state = HVUTIL_DEVICE_DYING;
359 cancel_delayed_work_sync(&fcopy_timeout_work);
360 hvutil_transport_destroy(hvt);
361}
362