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