1 #include "qemu/osdep.h" 2 #include "trace.h" 3 #include "ui/qemu-spice.h" 4 #include "chardev/char.h" 5 #include "chardev/spice.h" 6 #include "qapi/error.h" 7 #include "qemu/error-report.h" 8 #include "qemu/module.h" 9 #include "qemu/option.h" 10 #include <spice/protocol.h> 11 12 typedef struct SpiceCharSource { 13 GSource source; 14 SpiceChardev *scd; 15 } SpiceCharSource; 16 17 static QLIST_HEAD(, SpiceChardev) spice_chars = 18 QLIST_HEAD_INITIALIZER(spice_chars); 19 20 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) 21 { 22 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 23 Chardev *chr = CHARDEV(scd); 24 ssize_t out = 0; 25 ssize_t last_out; 26 uint8_t* p = (uint8_t*)buf; 27 28 while (len > 0) { 29 int can_write = qemu_chr_be_can_write(chr); 30 last_out = MIN(len, can_write); 31 if (last_out <= 0) { 32 break; 33 } 34 qemu_chr_be_write(chr, p, last_out); 35 out += last_out; 36 len -= last_out; 37 p += last_out; 38 } 39 40 trace_spice_vmc_write(out, len + out); 41 return out; 42 } 43 44 static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) 45 { 46 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 47 int bytes = MIN(len, scd->datalen); 48 49 if (bytes > 0) { 50 memcpy(buf, scd->datapos, bytes); 51 scd->datapos += bytes; 52 scd->datalen -= bytes; 53 assert(scd->datalen >= 0); 54 } 55 if (scd->datalen == 0) { 56 scd->datapos = 0; 57 scd->blocked = false; 58 } 59 trace_spice_vmc_read(bytes, len); 60 return bytes; 61 } 62 63 static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event) 64 { 65 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 66 Chardev *chr = CHARDEV(scd); 67 int chr_event; 68 69 switch (event) { 70 case SPICE_PORT_EVENT_BREAK: 71 chr_event = CHR_EVENT_BREAK; 72 break; 73 default: 74 return; 75 } 76 77 trace_spice_vmc_event(chr_event); 78 qemu_chr_be_event(chr, chr_event); 79 } 80 81 static void vmc_state(SpiceCharDeviceInstance *sin, int connected) 82 { 83 SpiceChardev *scd = container_of(sin, SpiceChardev, sin); 84 Chardev *chr = CHARDEV(scd); 85 86 if ((chr->be_open && connected) || 87 (!chr->be_open && !connected)) { 88 return; 89 } 90 91 qemu_chr_be_event(chr, 92 connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED); 93 } 94 95 static SpiceCharDeviceInterface vmc_interface = { 96 .base.type = SPICE_INTERFACE_CHAR_DEVICE, 97 .base.description = "spice virtual channel char device", 98 .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, 99 .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, 100 .state = vmc_state, 101 .write = vmc_write, 102 .read = vmc_read, 103 .event = vmc_event, 104 #if SPICE_SERVER_VERSION >= 0x000c06 105 .flags = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE, 106 #endif 107 }; 108 109 110 static void vmc_register_interface(SpiceChardev *scd) 111 { 112 if (scd->active) { 113 return; 114 } 115 scd->sin.base.sif = &vmc_interface.base; 116 qemu_spice_add_interface(&scd->sin.base); 117 scd->active = true; 118 trace_spice_vmc_register_interface(scd); 119 } 120 121 static void vmc_unregister_interface(SpiceChardev *scd) 122 { 123 if (!scd->active) { 124 return; 125 } 126 spice_server_remove_interface(&scd->sin.base); 127 scd->active = false; 128 trace_spice_vmc_unregister_interface(scd); 129 } 130 131 static gboolean spice_char_source_prepare(GSource *source, gint *timeout) 132 { 133 SpiceCharSource *src = (SpiceCharSource *)source; 134 Chardev *chr = CHARDEV(src->scd); 135 136 *timeout = -1; 137 138 if (!chr->be_open) { 139 return true; 140 } 141 142 return !src->scd->blocked; 143 } 144 145 static gboolean spice_char_source_check(GSource *source) 146 { 147 SpiceCharSource *src = (SpiceCharSource *)source; 148 Chardev *chr = CHARDEV(src->scd); 149 150 if (!chr->be_open) { 151 return true; 152 } 153 154 return !src->scd->blocked; 155 } 156 157 static gboolean spice_char_source_dispatch(GSource *source, 158 GSourceFunc callback, gpointer user_data) 159 { 160 SpiceCharSource *src = (SpiceCharSource *)source; 161 Chardev *chr = CHARDEV(src->scd); 162 GIOFunc func = (GIOFunc)callback; 163 GIOCondition cond = chr->be_open ? G_IO_OUT : G_IO_HUP; 164 165 return func(NULL, cond, user_data); 166 } 167 168 static GSourceFuncs SpiceCharSourceFuncs = { 169 .prepare = spice_char_source_prepare, 170 .check = spice_char_source_check, 171 .dispatch = spice_char_source_dispatch, 172 }; 173 174 static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond) 175 { 176 SpiceChardev *scd = SPICE_CHARDEV(chr); 177 SpiceCharSource *src; 178 179 assert(cond & G_IO_OUT); 180 181 src = (SpiceCharSource *)g_source_new(&SpiceCharSourceFuncs, 182 sizeof(SpiceCharSource)); 183 src->scd = scd; 184 185 return (GSource *)src; 186 } 187 188 static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len) 189 { 190 SpiceChardev *s = SPICE_CHARDEV(chr); 191 int read_bytes; 192 193 assert(s->datalen == 0); 194 195 if (!chr->be_open) { 196 trace_spice_chr_discard_write(len); 197 return len; 198 } 199 200 s->datapos = buf; 201 s->datalen = len; 202 spice_server_char_device_wakeup(&s->sin); 203 read_bytes = len - s->datalen; 204 if (read_bytes != len) { 205 /* We'll get passed in the unconsumed data with the next call */ 206 s->datalen = 0; 207 s->datapos = NULL; 208 s->blocked = true; 209 } 210 return read_bytes; 211 } 212 213 static void char_spice_finalize(Object *obj) 214 { 215 SpiceChardev *s = SPICE_CHARDEV(obj); 216 217 vmc_unregister_interface(s); 218 219 QLIST_SAFE_REMOVE(s, next); 220 221 g_free((char *)s->sin.subtype); 222 g_free((char *)s->sin.portname); 223 } 224 225 static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open) 226 { 227 SpiceChardev *s = SPICE_CHARDEV(chr); 228 if (fe_open) { 229 vmc_register_interface(s); 230 } else { 231 vmc_unregister_interface(s); 232 } 233 } 234 235 static void spice_port_set_fe_open(struct Chardev *chr, int fe_open) 236 { 237 SpiceChardev *s = SPICE_CHARDEV(chr); 238 239 if (fe_open) { 240 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED); 241 } else { 242 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED); 243 } 244 } 245 246 static void spice_chr_accept_input(struct Chardev *chr) 247 { 248 SpiceChardev *s = SPICE_CHARDEV(chr); 249 250 spice_server_char_device_wakeup(&s->sin); 251 } 252 253 static void chr_open(Chardev *chr, const char *subtype) 254 { 255 SpiceChardev *s = SPICE_CHARDEV(chr); 256 257 s->active = false; 258 s->sin.subtype = g_strdup(subtype); 259 260 QLIST_INSERT_HEAD(&spice_chars, s, next); 261 } 262 263 static void qemu_chr_open_spice_vmc(Chardev *chr, 264 ChardevBackend *backend, 265 bool *be_opened, 266 Error **errp) 267 { 268 ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data; 269 const char *type = spicevmc->type; 270 const char **psubtype = spice_server_char_device_recognized_subtypes(); 271 272 for (; *psubtype != NULL; ++psubtype) { 273 if (strcmp(type, *psubtype) == 0) { 274 break; 275 } 276 } 277 if (*psubtype == NULL) { 278 char *subtypes = g_strjoinv(", ", 279 (gchar **)spice_server_char_device_recognized_subtypes()); 280 281 error_setg(errp, "unsupported type name: %s", type); 282 error_append_hint(errp, "allowed spice char type names: %s\n", 283 subtypes); 284 285 g_free(subtypes); 286 return; 287 } 288 289 *be_opened = false; 290 #if SPICE_SERVER_VERSION < 0x000e02 291 /* Spice < 0.14.2 doesn't explicitly open smartcard chardev */ 292 if (strcmp(type, "smartcard") == 0) { 293 *be_opened = true; 294 } 295 #endif 296 chr_open(chr, type); 297 } 298 299 void qemu_chr_open_spice_port(Chardev *chr, 300 ChardevBackend *backend, 301 bool *be_opened, 302 Error **errp) 303 { 304 ChardevSpicePort *spiceport = backend->u.spiceport.data; 305 const char *name = spiceport->fqdn; 306 SpiceChardev *s; 307 308 if (name == NULL) { 309 error_setg(errp, "missing name parameter"); 310 return; 311 } 312 313 chr_open(chr, "port"); 314 315 *be_opened = false; 316 s = SPICE_CHARDEV(chr); 317 s->sin.portname = g_strdup(name); 318 319 if (using_spice) { 320 /* spice server already created */ 321 vmc_register_interface(s); 322 } 323 } 324 325 void qemu_spice_register_ports(void) 326 { 327 SpiceChardev *s; 328 329 QLIST_FOREACH(s, &spice_chars, next) { 330 if (s->sin.portname == NULL) { 331 continue; 332 } 333 vmc_register_interface(s); 334 } 335 } 336 337 static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend, 338 Error **errp) 339 { 340 const char *name = qemu_opt_get(opts, "name"); 341 ChardevSpiceChannel *spicevmc; 342 343 if (name == NULL) { 344 error_setg(errp, "chardev: spice channel: no name given"); 345 return; 346 } 347 backend->type = CHARDEV_BACKEND_KIND_SPICEVMC; 348 spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1); 349 qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc)); 350 spicevmc->type = g_strdup(name); 351 } 352 353 static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, 354 Error **errp) 355 { 356 const char *name = qemu_opt_get(opts, "name"); 357 ChardevSpicePort *spiceport; 358 359 if (name == NULL) { 360 error_setg(errp, "chardev: spice port: no name given"); 361 return; 362 } 363 backend->type = CHARDEV_BACKEND_KIND_SPICEPORT; 364 spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1); 365 qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport)); 366 spiceport->fqdn = g_strdup(name); 367 } 368 369 static void char_spice_class_init(ObjectClass *oc, void *data) 370 { 371 ChardevClass *cc = CHARDEV_CLASS(oc); 372 373 cc->chr_write = spice_chr_write; 374 cc->chr_add_watch = spice_chr_add_watch; 375 cc->chr_accept_input = spice_chr_accept_input; 376 } 377 378 static const TypeInfo char_spice_type_info = { 379 .name = TYPE_CHARDEV_SPICE, 380 .parent = TYPE_CHARDEV, 381 .instance_size = sizeof(SpiceChardev), 382 .instance_finalize = char_spice_finalize, 383 .class_init = char_spice_class_init, 384 .abstract = true, 385 }; 386 387 static void char_spicevmc_class_init(ObjectClass *oc, void *data) 388 { 389 ChardevClass *cc = CHARDEV_CLASS(oc); 390 391 cc->parse = qemu_chr_parse_spice_vmc; 392 cc->open = qemu_chr_open_spice_vmc; 393 cc->chr_set_fe_open = spice_vmc_set_fe_open; 394 } 395 396 static const TypeInfo char_spicevmc_type_info = { 397 .name = TYPE_CHARDEV_SPICEVMC, 398 .parent = TYPE_CHARDEV_SPICE, 399 .class_init = char_spicevmc_class_init, 400 }; 401 402 static void char_spiceport_class_init(ObjectClass *oc, void *data) 403 { 404 ChardevClass *cc = CHARDEV_CLASS(oc); 405 406 cc->parse = qemu_chr_parse_spice_port; 407 cc->open = qemu_chr_open_spice_port; 408 cc->chr_set_fe_open = spice_port_set_fe_open; 409 } 410 411 static const TypeInfo char_spiceport_type_info = { 412 .name = TYPE_CHARDEV_SPICEPORT, 413 .parent = TYPE_CHARDEV_SPICE, 414 .class_init = char_spiceport_class_init, 415 }; 416 417 static void register_types(void) 418 { 419 type_register_static(&char_spice_type_info); 420 type_register_static(&char_spicevmc_type_info); 421 type_register_static(&char_spiceport_type_info); 422 } 423 424 type_init(register_types); 425