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