xref: /openbmc/qemu/ui/vdagent.c (revision 37b6a7e45198c536b870a0c4a50d4303a079fde0)
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 
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 
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 
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 
212 static bool have_mouse(VDAgentChardev *vd)
213 {
214     return vd->mouse &&
215         (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE));
216 }
217 
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 
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 
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 
308 static bool have_clipboard(VDAgentChardev *vd)
309 {
310     return vd->clipboard &&
311         (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
312 }
313 
314 static bool have_selection(VDAgentChardev *vd)
315 {
316     return vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
317 }
318 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
623 static void vdagent_clipboard_recv_release(VDAgentChardev *vd, uint8_t s)
624 {
625     qemu_clipboard_peer_release(&vd->cbpeer, s);
626 }
627 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
1102 static void register_types(void)
1103 {
1104     type_register_static(&vdagent_chr_type_info);
1105 }
1106 
1107 type_init(register_types);
1108