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