> > From: Yuri Benditovich <yuri.benditovich@xxxxxxxxxx> > > 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@xxxxxxxxxx> > Signed-off-by: Victor Toso <victortoso@xxxxxxxxxx> 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel