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