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