1 #include "qemu/osdep.h"
2 #include "qapi/error.h"
3 #include "chardev/char.h"
4 #include "qemu/buffer.h"
5 #include "qemu/error-report.h"
6 #include "qemu/option.h"
7 #include "qemu/units.h"
8 #include "hw/qdev-core.h"
9 #include "ui/clipboard.h"
10 #include "ui/console.h"
11 #include "ui/input.h"
12 #include "migration/vmstate.h"
13 #include "trace.h"
14
15 #include "qapi/qapi-types-char.h"
16 #include "qapi/qapi-types-ui.h"
17
18 #include "spice/vd_agent.h"
19
20 #define CHECK_SPICE_PROTOCOL_VERSION(major, minor, micro) \
21 (CONFIG_SPICE_PROTOCOL_MAJOR > (major) || \
22 (CONFIG_SPICE_PROTOCOL_MAJOR == (major) && \
23 CONFIG_SPICE_PROTOCOL_MINOR > (minor)) || \
24 (CONFIG_SPICE_PROTOCOL_MAJOR == (major) && \
25 CONFIG_SPICE_PROTOCOL_MINOR == (minor) && \
26 CONFIG_SPICE_PROTOCOL_MICRO >= (micro)))
27
28 #define VDAGENT_BUFFER_LIMIT (1 * MiB)
29 #define VDAGENT_MOUSE_DEFAULT true
30 #define VDAGENT_CLIPBOARD_DEFAULT false
31
32 struct VDAgentChardev {
33 Chardev parent;
34
35 /* config */
36 bool mouse;
37 bool clipboard;
38
39 /* guest vdagent */
40 bool connected;
41 uint32_t caps;
42 VDIChunkHeader chunk;
43 uint32_t chunksize;
44 uint8_t *msgbuf;
45 uint32_t msgsize;
46 uint8_t *xbuf;
47 uint32_t xoff, xsize;
48 GByteArray *outbuf;
49
50 /* mouse */
51 DeviceState mouse_dev;
52 uint32_t mouse_x;
53 uint32_t mouse_y;
54 uint32_t mouse_btn;
55 uint32_t mouse_display;
56 QemuInputHandlerState *mouse_hs;
57
58 /* clipboard */
59 QemuClipboardPeer cbpeer;
60 uint32_t last_serial[QEMU_CLIPBOARD_SELECTION__COUNT];
61 uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT];
62 };
63 typedef struct VDAgentChardev VDAgentChardev;
64
65 #define TYPE_CHARDEV_QEMU_VDAGENT "chardev-qemu-vdagent"
66
67 DECLARE_INSTANCE_CHECKER(VDAgentChardev, QEMU_VDAGENT_CHARDEV,
68 TYPE_CHARDEV_QEMU_VDAGENT);
69
70 /* ------------------------------------------------------------------ */
71 /* names, for debug logging */
72
73 static const char *cap_name[] = {
74 [VD_AGENT_CAP_MOUSE_STATE] = "mouse-state",
75 [VD_AGENT_CAP_MONITORS_CONFIG] = "monitors-config",
76 [VD_AGENT_CAP_REPLY] = "reply",
77 [VD_AGENT_CAP_CLIPBOARD] = "clipboard",
78 [VD_AGENT_CAP_DISPLAY_CONFIG] = "display-config",
79 [VD_AGENT_CAP_CLIPBOARD_BY_DEMAND] = "clipboard-by-demand",
80 [VD_AGENT_CAP_CLIPBOARD_SELECTION] = "clipboard-selection",
81 [VD_AGENT_CAP_SPARSE_MONITORS_CONFIG] = "sparse-monitors-config",
82 [VD_AGENT_CAP_GUEST_LINEEND_LF] = "guest-lineend-lf",
83 [VD_AGENT_CAP_GUEST_LINEEND_CRLF] = "guest-lineend-crlf",
84 [VD_AGENT_CAP_MAX_CLIPBOARD] = "max-clipboard",
85 [VD_AGENT_CAP_AUDIO_VOLUME_SYNC] = "audio-volume-sync",
86 [VD_AGENT_CAP_MONITORS_CONFIG_POSITION] = "monitors-config-position",
87 [VD_AGENT_CAP_FILE_XFER_DISABLED] = "file-xfer-disabled",
88 [VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS] = "file-xfer-detailed-errors",
89 [VD_AGENT_CAP_GRAPHICS_DEVICE_INFO] = "graphics-device-info",
90 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
91 [VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB] = "clipboard-no-release-on-regrab",
92 [VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL] = "clipboard-grab-serial",
93 #endif
94 };
95
96 static const char *msg_name[] = {
97 [VD_AGENT_MOUSE_STATE] = "mouse-state",
98 [VD_AGENT_MONITORS_CONFIG] = "monitors-config",
99 [VD_AGENT_REPLY] = "reply",
100 [VD_AGENT_CLIPBOARD] = "clipboard",
101 [VD_AGENT_DISPLAY_CONFIG] = "display-config",
102 [VD_AGENT_ANNOUNCE_CAPABILITIES] = "announce-capabilities",
103 [VD_AGENT_CLIPBOARD_GRAB] = "clipboard-grab",
104 [VD_AGENT_CLIPBOARD_REQUEST] = "clipboard-request",
105 [VD_AGENT_CLIPBOARD_RELEASE] = "clipboard-release",
106 [VD_AGENT_FILE_XFER_START] = "file-xfer-start",
107 [VD_AGENT_FILE_XFER_STATUS] = "file-xfer-status",
108 [VD_AGENT_FILE_XFER_DATA] = "file-xfer-data",
109 [VD_AGENT_CLIENT_DISCONNECTED] = "client-disconnected",
110 [VD_AGENT_MAX_CLIPBOARD] = "max-clipboard",
111 [VD_AGENT_AUDIO_VOLUME_SYNC] = "audio-volume-sync",
112 [VD_AGENT_GRAPHICS_DEVICE_INFO] = "graphics-device-info",
113 };
114
115 static const char *sel_name[] = {
116 [VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD] = "clipboard",
117 [VD_AGENT_CLIPBOARD_SELECTION_PRIMARY] = "primary",
118 [VD_AGENT_CLIPBOARD_SELECTION_SECONDARY] = "secondary",
119 };
120
121 static const char *type_name[] = {
122 [VD_AGENT_CLIPBOARD_NONE] = "none",
123 [VD_AGENT_CLIPBOARD_UTF8_TEXT] = "text",
124 [VD_AGENT_CLIPBOARD_IMAGE_PNG] = "png",
125 [VD_AGENT_CLIPBOARD_IMAGE_BMP] = "bmp",
126 [VD_AGENT_CLIPBOARD_IMAGE_TIFF] = "tiff",
127 [VD_AGENT_CLIPBOARD_IMAGE_JPG] = "jpg",
128 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 3)
129 [VD_AGENT_CLIPBOARD_FILE_LIST] = "files",
130 #endif
131 };
132
133 #define GET_NAME(_m, _v) \
134 (((_v) < ARRAY_SIZE(_m) && (_m[_v])) ? (_m[_v]) : "???")
135
136 /* ------------------------------------------------------------------ */
137 /* send messages */
138
vdagent_send_buf(VDAgentChardev * vd)139 static void vdagent_send_buf(VDAgentChardev *vd)
140 {
141 uint32_t len;
142
143 while (vd->outbuf->len) {
144 len = qemu_chr_be_can_write(CHARDEV(vd));
145 if (len == 0) {
146 return;
147 }
148 if (len > vd->outbuf->len) {
149 len = vd->outbuf->len;
150 }
151 qemu_chr_be_write(CHARDEV(vd), vd->outbuf->data, len);
152 g_byte_array_remove_range(vd->outbuf, 0, len);
153 }
154 }
155
vdagent_send_msg(VDAgentChardev * vd,VDAgentMessage * msg)156 static void vdagent_send_msg(VDAgentChardev *vd, VDAgentMessage *msg)
157 {
158 uint8_t *msgbuf = (void *)msg;
159 uint32_t msgsize = sizeof(VDAgentMessage) + msg->size;
160 uint32_t msgoff = 0;
161 VDIChunkHeader chunk;
162
163 trace_vdagent_send(GET_NAME(msg_name, msg->type));
164
165 msg->protocol = VD_AGENT_PROTOCOL;
166
167 if (vd->outbuf->len + msgsize > VDAGENT_BUFFER_LIMIT) {
168 error_report("buffer full, dropping message");
169 return;
170 }
171
172 while (msgoff < msgsize) {
173 chunk.port = VDP_CLIENT_PORT;
174 chunk.size = msgsize - msgoff;
175 if (chunk.size > 1024) {
176 chunk.size = 1024;
177 }
178 g_byte_array_append(vd->outbuf, (void *)&chunk, sizeof(chunk));
179 g_byte_array_append(vd->outbuf, msgbuf + msgoff, chunk.size);
180 msgoff += chunk.size;
181 }
182 vdagent_send_buf(vd);
183 }
184
vdagent_send_caps(VDAgentChardev * vd,bool request)185 static void vdagent_send_caps(VDAgentChardev *vd, bool request)
186 {
187 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
188 sizeof(VDAgentAnnounceCapabilities) +
189 sizeof(uint32_t));
190 VDAgentAnnounceCapabilities *caps = (void *)msg->data;
191
192 msg->type = VD_AGENT_ANNOUNCE_CAPABILITIES;
193 msg->size = sizeof(VDAgentAnnounceCapabilities) + sizeof(uint32_t);
194 if (vd->mouse) {
195 caps->caps[0] |= (1 << VD_AGENT_CAP_MOUSE_STATE);
196 }
197 if (vd->clipboard) {
198 caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
199 caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
200 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
201 caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL);
202 #endif
203 }
204
205 caps->request = request;
206 vdagent_send_msg(vd, msg);
207 }
208
209 /* ------------------------------------------------------------------ */
210 /* mouse events */
211
have_mouse(VDAgentChardev * vd)212 static bool have_mouse(VDAgentChardev *vd)
213 {
214 return vd->mouse &&
215 (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE));
216 }
217
vdagent_send_mouse(VDAgentChardev * vd)218 static void vdagent_send_mouse(VDAgentChardev *vd)
219 {
220 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
221 sizeof(VDAgentMouseState));
222 VDAgentMouseState *mouse = (void *)msg->data;
223
224 msg->type = VD_AGENT_MOUSE_STATE;
225 msg->size = sizeof(VDAgentMouseState);
226
227 mouse->x = vd->mouse_x;
228 mouse->y = vd->mouse_y;
229 mouse->buttons = vd->mouse_btn;
230 mouse->display_id = vd->mouse_display;
231
232 vdagent_send_msg(vd, msg);
233 }
234
vdagent_pointer_event(DeviceState * dev,QemuConsole * src,InputEvent * evt)235 static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
236 InputEvent *evt)
237 {
238 static const int bmap[INPUT_BUTTON__MAX] = {
239 [INPUT_BUTTON_LEFT] = VD_AGENT_LBUTTON_MASK,
240 [INPUT_BUTTON_RIGHT] = VD_AGENT_RBUTTON_MASK,
241 [INPUT_BUTTON_MIDDLE] = VD_AGENT_MBUTTON_MASK,
242 [INPUT_BUTTON_WHEEL_UP] = VD_AGENT_UBUTTON_MASK,
243 [INPUT_BUTTON_WHEEL_DOWN] = VD_AGENT_DBUTTON_MASK,
244 #ifdef VD_AGENT_EBUTTON_MASK
245 [INPUT_BUTTON_SIDE] = VD_AGENT_SBUTTON_MASK,
246 [INPUT_BUTTON_EXTRA] = VD_AGENT_EBUTTON_MASK,
247 #endif
248 };
249
250 VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
251 InputMoveEvent *move;
252 InputBtnEvent *btn;
253 uint32_t xres, yres;
254
255 switch (evt->type) {
256 case INPUT_EVENT_KIND_ABS:
257 move = evt->u.abs.data;
258 xres = qemu_console_get_width(src, 1024);
259 yres = qemu_console_get_height(src, 768);
260 if (move->axis == INPUT_AXIS_X) {
261 vd->mouse_x = qemu_input_scale_axis(move->value,
262 INPUT_EVENT_ABS_MIN,
263 INPUT_EVENT_ABS_MAX,
264 0, xres);
265 } else if (move->axis == INPUT_AXIS_Y) {
266 vd->mouse_y = qemu_input_scale_axis(move->value,
267 INPUT_EVENT_ABS_MIN,
268 INPUT_EVENT_ABS_MAX,
269 0, yres);
270 }
271 vd->mouse_display = qemu_console_get_index(src);
272 break;
273
274 case INPUT_EVENT_KIND_BTN:
275 btn = evt->u.btn.data;
276 if (btn->down) {
277 vd->mouse_btn |= bmap[btn->button];
278 } else {
279 vd->mouse_btn &= ~bmap[btn->button];
280 }
281 break;
282
283 default:
284 /* keep gcc happy */
285 break;
286 }
287 }
288
vdagent_pointer_sync(DeviceState * dev)289 static void vdagent_pointer_sync(DeviceState *dev)
290 {
291 VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
292
293 if (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE)) {
294 vdagent_send_mouse(vd);
295 }
296 }
297
298 static const QemuInputHandler vdagent_mouse_handler = {
299 .name = "vdagent mouse",
300 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
301 .event = vdagent_pointer_event,
302 .sync = vdagent_pointer_sync,
303 };
304
305 /* ------------------------------------------------------------------ */
306 /* clipboard */
307
have_clipboard(VDAgentChardev * vd)308 static bool have_clipboard(VDAgentChardev *vd)
309 {
310 return vd->clipboard &&
311 (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
312 }
313
have_selection(VDAgentChardev * vd)314 static bool have_selection(VDAgentChardev *vd)
315 {
316 return vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
317 }
318
have_clipboard_serial(VDAgentChardev * vd)319 static bool have_clipboard_serial(VDAgentChardev *vd)
320 {
321 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
322 return vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL);
323 #else
324 return false;
325 #endif
326 }
327
type_qemu_to_vdagent(enum QemuClipboardType type)328 static uint32_t type_qemu_to_vdagent(enum QemuClipboardType type)
329 {
330 switch (type) {
331 case QEMU_CLIPBOARD_TYPE_TEXT:
332 return VD_AGENT_CLIPBOARD_UTF8_TEXT;
333 default:
334 return VD_AGENT_CLIPBOARD_NONE;
335 }
336 }
337
vdagent_send_clipboard_grab(VDAgentChardev * vd,QemuClipboardInfo * info)338 static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
339 QemuClipboardInfo *info)
340 {
341 g_autofree VDAgentMessage *msg =
342 g_malloc0(sizeof(VDAgentMessage) +
343 sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1) +
344 sizeof(uint32_t));
345 uint8_t *s = msg->data;
346 uint32_t *data = (uint32_t *)msg->data;
347 uint32_t q, type;
348
349 if (have_selection(vd)) {
350 *s = info->selection;
351 data++;
352 msg->size += sizeof(uint32_t);
353 } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
354 return;
355 }
356
357 if (have_clipboard_serial(vd)) {
358 if (!info->has_serial) {
359 /* client should win */
360 info->serial = vd->last_serial[info->selection]++;
361 info->has_serial = true;
362 }
363 *data = info->serial;
364 data++;
365 msg->size += sizeof(uint32_t);
366 }
367
368 for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) {
369 type = type_qemu_to_vdagent(q);
370 if (type != VD_AGENT_CLIPBOARD_NONE && info->types[q].available) {
371 *data = type;
372 data++;
373 msg->size += sizeof(uint32_t);
374 }
375 }
376
377 msg->type = VD_AGENT_CLIPBOARD_GRAB;
378 vdagent_send_msg(vd, msg);
379 }
380
vdagent_send_clipboard_release(VDAgentChardev * vd,QemuClipboardInfo * info)381 static void vdagent_send_clipboard_release(VDAgentChardev *vd,
382 QemuClipboardInfo *info)
383 {
384 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
385 sizeof(uint32_t));
386
387 if (have_selection(vd)) {
388 uint8_t *s = msg->data;
389 *s = info->selection;
390 msg->size += sizeof(uint32_t);
391 } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
392 return;
393 }
394
395 msg->type = VD_AGENT_CLIPBOARD_RELEASE;
396 vdagent_send_msg(vd, msg);
397 }
398
vdagent_send_clipboard_data(VDAgentChardev * vd,QemuClipboardInfo * info,QemuClipboardType type)399 static void vdagent_send_clipboard_data(VDAgentChardev *vd,
400 QemuClipboardInfo *info,
401 QemuClipboardType type)
402 {
403 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
404 sizeof(uint32_t) * 2 +
405 info->types[type].size);
406
407 uint8_t *s = msg->data;
408 uint32_t *data = (uint32_t *)msg->data;
409
410 if (have_selection(vd)) {
411 *s = info->selection;
412 data++;
413 msg->size += sizeof(uint32_t);
414 } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
415 return;
416 }
417
418 *data = type_qemu_to_vdagent(type);
419 data++;
420 msg->size += sizeof(uint32_t);
421
422 memcpy(data, info->types[type].data, info->types[type].size);
423 msg->size += info->types[type].size;
424
425 msg->type = VD_AGENT_CLIPBOARD;
426 vdagent_send_msg(vd, msg);
427 }
428
vdagent_send_empty_clipboard_data(VDAgentChardev * vd,QemuClipboardSelection selection,QemuClipboardType type)429 static void vdagent_send_empty_clipboard_data(VDAgentChardev *vd,
430 QemuClipboardSelection selection,
431 QemuClipboardType type)
432 {
433 g_autoptr(QemuClipboardInfo) info = qemu_clipboard_info_new(&vd->cbpeer, selection);
434
435 trace_vdagent_send_empty_clipboard();
436 vdagent_send_clipboard_data(vd, info, type);
437 }
438
vdagent_clipboard_update_info(VDAgentChardev * vd,QemuClipboardInfo * info)439 static void vdagent_clipboard_update_info(VDAgentChardev *vd,
440 QemuClipboardInfo *info)
441 {
442 QemuClipboardSelection s = info->selection;
443 QemuClipboardType type;
444 bool self_update = info->owner == &vd->cbpeer;
445
446 if (info != qemu_clipboard_info(s)) {
447 vd->cbpending[s] = 0;
448 if (!self_update) {
449 if (info->owner) {
450 vdagent_send_clipboard_grab(vd, info);
451 } else {
452 vdagent_send_clipboard_release(vd, info);
453 }
454 }
455 return;
456 }
457
458 if (self_update) {
459 return;
460 }
461
462 for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) {
463 if (vd->cbpending[s] & (1 << type)) {
464 vd->cbpending[s] &= ~(1 << type);
465 vdagent_send_clipboard_data(vd, info, type);
466 }
467 }
468 }
469
vdagent_clipboard_reset_serial(VDAgentChardev * vd)470 static void vdagent_clipboard_reset_serial(VDAgentChardev *vd)
471 {
472 Chardev *chr = CHARDEV(vd);
473
474 if (!have_clipboard_serial(vd)) {
475 return;
476 }
477 /* reopen the agent connection to reset the serial state */
478 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
479 /* OPENED again after the guest disconnected, see set_fe_open */
480 }
481
vdagent_clipboard_notify(Notifier * notifier,void * data)482 static void vdagent_clipboard_notify(Notifier *notifier, void *data)
483 {
484 VDAgentChardev *vd =
485 container_of(notifier, VDAgentChardev, cbpeer.notifier);
486 QemuClipboardNotify *notify = data;
487
488 switch (notify->type) {
489 case QEMU_CLIPBOARD_UPDATE_INFO:
490 vdagent_clipboard_update_info(vd, notify->info);
491 return;
492 case QEMU_CLIPBOARD_RESET_SERIAL:
493 vdagent_clipboard_reset_serial(vd);
494 return;
495 }
496 }
497
vdagent_clipboard_request(QemuClipboardInfo * info,QemuClipboardType qtype)498 static void vdagent_clipboard_request(QemuClipboardInfo *info,
499 QemuClipboardType qtype)
500 {
501 VDAgentChardev *vd = container_of(info->owner, VDAgentChardev, cbpeer);
502 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
503 sizeof(uint32_t) * 2);
504 uint32_t type = type_qemu_to_vdagent(qtype);
505 uint8_t *s = msg->data;
506 uint32_t *data = (uint32_t *)msg->data;
507
508 if (type == VD_AGENT_CLIPBOARD_NONE) {
509 return;
510 }
511
512 if (have_selection(vd)) {
513 *s = info->selection;
514 data++;
515 msg->size += sizeof(uint32_t);
516 }
517
518 *data = type;
519 msg->size += sizeof(uint32_t);
520
521 msg->type = VD_AGENT_CLIPBOARD_REQUEST;
522 vdagent_send_msg(vd, msg);
523 }
524
vdagent_clipboard_recv_grab(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)525 static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
526 {
527 g_autoptr(QemuClipboardInfo) info = NULL;
528
529 trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
530 info = qemu_clipboard_info_new(&vd->cbpeer, s);
531 if (have_clipboard_serial(vd)) {
532 if (size < sizeof(uint32_t)) {
533 /* this shouldn't happen! */
534 return;
535 }
536
537 info->has_serial = true;
538 info->serial = *(uint32_t *)data;
539 if (info->serial < vd->last_serial[s]) {
540 trace_vdagent_cb_grab_discard(GET_NAME(sel_name, s),
541 vd->last_serial[s], info->serial);
542 /* discard lower-ordering guest grab */
543 return;
544 }
545 vd->last_serial[s] = info->serial;
546 data += sizeof(uint32_t);
547 size -= sizeof(uint32_t);
548 }
549 if (size > sizeof(uint32_t) * 10) {
550 /*
551 * spice has 6 types as of 2021. Limiting to 10 entries
552 * so we have some wiggle room.
553 */
554 return;
555 }
556 while (size >= sizeof(uint32_t)) {
557 trace_vdagent_cb_grab_type(GET_NAME(type_name, *(uint32_t *)data));
558 switch (*(uint32_t *)data) {
559 case VD_AGENT_CLIPBOARD_UTF8_TEXT:
560 info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
561 break;
562 default:
563 break;
564 }
565 data += sizeof(uint32_t);
566 size -= sizeof(uint32_t);
567 }
568 qemu_clipboard_update(info);
569 }
570
vdagent_clipboard_recv_request(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)571 static void vdagent_clipboard_recv_request(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
572 {
573 QemuClipboardType type;
574 QemuClipboardInfo *info;
575
576 if (size < sizeof(uint32_t)) {
577 return;
578 }
579 switch (*(uint32_t *)data) {
580 case VD_AGENT_CLIPBOARD_UTF8_TEXT:
581 type = QEMU_CLIPBOARD_TYPE_TEXT;
582 break;
583 default:
584 return;
585 }
586
587 info = qemu_clipboard_info(s);
588 if (info && info->types[type].available && info->owner != &vd->cbpeer) {
589 if (info->types[type].data) {
590 vdagent_send_clipboard_data(vd, info, type);
591 } else {
592 vd->cbpending[s] |= (1 << type);
593 qemu_clipboard_request(info, type);
594 }
595 } else {
596 vdagent_send_empty_clipboard_data(vd, s, type);
597 }
598 }
599
vdagent_clipboard_recv_data(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)600 static void vdagent_clipboard_recv_data(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
601 {
602 QemuClipboardType type;
603
604 if (size < sizeof(uint32_t)) {
605 return;
606 }
607 switch (*(uint32_t *)data) {
608 case VD_AGENT_CLIPBOARD_UTF8_TEXT:
609 type = QEMU_CLIPBOARD_TYPE_TEXT;
610 break;
611 default:
612 return;
613 }
614 data += 4;
615 size -= 4;
616
617 if (qemu_clipboard_peer_owns(&vd->cbpeer, s)) {
618 qemu_clipboard_set_data(&vd->cbpeer, qemu_clipboard_info(s),
619 type, size, data, true);
620 }
621 }
622
vdagent_clipboard_recv_release(VDAgentChardev * vd,uint8_t s)623 static void vdagent_clipboard_recv_release(VDAgentChardev *vd, uint8_t s)
624 {
625 qemu_clipboard_peer_release(&vd->cbpeer, s);
626 }
627
vdagent_chr_recv_clipboard(VDAgentChardev * vd,VDAgentMessage * msg)628 static void vdagent_chr_recv_clipboard(VDAgentChardev *vd, VDAgentMessage *msg)
629 {
630 uint8_t s = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
631 uint32_t size = msg->size;
632 void *data = msg->data;
633
634 if (have_selection(vd)) {
635 if (size < 4) {
636 return;
637 }
638 s = *(uint8_t *)data;
639 if (s >= QEMU_CLIPBOARD_SELECTION__COUNT) {
640 return;
641 }
642 data += 4;
643 size -= 4;
644 }
645
646 switch (msg->type) {
647 case VD_AGENT_CLIPBOARD_GRAB:
648 return vdagent_clipboard_recv_grab(vd, s, size, data);
649 case VD_AGENT_CLIPBOARD_REQUEST:
650 return vdagent_clipboard_recv_request(vd, s, size, data);
651 case VD_AGENT_CLIPBOARD: /* data */
652 return vdagent_clipboard_recv_data(vd, s, size, data);
653 case VD_AGENT_CLIPBOARD_RELEASE:
654 return vdagent_clipboard_recv_release(vd, s);
655 default:
656 g_assert_not_reached();
657 }
658 }
659
660 /* ------------------------------------------------------------------ */
661 /* chardev backend */
662
vdagent_chr_open(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)663 static void vdagent_chr_open(Chardev *chr,
664 ChardevBackend *backend,
665 bool *be_opened,
666 Error **errp)
667 {
668 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
669 ChardevQemuVDAgent *cfg = backend->u.qemu_vdagent.data;
670
671 #if HOST_BIG_ENDIAN
672 /*
673 * TODO: vdagent protocol is defined to be LE,
674 * so we have to byteswap everything on BE hosts.
675 */
676 error_setg(errp, "vdagent is not supported on bigendian hosts");
677 return;
678 #endif
679
680 vd->mouse = VDAGENT_MOUSE_DEFAULT;
681 if (cfg->has_mouse) {
682 vd->mouse = cfg->mouse;
683 }
684
685 vd->clipboard = VDAGENT_CLIPBOARD_DEFAULT;
686 if (cfg->has_clipboard) {
687 vd->clipboard = cfg->clipboard;
688 }
689
690 if (vd->mouse) {
691 vd->mouse_hs = qemu_input_handler_register(&vd->mouse_dev,
692 &vdagent_mouse_handler);
693 }
694
695 *be_opened = true;
696 }
697
vdagent_clipboard_peer_register(VDAgentChardev * vd)698 static void vdagent_clipboard_peer_register(VDAgentChardev *vd)
699 {
700 if (vd->cbpeer.notifier.notify != NULL) {
701 return;
702 }
703
704 vd->cbpeer.name = "vdagent";
705 vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
706 vd->cbpeer.request = vdagent_clipboard_request;
707 qemu_clipboard_peer_register(&vd->cbpeer);
708 }
709
vdagent_chr_recv_caps(VDAgentChardev * vd,VDAgentMessage * msg)710 static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
711 {
712 VDAgentAnnounceCapabilities *caps = (void *)msg->data;
713 int i;
714
715 if (msg->size < (sizeof(VDAgentAnnounceCapabilities) +
716 sizeof(uint32_t))) {
717 return;
718 }
719
720 for (i = 0; i < ARRAY_SIZE(cap_name); i++) {
721 if (caps->caps[0] & (1 << i)) {
722 trace_vdagent_peer_cap(GET_NAME(cap_name, i));
723 }
724 }
725
726 vd->caps = caps->caps[0];
727 if (caps->request) {
728 vdagent_send_caps(vd, false);
729 }
730 if (have_mouse(vd) && vd->mouse_hs) {
731 qemu_input_handler_activate(vd->mouse_hs);
732 }
733
734 memset(vd->last_serial, 0, sizeof(vd->last_serial));
735
736 if (have_clipboard(vd)) {
737 qemu_clipboard_reset_serial();
738 vdagent_clipboard_peer_register(vd);
739 }
740 }
741
vdagent_chr_recv_msg(VDAgentChardev * vd,VDAgentMessage * msg)742 static void vdagent_chr_recv_msg(VDAgentChardev *vd, VDAgentMessage *msg)
743 {
744 trace_vdagent_recv_msg(GET_NAME(msg_name, msg->type), msg->size);
745
746 switch (msg->type) {
747 case VD_AGENT_ANNOUNCE_CAPABILITIES:
748 vdagent_chr_recv_caps(vd, msg);
749 break;
750 case VD_AGENT_CLIPBOARD:
751 case VD_AGENT_CLIPBOARD_GRAB:
752 case VD_AGENT_CLIPBOARD_REQUEST:
753 case VD_AGENT_CLIPBOARD_RELEASE:
754 if (have_clipboard(vd)) {
755 vdagent_chr_recv_clipboard(vd, msg);
756 }
757 break;
758 default:
759 break;
760 }
761 }
762
vdagent_reset_xbuf(VDAgentChardev * vd)763 static void vdagent_reset_xbuf(VDAgentChardev *vd)
764 {
765 g_clear_pointer(&vd->xbuf, g_free);
766 vd->xoff = 0;
767 vd->xsize = 0;
768 }
769
vdagent_chr_recv_chunk(VDAgentChardev * vd)770 static void vdagent_chr_recv_chunk(VDAgentChardev *vd)
771 {
772 VDAgentMessage *msg = (void *)vd->msgbuf;
773
774 if (!vd->xsize) {
775 if (vd->msgsize < sizeof(*msg)) {
776 error_report("%s: message too small: %d < %zd", __func__,
777 vd->msgsize, sizeof(*msg));
778 return;
779 }
780 if (vd->msgsize == msg->size + sizeof(*msg)) {
781 vdagent_chr_recv_msg(vd, msg);
782 return;
783 }
784 }
785
786 if (!vd->xsize) {
787 vd->xsize = msg->size + sizeof(*msg);
788 vd->xbuf = g_malloc0(vd->xsize);
789 }
790
791 if (vd->xoff + vd->msgsize > vd->xsize) {
792 error_report("%s: Oops: %d+%d > %d", __func__,
793 vd->xoff, vd->msgsize, vd->xsize);
794 vdagent_reset_xbuf(vd);
795 return;
796 }
797
798 memcpy(vd->xbuf + vd->xoff, vd->msgbuf, vd->msgsize);
799 vd->xoff += vd->msgsize;
800 if (vd->xoff < vd->xsize) {
801 return;
802 }
803
804 msg = (void *)vd->xbuf;
805 vdagent_chr_recv_msg(vd, msg);
806 vdagent_reset_xbuf(vd);
807 }
808
vdagent_reset_bufs(VDAgentChardev * vd)809 static void vdagent_reset_bufs(VDAgentChardev *vd)
810 {
811 memset(&vd->chunk, 0, sizeof(vd->chunk));
812 vd->chunksize = 0;
813 g_free(vd->msgbuf);
814 vd->msgbuf = NULL;
815 vd->msgsize = 0;
816 }
817
vdagent_chr_write(Chardev * chr,const uint8_t * buf,int len)818 static int vdagent_chr_write(Chardev *chr, const uint8_t *buf, int len)
819 {
820 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
821 uint32_t copy, ret = len;
822
823 while (len) {
824 if (vd->chunksize < sizeof(vd->chunk)) {
825 copy = sizeof(vd->chunk) - vd->chunksize;
826 if (copy > len) {
827 copy = len;
828 }
829 memcpy((void *)(&vd->chunk) + vd->chunksize, buf, copy);
830 vd->chunksize += copy;
831 buf += copy;
832 len -= copy;
833 if (vd->chunksize < sizeof(vd->chunk)) {
834 break;
835 }
836
837 assert(vd->msgbuf == NULL);
838 vd->msgbuf = g_malloc0(vd->chunk.size);
839 }
840
841 copy = vd->chunk.size - vd->msgsize;
842 if (copy > len) {
843 copy = len;
844 }
845 memcpy(vd->msgbuf + vd->msgsize, buf, copy);
846 vd->msgsize += copy;
847 buf += copy;
848 len -= copy;
849
850 if (vd->msgsize == vd->chunk.size) {
851 trace_vdagent_recv_chunk(vd->chunk.size);
852 vdagent_chr_recv_chunk(vd);
853 vdagent_reset_bufs(vd);
854 }
855 }
856
857 return ret;
858 }
859
vdagent_chr_accept_input(Chardev * chr)860 static void vdagent_chr_accept_input(Chardev *chr)
861 {
862 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
863
864 vdagent_send_buf(vd);
865 }
866
vdagent_disconnect(VDAgentChardev * vd)867 static void vdagent_disconnect(VDAgentChardev *vd)
868 {
869 trace_vdagent_disconnect();
870
871 vd->connected = false;
872 g_byte_array_set_size(vd->outbuf, 0);
873 vdagent_reset_bufs(vd);
874 vd->caps = 0;
875 if (vd->mouse_hs) {
876 qemu_input_handler_deactivate(vd->mouse_hs);
877 }
878 if (vd->cbpeer.notifier.notify) {
879 qemu_clipboard_peer_unregister(&vd->cbpeer);
880 memset(&vd->cbpeer, 0, sizeof(vd->cbpeer));
881 }
882 }
883
vdagent_chr_set_fe_open(struct Chardev * chr,int fe_open)884 static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
885 {
886 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
887
888 trace_vdagent_fe_open(fe_open);
889
890 if (vd->connected == fe_open) {
891 return;
892 }
893
894 if (!fe_open) {
895 trace_vdagent_close();
896 vdagent_disconnect(vd);
897 /* To reset_serial, we CLOSED our side. Make sure the other end knows we
898 * are ready again. */
899 qemu_chr_be_event(chr, CHR_EVENT_OPENED);
900 return;
901 }
902
903 vd->connected = true;
904 vdagent_send_caps(vd, true);
905 }
906
vdagent_chr_parse(QemuOpts * opts,ChardevBackend * backend,Error ** errp)907 static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
908 Error **errp)
909 {
910 ChardevQemuVDAgent *cfg;
911
912 backend->type = CHARDEV_BACKEND_KIND_QEMU_VDAGENT;
913 cfg = backend->u.qemu_vdagent.data = g_new0(ChardevQemuVDAgent, 1);
914 qemu_chr_parse_common(opts, qapi_ChardevQemuVDAgent_base(cfg));
915 cfg->has_mouse = true;
916 cfg->mouse = qemu_opt_get_bool(opts, "mouse", VDAGENT_MOUSE_DEFAULT);
917 cfg->has_clipboard = true;
918 cfg->clipboard = qemu_opt_get_bool(opts, "clipboard", VDAGENT_CLIPBOARD_DEFAULT);
919 }
920
921 /* ------------------------------------------------------------------ */
922
vdagent_chr_class_init(ObjectClass * oc,const void * data)923 static void vdagent_chr_class_init(ObjectClass *oc, const void *data)
924 {
925 ChardevClass *cc = CHARDEV_CLASS(oc);
926
927 cc->parse = vdagent_chr_parse;
928 cc->open = vdagent_chr_open;
929 cc->chr_write = vdagent_chr_write;
930 cc->chr_set_fe_open = vdagent_chr_set_fe_open;
931 cc->chr_accept_input = vdagent_chr_accept_input;
932 }
933
post_load(void * opaque,int version_id)934 static int post_load(void *opaque, int version_id)
935 {
936 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(opaque);
937
938 if (have_mouse(vd) && vd->mouse_hs) {
939 qemu_input_handler_activate(vd->mouse_hs);
940 }
941
942 if (have_clipboard(vd)) {
943 vdagent_clipboard_peer_register(vd);
944 }
945
946 return 0;
947 }
948
949 static const VMStateDescription vmstate_chunk = {
950 .name = "vdagent/chunk",
951 .version_id = 0,
952 .minimum_version_id = 0,
953 .fields = (const VMStateField[]) {
954 VMSTATE_UINT32(port, VDIChunkHeader),
955 VMSTATE_UINT32(size, VDIChunkHeader),
956 VMSTATE_END_OF_LIST()
957 }
958 };
959
960 static const VMStateDescription vmstate_vdba = {
961 .name = "vdagent/bytearray",
962 .version_id = 0,
963 .minimum_version_id = 0,
964 .fields = (const VMStateField[]) {
965 VMSTATE_UINT32(len, GByteArray),
966 VMSTATE_VBUFFER_ALLOC_UINT32(data, GByteArray, 0, 0, len),
967 VMSTATE_END_OF_LIST()
968 }
969 };
970
971 struct CBInfoArray {
972 uint32_t n;
973 QemuClipboardInfo cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
974 };
975
976 static const VMStateDescription vmstate_cbinfo_array = {
977 .name = "cbinfoarray",
978 .fields = (const VMStateField[]) {
979 VMSTATE_UINT32(n, struct CBInfoArray),
980 VMSTATE_STRUCT_VARRAY_UINT32(cbinfo, struct CBInfoArray, n,
981 0, vmstate_cbinfo, QemuClipboardInfo),
982 VMSTATE_END_OF_LIST()
983 }
984 };
985
put_cbinfo(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)986 static int put_cbinfo(QEMUFile *f, void *pv, size_t size,
987 const VMStateField *field, JSONWriter *vmdesc)
988 {
989 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv);
990 struct CBInfoArray cbinfo = {};
991 int i;
992
993 if (!have_clipboard(vd)) {
994 return 0;
995 }
996
997 for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
998 if (qemu_clipboard_peer_owns(&vd->cbpeer, i)) {
999 cbinfo.cbinfo[cbinfo.n++] = *qemu_clipboard_info(i);
1000 }
1001 }
1002
1003 return vmstate_save_state(f, &vmstate_cbinfo_array, &cbinfo, vmdesc);
1004 }
1005
get_cbinfo(QEMUFile * f,void * pv,size_t size,const VMStateField * field)1006 static int get_cbinfo(QEMUFile *f, void *pv, size_t size,
1007 const VMStateField *field)
1008 {
1009 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv);
1010 struct CBInfoArray cbinfo = {};
1011 int i, ret;
1012
1013 if (!have_clipboard(vd)) {
1014 return 0;
1015 }
1016
1017 vdagent_clipboard_peer_register(vd);
1018
1019 ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
1020 if (ret) {
1021 return ret;
1022 }
1023
1024 for (i = 0; i < cbinfo.n; i++) {
1025 g_autoptr(QemuClipboardInfo) info =
1026 qemu_clipboard_info_new(&vd->cbpeer, cbinfo.cbinfo[i].selection);
1027 /* this will steal clipboard data pointer from cbinfo.types */
1028 memcpy(info->types, cbinfo.cbinfo[i].types, sizeof(cbinfo.cbinfo[i].types));
1029 qemu_clipboard_update(info);
1030 }
1031
1032 return 0;
1033 }
1034
1035 static const VMStateInfo vmstate_cbinfos = {
1036 .name = "vdagent/cbinfos",
1037 .get = get_cbinfo,
1038 .put = put_cbinfo,
1039 };
1040
1041 static const VMStateDescription vmstate_vdagent = {
1042 .name = "vdagent",
1043 .version_id = 0,
1044 .minimum_version_id = 0,
1045 .post_load = post_load,
1046 .fields = (const VMStateField[]) {
1047 VMSTATE_BOOL(connected, VDAgentChardev),
1048 VMSTATE_UINT32(caps, VDAgentChardev),
1049 VMSTATE_STRUCT(chunk, VDAgentChardev, 0, vmstate_chunk, VDIChunkHeader),
1050 VMSTATE_UINT32(chunksize, VDAgentChardev),
1051 VMSTATE_UINT32(msgsize, VDAgentChardev),
1052 VMSTATE_VBUFFER_ALLOC_UINT32(msgbuf, VDAgentChardev, 0, 0, msgsize),
1053 VMSTATE_UINT32(xsize, VDAgentChardev),
1054 VMSTATE_UINT32(xoff, VDAgentChardev),
1055 VMSTATE_VBUFFER_ALLOC_UINT32(xbuf, VDAgentChardev, 0, 0, xsize),
1056 VMSTATE_STRUCT_POINTER(outbuf, VDAgentChardev, vmstate_vdba, GByteArray),
1057 VMSTATE_UINT32(mouse_x, VDAgentChardev),
1058 VMSTATE_UINT32(mouse_y, VDAgentChardev),
1059 VMSTATE_UINT32(mouse_btn, VDAgentChardev),
1060 VMSTATE_UINT32(mouse_display, VDAgentChardev),
1061 VMSTATE_UINT32_ARRAY(last_serial, VDAgentChardev,
1062 QEMU_CLIPBOARD_SELECTION__COUNT),
1063 VMSTATE_UINT32_ARRAY(cbpending, VDAgentChardev,
1064 QEMU_CLIPBOARD_SELECTION__COUNT),
1065 {
1066 .name = "cbinfos",
1067 .info = &vmstate_cbinfos,
1068 .flags = VMS_SINGLE,
1069 },
1070 VMSTATE_END_OF_LIST()
1071 }
1072 };
1073
vdagent_chr_init(Object * obj)1074 static void vdagent_chr_init(Object *obj)
1075 {
1076 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
1077
1078 vd->outbuf = g_byte_array_new();
1079 vmstate_register_any(NULL, &vmstate_vdagent, vd);
1080 }
1081
vdagent_chr_fini(Object * obj)1082 static void vdagent_chr_fini(Object *obj)
1083 {
1084 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
1085
1086 vdagent_disconnect(vd);
1087 if (vd->mouse_hs) {
1088 qemu_input_handler_unregister(vd->mouse_hs);
1089 }
1090 g_clear_pointer(&vd->outbuf, g_byte_array_unref);
1091 }
1092
1093 static const TypeInfo vdagent_chr_type_info = {
1094 .name = TYPE_CHARDEV_QEMU_VDAGENT,
1095 .parent = TYPE_CHARDEV,
1096 .instance_size = sizeof(VDAgentChardev),
1097 .instance_init = vdagent_chr_init,
1098 .instance_finalize = vdagent_chr_fini,
1099 .class_init = vdagent_chr_class_init,
1100 };
1101
register_types(void)1102 static void register_types(void)
1103 {
1104 type_register_static(&vdagent_chr_type_info);
1105 }
1106
1107 type_init(register_types);
1108