xref: /openbmc/qemu/ui/vdagent.c (revision 3cce8bd4d737f2ca688bbdcb92cd5cc683245bbd)
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