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