xref: /openbmc/qemu/ui/vdagent.c (revision 69fbfb8f)
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 "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     [VD_AGENT_CAP_GRAPHICS_DEVICE_INFO]           = "graphics-device-info",
92 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
93     [VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB] = "clipboard-no-release-on-regrab",
94     [VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL]          = "clipboard-grab-serial",
95 #endif
96 };
97 
98 static const char *msg_name[] = {
99     [VD_AGENT_MOUSE_STATE]           = "mouse-state",
100     [VD_AGENT_MONITORS_CONFIG]       = "monitors-config",
101     [VD_AGENT_REPLY]                 = "reply",
102     [VD_AGENT_CLIPBOARD]             = "clipboard",
103     [VD_AGENT_DISPLAY_CONFIG]        = "display-config",
104     [VD_AGENT_ANNOUNCE_CAPABILITIES] = "announce-capabilities",
105     [VD_AGENT_CLIPBOARD_GRAB]        = "clipboard-grab",
106     [VD_AGENT_CLIPBOARD_REQUEST]     = "clipboard-request",
107     [VD_AGENT_CLIPBOARD_RELEASE]     = "clipboard-release",
108     [VD_AGENT_FILE_XFER_START]       = "file-xfer-start",
109     [VD_AGENT_FILE_XFER_STATUS]      = "file-xfer-status",
110     [VD_AGENT_FILE_XFER_DATA]        = "file-xfer-data",
111     [VD_AGENT_CLIENT_DISCONNECTED]   = "client-disconnected",
112     [VD_AGENT_MAX_CLIPBOARD]         = "max-clipboard",
113     [VD_AGENT_AUDIO_VOLUME_SYNC]     = "audio-volume-sync",
114     [VD_AGENT_GRAPHICS_DEVICE_INFO]  = "graphics-device-info",
115 };
116 
117 static const char *sel_name[] = {
118     [VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD] = "clipboard",
119     [VD_AGENT_CLIPBOARD_SELECTION_PRIMARY]   = "primary",
120     [VD_AGENT_CLIPBOARD_SELECTION_SECONDARY] = "secondary",
121 };
122 
123 static const char *type_name[] = {
124     [VD_AGENT_CLIPBOARD_NONE]       = "none",
125     [VD_AGENT_CLIPBOARD_UTF8_TEXT]  = "text",
126     [VD_AGENT_CLIPBOARD_IMAGE_PNG]  = "png",
127     [VD_AGENT_CLIPBOARD_IMAGE_BMP]  = "bmp",
128     [VD_AGENT_CLIPBOARD_IMAGE_TIFF] = "tiff",
129     [VD_AGENT_CLIPBOARD_IMAGE_JPG]  = "jpg",
130 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 3)
131     [VD_AGENT_CLIPBOARD_FILE_LIST]  = "files",
132 #endif
133 };
134 
135 #define GET_NAME(_m, _v) \
136     (((_v) < ARRAY_SIZE(_m) && (_m[_v])) ? (_m[_v]) : "???")
137 
138 /* ------------------------------------------------------------------ */
139 /* send messages                                                      */
140 
141 static void vdagent_send_buf(VDAgentChardev *vd)
142 {
143     uint32_t len;
144 
145     while (!buffer_empty(&vd->outbuf)) {
146         len = qemu_chr_be_can_write(CHARDEV(vd));
147         if (len == 0) {
148             return;
149         }
150         if (len > vd->outbuf.offset) {
151             len = vd->outbuf.offset;
152         }
153         qemu_chr_be_write(CHARDEV(vd), vd->outbuf.buffer, len);
154         buffer_advance(&vd->outbuf, len);
155     }
156 }
157 
158 static void vdagent_send_msg(VDAgentChardev *vd, VDAgentMessage *msg)
159 {
160     uint8_t *msgbuf = (void *)msg;
161     uint32_t msgsize = sizeof(VDAgentMessage) + msg->size;
162     uint32_t msgoff = 0;
163     VDIChunkHeader chunk;
164 
165     trace_vdagent_send(GET_NAME(msg_name, msg->type));
166 
167     msg->protocol = VD_AGENT_PROTOCOL;
168 
169     if (vd->outbuf.offset + msgsize > VDAGENT_BUFFER_LIMIT) {
170         error_report("buffer full, dropping message");
171         return;
172     }
173 
174     while (msgoff < msgsize) {
175         chunk.port = VDP_CLIENT_PORT;
176         chunk.size = msgsize - msgoff;
177         if (chunk.size > 1024) {
178             chunk.size = 1024;
179         }
180         buffer_reserve(&vd->outbuf, sizeof(chunk) + chunk.size);
181         buffer_append(&vd->outbuf, &chunk, sizeof(chunk));
182         buffer_append(&vd->outbuf, msgbuf + msgoff, chunk.size);
183         msgoff += chunk.size;
184     }
185     vdagent_send_buf(vd);
186 }
187 
188 static void vdagent_send_caps(VDAgentChardev *vd)
189 {
190     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
191                                                sizeof(VDAgentAnnounceCapabilities) +
192                                                sizeof(uint32_t));
193     VDAgentAnnounceCapabilities *caps = (void *)msg->data;
194 
195     msg->type = VD_AGENT_ANNOUNCE_CAPABILITIES;
196     msg->size = sizeof(VDAgentAnnounceCapabilities) + sizeof(uint32_t);
197     if (vd->mouse) {
198         caps->caps[0] |= (1 << VD_AGENT_CAP_MOUSE_STATE);
199     }
200     if (vd->clipboard) {
201         caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
202         caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
203 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
204         caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL);
205 #endif
206     }
207 
208     vdagent_send_msg(vd, msg);
209 }
210 
211 /* ------------------------------------------------------------------ */
212 /* mouse events                                                       */
213 
214 static bool have_mouse(VDAgentChardev *vd)
215 {
216     return vd->mouse &&
217         (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE));
218 }
219 
220 static void vdagent_send_mouse(VDAgentChardev *vd)
221 {
222     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
223                                                sizeof(VDAgentMouseState));
224     VDAgentMouseState *mouse = (void *)msg->data;
225 
226     msg->type = VD_AGENT_MOUSE_STATE;
227     msg->size = sizeof(VDAgentMouseState);
228 
229     mouse->x          = vd->mouse_x;
230     mouse->y          = vd->mouse_y;
231     mouse->buttons    = vd->mouse_btn;
232     mouse->display_id = vd->mouse_display;
233 
234     vdagent_send_msg(vd, msg);
235 }
236 
237 static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
238                                   InputEvent *evt)
239 {
240     static const int bmap[INPUT_BUTTON__MAX] = {
241         [INPUT_BUTTON_LEFT]        = VD_AGENT_LBUTTON_MASK,
242         [INPUT_BUTTON_RIGHT]       = VD_AGENT_RBUTTON_MASK,
243         [INPUT_BUTTON_MIDDLE]      = VD_AGENT_MBUTTON_MASK,
244         [INPUT_BUTTON_WHEEL_UP]    = VD_AGENT_UBUTTON_MASK,
245         [INPUT_BUTTON_WHEEL_DOWN]  = VD_AGENT_DBUTTON_MASK,
246 #ifdef VD_AGENT_EBUTTON_MASK
247         [INPUT_BUTTON_SIDE]        = VD_AGENT_SBUTTON_MASK,
248         [INPUT_BUTTON_EXTRA]       = VD_AGENT_EBUTTON_MASK,
249 #endif
250     };
251 
252     VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
253     InputMoveEvent *move;
254     InputBtnEvent *btn;
255     uint32_t xres, yres;
256 
257     switch (evt->type) {
258     case INPUT_EVENT_KIND_ABS:
259         move = evt->u.abs.data;
260         xres = qemu_console_get_width(src, 1024);
261         yres = qemu_console_get_height(src, 768);
262         if (move->axis == INPUT_AXIS_X) {
263             vd->mouse_x = qemu_input_scale_axis(move->value,
264                                                 INPUT_EVENT_ABS_MIN,
265                                                 INPUT_EVENT_ABS_MAX,
266                                                 0, xres);
267         } else if (move->axis == INPUT_AXIS_Y) {
268             vd->mouse_y = qemu_input_scale_axis(move->value,
269                                                 INPUT_EVENT_ABS_MIN,
270                                                 INPUT_EVENT_ABS_MAX,
271                                                 0, yres);
272         }
273         vd->mouse_display = qemu_console_get_index(src);
274         break;
275 
276     case INPUT_EVENT_KIND_BTN:
277         btn = evt->u.btn.data;
278         if (btn->down) {
279             vd->mouse_btn |= bmap[btn->button];
280         } else {
281             vd->mouse_btn &= ~bmap[btn->button];
282         }
283         break;
284 
285     default:
286         /* keep gcc happy */
287         break;
288     }
289 }
290 
291 static void vdagent_pointer_sync(DeviceState *dev)
292 {
293     VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
294 
295     if (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE)) {
296         vdagent_send_mouse(vd);
297     }
298 }
299 
300 static QemuInputHandler vdagent_mouse_handler = {
301     .name  = "vdagent mouse",
302     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
303     .event = vdagent_pointer_event,
304     .sync  = vdagent_pointer_sync,
305 };
306 
307 /* ------------------------------------------------------------------ */
308 /* clipboard                                                          */
309 
310 static bool have_clipboard(VDAgentChardev *vd)
311 {
312     return vd->clipboard &&
313         (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
314 }
315 
316 static bool have_selection(VDAgentChardev *vd)
317 {
318     return vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
319 }
320 
321 static uint32_t type_qemu_to_vdagent(enum QemuClipboardType type)
322 {
323     switch (type) {
324     case QEMU_CLIPBOARD_TYPE_TEXT:
325         return VD_AGENT_CLIPBOARD_UTF8_TEXT;
326     default:
327         return VD_AGENT_CLIPBOARD_NONE;
328     }
329 }
330 
331 static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
332                                         QemuClipboardInfo *info)
333 {
334     g_autofree VDAgentMessage *msg =
335         g_malloc0(sizeof(VDAgentMessage) +
336                   sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1) +
337                   sizeof(uint32_t));
338     uint8_t *s = msg->data;
339     uint32_t *data = (uint32_t *)msg->data;
340     uint32_t q, type;
341 
342     if (have_selection(vd)) {
343         *s = info->selection;
344         data++;
345         msg->size += sizeof(uint32_t);
346     } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
347         return;
348     }
349 
350 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
351     if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
352         if (!info->has_serial) {
353             /* client should win */
354             info->serial = vd->last_serial[info->selection]++;
355             info->has_serial = true;
356         }
357         *data = info->serial;
358         data++;
359         msg->size += sizeof(uint32_t);
360     }
361 #endif
362 
363     for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) {
364         type = type_qemu_to_vdagent(q);
365         if (type != VD_AGENT_CLIPBOARD_NONE && info->types[q].available) {
366             *data = type;
367             data++;
368             msg->size += sizeof(uint32_t);
369         }
370     }
371 
372     msg->type = VD_AGENT_CLIPBOARD_GRAB;
373     vdagent_send_msg(vd, msg);
374 }
375 
376 static void vdagent_send_clipboard_release(VDAgentChardev *vd,
377                                            QemuClipboardInfo *info)
378 {
379     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
380                                                sizeof(uint32_t));
381 
382     if (have_selection(vd)) {
383         uint8_t *s = msg->data;
384         *s = info->selection;
385         msg->size += sizeof(uint32_t);
386     } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
387         return;
388     }
389 
390     msg->type = VD_AGENT_CLIPBOARD_RELEASE;
391     vdagent_send_msg(vd, msg);
392 }
393 
394 static void vdagent_send_clipboard_data(VDAgentChardev *vd,
395                                         QemuClipboardInfo *info,
396                                         QemuClipboardType type)
397 {
398     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
399                                                sizeof(uint32_t) * 2 +
400                                                info->types[type].size);
401 
402     uint8_t *s = msg->data;
403     uint32_t *data = (uint32_t *)msg->data;
404 
405     if (have_selection(vd)) {
406         *s = info->selection;
407         data++;
408         msg->size += sizeof(uint32_t);
409     } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
410         return;
411     }
412 
413     *data = type_qemu_to_vdagent(type);
414     data++;
415     msg->size += sizeof(uint32_t);
416 
417     memcpy(data, info->types[type].data, info->types[type].size);
418     msg->size += info->types[type].size;
419 
420     msg->type = VD_AGENT_CLIPBOARD;
421     vdagent_send_msg(vd, msg);
422 }
423 
424 static void vdagent_send_empty_clipboard_data(VDAgentChardev *vd,
425                                               QemuClipboardSelection selection,
426                                               QemuClipboardType type)
427 {
428     g_autoptr(QemuClipboardInfo) info = qemu_clipboard_info_new(&vd->cbpeer, selection);
429 
430     trace_vdagent_send_empty_clipboard();
431     vdagent_send_clipboard_data(vd, info, type);
432 }
433 
434 static void vdagent_clipboard_update_info(VDAgentChardev *vd,
435                                           QemuClipboardInfo *info)
436 {
437     QemuClipboardSelection s = info->selection;
438     QemuClipboardType type;
439     bool self_update = info->owner == &vd->cbpeer;
440 
441     if (info != qemu_clipboard_info(s)) {
442         vd->cbpending[s] = 0;
443         if (!self_update) {
444             if (info->owner) {
445                 vdagent_send_clipboard_grab(vd, info);
446             } else {
447                 vdagent_send_clipboard_release(vd, info);
448             }
449         }
450         return;
451     }
452 
453     if (self_update) {
454         return;
455     }
456 
457     for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) {
458         if (vd->cbpending[s] & (1 << type)) {
459             vd->cbpending[s] &= ~(1 << type);
460             vdagent_send_clipboard_data(vd, info, type);
461         }
462     }
463 }
464 
465 static void vdagent_clipboard_reset_serial(VDAgentChardev *vd)
466 {
467     Chardev *chr = CHARDEV(vd);
468 
469     /* reopen the agent connection to reset the serial state */
470     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
471     /* OPENED again after the guest disconnected, see set_fe_open */
472 }
473 
474 static void vdagent_clipboard_notify(Notifier *notifier, void *data)
475 {
476     VDAgentChardev *vd =
477         container_of(notifier, VDAgentChardev, cbpeer.notifier);
478     QemuClipboardNotify *notify = data;
479 
480     switch (notify->type) {
481     case QEMU_CLIPBOARD_UPDATE_INFO:
482         vdagent_clipboard_update_info(vd, notify->info);
483         return;
484     case QEMU_CLIPBOARD_RESET_SERIAL:
485         vdagent_clipboard_reset_serial(vd);
486         return;
487     }
488 }
489 
490 static void vdagent_clipboard_request(QemuClipboardInfo *info,
491                                       QemuClipboardType qtype)
492 {
493     VDAgentChardev *vd = container_of(info->owner, VDAgentChardev, cbpeer);
494     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
495                                                sizeof(uint32_t) * 2);
496     uint32_t type = type_qemu_to_vdagent(qtype);
497     uint8_t *s = msg->data;
498     uint32_t *data = (uint32_t *)msg->data;
499 
500     if (type == VD_AGENT_CLIPBOARD_NONE) {
501         return;
502     }
503 
504     if (have_selection(vd)) {
505         *s = info->selection;
506         data++;
507         msg->size += sizeof(uint32_t);
508     }
509 
510     *data = type;
511     msg->size += sizeof(uint32_t);
512 
513     msg->type = VD_AGENT_CLIPBOARD_REQUEST;
514     vdagent_send_msg(vd, msg);
515 }
516 
517 static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
518 {
519     g_autoptr(QemuClipboardInfo) info = NULL;
520 
521     trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
522     info = qemu_clipboard_info_new(&vd->cbpeer, s);
523 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
524     if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
525         if (size < sizeof(uint32_t)) {
526             /* this shouldn't happen! */
527             return;
528         }
529 
530         info->has_serial = true;
531         info->serial = *(uint32_t *)data;
532         if (info->serial < vd->last_serial[s]) {
533             trace_vdagent_cb_grab_discard(GET_NAME(sel_name, s),
534                                           vd->last_serial[s], info->serial);
535             /* discard lower-ordering guest grab */
536             return;
537         }
538         vd->last_serial[s] = info->serial;
539         data += sizeof(uint32_t);
540         size -= sizeof(uint32_t);
541     }
542 #endif
543     if (size > sizeof(uint32_t) * 10) {
544         /*
545          * spice has 6 types as of 2021. Limiting to 10 entries
546          * so we have some wiggle room.
547          */
548         return;
549     }
550     while (size >= sizeof(uint32_t)) {
551         trace_vdagent_cb_grab_type(GET_NAME(type_name, *(uint32_t *)data));
552         switch (*(uint32_t *)data) {
553         case VD_AGENT_CLIPBOARD_UTF8_TEXT:
554             info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
555             break;
556         default:
557             break;
558         }
559         data += sizeof(uint32_t);
560         size -= sizeof(uint32_t);
561     }
562     qemu_clipboard_update(info);
563 }
564 
565 static void vdagent_clipboard_recv_request(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
566 {
567     QemuClipboardType type;
568     QemuClipboardInfo *info;
569 
570     if (size < sizeof(uint32_t)) {
571         return;
572     }
573     switch (*(uint32_t *)data) {
574     case VD_AGENT_CLIPBOARD_UTF8_TEXT:
575         type = QEMU_CLIPBOARD_TYPE_TEXT;
576         break;
577     default:
578         return;
579     }
580 
581     info = qemu_clipboard_info(s);
582     if (info && info->types[type].available && info->owner != &vd->cbpeer) {
583         if (info->types[type].data) {
584             vdagent_send_clipboard_data(vd, info, type);
585         } else {
586             vd->cbpending[s] |= (1 << type);
587             qemu_clipboard_request(info, type);
588         }
589     } else {
590         vdagent_send_empty_clipboard_data(vd, s, type);
591     }
592 }
593 
594 static void vdagent_clipboard_recv_data(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
595 {
596     QemuClipboardType type;
597 
598     if (size < sizeof(uint32_t)) {
599         return;
600     }
601     switch (*(uint32_t *)data) {
602     case VD_AGENT_CLIPBOARD_UTF8_TEXT:
603         type = QEMU_CLIPBOARD_TYPE_TEXT;
604         break;
605     default:
606         return;
607     }
608     data += 4;
609     size -= 4;
610 
611     if (qemu_clipboard_peer_owns(&vd->cbpeer, s)) {
612         qemu_clipboard_set_data(&vd->cbpeer, qemu_clipboard_info(s),
613                                 type, size, data, true);
614     }
615 }
616 
617 static void vdagent_clipboard_recv_release(VDAgentChardev *vd, uint8_t s)
618 {
619     qemu_clipboard_peer_release(&vd->cbpeer, s);
620 }
621 
622 static void vdagent_chr_recv_clipboard(VDAgentChardev *vd, VDAgentMessage *msg)
623 {
624     uint8_t s = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
625     uint32_t size = msg->size;
626     void *data = msg->data;
627 
628     if (have_selection(vd)) {
629         if (size < 4) {
630             return;
631         }
632         s = *(uint8_t *)data;
633         if (s >= QEMU_CLIPBOARD_SELECTION__COUNT) {
634             return;
635         }
636         data += 4;
637         size -= 4;
638     }
639 
640     switch (msg->type) {
641     case VD_AGENT_CLIPBOARD_GRAB:
642         return vdagent_clipboard_recv_grab(vd, s, size, data);
643     case VD_AGENT_CLIPBOARD_REQUEST:
644         return vdagent_clipboard_recv_request(vd, s, size, data);
645     case VD_AGENT_CLIPBOARD: /* data */
646         return vdagent_clipboard_recv_data(vd, s, size, data);
647     case VD_AGENT_CLIPBOARD_RELEASE:
648         return vdagent_clipboard_recv_release(vd, s);
649     default:
650         g_assert_not_reached();
651     }
652 }
653 
654 /* ------------------------------------------------------------------ */
655 /* chardev backend                                                    */
656 
657 static void vdagent_chr_open(Chardev *chr,
658                              ChardevBackend *backend,
659                              bool *be_opened,
660                              Error **errp)
661 {
662     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
663     ChardevQemuVDAgent *cfg = backend->u.qemu_vdagent.data;
664 
665 #if HOST_BIG_ENDIAN
666     /*
667      * TODO: vdagent protocol is defined to be LE,
668      * so we have to byteswap everything on BE hosts.
669      */
670     error_setg(errp, "vdagent is not supported on bigendian hosts");
671     return;
672 #endif
673 
674     if (migrate_add_blocker(vd->migration_blocker, errp) != 0) {
675         return;
676     }
677 
678     vd->mouse = VDAGENT_MOUSE_DEFAULT;
679     if (cfg->has_mouse) {
680         vd->mouse = cfg->mouse;
681     }
682 
683     vd->clipboard = VDAGENT_CLIPBOARD_DEFAULT;
684     if (cfg->has_clipboard) {
685         vd->clipboard = cfg->clipboard;
686     }
687 
688     if (vd->mouse) {
689         vd->mouse_hs = qemu_input_handler_register(&vd->mouse_dev,
690                                                    &vdagent_mouse_handler);
691     }
692 
693     *be_opened = true;
694 }
695 
696 static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
697 {
698     VDAgentAnnounceCapabilities *caps = (void *)msg->data;
699     int i;
700 
701     if (msg->size < (sizeof(VDAgentAnnounceCapabilities) +
702                      sizeof(uint32_t))) {
703         return;
704     }
705 
706     for (i = 0; i < ARRAY_SIZE(cap_name); i++) {
707         if (caps->caps[0] & (1 << i)) {
708             trace_vdagent_peer_cap(GET_NAME(cap_name, i));
709         }
710     }
711 
712     vd->caps = caps->caps[0];
713     if (caps->request) {
714         vdagent_send_caps(vd);
715     }
716     if (have_mouse(vd) && vd->mouse_hs) {
717         qemu_input_handler_activate(vd->mouse_hs);
718     }
719 
720     memset(vd->last_serial, 0, sizeof(vd->last_serial));
721 
722     if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
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     trace_vdagent_disconnect();
858 
859     buffer_reset(&vd->outbuf);
860     vdagent_reset_bufs(vd);
861     vd->caps = 0;
862     if (vd->mouse_hs) {
863         qemu_input_handler_deactivate(vd->mouse_hs);
864     }
865     if (vd->cbpeer.notifier.notify) {
866         qemu_clipboard_peer_unregister(&vd->cbpeer);
867         memset(&vd->cbpeer, 0, sizeof(vd->cbpeer));
868     }
869 }
870 
871 static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
872 {
873     if (!fe_open) {
874         trace_vdagent_close();
875         /* To reset_serial, we CLOSED our side. Make sure the other end knows we
876          * are ready again. */
877         qemu_chr_be_event(chr, CHR_EVENT_OPENED);
878         return;
879     }
880 
881     trace_vdagent_open();
882 }
883 
884 static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
885                               Error **errp)
886 {
887     ChardevQemuVDAgent *cfg;
888 
889     backend->type = CHARDEV_BACKEND_KIND_QEMU_VDAGENT;
890     cfg = backend->u.qemu_vdagent.data = g_new0(ChardevQemuVDAgent, 1);
891     qemu_chr_parse_common(opts, qapi_ChardevQemuVDAgent_base(cfg));
892     cfg->has_mouse = true;
893     cfg->mouse = qemu_opt_get_bool(opts, "mouse", VDAGENT_MOUSE_DEFAULT);
894     cfg->has_clipboard = true;
895     cfg->clipboard = qemu_opt_get_bool(opts, "clipboard", VDAGENT_CLIPBOARD_DEFAULT);
896 }
897 
898 /* ------------------------------------------------------------------ */
899 
900 static void vdagent_chr_class_init(ObjectClass *oc, void *data)
901 {
902     ChardevClass *cc = CHARDEV_CLASS(oc);
903 
904     cc->parse            = vdagent_chr_parse;
905     cc->open             = vdagent_chr_open;
906     cc->chr_write        = vdagent_chr_write;
907     cc->chr_set_fe_open  = vdagent_chr_set_fe_open;
908     cc->chr_accept_input = vdagent_chr_accept_input;
909 }
910 
911 static void vdagent_chr_init(Object *obj)
912 {
913     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
914 
915     buffer_init(&vd->outbuf, "vdagent-outbuf");
916     error_setg(&vd->migration_blocker,
917                "The vdagent chardev doesn't yet support migration");
918 }
919 
920 static void vdagent_chr_fini(Object *obj)
921 {
922     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
923 
924     migrate_del_blocker(vd->migration_blocker);
925     vdagent_disconnect(vd);
926     buffer_free(&vd->outbuf);
927     error_free(vd->migration_blocker);
928 }
929 
930 static const TypeInfo vdagent_chr_type_info = {
931     .name = TYPE_CHARDEV_QEMU_VDAGENT,
932     .parent = TYPE_CHARDEV,
933     .instance_size = sizeof(VDAgentChardev),
934     .instance_init = vdagent_chr_init,
935     .instance_finalize = vdagent_chr_fini,
936     .class_init = vdagent_chr_class_init,
937 };
938 
939 static void register_types(void)
940 {
941     type_register_static(&vdagent_chr_type_info);
942 }
943 
944 type_init(register_types);
945