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 if (s->next.le_prev) { 220 QLIST_REMOVE(s, next); 221 } 222 223 g_free((char *)s->sin.subtype); 224 g_free((char *)s->sin.portname); 225 } 226 227 static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open) 228 { 229 SpiceChardev *s = SPICE_CHARDEV(chr); 230 if (fe_open) { 231 vmc_register_interface(s); 232 } else { 233 vmc_unregister_interface(s); 234 } 235 } 236 237 static void spice_port_set_fe_open(struct Chardev *chr, int fe_open) 238 { 239 SpiceChardev *s = SPICE_CHARDEV(chr); 240 241 if (fe_open) { 242 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED); 243 } else { 244 spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED); 245 } 246 } 247 248 static void spice_chr_accept_input(struct Chardev *chr) 249 { 250 SpiceChardev *s = SPICE_CHARDEV(chr); 251 252 spice_server_char_device_wakeup(&s->sin); 253 } 254 255 static void chr_open(Chardev *chr, const char *subtype) 256 { 257 SpiceChardev *s = SPICE_CHARDEV(chr); 258 259 s->active = false; 260 s->sin.subtype = g_strdup(subtype); 261 262 QLIST_INSERT_HEAD(&spice_chars, s, next); 263 } 264 265 static void qemu_chr_open_spice_vmc(Chardev *chr, 266 ChardevBackend *backend, 267 bool *be_opened, 268 Error **errp) 269 { 270 ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data; 271 const char *type = spicevmc->type; 272 const char **psubtype = spice_server_char_device_recognized_subtypes(); 273 274 for (; *psubtype != NULL; ++psubtype) { 275 if (strcmp(type, *psubtype) == 0) { 276 break; 277 } 278 } 279 if (*psubtype == NULL) { 280 char *subtypes = g_strjoinv(", ", 281 (gchar **)spice_server_char_device_recognized_subtypes()); 282 283 error_setg(errp, "unsupported type name: %s", type); 284 error_append_hint(errp, "allowed spice char type names: %s\n", 285 subtypes); 286 287 g_free(subtypes); 288 return; 289 } 290 291 *be_opened = false; 292 #if SPICE_SERVER_VERSION < 0x000e02 293 /* Spice < 0.14.2 doesn't explicitly open smartcard chardev */ 294 if (strcmp(type, "smartcard") == 0) { 295 *be_opened = true; 296 } 297 #endif 298 chr_open(chr, type); 299 } 300 301 void qemu_chr_open_spice_port(Chardev *chr, 302 ChardevBackend *backend, 303 bool *be_opened, 304 Error **errp) 305 { 306 ChardevSpicePort *spiceport = backend->u.spiceport.data; 307 const char *name = spiceport->fqdn; 308 SpiceChardev *s; 309 310 if (name == NULL) { 311 error_setg(errp, "missing name parameter"); 312 return; 313 } 314 315 chr_open(chr, "port"); 316 317 *be_opened = false; 318 s = SPICE_CHARDEV(chr); 319 s->sin.portname = g_strdup(name); 320 321 if (using_spice) { 322 /* spice server already created */ 323 vmc_register_interface(s); 324 } 325 } 326 327 void qemu_spice_register_ports(void) 328 { 329 SpiceChardev *s; 330 331 QLIST_FOREACH(s, &spice_chars, next) { 332 if (s->sin.portname == NULL) { 333 continue; 334 } 335 vmc_register_interface(s); 336 } 337 } 338 339 static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend, 340 Error **errp) 341 { 342 const char *name = qemu_opt_get(opts, "name"); 343 ChardevSpiceChannel *spicevmc; 344 345 if (name == NULL) { 346 error_setg(errp, "chardev: spice channel: no name given"); 347 return; 348 } 349 backend->type = CHARDEV_BACKEND_KIND_SPICEVMC; 350 spicevmc = backend->u.spicevmc.data = g_new0(ChardevSpiceChannel, 1); 351 qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc)); 352 spicevmc->type = g_strdup(name); 353 } 354 355 static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, 356 Error **errp) 357 { 358 const char *name = qemu_opt_get(opts, "name"); 359 ChardevSpicePort *spiceport; 360 361 if (name == NULL) { 362 error_setg(errp, "chardev: spice port: no name given"); 363 return; 364 } 365 backend->type = CHARDEV_BACKEND_KIND_SPICEPORT; 366 spiceport = backend->u.spiceport.data = g_new0(ChardevSpicePort, 1); 367 qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport)); 368 spiceport->fqdn = g_strdup(name); 369 } 370 371 static void char_spice_class_init(ObjectClass *oc, void *data) 372 { 373 ChardevClass *cc = CHARDEV_CLASS(oc); 374 375 cc->chr_write = spice_chr_write; 376 cc->chr_add_watch = spice_chr_add_watch; 377 cc->chr_accept_input = spice_chr_accept_input; 378 } 379 380 static const TypeInfo char_spice_type_info = { 381 .name = TYPE_CHARDEV_SPICE, 382 .parent = TYPE_CHARDEV, 383 .instance_size = sizeof(SpiceChardev), 384 .instance_finalize = char_spice_finalize, 385 .class_init = char_spice_class_init, 386 .abstract = true, 387 }; 388 389 static void char_spicevmc_class_init(ObjectClass *oc, void *data) 390 { 391 ChardevClass *cc = CHARDEV_CLASS(oc); 392 393 cc->parse = qemu_chr_parse_spice_vmc; 394 cc->open = qemu_chr_open_spice_vmc; 395 cc->chr_set_fe_open = spice_vmc_set_fe_open; 396 } 397 398 static const TypeInfo char_spicevmc_type_info = { 399 .name = TYPE_CHARDEV_SPICEVMC, 400 .parent = TYPE_CHARDEV_SPICE, 401 .class_init = char_spicevmc_class_init, 402 }; 403 404 static void char_spiceport_class_init(ObjectClass *oc, void *data) 405 { 406 ChardevClass *cc = CHARDEV_CLASS(oc); 407 408 cc->parse = qemu_chr_parse_spice_port; 409 cc->open = qemu_chr_open_spice_port; 410 cc->chr_set_fe_open = spice_port_set_fe_open; 411 } 412 413 static const TypeInfo char_spiceport_type_info = { 414 .name = TYPE_CHARDEV_SPICEPORT, 415 .parent = TYPE_CHARDEV_SPICE, 416 .class_init = char_spiceport_class_init, 417 }; 418 419 static void register_types(void) 420 { 421 type_register_static(&char_spice_type_info); 422 type_register_static(&char_spicevmc_type_info); 423 type_register_static(&char_spiceport_type_info); 424 } 425 426 type_init(register_types); 427