xref: /openbmc/qemu/ui/vdagent.c (revision 865714cb)
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 
vdagent_send_buf(VDAgentChardev * vd)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 
vdagent_send_msg(VDAgentChardev * vd,VDAgentMessage * msg)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 
vdagent_send_caps(VDAgentChardev * vd,bool request)188 static void vdagent_send_caps(VDAgentChardev *vd, bool request)
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     caps->request = request;
209     vdagent_send_msg(vd, msg);
210 }
211 
212 /* ------------------------------------------------------------------ */
213 /* mouse events                                                       */
214 
have_mouse(VDAgentChardev * vd)215 static bool have_mouse(VDAgentChardev *vd)
216 {
217     return vd->mouse &&
218         (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE));
219 }
220 
vdagent_send_mouse(VDAgentChardev * vd)221 static void vdagent_send_mouse(VDAgentChardev *vd)
222 {
223     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
224                                                sizeof(VDAgentMouseState));
225     VDAgentMouseState *mouse = (void *)msg->data;
226 
227     msg->type = VD_AGENT_MOUSE_STATE;
228     msg->size = sizeof(VDAgentMouseState);
229 
230     mouse->x          = vd->mouse_x;
231     mouse->y          = vd->mouse_y;
232     mouse->buttons    = vd->mouse_btn;
233     mouse->display_id = vd->mouse_display;
234 
235     vdagent_send_msg(vd, msg);
236 }
237 
vdagent_pointer_event(DeviceState * dev,QemuConsole * src,InputEvent * evt)238 static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
239                                   InputEvent *evt)
240 {
241     static const int bmap[INPUT_BUTTON__MAX] = {
242         [INPUT_BUTTON_LEFT]        = VD_AGENT_LBUTTON_MASK,
243         [INPUT_BUTTON_RIGHT]       = VD_AGENT_RBUTTON_MASK,
244         [INPUT_BUTTON_MIDDLE]      = VD_AGENT_MBUTTON_MASK,
245         [INPUT_BUTTON_WHEEL_UP]    = VD_AGENT_UBUTTON_MASK,
246         [INPUT_BUTTON_WHEEL_DOWN]  = VD_AGENT_DBUTTON_MASK,
247 #ifdef VD_AGENT_EBUTTON_MASK
248         [INPUT_BUTTON_SIDE]        = VD_AGENT_SBUTTON_MASK,
249         [INPUT_BUTTON_EXTRA]       = VD_AGENT_EBUTTON_MASK,
250 #endif
251     };
252 
253     VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
254     InputMoveEvent *move;
255     InputBtnEvent *btn;
256     uint32_t xres, yres;
257 
258     switch (evt->type) {
259     case INPUT_EVENT_KIND_ABS:
260         move = evt->u.abs.data;
261         xres = qemu_console_get_width(src, 1024);
262         yres = qemu_console_get_height(src, 768);
263         if (move->axis == INPUT_AXIS_X) {
264             vd->mouse_x = qemu_input_scale_axis(move->value,
265                                                 INPUT_EVENT_ABS_MIN,
266                                                 INPUT_EVENT_ABS_MAX,
267                                                 0, xres);
268         } else if (move->axis == INPUT_AXIS_Y) {
269             vd->mouse_y = qemu_input_scale_axis(move->value,
270                                                 INPUT_EVENT_ABS_MIN,
271                                                 INPUT_EVENT_ABS_MAX,
272                                                 0, yres);
273         }
274         vd->mouse_display = qemu_console_get_index(src);
275         break;
276 
277     case INPUT_EVENT_KIND_BTN:
278         btn = evt->u.btn.data;
279         if (btn->down) {
280             vd->mouse_btn |= bmap[btn->button];
281         } else {
282             vd->mouse_btn &= ~bmap[btn->button];
283         }
284         break;
285 
286     default:
287         /* keep gcc happy */
288         break;
289     }
290 }
291 
vdagent_pointer_sync(DeviceState * dev)292 static void vdagent_pointer_sync(DeviceState *dev)
293 {
294     VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
295 
296     if (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE)) {
297         vdagent_send_mouse(vd);
298     }
299 }
300 
301 static const QemuInputHandler vdagent_mouse_handler = {
302     .name  = "vdagent mouse",
303     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
304     .event = vdagent_pointer_event,
305     .sync  = vdagent_pointer_sync,
306 };
307 
308 /* ------------------------------------------------------------------ */
309 /* clipboard                                                          */
310 
have_clipboard(VDAgentChardev * vd)311 static bool have_clipboard(VDAgentChardev *vd)
312 {
313     return vd->clipboard &&
314         (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
315 }
316 
have_selection(VDAgentChardev * vd)317 static bool have_selection(VDAgentChardev *vd)
318 {
319     return vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
320 }
321 
type_qemu_to_vdagent(enum QemuClipboardType type)322 static uint32_t type_qemu_to_vdagent(enum QemuClipboardType type)
323 {
324     switch (type) {
325     case QEMU_CLIPBOARD_TYPE_TEXT:
326         return VD_AGENT_CLIPBOARD_UTF8_TEXT;
327     default:
328         return VD_AGENT_CLIPBOARD_NONE;
329     }
330 }
331 
vdagent_send_clipboard_grab(VDAgentChardev * vd,QemuClipboardInfo * info)332 static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
333                                         QemuClipboardInfo *info)
334 {
335     g_autofree VDAgentMessage *msg =
336         g_malloc0(sizeof(VDAgentMessage) +
337                   sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1) +
338                   sizeof(uint32_t));
339     uint8_t *s = msg->data;
340     uint32_t *data = (uint32_t *)msg->data;
341     uint32_t q, type;
342 
343     if (have_selection(vd)) {
344         *s = info->selection;
345         data++;
346         msg->size += sizeof(uint32_t);
347     } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
348         return;
349     }
350 
351 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
352     if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
353         if (!info->has_serial) {
354             /* client should win */
355             info->serial = vd->last_serial[info->selection]++;
356             info->has_serial = true;
357         }
358         *data = info->serial;
359         data++;
360         msg->size += sizeof(uint32_t);
361     }
362 #endif
363 
364     for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) {
365         type = type_qemu_to_vdagent(q);
366         if (type != VD_AGENT_CLIPBOARD_NONE && info->types[q].available) {
367             *data = type;
368             data++;
369             msg->size += sizeof(uint32_t);
370         }
371     }
372 
373     msg->type = VD_AGENT_CLIPBOARD_GRAB;
374     vdagent_send_msg(vd, msg);
375 }
376 
vdagent_send_clipboard_release(VDAgentChardev * vd,QemuClipboardInfo * info)377 static void vdagent_send_clipboard_release(VDAgentChardev *vd,
378                                            QemuClipboardInfo *info)
379 {
380     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
381                                                sizeof(uint32_t));
382 
383     if (have_selection(vd)) {
384         uint8_t *s = msg->data;
385         *s = info->selection;
386         msg->size += sizeof(uint32_t);
387     } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
388         return;
389     }
390 
391     msg->type = VD_AGENT_CLIPBOARD_RELEASE;
392     vdagent_send_msg(vd, msg);
393 }
394 
vdagent_send_clipboard_data(VDAgentChardev * vd,QemuClipboardInfo * info,QemuClipboardType type)395 static void vdagent_send_clipboard_data(VDAgentChardev *vd,
396                                         QemuClipboardInfo *info,
397                                         QemuClipboardType type)
398 {
399     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
400                                                sizeof(uint32_t) * 2 +
401                                                info->types[type].size);
402 
403     uint8_t *s = msg->data;
404     uint32_t *data = (uint32_t *)msg->data;
405 
406     if (have_selection(vd)) {
407         *s = info->selection;
408         data++;
409         msg->size += sizeof(uint32_t);
410     } else if (info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
411         return;
412     }
413 
414     *data = type_qemu_to_vdagent(type);
415     data++;
416     msg->size += sizeof(uint32_t);
417 
418     memcpy(data, info->types[type].data, info->types[type].size);
419     msg->size += info->types[type].size;
420 
421     msg->type = VD_AGENT_CLIPBOARD;
422     vdagent_send_msg(vd, msg);
423 }
424 
vdagent_send_empty_clipboard_data(VDAgentChardev * vd,QemuClipboardSelection selection,QemuClipboardType type)425 static void vdagent_send_empty_clipboard_data(VDAgentChardev *vd,
426                                               QemuClipboardSelection selection,
427                                               QemuClipboardType type)
428 {
429     g_autoptr(QemuClipboardInfo) info = qemu_clipboard_info_new(&vd->cbpeer, selection);
430 
431     trace_vdagent_send_empty_clipboard();
432     vdagent_send_clipboard_data(vd, info, type);
433 }
434 
vdagent_clipboard_update_info(VDAgentChardev * vd,QemuClipboardInfo * info)435 static void vdagent_clipboard_update_info(VDAgentChardev *vd,
436                                           QemuClipboardInfo *info)
437 {
438     QemuClipboardSelection s = info->selection;
439     QemuClipboardType type;
440     bool self_update = info->owner == &vd->cbpeer;
441 
442     if (info != qemu_clipboard_info(s)) {
443         vd->cbpending[s] = 0;
444         if (!self_update) {
445             if (info->owner) {
446                 vdagent_send_clipboard_grab(vd, info);
447             } else {
448                 vdagent_send_clipboard_release(vd, info);
449             }
450         }
451         return;
452     }
453 
454     if (self_update) {
455         return;
456     }
457 
458     for (type = 0; type < QEMU_CLIPBOARD_TYPE__COUNT; type++) {
459         if (vd->cbpending[s] & (1 << type)) {
460             vd->cbpending[s] &= ~(1 << type);
461             vdagent_send_clipboard_data(vd, info, type);
462         }
463     }
464 }
465 
vdagent_clipboard_reset_serial(VDAgentChardev * vd)466 static void vdagent_clipboard_reset_serial(VDAgentChardev *vd)
467 {
468     Chardev *chr = CHARDEV(vd);
469 
470     /* reopen the agent connection to reset the serial state */
471     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
472     /* OPENED again after the guest disconnected, see set_fe_open */
473 }
474 
vdagent_clipboard_notify(Notifier * notifier,void * data)475 static void vdagent_clipboard_notify(Notifier *notifier, void *data)
476 {
477     VDAgentChardev *vd =
478         container_of(notifier, VDAgentChardev, cbpeer.notifier);
479     QemuClipboardNotify *notify = data;
480 
481     switch (notify->type) {
482     case QEMU_CLIPBOARD_UPDATE_INFO:
483         vdagent_clipboard_update_info(vd, notify->info);
484         return;
485     case QEMU_CLIPBOARD_RESET_SERIAL:
486         vdagent_clipboard_reset_serial(vd);
487         return;
488     }
489 }
490 
vdagent_clipboard_request(QemuClipboardInfo * info,QemuClipboardType qtype)491 static void vdagent_clipboard_request(QemuClipboardInfo *info,
492                                       QemuClipboardType qtype)
493 {
494     VDAgentChardev *vd = container_of(info->owner, VDAgentChardev, cbpeer);
495     g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
496                                                sizeof(uint32_t) * 2);
497     uint32_t type = type_qemu_to_vdagent(qtype);
498     uint8_t *s = msg->data;
499     uint32_t *data = (uint32_t *)msg->data;
500 
501     if (type == VD_AGENT_CLIPBOARD_NONE) {
502         return;
503     }
504 
505     if (have_selection(vd)) {
506         *s = info->selection;
507         data++;
508         msg->size += sizeof(uint32_t);
509     }
510 
511     *data = type;
512     msg->size += sizeof(uint32_t);
513 
514     msg->type = VD_AGENT_CLIPBOARD_REQUEST;
515     vdagent_send_msg(vd, msg);
516 }
517 
vdagent_clipboard_recv_grab(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)518 static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
519 {
520     g_autoptr(QemuClipboardInfo) info = NULL;
521 
522     trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
523     info = qemu_clipboard_info_new(&vd->cbpeer, s);
524 #if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
525     if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
526         if (size < sizeof(uint32_t)) {
527             /* this shouldn't happen! */
528             return;
529         }
530 
531         info->has_serial = true;
532         info->serial = *(uint32_t *)data;
533         if (info->serial < vd->last_serial[s]) {
534             trace_vdagent_cb_grab_discard(GET_NAME(sel_name, s),
535                                           vd->last_serial[s], info->serial);
536             /* discard lower-ordering guest grab */
537             return;
538         }
539         vd->last_serial[s] = info->serial;
540         data += sizeof(uint32_t);
541         size -= sizeof(uint32_t);
542     }
543 #endif
544     if (size > sizeof(uint32_t) * 10) {
545         /*
546          * spice has 6 types as of 2021. Limiting to 10 entries
547          * so we have some wiggle room.
548          */
549         return;
550     }
551     while (size >= sizeof(uint32_t)) {
552         trace_vdagent_cb_grab_type(GET_NAME(type_name, *(uint32_t *)data));
553         switch (*(uint32_t *)data) {
554         case VD_AGENT_CLIPBOARD_UTF8_TEXT:
555             info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
556             break;
557         default:
558             break;
559         }
560         data += sizeof(uint32_t);
561         size -= sizeof(uint32_t);
562     }
563     qemu_clipboard_update(info);
564 }
565 
vdagent_clipboard_recv_request(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)566 static void vdagent_clipboard_recv_request(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
567 {
568     QemuClipboardType type;
569     QemuClipboardInfo *info;
570 
571     if (size < sizeof(uint32_t)) {
572         return;
573     }
574     switch (*(uint32_t *)data) {
575     case VD_AGENT_CLIPBOARD_UTF8_TEXT:
576         type = QEMU_CLIPBOARD_TYPE_TEXT;
577         break;
578     default:
579         return;
580     }
581 
582     info = qemu_clipboard_info(s);
583     if (info && info->types[type].available && info->owner != &vd->cbpeer) {
584         if (info->types[type].data) {
585             vdagent_send_clipboard_data(vd, info, type);
586         } else {
587             vd->cbpending[s] |= (1 << type);
588             qemu_clipboard_request(info, type);
589         }
590     } else {
591         vdagent_send_empty_clipboard_data(vd, s, type);
592     }
593 }
594 
vdagent_clipboard_recv_data(VDAgentChardev * vd,uint8_t s,uint32_t size,void * data)595 static void vdagent_clipboard_recv_data(VDAgentChardev *vd, uint8_t s, uint32_t size, void *data)
596 {
597     QemuClipboardType type;
598 
599     if (size < sizeof(uint32_t)) {
600         return;
601     }
602     switch (*(uint32_t *)data) {
603     case VD_AGENT_CLIPBOARD_UTF8_TEXT:
604         type = QEMU_CLIPBOARD_TYPE_TEXT;
605         break;
606     default:
607         return;
608     }
609     data += 4;
610     size -= 4;
611 
612     if (qemu_clipboard_peer_owns(&vd->cbpeer, s)) {
613         qemu_clipboard_set_data(&vd->cbpeer, qemu_clipboard_info(s),
614                                 type, size, data, true);
615     }
616 }
617 
vdagent_clipboard_recv_release(VDAgentChardev * vd,uint8_t s)618 static void vdagent_clipboard_recv_release(VDAgentChardev *vd, uint8_t s)
619 {
620     qemu_clipboard_peer_release(&vd->cbpeer, s);
621 }
622 
vdagent_chr_recv_clipboard(VDAgentChardev * vd,VDAgentMessage * msg)623 static void vdagent_chr_recv_clipboard(VDAgentChardev *vd, VDAgentMessage *msg)
624 {
625     uint8_t s = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
626     uint32_t size = msg->size;
627     void *data = msg->data;
628 
629     if (have_selection(vd)) {
630         if (size < 4) {
631             return;
632         }
633         s = *(uint8_t *)data;
634         if (s >= QEMU_CLIPBOARD_SELECTION__COUNT) {
635             return;
636         }
637         data += 4;
638         size -= 4;
639     }
640 
641     switch (msg->type) {
642     case VD_AGENT_CLIPBOARD_GRAB:
643         return vdagent_clipboard_recv_grab(vd, s, size, data);
644     case VD_AGENT_CLIPBOARD_REQUEST:
645         return vdagent_clipboard_recv_request(vd, s, size, data);
646     case VD_AGENT_CLIPBOARD: /* data */
647         return vdagent_clipboard_recv_data(vd, s, size, data);
648     case VD_AGENT_CLIPBOARD_RELEASE:
649         return vdagent_clipboard_recv_release(vd, s);
650     default:
651         g_assert_not_reached();
652     }
653 }
654 
655 /* ------------------------------------------------------------------ */
656 /* chardev backend                                                    */
657 
vdagent_chr_open(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)658 static void vdagent_chr_open(Chardev *chr,
659                              ChardevBackend *backend,
660                              bool *be_opened,
661                              Error **errp)
662 {
663     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
664     ChardevQemuVDAgent *cfg = backend->u.qemu_vdagent.data;
665 
666 #if HOST_BIG_ENDIAN
667     /*
668      * TODO: vdagent protocol is defined to be LE,
669      * so we have to byteswap everything on BE hosts.
670      */
671     error_setg(errp, "vdagent is not supported on bigendian hosts");
672     return;
673 #endif
674 
675     if (migrate_add_blocker(&vd->migration_blocker, errp) != 0) {
676         return;
677     }
678 
679     vd->mouse = VDAGENT_MOUSE_DEFAULT;
680     if (cfg->has_mouse) {
681         vd->mouse = cfg->mouse;
682     }
683 
684     vd->clipboard = VDAGENT_CLIPBOARD_DEFAULT;
685     if (cfg->has_clipboard) {
686         vd->clipboard = cfg->clipboard;
687     }
688 
689     if (vd->mouse) {
690         vd->mouse_hs = qemu_input_handler_register(&vd->mouse_dev,
691                                                    &vdagent_mouse_handler);
692     }
693 
694     *be_opened = true;
695 }
696 
vdagent_chr_recv_caps(VDAgentChardev * vd,VDAgentMessage * msg)697 static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
698 {
699     VDAgentAnnounceCapabilities *caps = (void *)msg->data;
700     int i;
701 
702     if (msg->size < (sizeof(VDAgentAnnounceCapabilities) +
703                      sizeof(uint32_t))) {
704         return;
705     }
706 
707     for (i = 0; i < ARRAY_SIZE(cap_name); i++) {
708         if (caps->caps[0] & (1 << i)) {
709             trace_vdagent_peer_cap(GET_NAME(cap_name, i));
710         }
711     }
712 
713     vd->caps = caps->caps[0];
714     if (caps->request) {
715         vdagent_send_caps(vd, false);
716     }
717     if (have_mouse(vd) && vd->mouse_hs) {
718         qemu_input_handler_activate(vd->mouse_hs);
719     }
720 
721     memset(vd->last_serial, 0, sizeof(vd->last_serial));
722 
723     if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
724         qemu_clipboard_reset_serial();
725 
726         vd->cbpeer.name = "vdagent";
727         vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
728         vd->cbpeer.request = vdagent_clipboard_request;
729         qemu_clipboard_peer_register(&vd->cbpeer);
730     }
731 }
732 
vdagent_chr_recv_msg(VDAgentChardev * vd,VDAgentMessage * msg)733 static void vdagent_chr_recv_msg(VDAgentChardev *vd, VDAgentMessage *msg)
734 {
735     trace_vdagent_recv_msg(GET_NAME(msg_name, msg->type), msg->size);
736 
737     switch (msg->type) {
738     case VD_AGENT_ANNOUNCE_CAPABILITIES:
739         vdagent_chr_recv_caps(vd, msg);
740         break;
741     case VD_AGENT_CLIPBOARD:
742     case VD_AGENT_CLIPBOARD_GRAB:
743     case VD_AGENT_CLIPBOARD_REQUEST:
744     case VD_AGENT_CLIPBOARD_RELEASE:
745         if (have_clipboard(vd)) {
746             vdagent_chr_recv_clipboard(vd, msg);
747         }
748         break;
749     default:
750         break;
751     }
752 }
753 
vdagent_reset_xbuf(VDAgentChardev * vd)754 static void vdagent_reset_xbuf(VDAgentChardev *vd)
755 {
756     g_clear_pointer(&vd->xbuf, g_free);
757     vd->xoff = 0;
758     vd->xsize = 0;
759 }
760 
vdagent_chr_recv_chunk(VDAgentChardev * vd)761 static void vdagent_chr_recv_chunk(VDAgentChardev *vd)
762 {
763     VDAgentMessage *msg = (void *)vd->msgbuf;
764 
765     if (!vd->xsize) {
766         if (vd->msgsize < sizeof(*msg)) {
767             error_report("%s: message too small: %d < %zd", __func__,
768                          vd->msgsize, sizeof(*msg));
769             return;
770         }
771         if (vd->msgsize == msg->size + sizeof(*msg)) {
772             vdagent_chr_recv_msg(vd, msg);
773             return;
774         }
775     }
776 
777     if (!vd->xsize) {
778         vd->xsize = msg->size + sizeof(*msg);
779         vd->xbuf = g_malloc0(vd->xsize);
780     }
781 
782     if (vd->xoff + vd->msgsize > vd->xsize) {
783         error_report("%s: Oops: %d+%d > %d", __func__,
784                      vd->xoff, vd->msgsize, vd->xsize);
785         vdagent_reset_xbuf(vd);
786         return;
787     }
788 
789     memcpy(vd->xbuf + vd->xoff, vd->msgbuf, vd->msgsize);
790     vd->xoff += vd->msgsize;
791     if (vd->xoff < vd->xsize) {
792         return;
793     }
794 
795     msg = (void *)vd->xbuf;
796     vdagent_chr_recv_msg(vd, msg);
797     vdagent_reset_xbuf(vd);
798 }
799 
vdagent_reset_bufs(VDAgentChardev * vd)800 static void vdagent_reset_bufs(VDAgentChardev *vd)
801 {
802     memset(&vd->chunk, 0, sizeof(vd->chunk));
803     vd->chunksize = 0;
804     g_free(vd->msgbuf);
805     vd->msgbuf = NULL;
806     vd->msgsize = 0;
807 }
808 
vdagent_chr_write(Chardev * chr,const uint8_t * buf,int len)809 static int vdagent_chr_write(Chardev *chr, const uint8_t *buf, int len)
810 {
811     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
812     uint32_t copy, ret = len;
813 
814     while (len) {
815         if (vd->chunksize < sizeof(vd->chunk)) {
816             copy = sizeof(vd->chunk) - vd->chunksize;
817             if (copy > len) {
818                 copy = len;
819             }
820             memcpy((void *)(&vd->chunk) + vd->chunksize, buf, copy);
821             vd->chunksize += copy;
822             buf += copy;
823             len -= copy;
824             if (vd->chunksize < sizeof(vd->chunk)) {
825                 break;
826             }
827 
828             assert(vd->msgbuf == NULL);
829             vd->msgbuf = g_malloc0(vd->chunk.size);
830         }
831 
832         copy = vd->chunk.size - vd->msgsize;
833         if (copy > len) {
834             copy = len;
835         }
836         memcpy(vd->msgbuf + vd->msgsize, buf, copy);
837         vd->msgsize += copy;
838         buf += copy;
839         len -= copy;
840 
841         if (vd->msgsize == vd->chunk.size) {
842             trace_vdagent_recv_chunk(vd->chunk.size);
843             vdagent_chr_recv_chunk(vd);
844             vdagent_reset_bufs(vd);
845         }
846     }
847 
848     return ret;
849 }
850 
vdagent_chr_accept_input(Chardev * chr)851 static void vdagent_chr_accept_input(Chardev *chr)
852 {
853     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
854 
855     vdagent_send_buf(vd);
856 }
857 
vdagent_disconnect(VDAgentChardev * vd)858 static void vdagent_disconnect(VDAgentChardev *vd)
859 {
860     trace_vdagent_disconnect();
861 
862     buffer_reset(&vd->outbuf);
863     vdagent_reset_bufs(vd);
864     vd->caps = 0;
865     if (vd->mouse_hs) {
866         qemu_input_handler_deactivate(vd->mouse_hs);
867     }
868     if (vd->cbpeer.notifier.notify) {
869         qemu_clipboard_peer_unregister(&vd->cbpeer);
870         memset(&vd->cbpeer, 0, sizeof(vd->cbpeer));
871     }
872 }
873 
vdagent_chr_set_fe_open(struct Chardev * chr,int fe_open)874 static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
875 {
876     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
877 
878     trace_vdagent_fe_open(fe_open);
879 
880     if (!fe_open) {
881         trace_vdagent_close();
882         vdagent_disconnect(vd);
883         /* To reset_serial, we CLOSED our side. Make sure the other end knows we
884          * are ready again. */
885         qemu_chr_be_event(chr, CHR_EVENT_OPENED);
886         return;
887     }
888 
889     vdagent_send_caps(vd, true);
890 }
891 
vdagent_chr_parse(QemuOpts * opts,ChardevBackend * backend,Error ** errp)892 static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
893                               Error **errp)
894 {
895     ChardevQemuVDAgent *cfg;
896 
897     backend->type = CHARDEV_BACKEND_KIND_QEMU_VDAGENT;
898     cfg = backend->u.qemu_vdagent.data = g_new0(ChardevQemuVDAgent, 1);
899     qemu_chr_parse_common(opts, qapi_ChardevQemuVDAgent_base(cfg));
900     cfg->has_mouse = true;
901     cfg->mouse = qemu_opt_get_bool(opts, "mouse", VDAGENT_MOUSE_DEFAULT);
902     cfg->has_clipboard = true;
903     cfg->clipboard = qemu_opt_get_bool(opts, "clipboard", VDAGENT_CLIPBOARD_DEFAULT);
904 }
905 
906 /* ------------------------------------------------------------------ */
907 
vdagent_chr_class_init(ObjectClass * oc,void * data)908 static void vdagent_chr_class_init(ObjectClass *oc, void *data)
909 {
910     ChardevClass *cc = CHARDEV_CLASS(oc);
911 
912     cc->parse            = vdagent_chr_parse;
913     cc->open             = vdagent_chr_open;
914     cc->chr_write        = vdagent_chr_write;
915     cc->chr_set_fe_open  = vdagent_chr_set_fe_open;
916     cc->chr_accept_input = vdagent_chr_accept_input;
917 }
918 
vdagent_chr_init(Object * obj)919 static void vdagent_chr_init(Object *obj)
920 {
921     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
922 
923     buffer_init(&vd->outbuf, "vdagent-outbuf");
924     error_setg(&vd->migration_blocker,
925                "The vdagent chardev doesn't yet support migration");
926 }
927 
vdagent_chr_fini(Object * obj)928 static void vdagent_chr_fini(Object *obj)
929 {
930     VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
931 
932     migrate_del_blocker(&vd->migration_blocker);
933     vdagent_disconnect(vd);
934     if (vd->mouse_hs) {
935         qemu_input_handler_unregister(vd->mouse_hs);
936     }
937     buffer_free(&vd->outbuf);
938 }
939 
940 static const TypeInfo vdagent_chr_type_info = {
941     .name = TYPE_CHARDEV_QEMU_VDAGENT,
942     .parent = TYPE_CHARDEV,
943     .instance_size = sizeof(VDAgentChardev),
944     .instance_init = vdagent_chr_init,
945     .instance_finalize = vdagent_chr_fini,
946     .class_init = vdagent_chr_class_init,
947 };
948 
register_types(void)949 static void register_types(void)
950 {
951     type_register_static(&vdagent_chr_type_info);
952 }
953 
954 type_init(register_types);
955