[Spice-devel] [PATCH v7 07/20] usb-backend: include usbredirparser
Frediano Ziglio
fziglio at redhat.com
Wed Sep 18 10:17:16 UTC 2019
>
> From: Yuri Benditovich <yuri.benditovich at daynix.com>
>
> This patch introduces the usage of usbredirparser in
> SpiceUsbBackendChannel.
>
> The focus of this patch is to the code path of real devices. As we
> don't know beforehand if a SpiceUsbBackendChannel will be used by real
> or emulated devices, an instance of usbredirparser must be initialized
> with the usbredirhost's first hello message.
>
> This is a must to the current design on supporting emulated devices.
> This will be extended in the next patch to match remote's usbredirhost
> capabilities and providing support to emulated devices.
>
> Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
> Signed-off-by: Victor Toso <victortoso at redhat.com>
Please add my signed off.
> ---
> src/usb-backend.c | 223 ++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 218 insertions(+), 5 deletions(-)
>
> diff --git a/src/usb-backend.c b/src/usb-backend.c
> index 68faaae..ef29901 100644
> --- a/src/usb-backend.c
> +++ b/src/usb-backend.c
> @@ -45,6 +45,7 @@
> #include "usbutil.h"
>
> #define LOUD_DEBUG(x, ...)
> +#define USBREDIR_CALLBACK_NOT_IMPLEMENTED() spice_debug("%s not implemented
> - FIXME", __func__)
>
> struct _SpiceUsbDevice
> {
> @@ -82,6 +83,7 @@ struct _SpiceUsbBackend
> struct _SpiceUsbBackendChannel
> {
> struct usbredirhost *usbredirhost;
> + struct usbredirparser *parser;
> uint8_t *read_buf;
> int read_buf_size;
> struct usbredirfilter_rule *rules;
> @@ -630,11 +632,48 @@ static void usbredir_log(void *user_data, int level,
> const char *msg)
> }
> }
>
> +static struct usbredirparser *create_parser(SpiceUsbBackendChannel *ch);
> +
> static int usbredir_write_callback(void *user_data, uint8_t *data, int
> count)
> {
> SpiceUsbBackendChannel *ch = user_data;
> int res;
> SPICE_DEBUG("%s ch %p, %d bytes", __FUNCTION__, ch, count);
> +
> + // handle first packet (HELLO) creating parser from capabilities
> + if (SPICE_UNLIKELY(ch->parser == NULL)) {
> + // Here we return 0 from this function to keep the packet in
> + // the queue. The packet will then be sent to the guest.
> + // We are initializing SpiceUsbBackendChannel, the
> + // SpiceUsbredirChannel is not ready to receive packets.
> +
> + // we are still initializing the host
> + if (ch->usbredirhost == NULL) {
> + return 0;
> + }
> +
> + ch->parser = create_parser(ch);
> + if (!ch->parser) {
> + return 0;
> + }
> +
> + /* hello is short header (12) + hello struct (64) */
> + const int hello_size = 12 + sizeof(struct usb_redir_hello_header);
> + g_assert(count >= hello_size + 4);
> + g_assert(SPICE_ALIGNED_CAST(struct usb_redir_header *, data)->type
> == usb_redir_hello);
> +
> + const uint32_t flags =
> + usbredirparser_fl_write_cb_owns_buffer |
> usbredirparser_fl_usb_host |
> + usbredirparser_fl_no_hello;
> +
> + usbredirparser_init(ch->parser,
> + PACKAGE_STRING,
> + SPICE_ALIGNED_CAST(uint32_t *, data +
> hello_size),
> + (count - hello_size) / sizeof(uint32_t),
> + flags);
> +
> + return 0;
> + }
> res = spice_usbredir_write(ch->usbredir_channel, data, count);
> return res;
> }
> @@ -701,6 +740,165 @@ GError *spice_usb_backend_get_error_details(int
> error_code, gchar *desc)
> return err;
> }
>
> +static void
> +usbredir_control_packet(void *priv, uint64_t id, struct
> usb_redir_control_packet_header *h,
> + uint8_t *data, int data_len)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void
> +usbredir_bulk_packet(void *priv, uint64_t id, struct
> usb_redir_bulk_packet_header *h,
> + uint8_t *data, int data_len)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void usbredir_device_reset(void *priv)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void
> +usbredir_interface_info(void *priv, struct usb_redir_interface_info_header
> *interface_info)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void
> +usbredir_interface_ep_info(void *priv, struct usb_redir_ep_info_header
> *ep_info)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void
> +usbredir_set_configuration(void *priv, uint64_t id,
> + struct usb_redir_set_configuration_header
> *set_configuration)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void usbredir_get_configuration(void *priv, uint64_t id)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void
> +usbredir_set_alt_setting(void *priv, uint64_t id, struct
> usb_redir_set_alt_setting_header *s)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void
> +usbredir_get_alt_setting(void *priv, uint64_t id, struct
> usb_redir_get_alt_setting_header *s)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void usbredir_cancel_data(void *priv, uint64_t id)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void usbredir_filter_reject(void *priv)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +/* Note that the ownership of the rules array is passed on to the callback.
> */
> +static void
> +usbredir_filter_filter(void *priv, struct usbredirfilter_rule *r, int count)
> +{
> + SpiceUsbBackendChannel *ch = priv;
> + SPICE_DEBUG("%s ch %p %d filters", __FUNCTION__, ch, count);
> +
> + free(ch->rules);
> + ch->rules = r;
> + ch->rules_count = count;
> + if (count) {
> + int i;
> + for (i = 0; i < count; i++) {
> + SPICE_DEBUG("%s class %d, %X:%X",
> + r[i].allow ? "allowed" : "denied", r[i].device_class,
> + (uint32_t)r[i].vendor_id, (uint32_t)r[i].product_id);
> + }
> + }
> +}
> +
> +static void usbredir_device_disconnect_ack(void *priv)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void
> +usbredir_hello(void *priv, struct usb_redir_hello_header *hello)
> +{
> + USBREDIR_CALLBACK_NOT_IMPLEMENTED();
> +}
> +
> +static void initialize_parser(SpiceUsbBackendChannel *ch)
> +{
> + uint32_t flags, caps[USB_REDIR_CAPS_SIZE] = { 0 };
> +
> + g_assert(ch->usbredirhost == NULL);
> +
> + flags = usbredirparser_fl_write_cb_owns_buffer |
> usbredirparser_fl_usb_host;
> +
> + usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
> + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
> + usbredirparser_caps_set_cap(caps, usb_redir_cap_device_disconnect_ack);
> + usbredirparser_caps_set_cap(caps,
> usb_redir_cap_ep_info_max_packet_size);
> + usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
> + usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
> + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
> + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
> +
> + usbredirparser_init(ch->parser, PACKAGE_STRING, caps,
> USB_REDIR_CAPS_SIZE, flags);
> +}
> +
> +/*
> + We can initialize the usbredirparser with HELLO enabled only in case
> + the libusb is not active and the usbredirhost does not function.
> + Then the parser sends session HELLO and receives server's response.
> + Otherwise (usbredirparser initialized with HELLO disabled):
> + - the usbredirhost sends session HELLO
> + - we look into it to know set of capabilities we shall initialize
> + the parser with
> + - when we receive server's response to HELLO we provide it also to
> + parser to let it synchronize with server's capabilities
> +*/
> +static struct usbredirparser *create_parser(SpiceUsbBackendChannel *ch)
> +{
> + struct usbredirparser *parser = usbredirparser_create();
> +
> + g_return_val_if_fail(parser != NULL, NULL);
> +
> + parser->priv = ch;
> + parser->log_func = usbredir_log;
> + parser->read_func = usbredir_read_callback;
> + parser->write_func = usbredir_write_callback;
> + parser->reset_func = usbredir_device_reset;
> + parser->set_configuration_func = usbredir_set_configuration;
> + parser->get_configuration_func = usbredir_get_configuration;
> + parser->set_alt_setting_func = usbredir_set_alt_setting;
> + parser->get_alt_setting_func = usbredir_get_alt_setting;
> + parser->cancel_data_packet_func = usbredir_cancel_data;
> + parser->control_packet_func = usbredir_control_packet;
> + parser->bulk_packet_func = usbredir_bulk_packet;
> + parser->alloc_lock_func = usbredir_alloc_lock;
> + parser->lock_func = usbredir_lock_lock;
> + parser->unlock_func = usbredir_unlock_lock;
> + parser->free_lock_func = usbredir_free_lock;
> + parser->hello_func = usbredir_hello;
> + parser->filter_reject_func = usbredir_filter_reject;
> + parser->device_disconnect_ack_func = usbredir_device_disconnect_ack;
> + parser->interface_info_func = usbredir_interface_info;
> + parser->ep_info_func = usbredir_interface_ep_info;
> + parser->filter_filter_func = usbredir_filter_filter;
> +
> + return parser;
> +}
> +
> void spice_usb_backend_return_write_data(SpiceUsbBackendChannel *ch, void
> *data)
> {
> if (ch->usbredirhost) {
> @@ -799,11 +997,22 @@ spice_usb_backend_channel_new(SpiceUsbBackend *be,
> spice_util_get_debug() ? usbredirparser_debug :
> usbredirparser_warning,
> usbredirhost_fl_write_cb_owns_buffer);
> g_warn_if_fail(ch->usbredirhost != NULL);
> - }
> - if (ch->usbredirhost) {
> - usbredirhost_set_buffered_output_size_cb(ch->usbredirhost,
> usbredir_buffered_output_size_callback);
> + if (ch->usbredirhost) {
> + usbredirhost_set_buffered_output_size_cb(ch->usbredirhost,
> usbredir_buffered_output_size_callback);
> + // force flush of HELLO packet and creation of parser
> + usbredirhost_write_guest_data(ch->usbredirhost);
> + }
> } else {
> - g_free(ch);
> + // no physical device support, only emulated, create the
> + // parser
> + ch->parser = create_parser(ch);
> + if (ch->parser != NULL) {
> + initialize_parser(ch);
> + }
> + }
> +
> + if (!ch->parser) {
> + spice_usb_backend_channel_delete(ch);
> ch = NULL;
> }
>
> @@ -828,9 +1037,13 @@ void
> spice_usb_backend_channel_delete(SpiceUsbBackendChannel *ch)
> if (ch->usbredirhost) {
> usbredirhost_close(ch->usbredirhost);
> }
> + if (ch->parser) {
> + usbredirparser_destroy(ch->parser);
> + }
>
> if (ch->rules) {
> - g_free(ch->rules);
> + /* rules were allocated by usbredirparser */
> + free(ch->rules);
> }
>
> g_free(ch);
Fine for me, I would wait Yuri opinion (on merging my changes and
split this patch, same comment for next patch).
Frediano
More information about the Spice-devel
mailing list