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
type_qemu_to_vdagent(enum QemuClipboardType type)319 static uint32_t type_qemu_to_vdagent(enum QemuClipboardType type)
320 {
321 switch (type) {
322 case QEMU_CLIPBOARD_TYPE_TEXT:
323 return VD_AGENT_CLIPBOARD_UTF8_TEXT;
324 default:
325 return VD_AGENT_CLIPBOARD_NONE;
326 }
327 }
328
vdagent_send_clipboard_grab(VDAgentChardev * vd,QemuClipboardInfo * info)329 static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
330 QemuClipboardInfo *info)
331 {
332 g_autofree VDAgentMessage *msg =
333 g_malloc0(sizeof(VDAgentMessage) +
334 sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1) +
335 sizeof(uint32_t));
336 uint8_t *s = msg->data;
337 uint32_t *data = (uint32_t *)msg->data;
338 uint32_t q, type;
339
340 if (have_selection(vd)) {
341 *s = info->selection;
342 data++;
343 msg->size += sizeof(uint32_t);
344 } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
345 return;
346 }
347
348 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
349 if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
350 if (!info->has_serial) {
351 /* client should win */
352 info->serial = vd->last_serial[info->selection]++;
353 info->has_serial = true;
354 }
355 *data = info->serial;
356 data++;
357 msg->size += sizeof(uint32_t);
358 }
359 #endif
360
361 for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) {
362 type = type_qemu_to_vdagent(q);
363 if (type != VD_AGENT_CLIPBOARD_NONE && info->types[q].available) {
364 *data = type;
365 data++;
366 msg->size += sizeof(uint32_t);
367 }
368 }
369
370 msg->type = VD_AGENT_CLIPBOARD_GRAB;
371 vdagent_send_msg(vd, msg);
372 }
373
vdagent_send_clipboard_release(VDAgentChardev * vd,QemuClipboardInfo * info)374 static void vdagent_send_clipboard_release(VDAgentChardev *vd,
375 QemuClipboardInfo *info)
376 {
377 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
378 sizeof(uint32_t));
379
380 if (have_selection(vd)) {
381 uint8_t *s = msg->data;
382 *s = info->selection;
383 msg->size += sizeof(uint32_t);
384 } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
385 return;
386 }
387
388 msg->type = VD_AGENT_CLIPBOARD_RELEASE;
389 vdagent_send_msg(vd, msg);
390 }
391
vdagent_send_clipboard_data(VDAgentChardev * vd,QemuClipboardInfo * info,QemuClipboardType type)392 static void vdagent_send_clipboard_data(VDAgentChardev *vd,
393 QemuClipboardInfo *info,
394 QemuClipboardType type)
395 {
396 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
397 sizeof(uint32_t) * 2 +
398 info->types[type].size);
399
400 uint8_t *s = msg->data;
401 uint32_t *data = (uint32_t *)msg->data;
402
403 if (have_selection(vd)) {
404 *s = info->selection;
405 data++;
406 msg->size += sizeof(uint32_t);
407 } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
408 return;
409 }
410
411 *data = type_qemu_to_vdagent(type);
412 data++;
413 msg->size += sizeof(uint32_t);
414
415 memcpy(data, info->types[type].data, info->types[type].size);
416 msg->size += info->types[type].size;
417
418 msg->type = VD_AGENT_CLIPBOARD;
419 vdagent_send_msg(vd, msg);
420 }
421
vdagent_send_empty_clipboard_data(VDAgentChardev * vd,QemuClipboardSelection selection,QemuClipboardType type)422 static void vdagent_send_empty_clipboard_data(VDAgentChardev *vd,
423 QemuClipboardSelection selection,
424 QemuClipboardType type)
425 {
426 g_autoptr(QemuClipboardInfo) info = qemu_clipboard_info_new(&vd->cbpeer, selection);
427
428 trace_vdagent_send_empty_clipboard();
429 vdagent_send_clipboard_data(vd, info, type);
430 }
431
vdagent_clipboard_update_info(VDAgentChardev * vd,QemuClipboardInfo * info)432 static void vdagent_clipboard_update_info(VDAgentChardev *vd,
433 QemuClipboardInfo *info)
434 {
435 QemuClipboardSelection s = info->selection;
436 QemuClipboardType type;
437 bool self_update = info->owner == &vd->cbpeer;
438
439 if (info != qemu_clipboard_info(s)) {
440 vd->cbpending[s] = 0;
441 if (!self_update) {
442 if (info->owner) {
443 vdagent_send_clipboard_grab(vd, info);
444 } else {
445 vdagent_send_clipboard_release(vd, info);
446 }
447 }
448 return;
449 }
450
451 if (self_update) {
452 return;
453 }
454
455 for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) {
456 if (vd->cbpending[s] & (1 << type)) {
457 vd->cbpending[s] &= ~(1 << type);
458 vdagent_send_clipboard_data(vd, info, type);
459 }
460 }
461 }
462
vdagent_clipboard_reset_serial(VDAgentChardev * vd)463 static void vdagent_clipboard_reset_serial(VDAgentChardev *vd)
464 {
465 Chardev *chr = CHARDEV(vd);
466
467 /* reopen the agent connection to reset the serial state */
468 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
469 /* OPENED again after the guest disconnected, see set_fe_open */
470 }
471
vdagent_clipboard_notify(Notifier * notifier,void * data)472 static void vdagent_clipboard_notify(Notifier *notifier, void *data)
473 {
474 VDAgentChardev *vd =
475 container_of(notifier, VDAgentChardev, cbpeer.notifier);
476 QemuClipboardNotify *notify = data;
477
478 switch (notify->type) {
479 case QEMU_CLIPBOARD_UPDATE_INFO:
480 vdagent_clipboard_update_info(vd, notify->info);
481 return;
482 case QEMU_CLIPBOARD_RESET_SERIAL:
483 vdagent_clipboard_reset_serial(vd);
484 return;
485 }
486 }
487
vdagent_clipboard_request(QemuClipboardInfo * info,QemuClipboardType qtype)488 static void vdagent_clipboard_request(QemuClipboardInfo *info,
489 QemuClipboardType qtype)
490 {
491 VDAgentChardev *vd = container_of(info->owner, VDAgentChardev, cbpeer);
492 g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
493 sizeof(uint32_t) * 2);
494 uint32_t type = type_qemu_to_vdagent(qtype);
495 uint8_t *s = msg->data;
496 uint32_t *data = (uint32_t *)msg->data;
497
498 if (type == VD_AGENT_CLIPBOARD_NONE) {
499 return;
500 }
501
502 if (have_selection(vd)) {
503 *s = info->selection;
504 data++;
505 msg->size += sizeof(uint32_t);
506 }
507
508 *data = type;
509 msg->size += sizeof(uint32_t);
510
511 msg->type = VD_AGENT_CLIPBOARD_REQUEST;
512 vdagent_send_msg(vd, msg);
513 }
514
vdagent_clipboard_recv_grab(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)515 static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
516 {
517 g_autoptr(QemuClipboardInfo) info = NULL;
518
519 trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
520 info = qemu_clipboard_info_new(&vd->cbpeer, s);
521 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
522 if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
523 if (size < sizeof(uint32_t)) {
524 /* this shouldn't happen! */
525 return;
526 }
527
528 info->has_serial = true;
529 info->serial = *(uint32_t *)data;
530 if (info->serial < vd->last_serial[s]) {
531 trace_vdagent_cb_grab_discard(GET_NAME(sel_name, s),
532 vd->last_serial[s], info->serial);
533 /* discard lower-ordering guest grab */
534 return;
535 }
536 vd->last_serial[s] = info->serial;
537 data += sizeof(uint32_t);
538 size -= sizeof(uint32_t);
539 }
540 #endif
541 if (size > sizeof(uint32_t) * 10) {
542 /*
543 * spice has 6 types as of 2021. Limiting to 10 entries
544 * so we have some wiggle room.
545 */
546 return;
547 }
548 while (size >= sizeof(uint32_t)) {
549 trace_vdagent_cb_grab_type(GET_NAME(type_name, *(uint32_t *)data));
550 switch (*(uint32_t *)data) {
551 case VD_AGENT_CLIPBOARD_UTF8_TEXT:
552 info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
553 break;
554 default:
555 break;
556 }
557 data += sizeof(uint32_t);
558 size -= sizeof(uint32_t);
559 }
560 qemu_clipboard_update(info);
561 }
562
vdagent_clipboard_recv_request(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)563 static void vdagent_clipboard_recv_request(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
564 {
565 QemuClipboardType type;
566 QemuClipboardInfo *info;
567
568 if (size < sizeof(uint32_t)) {
569 return;
570 }
571 switch (*(uint32_t *)data) {
572 case VD_AGENT_CLIPBOARD_UTF8_TEXT:
573 type = QEMU_CLIPBOARD_TYPE_TEXT;
574 break;
575 default:
576 return;
577 }
578
579 info = qemu_clipboard_info(s);
580 if (info && info->types[type].available && info->owner != &vd->cbpeer) {
581 if (info->types[type].data) {
582 vdagent_send_clipboard_data(vd, info, type);
583 } else {
584 vd->cbpending[s] |= (1 << type);
585 qemu_clipboard_request(info, type);
586 }
587 } else {
588 vdagent_send_empty_clipboard_data(vd, s, type);
589 }
590 }
591
vdagent_clipboard_recv_data(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)592 static void vdagent_clipboard_recv_data(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
593 {
594 QemuClipboardType type;
595
596 if (size < sizeof(uint32_t)) {
597 return;
598 }
599 switch (*(uint32_t *)data) {
600 case VD_AGENT_CLIPBOARD_UTF8_TEXT:
601 type = QEMU_CLIPBOARD_TYPE_TEXT;
602 break;
603 default:
604 return;
605 }
606 data += 4;
607 size -= 4;
608
609 if (qemu_clipboard_peer_owns(&vd->cbpeer, s)) {
610 qemu_clipboard_set_data(&vd->cbpeer, qemu_clipboard_info(s),
611 type, size, data, true);
612 }
613 }
614
vdagent_clipboard_recv_release(VDAgentChardev * vd,uint8_t s)615 static void vdagent_clipboard_recv_release(VDAgentChardev *vd, uint8_t s)
616 {
617 qemu_clipboard_peer_release(&vd->cbpeer, s);
618 }
619
vdagent_chr_recv_clipboard(VDAgentChardev * vd,VDAgentMessage * msg)620 static void vdagent_chr_recv_clipboard(VDAgentChardev *vd, VDAgentMessage *msg)
621 {
622 uint8_t s = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
623 uint32_t size = msg->size;
624 void *data = msg->data;
625
626 if (have_selection(vd)) {
627 if (size < 4) {
628 return;
629 }
630 s = *(uint8_t *)data;
631 if (s >= QEMU_CLIPBOARD_SELECTION__COUNT) {
632 return;
633 }
634 data += 4;
635 size -= 4;
636 }
637
638 switch (msg->type) {
639 case VD_AGENT_CLIPBOARD_GRAB:
640 return vdagent_clipboard_recv_grab(vd, s, size, data);
641 case VD_AGENT_CLIPBOARD_REQUEST:
642 return vdagent_clipboard_recv_request(vd, s, size, data);
643 case VD_AGENT_CLIPBOARD: /* data */
644 return vdagent_clipboard_recv_data(vd, s, size, data);
645 case VD_AGENT_CLIPBOARD_RELEASE:
646 return vdagent_clipboard_recv_release(vd, s);
647 default:
648 g_assert_not_reached();
649 }
650 }
651
652 /* ------------------------------------------------------------------ */
653 /* chardev backend */
654
vdagent_chr_open(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)655 static void vdagent_chr_open(Chardev *chr,
656 ChardevBackend *backend,
657 bool *be_opened,
658 Error **errp)
659 {
660 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
661 ChardevQemuVDAgent *cfg = backend->u.qemu_vdagent.data;
662
663 #if HOST_BIG_ENDIAN
664 /*
665 * TODO: vdagent protocol is defined to be LE,
666 * so we have to byteswap everything on BE hosts.
667 */
668 error_setg(errp, "vdagent is not supported on bigendian hosts");
669 return;
670 #endif
671
672 vd->mouse = VDAGENT_MOUSE_DEFAULT;
673 if (cfg->has_mouse) {
674 vd->mouse = cfg->mouse;
675 }
676
677 vd->clipboard = VDAGENT_CLIPBOARD_DEFAULT;
678 if (cfg->has_clipboard) {
679 vd->clipboard = cfg->clipboard;
680 }
681
682 if (vd->mouse) {
683 vd->mouse_hs = qemu_input_handler_register(&vd->mouse_dev,
684 &vdagent_mouse_handler);
685 }
686
687 *be_opened = true;
688 }
689
vdagent_clipboard_peer_register(VDAgentChardev * vd)690 static void vdagent_clipboard_peer_register(VDAgentChardev *vd)
691 {
692 if (vd->cbpeer.notifier.notify != NULL) {
693 return;
694 }
695
696 vd->cbpeer.name = "vdagent";
697 vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
698 vd->cbpeer.request = vdagent_clipboard_request;
699 qemu_clipboard_peer_register(&vd->cbpeer);
700 }
701
vdagent_chr_recv_caps(VDAgentChardev * vd,VDAgentMessage * msg)702 static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
703 {
704 VDAgentAnnounceCapabilities *caps = (void *)msg->data;
705 int i;
706
707 if (msg->size < (sizeof(VDAgentAnnounceCapabilities) +
708 sizeof(uint32_t))) {
709 return;
710 }
711
712 for (i = 0; i < ARRAY_SIZE(cap_name); i++) {
713 if (caps->caps[0] & (1 << i)) {
714 trace_vdagent_peer_cap(GET_NAME(cap_name, i));
715 }
716 }
717
718 vd->caps = caps->caps[0];
719 if (caps->request) {
720 vdagent_send_caps(vd, false);
721 }
722 if (have_mouse(vd) && vd->mouse_hs) {
723 qemu_input_handler_activate(vd->mouse_hs);
724 }
725
726 memset(vd->last_serial, 0, sizeof(vd->last_serial));
727
728 if (have_clipboard(vd)) {
729 qemu_clipboard_reset_serial();
730 vdagent_clipboard_peer_register(vd);
731 }
732 }
733
vdagent_chr_recv_msg(VDAgentChardev * vd,VDAgentMessage * msg)734 static void vdagent_chr_recv_msg(VDAgentChardev *vd, VDAgentMessage *msg)
735 {
736 trace_vdagent_recv_msg(GET_NAME(msg_name, msg->type), msg->size);
737
738 switch (msg->type) {
739 case VD_AGENT_ANNOUNCE_CAPABILITIES:
740 vdagent_chr_recv_caps(vd, msg);
741 break;
742 case VD_AGENT_CLIPBOARD:
743 case VD_AGENT_CLIPBOARD_GRAB:
744 case VD_AGENT_CLIPBOARD_REQUEST:
745 case VD_AGENT_CLIPBOARD_RELEASE:
746 if (have_clipboard(vd)) {
747 vdagent_chr_recv_clipboard(vd, msg);
748 }
749 break;
750 default:
751 break;
752 }
753 }
754
vdagent_reset_xbuf(VDAgentChardev * vd)755 static void vdagent_reset_xbuf(VDAgentChardev *vd)
756 {
757 g_clear_pointer(&vd->xbuf, g_free);
758 vd->xoff = 0;
759 vd->xsize = 0;
760 }
761
vdagent_chr_recv_chunk(VDAgentChardev * vd)762 static void vdagent_chr_recv_chunk(VDAgentChardev *vd)
763 {
764 VDAgentMessage *msg = (void *)vd->msgbuf;
765
766 if (!vd->xsize) {
767 if (vd->msgsize < sizeof(*msg)) {
768 error_report("%s: message too small: %d < %zd", __func__,
769 vd->msgsize, sizeof(*msg));
770 return;
771 }
772 if (vd->msgsize == msg->size + sizeof(*msg)) {
773 vdagent_chr_recv_msg(vd, msg);
774 return;
775 }
776 }
777
778 if (!vd->xsize) {
779 vd->xsize = msg->size + sizeof(*msg);
780 vd->xbuf = g_malloc0(vd->xsize);
781 }
782
783 if (vd->xoff + vd->msgsize > vd->xsize) {
784 error_report("%s: Oops: %d+%d > %d", __func__,
785 vd->xoff, vd->msgsize, vd->xsize);
786 vdagent_reset_xbuf(vd);
787 return;
788 }
789
790 memcpy(vd->xbuf + vd->xoff, vd->msgbuf, vd->msgsize);
791 vd->xoff += vd->msgsize;
792 if (vd->xoff < vd->xsize) {
793 return;
794 }
795
796 msg = (void *)vd->xbuf;
797 vdagent_chr_recv_msg(vd, msg);
798 vdagent_reset_xbuf(vd);
799 }
800
vdagent_reset_bufs(VDAgentChardev * vd)801 static void vdagent_reset_bufs(VDAgentChardev *vd)
802 {
803 memset(&vd->chunk, 0, sizeof(vd->chunk));
804 vd->chunksize = 0;
805 g_free(vd->msgbuf);
806 vd->msgbuf = NULL;
807 vd->msgsize = 0;
808 }
809
vdagent_chr_write(Chardev * chr,const uint8_t * buf,int len)810 static int vdagent_chr_write(Chardev *chr, const uint8_t *buf, int len)
811 {
812 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
813 uint32_t copy, ret = len;
814
815 while (len) {
816 if (vd->chunksize < sizeof(vd->chunk)) {
817 copy = sizeof(vd->chunk) - vd->chunksize;
818 if (copy > len) {
819 copy = len;
820 }
821 memcpy((void *)(&vd->chunk) + vd->chunksize, buf, copy);
822 vd->chunksize += copy;
823 buf += copy;
824 len -= copy;
825 if (vd->chunksize < sizeof(vd->chunk)) {
826 break;
827 }
828
829 assert(vd->msgbuf == NULL);
830 vd->msgbuf = g_malloc0(vd->chunk.size);
831 }
832
833 copy = vd->chunk.size - vd->msgsize;
834 if (copy > len) {
835 copy = len;
836 }
837 memcpy(vd->msgbuf + vd->msgsize, buf, copy);
838 vd->msgsize += copy;
839 buf += copy;
840 len -= copy;
841
842 if (vd->msgsize == vd->chunk.size) {
843 trace_vdagent_recv_chunk(vd->chunk.size);
844 vdagent_chr_recv_chunk(vd);
845 vdagent_reset_bufs(vd);
846 }
847 }
848
849 return ret;
850 }
851
vdagent_chr_accept_input(Chardev * chr)852 static void vdagent_chr_accept_input(Chardev *chr)
853 {
854 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
855
856 vdagent_send_buf(vd);
857 }
858
vdagent_disconnect(VDAgentChardev * vd)859 static void vdagent_disconnect(VDAgentChardev *vd)
860 {
861 trace_vdagent_disconnect();
862
863 vd->connected = false;
864 g_byte_array_set_size(vd->outbuf, 0);
865 vdagent_reset_bufs(vd);
866 vd->caps = 0;
867 if (vd->mouse_hs) {
868 qemu_input_handler_deactivate(vd->mouse_hs);
869 }
870 if (vd->cbpeer.notifier.notify) {
871 qemu_clipboard_peer_unregister(&vd->cbpeer);
872 memset(&vd->cbpeer, 0, sizeof(vd->cbpeer));
873 }
874 }
875
vdagent_chr_set_fe_open(struct Chardev * chr,int fe_open)876 static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
877 {
878 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
879
880 trace_vdagent_fe_open(fe_open);
881
882 if (vd->connected == fe_open) {
883 return;
884 }
885
886 if (!fe_open) {
887 trace_vdagent_close();
888 vdagent_disconnect(vd);
889 /* To reset_serial, we CLOSED our side. Make sure the other end knows we
890 * are ready again. */
891 qemu_chr_be_event(chr, CHR_EVENT_OPENED);
892 return;
893 }
894
895 vd->connected = true;
896 vdagent_send_caps(vd, true);
897 }
898
vdagent_chr_parse(QemuOpts * opts,ChardevBackend * backend,Error ** errp)899 static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
900 Error **errp)
901 {
902 ChardevQemuVDAgent *cfg;
903
904 backend->type = CHARDEV_BACKEND_KIND_QEMU_VDAGENT;
905 cfg = backend->u.qemu_vdagent.data = g_new0(ChardevQemuVDAgent, 1);
906 qemu_chr_parse_common(opts, qapi_ChardevQemuVDAgent_base(cfg));
907 cfg->has_mouse = true;
908 cfg->mouse = qemu_opt_get_bool(opts, "mouse", VDAGENT_MOUSE_DEFAULT);
909 cfg->has_clipboard = true;
910 cfg->clipboard = qemu_opt_get_bool(opts, "clipboard", VDAGENT_CLIPBOARD_DEFAULT);
911 }
912
913 /* ------------------------------------------------------------------ */
914
vdagent_chr_class_init(ObjectClass * oc,const void * data)915 static void vdagent_chr_class_init(ObjectClass *oc, const void *data)
916 {
917 ChardevClass *cc = CHARDEV_CLASS(oc);
918
919 cc->parse = vdagent_chr_parse;
920 cc->open = vdagent_chr_open;
921 cc->chr_write = vdagent_chr_write;
922 cc->chr_set_fe_open = vdagent_chr_set_fe_open;
923 cc->chr_accept_input = vdagent_chr_accept_input;
924 }
925
post_load(void * opaque,int version_id)926 static int post_load(void *opaque, int version_id)
927 {
928 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(opaque);
929
930 if (have_mouse(vd) && vd->mouse_hs) {
931 qemu_input_handler_activate(vd->mouse_hs);
932 }
933
934 if (have_clipboard(vd)) {
935 vdagent_clipboard_peer_register(vd);
936 }
937
938 return 0;
939 }
940
941 static const VMStateDescription vmstate_chunk = {
942 .name = "vdagent/chunk",
943 .version_id = 0,
944 .minimum_version_id = 0,
945 .fields = (const VMStateField[]) {
946 VMSTATE_UINT32(port, VDIChunkHeader),
947 VMSTATE_UINT32(size, VDIChunkHeader),
948 VMSTATE_END_OF_LIST()
949 }
950 };
951
952 static const VMStateDescription vmstate_vdba = {
953 .name = "vdagent/bytearray",
954 .version_id = 0,
955 .minimum_version_id = 0,
956 .fields = (const VMStateField[]) {
957 VMSTATE_UINT32(len, GByteArray),
958 VMSTATE_VBUFFER_ALLOC_UINT32(data, GByteArray, 0, 0, len),
959 VMSTATE_END_OF_LIST()
960 }
961 };
962
963 struct CBInfoArray {
964 uint32_t n;
965 QemuClipboardInfo cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
966 };
967
968 static const VMStateDescription vmstate_cbinfo_array = {
969 .name = "cbinfoarray",
970 .fields = (const VMStateField[]) {
971 VMSTATE_UINT32(n, struct CBInfoArray),
972 VMSTATE_STRUCT_VARRAY_UINT32(cbinfo, struct CBInfoArray, n,
973 0, vmstate_cbinfo, QemuClipboardInfo),
974 VMSTATE_END_OF_LIST()
975 }
976 };
977
put_cbinfo(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)978 static int put_cbinfo(QEMUFile *f, void *pv, size_t size,
979 const VMStateField *field, JSONWriter *vmdesc)
980 {
981 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv);
982 struct CBInfoArray cbinfo = {};
983 int i;
984
985 if (!have_clipboard(vd)) {
986 return 0;
987 }
988
989 for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
990 if (qemu_clipboard_peer_owns(&vd->cbpeer, i)) {
991 cbinfo.cbinfo[cbinfo.n++] = *qemu_clipboard_info(i);
992 }
993 }
994
995 return vmstate_save_state(f, &vmstate_cbinfo_array, &cbinfo, vmdesc);
996 }
997
get_cbinfo(QEMUFile * f,void * pv,size_t size,const VMStateField * field)998 static int get_cbinfo(QEMUFile *f, void *pv, size_t size,
999 const VMStateField *field)
1000 {
1001 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv);
1002 struct CBInfoArray cbinfo = {};
1003 int i, ret;
1004
1005 if (!have_clipboard(vd)) {
1006 return 0;
1007 }
1008
1009 vdagent_clipboard_peer_register(vd);
1010
1011 ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0);
1012 if (ret) {
1013 return ret;
1014 }
1015
1016 for (i = 0; i < cbinfo.n; i++) {
1017 g_autoptr(QemuClipboardInfo) info =
1018 qemu_clipboard_info_new(&vd->cbpeer, cbinfo.cbinfo[i].selection);
1019 /* this will steal clipboard data pointer from cbinfo.types */
1020 memcpy(info->types, cbinfo.cbinfo[i].types, sizeof(cbinfo.cbinfo[i].types));
1021 qemu_clipboard_update(info);
1022 }
1023
1024 return 0;
1025 }
1026
1027 static const VMStateInfo vmstate_cbinfos = {
1028 .name = "vdagent/cbinfos",
1029 .get = get_cbinfo,
1030 .put = put_cbinfo,
1031 };
1032
1033 static const VMStateDescription vmstate_vdagent = {
1034 .name = "vdagent",
1035 .version_id = 0,
1036 .minimum_version_id = 0,
1037 .post_load = post_load,
1038 .fields = (const VMStateField[]) {
1039 VMSTATE_BOOL(connected, VDAgentChardev),
1040 VMSTATE_UINT32(caps, VDAgentChardev),
1041 VMSTATE_STRUCT(chunk, VDAgentChardev, 0, vmstate_chunk, VDIChunkHeader),
1042 VMSTATE_UINT32(chunksize, VDAgentChardev),
1043 VMSTATE_UINT32(msgsize, VDAgentChardev),
1044 VMSTATE_VBUFFER_ALLOC_UINT32(msgbuf, VDAgentChardev, 0, 0, msgsize),
1045 VMSTATE_UINT32(xsize, VDAgentChardev),
1046 VMSTATE_UINT32(xoff, VDAgentChardev),
1047 VMSTATE_VBUFFER_ALLOC_UINT32(xbuf, VDAgentChardev, 0, 0, xsize),
1048 VMSTATE_STRUCT_POINTER(outbuf, VDAgentChardev, vmstate_vdba, GByteArray),
1049 VMSTATE_UINT32(mouse_x, VDAgentChardev),
1050 VMSTATE_UINT32(mouse_y, VDAgentChardev),
1051 VMSTATE_UINT32(mouse_btn, VDAgentChardev),
1052 VMSTATE_UINT32(mouse_display, VDAgentChardev),
1053 VMSTATE_UINT32_ARRAY(last_serial, VDAgentChardev,
1054 QEMU_CLIPBOARD_SELECTION__COUNT),
1055 VMSTATE_UINT32_ARRAY(cbpending, VDAgentChardev,
1056 QEMU_CLIPBOARD_SELECTION__COUNT),
1057 {
1058 .name = "cbinfos",
1059 .info = &vmstate_cbinfos,
1060 .flags = VMS_SINGLE,
1061 },
1062 VMSTATE_END_OF_LIST()
1063 }
1064 };
1065
vdagent_chr_init(Object * obj)1066 static void vdagent_chr_init(Object *obj)
1067 {
1068 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
1069
1070 vd->outbuf = g_byte_array_new();
1071 vmstate_register_any(NULL, &vmstate_vdagent, vd);
1072 }
1073
vdagent_chr_fini(Object * obj)1074 static void vdagent_chr_fini(Object *obj)
1075 {
1076 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
1077
1078 vdagent_disconnect(vd);
1079 if (vd->mouse_hs) {
1080 qemu_input_handler_unregister(vd->mouse_hs);
1081 }
1082 g_clear_pointer(&vd->outbuf, g_byte_array_unref);
1083 }
1084
1085 static const TypeInfo vdagent_chr_type_info = {
1086 .name = TYPE_CHARDEV_QEMU_VDAGENT,
1087 .parent = TYPE_CHARDEV,
1088 .instance_size = sizeof(VDAgentChardev),
1089 .instance_init = vdagent_chr_init,
1090 .instance_finalize = vdagent_chr_fini,
1091 .class_init = vdagent_chr_class_init,
1092 };
1093
register_types(void)1094 static void register_types(void)
1095 {
1096 type_register_static(&vdagent_chr_type_info);
1097 }
1098
1099 type_init(register_types);
1100