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