Blame usbredirhost/usbredirhost.c

Packit 9795e1
/* usbredirhost.c usb network redirection usb host code.
Packit 9795e1
Packit 9795e1
   Copyright 2010-2012 Red Hat, Inc.
Packit 9795e1
Packit 9795e1
   Red Hat Authors:
Packit 9795e1
   Hans de Goede <hdegoede@redhat.com>
Packit 9795e1
Packit 9795e1
   This library is free software; you can redistribute it and/or
Packit 9795e1
   modify it under the terms of the GNU Lesser General Public
Packit 9795e1
   License as published by the Free Software Foundation; either
Packit 9795e1
   version 2.1 of the License, or (at your option) any later version.
Packit 9795e1
Packit 9795e1
   This library is distributed in the hope that it will be useful,
Packit 9795e1
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 9795e1
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 9795e1
   Lesser General Public License for more details.
Packit 9795e1
Packit 9795e1
   You should have received a copy of the GNU Lesser General Public
Packit 9795e1
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit 9795e1
*/
Packit 9795e1
#include "config.h"
Packit 9795e1
Packit 9795e1
#include <stdio.h>
Packit 9795e1
#include <stdlib.h>
Packit 9795e1
#include <stdarg.h>
Packit 9795e1
#include <stdbool.h>
Packit 9795e1
#include <string.h>
Packit 9795e1
#include <errno.h>
Packit 9795e1
#include <unistd.h>
Packit 9795e1
#include <inttypes.h>
Packit 9795e1
#include "usbredirhost.h"
Packit 9795e1
Packit 9795e1
#define MAX_ENDPOINTS        32
Packit 9795e1
#define MAX_INTERFACES       32 /* Max 32 endpoints and thus interfaces */
Packit 9795e1
#define CTRL_TIMEOUT       5000 /* USB specifies a 5 second max timeout */
Packit 9795e1
#define BULK_TIMEOUT          0 /* No timeout for bulk transfers */
Packit 9795e1
#define ISO_TIMEOUT        1000
Packit 9795e1
#define INTERRUPT_TIMEOUT     0 /* No timeout for interrupt transfers */
Packit 9795e1
Packit 9795e1
#define MAX_TRANSFER_COUNT        16
Packit 9795e1
#define MAX_PACKETS_PER_TRANSFER  32
Packit 9795e1
#define INTERRUPT_TRANSFER_COUNT   5
Packit 9795e1
/* Special packet_idx value indicating a submitted transfer */
Packit 9795e1
#define SUBMITTED_IDX             -1
Packit 9795e1
Packit 9795e1
/* quirk flags */
Packit 9795e1
#define QUIRK_DO_NOT_RESET    0x01
Packit 9795e1
Packit 9795e1
/* Macros to go from an endpoint address to an index for our ep array */
Packit 9795e1
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
Packit 9795e1
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
Packit 9795e1
Packit 9795e1
/* Locking convenience macros */
Packit 9795e1
#define LOCK(host) \
Packit 9795e1
    do { \
Packit 9795e1
        if ((host)->lock) \
Packit 9795e1
            (host)->parser->lock_func((host)->lock); \
Packit 9795e1
    } while (0)
Packit 9795e1
Packit 9795e1
#define UNLOCK(host) \
Packit 9795e1
    do { \
Packit 9795e1
        if ((host)->lock) \
Packit 9795e1
            (host)->parser->unlock_func((host)->lock); \
Packit 9795e1
    } while (0)
Packit 9795e1
Packit 9795e1
#define FLUSH(host) \
Packit 9795e1
    do { \
Packit 9795e1
        if ((host)->flush_writes_func) \
Packit 9795e1
            (host)->flush_writes_func((host)->func_priv); \
Packit 9795e1
    } while (0)
Packit 9795e1
Packit 9795e1
struct usbredirtransfer {
Packit 9795e1
    struct usbredirhost *host;        /* Back pointer to the the redirhost */
Packit 9795e1
    struct libusb_transfer *transfer; /* Back pointer to the libusb transfer */
Packit 9795e1
    uint64_t id;
Packit 9795e1
    uint8_t cancelled;
Packit 9795e1
    int packet_idx;
Packit 9795e1
    union {
Packit 9795e1
        struct usb_redir_control_packet_header control_packet;
Packit 9795e1
        struct usb_redir_bulk_packet_header bulk_packet;
Packit 9795e1
        struct usb_redir_iso_packet_header iso_packet;
Packit 9795e1
        struct usb_redir_interrupt_packet_header interrupt_packet;
Packit 9795e1
    };
Packit 9795e1
    struct usbredirtransfer *next;
Packit 9795e1
    struct usbredirtransfer *prev;
Packit 9795e1
};
Packit 9795e1
Packit 9795e1
struct usbredirhost_ep {
Packit 9795e1
    uint8_t type;
Packit 9795e1
    uint8_t interval;
Packit 9795e1
    uint8_t interface;
Packit 9795e1
    uint8_t warn_on_drop;
Packit 9795e1
    uint8_t stream_started;
Packit 9795e1
    uint8_t pkts_per_transfer;
Packit 9795e1
    uint8_t transfer_count;
Packit 9795e1
    int out_idx;
Packit 9795e1
    int drop_packets;
Packit 9795e1
    int max_packetsize;
Packit 9795e1
    unsigned int max_streams;
Packit 9795e1
    struct usbredirtransfer *transfer[MAX_TRANSFER_COUNT];
Packit 9795e1
};
Packit 9795e1
Packit 9795e1
struct usbredirhost {
Packit 9795e1
    struct usbredirparser *parser;
Packit 9795e1
Packit 9795e1
    void *lock;
Packit 9795e1
    void *disconnect_lock;
Packit 9795e1
Packit 9795e1
    usbredirparser_log log_func;
Packit 9795e1
    usbredirparser_read read_func;
Packit 9795e1
    usbredirparser_write write_func;
Packit 9795e1
    usbredirhost_flush_writes flush_writes_func;
Packit 9795e1
    usbredirhost_buffered_output_size buffered_output_size_func;
Packit 9795e1
    void *func_priv;
Packit 9795e1
    int verbose;
Packit 9795e1
    libusb_context *ctx;
Packit 9795e1
    libusb_device *dev;
Packit 9795e1
    libusb_device_handle *handle;
Packit 9795e1
    struct libusb_device_descriptor desc;
Packit 9795e1
    struct libusb_config_descriptor *config;
Packit 9795e1
    int quirks;
Packit 9795e1
    int restore_config;
Packit 9795e1
    int claimed;
Packit 9795e1
    int reset;
Packit 9795e1
    int disconnected;
Packit 9795e1
    int read_status;
Packit 9795e1
    int cancels_pending;
Packit 9795e1
    int wait_disconnect;
Packit 9795e1
    int connect_pending;
Packit 9795e1
    struct usbredirhost_ep endpoint[MAX_ENDPOINTS];
Packit 9795e1
    uint8_t alt_setting[MAX_INTERFACES];
Packit 9795e1
    struct usbredirtransfer transfers_head;
Packit 9795e1
    struct usbredirfilter_rule *filter_rules;
Packit 9795e1
    int filter_rules_count;
Packit 9795e1
    struct {
Packit 9795e1
        uint64_t higher;
Packit 9795e1
        uint64_t lower;
Packit 9795e1
        bool dropping;
Packit 9795e1
    } iso_threshold;
Packit 9795e1
};
Packit 9795e1
Packit 9795e1
struct usbredirhost_dev_ids {
Packit 9795e1
    int vendor_id;
Packit 9795e1
    int product_id;
Packit 9795e1
};
Packit 9795e1
Packit 9795e1
static const struct usbredirhost_dev_ids usbredirhost_reset_blacklist[] = {
Packit 9795e1
    { 0x1210, 0x001c },
Packit 9795e1
    { 0x2798, 0x0001 },
Packit 9795e1
    { -1, -1 } /* Terminating Entry */
Packit 9795e1
};
Packit 9795e1
Packit 9795e1
static void
Packit 9795e1
#if defined __GNUC__
Packit 9795e1
__attribute__((format(printf, 3, 4)))
Packit 9795e1
#endif
Packit 9795e1
va_log(struct usbredirhost *host, int level, const char *fmt, ...)
Packit 9795e1
{
Packit 9795e1
    char buf[512];
Packit 9795e1
    va_list ap;
Packit 9795e1
    int n;
Packit 9795e1
Packit 9795e1
    if (level > host->verbose) {
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    n = sprintf(buf, "usbredirhost: ");
Packit 9795e1
    va_start(ap, fmt);
Packit 9795e1
    vsnprintf(buf + n, sizeof(buf) - n, fmt, ap);
Packit 9795e1
    va_end(ap);
Packit 9795e1
Packit 9795e1
    host->log_func(host->func_priv, level, buf);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
#ifdef ERROR /* defined on WIN32 */
Packit 9795e1
#undef ERROR
Packit 9795e1
#endif
Packit 9795e1
#define ERROR(...)   va_log(host, usbredirparser_error, __VA_ARGS__)
Packit 9795e1
#define WARNING(...) va_log(host, usbredirparser_warning, __VA_ARGS__)
Packit 9795e1
#define INFO(...)    va_log(host, usbredirparser_info, __VA_ARGS__)
Packit 9795e1
#define DEBUG(...)   va_log(host, usbredirparser_debug, __VA_ARGS__)
Packit 9795e1
Packit 9795e1
static void usbredirhost_hello(void *priv, struct usb_redir_hello_header *h);
Packit 9795e1
static void usbredirhost_reset(void *priv);
Packit 9795e1
static void usbredirhost_set_configuration(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_set_configuration_header *set_configuration);
Packit 9795e1
static void usbredirhost_get_configuration(void *priv, uint64_t id);
Packit 9795e1
static void usbredirhost_set_alt_setting(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_set_alt_setting_header *set_alt_setting);
Packit 9795e1
static void usbredirhost_get_alt_setting(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_get_alt_setting_header *get_alt_setting);
Packit 9795e1
static void usbredirhost_start_iso_stream(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_start_iso_stream_header *start_iso_stream);
Packit 9795e1
static void usbredirhost_stop_iso_stream(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_stop_iso_stream_header *stop_iso_stream);
Packit 9795e1
static void usbredirhost_start_interrupt_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_start_interrupt_receiving_header *start_interrupt_receiving);
Packit 9795e1
static void usbredirhost_stop_interrupt_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_stop_interrupt_receiving_header *stop_interrupt_receiving);
Packit 9795e1
static void usbredirhost_alloc_bulk_streams(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_alloc_bulk_streams_header *alloc_bulk_streams);
Packit 9795e1
static void usbredirhost_free_bulk_streams(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_free_bulk_streams_header *free_bulk_streams);
Packit 9795e1
static void usbredirhost_cancel_data_packet(void *priv, uint64_t id);
Packit 9795e1
static void usbredirhost_filter_reject(void *priv);
Packit 9795e1
static void usbredirhost_filter_filter(void *priv,
Packit 9795e1
    struct usbredirfilter_rule *rules, int rules_count);
Packit 9795e1
static void usbredirhost_device_disconnect_ack(void *priv);
Packit 9795e1
static void usbredirhost_start_bulk_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_start_bulk_receiving_header *start_bulk_receiving);
Packit 9795e1
static void usbredirhost_stop_bulk_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_stop_bulk_receiving_header *stop_bulk_receiving);
Packit 9795e1
static void usbredirhost_control_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_control_packet_header *control_packet,
Packit 9795e1
    uint8_t *data, int data_len);
Packit 9795e1
static void usbredirhost_bulk_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_bulk_packet_header *bulk_packet,
Packit 9795e1
    uint8_t *data, int data_len);
Packit 9795e1
static void usbredirhost_iso_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_iso_packet_header *iso_packet,
Packit 9795e1
    uint8_t *data, int data_len);
Packit 9795e1
static void usbredirhost_interrupt_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_interrupt_packet_header *interrupt_packet,
Packit 9795e1
    uint8_t *data, int data_len);
Packit 9795e1
Packit 9795e1
static void LIBUSB_CALL usbredirhost_iso_packet_complete(
Packit 9795e1
    struct libusb_transfer *libusb_transfer);
Packit 9795e1
static void LIBUSB_CALL usbredirhost_buffered_packet_complete(
Packit 9795e1
    struct libusb_transfer *libusb_transfer);
Packit 9795e1
static int usbredirhost_cancel_pending_urbs(struct usbredirhost *host,
Packit 9795e1
                                            int notify_guest);
Packit 9795e1
static void usbredirhost_wait_for_cancel_completion(struct usbredirhost *host);
Packit 9795e1
static void usbredirhost_clear_device(struct usbredirhost *host);
Packit 9795e1
Packit 9795e1
static void usbredirhost_log(void *priv, int level, const char *msg)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
Packit 9795e1
    host->log_func(host->func_priv, level, msg);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static int usbredirhost_read(void *priv, uint8_t *data, int count)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
Packit 9795e1
    if (host->read_status) {
Packit 9795e1
        int ret = host->read_status;
Packit 9795e1
        host->read_status = 0;
Packit 9795e1
        return ret;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    return host->read_func(host->func_priv, data, count);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static int usbredirhost_write(void *priv, uint8_t *data, int count)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
Packit 9795e1
    return host->write_func(host->func_priv, data, count);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Can be called both from parser read callbacks as well as from libusb
Packit 9795e1
   packet completion callbacks */
Packit 9795e1
static void usbredirhost_handle_disconnect(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    /* Disconnect uses its own lock to avoid needing nesting capable locks */
Packit 9795e1
    if (host->disconnect_lock) {
Packit 9795e1
        host->parser->lock_func(host->disconnect_lock);
Packit 9795e1
    }
Packit 9795e1
    if (!host->disconnected) {
Packit 9795e1
        INFO("device disconnected");
Packit 9795e1
        usbredirparser_send_device_disconnect(host->parser);
Packit 9795e1
        if (usbredirparser_peer_has_cap(host->parser,
Packit 9795e1
                                        usb_redir_cap_device_disconnect_ack))
Packit 9795e1
            host->wait_disconnect = 1;
Packit 9795e1
        host->disconnected = 1;
Packit 9795e1
    }
Packit 9795e1
    if (host->disconnect_lock) {
Packit 9795e1
        host->parser->unlock_func(host->disconnect_lock);
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* One function to convert either a transfer status code, or a libusb error
Packit 9795e1
   code to a usb_redir status. We handle both in one conversion function so
Packit 9795e1
   that we can pass error codes as status codes to the completion handler
Packit 9795e1
   in case of submission error (the codes don't overlap), using the completion
Packit 9795e1
   handler to report back the status and cleanup as it would on completion of
Packit 9795e1
   a successfully submitted transfer. */
Packit 9795e1
static int libusb_status_or_error_to_redir_status(struct usbredirhost *host,
Packit 9795e1
                                                  int status)
Packit 9795e1
{
Packit 9795e1
    switch (status) {
Packit 9795e1
        case LIBUSB_TRANSFER_COMPLETED:
Packit 9795e1
            return usb_redir_success;
Packit 9795e1
        case LIBUSB_TRANSFER_ERROR:
Packit 9795e1
            return usb_redir_ioerror;
Packit 9795e1
        case LIBUSB_TRANSFER_TIMED_OUT:
Packit 9795e1
            return usb_redir_timeout;
Packit 9795e1
        case LIBUSB_TRANSFER_CANCELLED:
Packit 9795e1
            return usb_redir_cancelled;
Packit 9795e1
        case LIBUSB_TRANSFER_STALL:
Packit 9795e1
            return usb_redir_stall;
Packit 9795e1
        case LIBUSB_TRANSFER_NO_DEVICE:
Packit 9795e1
            usbredirhost_handle_disconnect(host);
Packit 9795e1
            return usb_redir_ioerror;
Packit 9795e1
        case LIBUSB_TRANSFER_OVERFLOW:
Packit 9795e1
            return usb_redir_babble;
Packit 9795e1
Packit 9795e1
        case LIBUSB_ERROR_INVALID_PARAM:
Packit 9795e1
            return usb_redir_inval;
Packit 9795e1
        case LIBUSB_ERROR_NO_DEVICE:
Packit 9795e1
            usbredirhost_handle_disconnect(host);
Packit 9795e1
            return usb_redir_ioerror;
Packit 9795e1
        case LIBUSB_ERROR_TIMEOUT:
Packit 9795e1
            return usb_redir_timeout;
Packit 9795e1
        default:
Packit 9795e1
            return usb_redir_ioerror;
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_set_max_packetsize(struct usbredirhost *host,
Packit 9795e1
    uint8_t ep, uint16_t wMaxPacketSize)
Packit 9795e1
{
Packit 9795e1
    int maxp, mult = 1;
Packit 9795e1
Packit 9795e1
    maxp = wMaxPacketSize & 0x7ff;
Packit 9795e1
Packit 9795e1
    if (libusb_get_device_speed(host->dev) == LIBUSB_SPEED_HIGH &&
Packit 9795e1
             host->endpoint[EP2I(ep)].type == usb_redir_type_iso) {
Packit 9795e1
        switch ((wMaxPacketSize >> 11) & 3) {
Packit 9795e1
        case 1:  mult = 2; break;
Packit 9795e1
        case 2:  mult = 3; break;
Packit 9795e1
        default: mult = 1; break;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->endpoint[EP2I(ep)].max_packetsize = maxp * mult;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_set_max_streams(struct usbredirhost *host,
Packit 9795e1
    const struct libusb_endpoint_descriptor *endp)
Packit 9795e1
{
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000102
Packit 9795e1
    struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
Packit 9795e1
    int max_streams, i = EP2I(endp->bEndpointAddress);
Packit 9795e1
Packit 9795e1
    host->endpoint[i].max_streams = 0;
Packit 9795e1
Packit 9795e1
    if (host->endpoint[i].type == usb_redir_type_bulk &&
Packit 9795e1
            libusb_get_ss_endpoint_companion_descriptor(host->ctx, endp,
Packit 9795e1
                &endp_ss_comp) == LIBUSB_SUCCESS) {
Packit 9795e1
        max_streams = endp_ss_comp->bmAttributes & 0x1f;
Packit 9795e1
        if (max_streams)
Packit 9795e1
            host->endpoint[i].max_streams = 1 << max_streams;
Packit 9795e1
        libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp);
Packit 9795e1
    }
Packit 9795e1
#endif
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from open/close and parser read callbacks */
Packit 9795e1
static void usbredirhost_send_interface_n_ep_info(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    int i;
Packit 9795e1
    const struct libusb_interface_descriptor *intf_desc;
Packit 9795e1
    struct usb_redir_ep_info_header ep_info;
Packit 9795e1
    struct usb_redir_interface_info_header interface_info = { 0, };
Packit 9795e1
Packit 9795e1
    if (host->config)
Packit 9795e1
        interface_info.interface_count = host->config->bNumInterfaces;
Packit 9795e1
Packit 9795e1
    for (i = 0; i < interface_info.interface_count; i++) {
Packit 9795e1
        intf_desc =
Packit 9795e1
            &host->config->interface[i].altsetting[host->alt_setting[i]];
Packit 9795e1
Packit 9795e1
        interface_info.interface[i] = intf_desc->bInterfaceNumber;
Packit 9795e1
        interface_info.interface_class[i] = intf_desc->bInterfaceClass;
Packit 9795e1
        interface_info.interface_subclass[i] = intf_desc->bInterfaceSubClass;
Packit 9795e1
        interface_info.interface_protocol[i] = intf_desc->bInterfaceProtocol;
Packit 9795e1
    }
Packit 9795e1
    usbredirparser_send_interface_info(host->parser, &interface_info);
Packit 9795e1
Packit 9795e1
    for (i = 0; i < MAX_ENDPOINTS; i++) {
Packit 9795e1
        ep_info.type[i] = host->endpoint[i].type;
Packit 9795e1
        ep_info.interval[i] = host->endpoint[i].interval;
Packit 9795e1
        ep_info.interface[i] = host->endpoint[i].interface;
Packit 9795e1
        ep_info.max_packet_size[i] = host->endpoint[i].max_packetsize;
Packit 9795e1
        ep_info.max_streams[i] = host->endpoint[i].max_streams;
Packit 9795e1
    }
Packit 9795e1
    usbredirparser_send_ep_info(host->parser, &ep_info);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from open/close and parser read callbacks */
Packit 9795e1
static void usbredirhost_send_device_connect(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    struct usb_redir_device_connect_header device_connect;
Packit 9795e1
    enum libusb_speed speed;
Packit 9795e1
Packit 9795e1
    if (!host->disconnected) {
Packit 9795e1
        ERROR("internal error sending device_connect but already connected");
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (!usbredirparser_have_peer_caps(host->parser) ||
Packit 9795e1
            host->wait_disconnect) {
Packit 9795e1
        host->connect_pending = 1;
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    speed = libusb_get_device_speed(host->dev);
Packit 9795e1
    switch (speed) {
Packit 9795e1
    case LIBUSB_SPEED_LOW:
Packit 9795e1
        device_connect.speed = usb_redir_speed_low; break;
Packit 9795e1
    case LIBUSB_SPEED_FULL:
Packit 9795e1
        device_connect.speed = usb_redir_speed_full; break;
Packit 9795e1
    case LIBUSB_SPEED_HIGH:
Packit 9795e1
        device_connect.speed = usb_redir_speed_high; break;
Packit 9795e1
    case LIBUSB_SPEED_SUPER:
Packit 9795e1
        device_connect.speed = usb_redir_speed_super; break;
Packit 9795e1
    default:
Packit 9795e1
        device_connect.speed = usb_redir_speed_unknown;
Packit 9795e1
    }
Packit 9795e1
    device_connect.device_class = host->desc.bDeviceClass;
Packit 9795e1
    device_connect.device_subclass = host->desc.bDeviceSubClass;
Packit 9795e1
    device_connect.device_protocol = host->desc.bDeviceProtocol;
Packit 9795e1
    device_connect.vendor_id = host->desc.idVendor;
Packit 9795e1
    device_connect.product_id = host->desc.idProduct;
Packit 9795e1
    device_connect.device_version_bcd = host->desc.bcdDevice;
Packit 9795e1
Packit 9795e1
    usbredirhost_send_interface_n_ep_info(host);
Packit 9795e1
    usbredirparser_send_device_connect(host->parser, &device_connect);
Packit 9795e1
    host->connect_pending = 0;
Packit 9795e1
    host->disconnected = 0; /* The guest may now use the device */
Packit 9795e1
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from open/close and parser read callbacks */
Packit 9795e1
static void usbredirhost_parse_interface(struct usbredirhost *host, int i)
Packit 9795e1
{
Packit 9795e1
    int j;
Packit 9795e1
    const struct libusb_interface_descriptor *intf_desc;
Packit 9795e1
    uint8_t ep_address;
Packit 9795e1
Packit 9795e1
    intf_desc =
Packit 9795e1
        &host->config->interface[i].altsetting[host->alt_setting[i]];
Packit 9795e1
Packit 9795e1
    for (j = 0; j < intf_desc->bNumEndpoints; j++) {
Packit 9795e1
        ep_address = intf_desc->endpoint[j].bEndpointAddress;
Packit 9795e1
        host->endpoint[EP2I(ep_address)].type =
Packit 9795e1
            intf_desc->endpoint[j].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK;
Packit 9795e1
        host->endpoint[EP2I(ep_address)].interval =
Packit 9795e1
            intf_desc->endpoint[j].bInterval;
Packit 9795e1
        host->endpoint[EP2I(ep_address)].interface =
Packit 9795e1
            intf_desc->bInterfaceNumber;
Packit 9795e1
        usbredirhost_set_max_packetsize(host, ep_address,
Packit 9795e1
                                        intf_desc->endpoint[j].wMaxPacketSize);
Packit 9795e1
        usbredirhost_set_max_streams(host, &intf_desc->endpoint[j]);
Packit 9795e1
        host->endpoint[EP2I(ep_address)].warn_on_drop = 1;
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_parse_config(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    int i;
Packit 9795e1
Packit 9795e1
    for (i = 0; i < MAX_ENDPOINTS; i++) {
Packit 9795e1
        if ((i & 0x0f) == 0) {
Packit 9795e1
            host->endpoint[i].type = usb_redir_type_control;
Packit 9795e1
        } else {
Packit 9795e1
            host->endpoint[i].type = usb_redir_type_invalid;
Packit 9795e1
        }
Packit 9795e1
        host->endpoint[i].interval = 0;
Packit 9795e1
        host->endpoint[i].interface = 0;
Packit 9795e1
        host->endpoint[i].max_packetsize = 0;
Packit 9795e1
        host->endpoint[i].max_streams = 0;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    for (i = 0; host->config && i < host->config->bNumInterfaces; i++) {
Packit 9795e1
        usbredirhost_parse_interface(host, i);
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from open/close and parser read callbacks */
Packit 9795e1
static int usbredirhost_claim(struct usbredirhost *host, int initial_claim)
Packit 9795e1
{
Packit 9795e1
    int i, n, r;
Packit 9795e1
Packit 9795e1
    if (host->config) {
Packit 9795e1
        libusb_free_config_descriptor(host->config);
Packit 9795e1
        host->config = NULL;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    r = libusb_get_device_descriptor(host->dev, &host->desc);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        ERROR("could not get device descriptor: %s", libusb_error_name(r));
Packit 9795e1
        return libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    r = libusb_get_active_config_descriptor(host->dev, &host->config);
Packit 9795e1
    if (r < 0 && r != LIBUSB_ERROR_NOT_FOUND) {
Packit 9795e1
        ERROR("could not get descriptors for active configuration: %s",
Packit 9795e1
              libusb_error_name(r));
Packit 9795e1
        return libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
    }
Packit 9795e1
    if (host->config && host->config->bNumInterfaces > MAX_INTERFACES) {
Packit 9795e1
        ERROR("usb decriptor has too much intefaces (%d > %d)",
Packit 9795e1
              (int)host->config->bNumInterfaces, MAX_INTERFACES);
Packit 9795e1
        return usb_redir_ioerror;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (initial_claim) {
Packit 9795e1
        if (host->config)
Packit 9795e1
            host->restore_config = host->config->bConfigurationValue;
Packit 9795e1
        else
Packit 9795e1
            host->restore_config = -1; /* unconfigured */
Packit 9795e1
Packit 9795e1
        /* If the device is unconfigured and has only 1 config, we assume
Packit 9795e1
           this is the result of the user doing "safely remove hardware",
Packit 9795e1
           and we try to reset the device configuration to this config when
Packit 9795e1
           we release the device, so that it becomes usable again. */
Packit 9795e1
        if (host->restore_config == -1 && host->desc.bNumConfigurations == 1) {
Packit 9795e1
            struct libusb_config_descriptor *config;
Packit 9795e1
Packit 9795e1
            r = libusb_get_config_descriptor(host->dev, 0, &config);
Packit 9795e1
            if (r == 0) {
Packit 9795e1
                host->restore_config = config->bConfigurationValue;
Packit 9795e1
                libusb_free_config_descriptor(config);
Packit 9795e1
            }
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* All interfaces begin at alt setting 0 when (re)claimed */
Packit 9795e1
    memset(host->alt_setting, 0, MAX_INTERFACES);
Packit 9795e1
Packit 9795e1
    host->claimed = 1;
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000102
Packit 9795e1
    libusb_set_auto_detach_kernel_driver(host->handle, 1);
Packit 9795e1
#endif
Packit 9795e1
    for (i = 0; host->config && i < host->config->bNumInterfaces; i++) {
Packit 9795e1
        n = host->config->interface[i].altsetting[0].bInterfaceNumber;
Packit 9795e1
Packit 9795e1
#if LIBUSBX_API_VERSION < 0x01000102
Packit 9795e1
        r = libusb_detach_kernel_driver(host->handle, n);
Packit 9795e1
        if (r < 0 && r != LIBUSB_ERROR_NOT_FOUND
Packit 9795e1
                  && r != LIBUSB_ERROR_NOT_SUPPORTED) {
Packit 9795e1
            ERROR("could not detach driver from interface %d (configuration %d): %s",
Packit 9795e1
                  n, host->config->bConfigurationValue, libusb_error_name(r));
Packit 9795e1
            return libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
        }
Packit 9795e1
#endif
Packit 9795e1
Packit 9795e1
        r = libusb_claim_interface(host->handle, n);
Packit 9795e1
        if (r < 0) {
Packit 9795e1
            if (r == LIBUSB_ERROR_BUSY)
Packit 9795e1
                ERROR("Device is in use by another application");
Packit 9795e1
            else
Packit 9795e1
                ERROR("could not claim interface %d (configuration %d): %s",
Packit 9795e1
                      n, host->config->bConfigurationValue,
Packit 9795e1
                      libusb_error_name(r));
Packit 9795e1
            return libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_parse_config(host);
Packit 9795e1
    return usb_redir_success;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from open/close and parser read callbacks */
Packit 9795e1
static void usbredirhost_release(struct usbredirhost *host, int attach_drivers)
Packit 9795e1
{
Packit 9795e1
    int i, n, r, current_config = -1;
Packit 9795e1
Packit 9795e1
    if (!host->claimed)
Packit 9795e1
        return;
Packit 9795e1
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000102
Packit 9795e1
    /* We want to always do the attach ourselves because:
Packit 9795e1
       1) For compound interfaces such as usb-audio we must first release all
Packit 9795e1
          interfaces before we can attach the driver;
Packit 9795e1
       2) When releasing interfaces before calling libusb_set_configuration,
Packit 9795e1
          we don't want the kernel driver to get attached (our attach_drivers
Packit 9795e1
          parameter is 0 in this case). */
Packit 9795e1
    libusb_set_auto_detach_kernel_driver(host->handle, 0);
Packit 9795e1
#endif
Packit 9795e1
Packit 9795e1
    for (i = 0; host->config && i < host->config->bNumInterfaces; i++) {
Packit 9795e1
        n = host->config->interface[i].altsetting[0].bInterfaceNumber;
Packit 9795e1
Packit 9795e1
        r = libusb_release_interface(host->handle, n);
Packit 9795e1
        if (r < 0 && r != LIBUSB_ERROR_NOT_FOUND
Packit 9795e1
                  && r != LIBUSB_ERROR_NO_DEVICE) {
Packit 9795e1
            ERROR("could not release interface %d (configuration %d): %s",
Packit 9795e1
                  n, host->config->bConfigurationValue, libusb_error_name(r));
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (!attach_drivers)
Packit 9795e1
        return;
Packit 9795e1
Packit 9795e1
    host->claimed = 0;
Packit 9795e1
Packit 9795e1
    /* reset the device before re-binding the kernel drivers, so that the
Packit 9795e1
       kernel drivers get the device in a clean state. */
Packit 9795e1
    if (!(host->quirks & QUIRK_DO_NOT_RESET)) {
Packit 9795e1
        r = libusb_reset_device(host->handle);
Packit 9795e1
        if (r != 0) {
Packit 9795e1
            /* if we're releasing the device because it was removed, resetting
Packit 9795e1
             * will fail. Don't print a warning in this situation */
Packit 9795e1
            if (r != LIBUSB_ERROR_NO_DEVICE) {
Packit 9795e1
                ERROR("error resetting device: %s", libusb_error_name(r));
Packit 9795e1
            }
Packit 9795e1
            return;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->config)
Packit 9795e1
        current_config = host->config->bConfigurationValue;
Packit 9795e1
Packit 9795e1
    if (current_config != host->restore_config) {
Packit 9795e1
        r = libusb_set_configuration(host->handle, host->restore_config);
Packit 9795e1
        if (r < 0)
Packit 9795e1
            ERROR("could not restore configuration to %d: %s",
Packit 9795e1
                  host->restore_config, libusb_error_name(r));
Packit 9795e1
        return; /* set_config automatically binds drivers for the new config */
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    for (i = 0; host->config && i < host->config->bNumInterfaces; i++) {
Packit 9795e1
        n = host->config->interface[i].altsetting[0].bInterfaceNumber;
Packit 9795e1
        r = libusb_attach_kernel_driver(host->handle, n);
Packit 9795e1
        if (r < 0 && r != LIBUSB_ERROR_NOT_FOUND /* No driver */
Packit 9795e1
                  && r != LIBUSB_ERROR_NO_DEVICE /* Device unplugged */
Packit 9795e1
                  && r != LIBUSB_ERROR_NOT_SUPPORTED /* Not supported */
Packit 9795e1
                  && r != LIBUSB_ERROR_BUSY /* driver rebound already */) {
Packit 9795e1
            ERROR("could not re-attach driver to interface %d (configuration %d): %s",
Packit 9795e1
                  n, host->config->bConfigurationValue, libusb_error_name(r));
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
struct usbredirhost *usbredirhost_open(
Packit 9795e1
    libusb_context *usb_ctx,
Packit 9795e1
    libusb_device_handle *usb_dev_handle,
Packit 9795e1
    usbredirparser_log log_func,
Packit 9795e1
    usbredirparser_read  read_guest_data_func,
Packit 9795e1
    usbredirparser_write write_guest_data_func,
Packit 9795e1
    void *func_priv, const char *version, int verbose, int flags)
Packit 9795e1
{
Packit 9795e1
    return usbredirhost_open_full(usb_ctx, usb_dev_handle, log_func,
Packit 9795e1
                                  read_guest_data_func, write_guest_data_func,
Packit 9795e1
                                  NULL, NULL, NULL, NULL, NULL,
Packit 9795e1
                                  func_priv, version, verbose, flags);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
struct usbredirhost *usbredirhost_open_full(
Packit 9795e1
    libusb_context *usb_ctx,
Packit 9795e1
    libusb_device_handle *usb_dev_handle,
Packit 9795e1
    usbredirparser_log log_func,
Packit 9795e1
    usbredirparser_read  read_guest_data_func,
Packit 9795e1
    usbredirparser_write write_guest_data_func,
Packit 9795e1
    usbredirhost_flush_writes flush_writes_func,
Packit 9795e1
    usbredirparser_alloc_lock alloc_lock_func,
Packit 9795e1
    usbredirparser_lock lock_func,
Packit 9795e1
    usbredirparser_unlock unlock_func,
Packit 9795e1
    usbredirparser_free_lock free_lock_func,
Packit 9795e1
    void *func_priv, const char *version, int verbose, int flags)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host;
Packit 9795e1
    int parser_flags = usbredirparser_fl_usb_host;
Packit 9795e1
    uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
Packit 9795e1
Packit 9795e1
    host = calloc(1, sizeof(*host));
Packit 9795e1
    if (!host) {
Packit 9795e1
        log_func(func_priv, usbredirparser_error,
Packit 9795e1
            "usbredirhost error: Out of memory allocating usbredirhost");
Packit 9795e1
        libusb_close(usb_dev_handle);
Packit 9795e1
        return NULL;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->ctx = usb_ctx;
Packit 9795e1
    host->log_func = log_func;
Packit 9795e1
    host->read_func = read_guest_data_func;
Packit 9795e1
    host->write_func = write_guest_data_func;
Packit 9795e1
    host->flush_writes_func = flush_writes_func;
Packit 9795e1
    host->func_priv = func_priv;
Packit 9795e1
    host->verbose = verbose;
Packit 9795e1
    host->disconnected = 1; /* No device is connected initially */
Packit 9795e1
    host->parser = usbredirparser_create();
Packit 9795e1
    if (!host->parser) {
Packit 9795e1
        log_func(func_priv, usbredirparser_error,
Packit 9795e1
            "usbredirhost error: Out of memory allocating usbredirparser");
Packit 9795e1
        usbredirhost_close(host);
Packit 9795e1
        return NULL;
Packit 9795e1
    }
Packit 9795e1
    host->parser->priv = host;
Packit 9795e1
    host->parser->log_func = usbredirhost_log;
Packit 9795e1
    host->parser->read_func = usbredirhost_read;
Packit 9795e1
    host->parser->write_func = usbredirhost_write;
Packit 9795e1
    host->parser->hello_func = usbredirhost_hello;
Packit 9795e1
    host->parser->reset_func = usbredirhost_reset;
Packit 9795e1
    host->parser->set_configuration_func = usbredirhost_set_configuration;
Packit 9795e1
    host->parser->get_configuration_func = usbredirhost_get_configuration;
Packit 9795e1
    host->parser->set_alt_setting_func = usbredirhost_set_alt_setting;
Packit 9795e1
    host->parser->get_alt_setting_func = usbredirhost_get_alt_setting;
Packit 9795e1
    host->parser->start_iso_stream_func = usbredirhost_start_iso_stream;
Packit 9795e1
    host->parser->stop_iso_stream_func = usbredirhost_stop_iso_stream;
Packit 9795e1
    host->parser->start_interrupt_receiving_func =
Packit 9795e1
        usbredirhost_start_interrupt_receiving;
Packit 9795e1
    host->parser->stop_interrupt_receiving_func =
Packit 9795e1
        usbredirhost_stop_interrupt_receiving;
Packit 9795e1
    host->parser->alloc_bulk_streams_func = usbredirhost_alloc_bulk_streams;
Packit 9795e1
    host->parser->free_bulk_streams_func = usbredirhost_free_bulk_streams;
Packit 9795e1
    host->parser->cancel_data_packet_func = usbredirhost_cancel_data_packet;
Packit 9795e1
    host->parser->filter_reject_func = usbredirhost_filter_reject;
Packit 9795e1
    host->parser->filter_filter_func = usbredirhost_filter_filter;
Packit 9795e1
    host->parser->device_disconnect_ack_func =
Packit 9795e1
        usbredirhost_device_disconnect_ack;
Packit 9795e1
    host->parser->start_bulk_receiving_func =
Packit 9795e1
        usbredirhost_start_bulk_receiving;
Packit 9795e1
    host->parser->stop_bulk_receiving_func =
Packit 9795e1
        usbredirhost_stop_bulk_receiving;
Packit 9795e1
    host->parser->control_packet_func = usbredirhost_control_packet;
Packit 9795e1
    host->parser->bulk_packet_func = usbredirhost_bulk_packet;
Packit 9795e1
    host->parser->iso_packet_func = usbredirhost_iso_packet;
Packit 9795e1
    host->parser->interrupt_packet_func = usbredirhost_interrupt_packet;
Packit 9795e1
    host->parser->alloc_lock_func = alloc_lock_func;
Packit 9795e1
    host->parser->lock_func = lock_func;
Packit 9795e1
    host->parser->unlock_func = unlock_func;
Packit 9795e1
    host->parser->free_lock_func = free_lock_func;
Packit 9795e1
Packit 9795e1
    if (host->parser->alloc_lock_func) {
Packit 9795e1
        host->lock = host->parser->alloc_lock_func();
Packit 9795e1
        host->disconnect_lock = host->parser->alloc_lock_func();
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (flags & usbredirhost_fl_write_cb_owns_buffer) {
Packit 9795e1
        parser_flags |= usbredirparser_fl_write_cb_owns_buffer;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_device_disconnect_ack);
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size);
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000103
Packit 9795e1
    usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
Packit 9795e1
#endif
Packit 9795e1
Packit 9795e1
    usbredirparser_init(host->parser, version, caps, USB_REDIR_CAPS_SIZE,
Packit 9795e1
                        parser_flags);
Packit 9795e1
Packit 9795e1
#if LIBUSB_API_VERSION >= 0x01000106
Packit 9795e1
    libusb_set_option(host->ctx, LIBUSB_OPTION_LOG_LEVEL, host->verbose);
Packit 9795e1
#else
Packit 9795e1
    libusb_set_debug(host->ctx, host->verbose);
Packit 9795e1
#endif
Packit 9795e1
Packit 9795e1
    if (usbredirhost_set_device(host, usb_dev_handle) != usb_redir_success) {
Packit 9795e1
        usbredirhost_close(host);
Packit 9795e1
        return NULL;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    FLUSH(host);
Packit 9795e1
Packit 9795e1
    return host;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
void usbredirhost_close(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    usbredirhost_clear_device(host);
Packit 9795e1
Packit 9795e1
    if (host->lock) {
Packit 9795e1
        host->parser->free_lock_func(host->lock);
Packit 9795e1
    }
Packit 9795e1
    if (host->disconnect_lock) {
Packit 9795e1
        host->parser->free_lock_func(host->disconnect_lock);
Packit 9795e1
    }
Packit 9795e1
    if (host->parser) {
Packit 9795e1
        usbredirparser_destroy(host->parser);
Packit 9795e1
    }
Packit 9795e1
    free(host->filter_rules);
Packit 9795e1
    free(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static int usbredirhost_reset_device(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    int r;
Packit 9795e1
Packit 9795e1
    if (host->quirks & QUIRK_DO_NOT_RESET) {
Packit 9795e1
        return 0;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    r = libusb_reset_device(host->handle);
Packit 9795e1
    if (r != 0) {
Packit 9795e1
        ERROR("error resetting device: %s", libusb_error_name(r));
Packit 9795e1
        usbredirhost_clear_device(host);
Packit 9795e1
        return r;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->reset = 1;
Packit 9795e1
    return 0;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
int usbredirhost_set_device(struct usbredirhost *host,
Packit 9795e1
                             libusb_device_handle *usb_dev_handle)
Packit 9795e1
{
Packit 9795e1
    int i, r, status;
Packit 9795e1
Packit 9795e1
    usbredirhost_clear_device(host);
Packit 9795e1
Packit 9795e1
    if (!usb_dev_handle)
Packit 9795e1
        return usb_redir_success;
Packit 9795e1
Packit 9795e1
    host->dev = libusb_get_device(usb_dev_handle);
Packit 9795e1
    host->handle = usb_dev_handle;
Packit 9795e1
Packit 9795e1
    status = usbredirhost_claim(host, 1);
Packit 9795e1
    if (status != usb_redir_success) {
Packit 9795e1
        usbredirhost_clear_device(host);
Packit 9795e1
        return status;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    for (i = 0; usbredirhost_reset_blacklist[i].vendor_id != -1; i++) {
Packit 9795e1
        if (host->desc.idVendor == usbredirhost_reset_blacklist[i].vendor_id &&
Packit 9795e1
            host->desc.idProduct ==
Packit 9795e1
                                usbredirhost_reset_blacklist[i].product_id) {
Packit 9795e1
            host->quirks |= QUIRK_DO_NOT_RESET;
Packit 9795e1
            break;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* The first thing almost any usb-guest does is a (slow) device-reset
Packit 9795e1
       so lets do that before hand */
Packit 9795e1
    r = usbredirhost_reset_device(host);
Packit 9795e1
    if (r != 0) {
Packit 9795e1
        return libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_send_device_connect(host);
Packit 9795e1
Packit 9795e1
    return usb_redir_success;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_clear_device(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    if (!host->dev)
Packit 9795e1
        return;
Packit 9795e1
Packit 9795e1
    if (usbredirhost_cancel_pending_urbs(host, 0))
Packit 9795e1
        usbredirhost_wait_for_cancel_completion(host);
Packit 9795e1
Packit 9795e1
    usbredirhost_release(host, 1);
Packit 9795e1
Packit 9795e1
    if (host->config) {
Packit 9795e1
        libusb_free_config_descriptor(host->config);
Packit 9795e1
        host->config = NULL;
Packit 9795e1
    }
Packit 9795e1
    if (host->handle) {
Packit 9795e1
        libusb_close(host->handle);
Packit 9795e1
        host->handle = NULL;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->connect_pending = 0;
Packit 9795e1
    host->quirks = 0;
Packit 9795e1
    host->dev = NULL;
Packit 9795e1
Packit 9795e1
    usbredirhost_handle_disconnect(host);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
int usbredirhost_read_guest_data(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    return usbredirparser_do_read(host->parser);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
int usbredirhost_has_data_to_write(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    return usbredirparser_has_data_to_write(host->parser);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
int usbredirhost_write_guest_data(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    return usbredirparser_do_write(host->parser);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
void usbredirhost_free_write_buffer(struct usbredirhost *host, uint8_t *data)
Packit 9795e1
{
Packit 9795e1
    usbredirparser_free_write_buffer(host->parser, data);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
static struct usbredirtransfer *usbredirhost_alloc_transfer(
Packit 9795e1
    struct usbredirhost *host, int iso_packets)
Packit 9795e1
{
Packit 9795e1
    struct usbredirtransfer *redir_transfer;
Packit 9795e1
    struct libusb_transfer *libusb_transfer;
Packit 9795e1
Packit 9795e1
    redir_transfer  = calloc(1, sizeof(*redir_transfer));
Packit 9795e1
    libusb_transfer = libusb_alloc_transfer(iso_packets);
Packit 9795e1
    if (!redir_transfer || !libusb_transfer) {
Packit 9795e1
        ERROR("out of memory allocating usb transfer, dropping packet");
Packit 9795e1
        free(redir_transfer);
Packit 9795e1
        libusb_free_transfer(libusb_transfer);
Packit 9795e1
        return NULL;
Packit 9795e1
    }
Packit 9795e1
    redir_transfer->host       = host;
Packit 9795e1
    redir_transfer->transfer   = libusb_transfer;
Packit 9795e1
    libusb_transfer->user_data = redir_transfer;
Packit 9795e1
Packit 9795e1
    return redir_transfer;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_free_transfer(struct usbredirtransfer *transfer)
Packit 9795e1
{
Packit 9795e1
    if (!transfer)
Packit 9795e1
        return;
Packit 9795e1
Packit 9795e1
    /* In certain cases this should really be a usbredirparser_free_packet_data
Packit 9795e1
       but since we use the same malloc impl. as usbredirparser this is ok. */
Packit 9795e1
    free(transfer->transfer->buffer);
Packit 9795e1
    libusb_free_transfer(transfer->transfer);
Packit 9795e1
    free(transfer);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_add_transfer(struct usbredirhost *host,
Packit 9795e1
    struct usbredirtransfer *new_transfer)
Packit 9795e1
{
Packit 9795e1
    struct usbredirtransfer *transfer = &host->transfers_head;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
    while (transfer->next) {
Packit 9795e1
        transfer = transfer->next;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    new_transfer->prev = transfer;
Packit 9795e1
    transfer->next = new_transfer;
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Note caller must hold the host lock */
Packit 9795e1
static void usbredirhost_remove_and_free_transfer(
Packit 9795e1
    struct usbredirtransfer *transfer)
Packit 9795e1
{
Packit 9795e1
    if (transfer->next)
Packit 9795e1
        transfer->next->prev = transfer->prev;
Packit 9795e1
    if (transfer->prev)
Packit 9795e1
        transfer->prev->next = transfer->next;
Packit 9795e1
    usbredirhost_free_transfer(transfer);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
/* Called from both parser read and packet complete callbacks */
Packit 9795e1
static void usbredirhost_cancel_stream_unlocked(struct usbredirhost *host,
Packit 9795e1
    uint8_t ep)
Packit 9795e1
{
Packit 9795e1
    int i;
Packit 9795e1
    struct usbredirtransfer *transfer;
Packit 9795e1
Packit 9795e1
    for (i = 0; i < host->endpoint[EP2I(ep)].transfer_count; i++) {
Packit 9795e1
        transfer = host->endpoint[EP2I(ep)].transfer[i];
Packit 9795e1
        if (transfer->packet_idx == SUBMITTED_IDX) {
Packit 9795e1
            libusb_cancel_transfer(transfer->transfer);
Packit 9795e1
            transfer->cancelled = 1;
Packit 9795e1
            host->cancels_pending++;
Packit 9795e1
        } else {
Packit 9795e1
            usbredirhost_free_transfer(transfer);
Packit 9795e1
        }
Packit 9795e1
        host->endpoint[EP2I(ep)].transfer[i] = NULL;
Packit 9795e1
    }
Packit 9795e1
    host->endpoint[EP2I(ep)].out_idx = 0;
Packit 9795e1
    host->endpoint[EP2I(ep)].stream_started = 0;
Packit 9795e1
    host->endpoint[EP2I(ep)].drop_packets = 0;
Packit 9795e1
    host->endpoint[EP2I(ep)].pkts_per_transfer = 0;
Packit 9795e1
    host->endpoint[EP2I(ep)].transfer_count = 0;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_cancel_stream(struct usbredirhost *host,
Packit 9795e1
    uint8_t ep)
Packit 9795e1
{
Packit 9795e1
    LOCK(host);
Packit 9795e1
    usbredirhost_cancel_stream_unlocked(host, ep);
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_send_stream_status(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, uint8_t ep, uint8_t status)
Packit 9795e1
{
Packit 9795e1
    switch (host->endpoint[EP2I(ep)].type) {
Packit 9795e1
    case usb_redir_type_iso: {
Packit 9795e1
        struct usb_redir_iso_stream_status_header iso_status = {
Packit 9795e1
            .endpoint = ep,
Packit 9795e1
            .status   = status,
Packit 9795e1
        };
Packit 9795e1
        usbredirparser_send_iso_stream_status(host->parser, id, &iso_status);
Packit 9795e1
        break;
Packit 9795e1
    }
Packit 9795e1
    case usb_redir_type_bulk: {
Packit 9795e1
        struct usb_redir_bulk_receiving_status_header bulk_status = {
Packit 9795e1
            .endpoint = ep,
Packit 9795e1
            .status   = status,
Packit 9795e1
        };
Packit 9795e1
        usbredirparser_send_bulk_receiving_status(host->parser, id,
Packit 9795e1
                                                  &bulk_status);
Packit 9795e1
        break;
Packit 9795e1
    }
Packit 9795e1
    case usb_redir_type_interrupt: {
Packit 9795e1
        struct usb_redir_interrupt_receiving_status_header interrupt_status = {
Packit 9795e1
            .endpoint = ep,
Packit 9795e1
            .status   = status,
Packit 9795e1
        };
Packit 9795e1
        usbredirparser_send_interrupt_receiving_status(host->parser, id,
Packit 9795e1
                                                       &interrupt_status);
Packit 9795e1
        break;
Packit 9795e1
    }
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static int usbredirhost_can_write_iso_package(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    uint64_t size;
Packit 9795e1
Packit 9795e1
    if (!host->buffered_output_size_func)
Packit 9795e1
        return true;
Packit 9795e1
Packit 9795e1
    size = host->buffered_output_size_func(host->func_priv);
Packit 9795e1
    if (size >= host->iso_threshold.higher) {
Packit 9795e1
        if (!host->iso_threshold.dropping)
Packit 9795e1
            DEBUG("START dropping isoc packets %" PRIu64 " buffer > %" PRIu64 " hi threshold",
Packit 9795e1
                  size, host->iso_threshold.higher);
Packit 9795e1
        host->iso_threshold.dropping = true;
Packit 9795e1
    } else if (size < host->iso_threshold.lower) {
Packit 9795e1
        if (host->iso_threshold.dropping)
Packit 9795e1
            DEBUG("STOP dropping isoc packets %" PRIu64 " buffer < %" PRIu64 " low threshold",
Packit 9795e1
                  size, host->iso_threshold.lower);
Packit 9795e1
Packit 9795e1
        host->iso_threshold.dropping = false;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    return !host->iso_threshold.dropping;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_send_stream_data(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, uint8_t ep, uint8_t status, uint8_t *data, int len)
Packit 9795e1
{
Packit 9795e1
    /* USB-2 is max 8000 packets / sec, if we've queued up more then 0.1 sec,
Packit 9795e1
       assume our connection is not keeping up and start dropping packets. */
Packit 9795e1
    if (usbredirparser_has_data_to_write(host->parser) > 800) {
Packit 9795e1
        if (host->endpoint[EP2I(ep)].warn_on_drop) {
Packit 9795e1
            WARNING("buffered stream on endpoint %02X, connection too slow, "
Packit 9795e1
                    "dropping packets", ep);
Packit 9795e1
            host->endpoint[EP2I(ep)].warn_on_drop = 0;
Packit 9795e1
        }
Packit 9795e1
        DEBUG("buffered complete ep %02X dropping packet status %d len %d",
Packit 9795e1
              ep, status, len);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    DEBUG("buffered complete ep %02X status %d len %d", ep, status, len);
Packit 9795e1
Packit 9795e1
    switch (host->endpoint[EP2I(ep)].type) {
Packit 9795e1
    case usb_redir_type_iso: {
Packit 9795e1
        struct usb_redir_iso_packet_header iso_packet = {
Packit 9795e1
            .endpoint = ep,
Packit 9795e1
            .status   = status,
Packit 9795e1
            .length   = len,
Packit 9795e1
        };
Packit 9795e1
Packit 9795e1
        if (usbredirhost_can_write_iso_package(host))
Packit 9795e1
            usbredirparser_send_iso_packet(host->parser, id, &iso_packet,
Packit 9795e1
                                           data, len);
Packit 9795e1
        break;
Packit 9795e1
    }
Packit 9795e1
    case usb_redir_type_bulk: {
Packit 9795e1
        struct usb_redir_buffered_bulk_packet_header bulk_packet = {
Packit 9795e1
            .endpoint = ep,
Packit 9795e1
            .status   = status,
Packit 9795e1
            .length   = len,
Packit 9795e1
        };
Packit 9795e1
        usbredirparser_send_buffered_bulk_packet(host->parser, id,
Packit 9795e1
                                                 &bulk_packet, data, len);
Packit 9795e1
        break;
Packit 9795e1
    }
Packit 9795e1
    case usb_redir_type_interrupt: {
Packit 9795e1
        struct usb_redir_interrupt_packet_header interrupt_packet = {
Packit 9795e1
            .endpoint = ep,
Packit 9795e1
            .status   = status,
Packit 9795e1
            .length   = len,
Packit 9795e1
        };
Packit 9795e1
        usbredirparser_send_interrupt_packet(host->parser, id,
Packit 9795e1
                                             &interrupt_packet, data, len);
Packit 9795e1
        break;
Packit 9795e1
    }
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from both parser read and packet complete callbacks */
Packit 9795e1
static int usbredirhost_submit_stream_transfer_unlocked(
Packit 9795e1
    struct usbredirhost *host, struct usbredirtransfer *transfer)
Packit 9795e1
{
Packit 9795e1
    int r;
Packit 9795e1
Packit 9795e1
    host->reset = 0;
Packit 9795e1
Packit 9795e1
    r = libusb_submit_transfer(transfer->transfer);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        uint8_t ep = transfer->transfer->endpoint;
Packit 9795e1
        if (r == LIBUSB_ERROR_NO_DEVICE) {
Packit 9795e1
            usbredirhost_handle_disconnect(host);
Packit 9795e1
        } else {
Packit 9795e1
            ERROR("error submitting transfer on ep %02X: %s, stopping stream",
Packit 9795e1
                  ep, libusb_error_name(r));
Packit 9795e1
            usbredirhost_cancel_stream_unlocked(host, ep);
Packit 9795e1
            usbredirhost_send_stream_status(host, transfer->id, ep,
Packit 9795e1
                                            usb_redir_stall);
Packit 9795e1
        }
Packit 9795e1
        return usb_redir_stall;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    transfer->packet_idx = SUBMITTED_IDX;
Packit 9795e1
    return usb_redir_success;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from both parser read and packet complete callbacks */
Packit 9795e1
static int usbredirhost_start_stream_unlocked(struct usbredirhost *host,
Packit 9795e1
    uint8_t ep)
Packit 9795e1
{
Packit 9795e1
    unsigned int i, count = host->endpoint[EP2I(ep)].transfer_count;
Packit 9795e1
    int status;
Packit 9795e1
Packit 9795e1
    /* For out endpoints 1/2 the transfers are a buffer for usb-guest data */
Packit 9795e1
    if (!(ep & LIBUSB_ENDPOINT_IN)) {
Packit 9795e1
        count /= 2;
Packit 9795e1
    }
Packit 9795e1
    for (i = 0; i < count; i++) {
Packit 9795e1
        if (ep & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
            host->endpoint[EP2I(ep)].transfer[i]->id =
Packit 9795e1
                i * host->endpoint[EP2I(ep)].pkts_per_transfer;
Packit 9795e1
        }
Packit 9795e1
        status = usbredirhost_submit_stream_transfer_unlocked(host,
Packit 9795e1
                               host->endpoint[EP2I(ep)].transfer[i]);
Packit 9795e1
        if (status != usb_redir_success) {
Packit 9795e1
            return status;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
    host->endpoint[EP2I(ep)].stream_started = 1;
Packit 9795e1
    return usb_redir_success;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_stop_stream(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, uint8_t ep)
Packit 9795e1
{
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_cancel_stream(host, ep);
Packit 9795e1
    usbredirhost_send_stream_status(host, id, ep, usb_redir_success);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_set_iso_threshold(struct usbredirhost *host,
Packit 9795e1
    uint8_t pkts_per_transfer, uint8_t transfer_count, uint16_t max_packetsize)
Packit 9795e1
{
Packit 9795e1
    uint64_t reference = pkts_per_transfer * transfer_count * max_packetsize;
Packit 9795e1
    host->iso_threshold.lower = reference / 2;
Packit 9795e1
    host->iso_threshold.higher = reference * 3;
Packit 9795e1
    DEBUG("higher threshold is %" PRIu64 " bytes | lower threshold is %" PRIu64 " bytes",
Packit 9795e1
           host->iso_threshold.higher, host->iso_threshold.lower);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from both parser read and packet complete callbacks */
Packit 9795e1
static void usbredirhost_alloc_stream_unlocked(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, uint8_t ep, uint8_t type, uint8_t pkts_per_transfer,
Packit 9795e1
    int pkt_size, uint8_t transfer_count, int send_success)
Packit 9795e1
{
Packit 9795e1
    int i, buf_size, status = usb_redir_success;
Packit 9795e1
    unsigned char *buffer;
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        goto error;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].type != type) {
Packit 9795e1
        ERROR("error start stream type %d on type %d endpoint",
Packit 9795e1
              type, host->endpoint[EP2I(ep)].type);
Packit 9795e1
        goto error;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (   pkts_per_transfer < 1 ||
Packit 9795e1
           pkts_per_transfer > MAX_PACKETS_PER_TRANSFER ||
Packit 9795e1
           transfer_count < 1 ||
Packit 9795e1
           transfer_count > MAX_TRANSFER_COUNT ||
Packit 9795e1
           host->endpoint[EP2I(ep)].max_packetsize == 0 ||
Packit 9795e1
           (pkt_size % host->endpoint[EP2I(ep)].max_packetsize) != 0) {
Packit 9795e1
        ERROR("error start stream type %d invalid parameters", type);
Packit 9795e1
        goto error;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].transfer_count) {
Packit 9795e1
        ERROR("error received start type %d for already started stream", type);
Packit 9795e1
        usbredirhost_send_stream_status(host, id, ep, usb_redir_inval);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    DEBUG("allocating stream ep %02X type %d packet-size %d pkts %d urbs %d",
Packit 9795e1
          ep, type, pkt_size, pkts_per_transfer, transfer_count);
Packit 9795e1
    for (i = 0; i < transfer_count; i++) {
Packit 9795e1
        host->endpoint[EP2I(ep)].transfer[i] =
Packit 9795e1
            usbredirhost_alloc_transfer(host, (type == usb_redir_type_iso) ?
Packit 9795e1
                                              pkts_per_transfer : 0);
Packit 9795e1
        if (!host->endpoint[EP2I(ep)].transfer[i]) {
Packit 9795e1
            goto alloc_error;
Packit 9795e1
        }
Packit 9795e1
Packit 9795e1
        buf_size = pkt_size * pkts_per_transfer;
Packit 9795e1
        buffer = malloc(buf_size);
Packit 9795e1
        if (!buffer) {
Packit 9795e1
            goto alloc_error;
Packit 9795e1
        }
Packit 9795e1
        switch (type) {
Packit 9795e1
        case usb_redir_type_iso:
Packit 9795e1
            libusb_fill_iso_transfer(
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i]->transfer, host->handle,
Packit 9795e1
                ep, buffer, buf_size, pkts_per_transfer,
Packit 9795e1
                usbredirhost_iso_packet_complete,
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i], ISO_TIMEOUT);
Packit 9795e1
            libusb_set_iso_packet_lengths(
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i]->transfer, pkt_size);
Packit 9795e1
Packit 9795e1
            usbredirhost_set_iso_threshold(
Packit 9795e1
                host, pkts_per_transfer,  transfer_count,
Packit 9795e1
                host->endpoint[EP2I(ep)].max_packetsize);
Packit 9795e1
            break;
Packit 9795e1
        case usb_redir_type_bulk:
Packit 9795e1
            libusb_fill_bulk_transfer(
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i]->transfer, host->handle,
Packit 9795e1
                ep, buffer, buf_size, usbredirhost_buffered_packet_complete,
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i], BULK_TIMEOUT);
Packit 9795e1
            break;
Packit 9795e1
        case usb_redir_type_interrupt:
Packit 9795e1
            libusb_fill_interrupt_transfer(
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i]->transfer, host->handle,
Packit 9795e1
                ep, buffer, buf_size, usbredirhost_buffered_packet_complete,
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i], INTERRUPT_TIMEOUT);
Packit 9795e1
            break;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
    host->endpoint[EP2I(ep)].out_idx = 0;
Packit 9795e1
    host->endpoint[EP2I(ep)].drop_packets = 0;
Packit 9795e1
    host->endpoint[EP2I(ep)].pkts_per_transfer = pkts_per_transfer;
Packit 9795e1
    host->endpoint[EP2I(ep)].transfer_count = transfer_count;
Packit 9795e1
Packit 9795e1
    /* For input endpoints submit the transfers now */
Packit 9795e1
    if (ep & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
        status = usbredirhost_start_stream_unlocked(host, ep);
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (send_success && status == usb_redir_success) {
Packit 9795e1
        usbredirhost_send_stream_status(host, id, ep, status);
Packit 9795e1
    }
Packit 9795e1
    return;
Packit 9795e1
Packit 9795e1
alloc_error:
Packit 9795e1
    ERROR("out of memory allocating type %d stream buffers", type);
Packit 9795e1
    do {
Packit 9795e1
        usbredirhost_free_transfer(host->endpoint[EP2I(ep)].transfer[i]);
Packit 9795e1
        host->endpoint[EP2I(ep)].transfer[i] = NULL;
Packit 9795e1
        i--;
Packit 9795e1
    } while (i >= 0);
Packit 9795e1
error:
Packit 9795e1
    usbredirhost_send_stream_status(host, id, ep, usb_redir_stall);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_alloc_stream(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, uint8_t ep, uint8_t type, uint8_t pkts_per_transfer,
Packit 9795e1
    int pkt_size, uint8_t transfer_count, int send_success)
Packit 9795e1
{
Packit 9795e1
    LOCK(host);
Packit 9795e1
    usbredirhost_alloc_stream_unlocked(host, id, ep, type, pkts_per_transfer,
Packit 9795e1
                                       pkt_size, transfer_count, send_success);
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_clear_stream_stall_unlocked(
Packit 9795e1
    struct usbredirhost *host, uint64_t id, uint8_t ep)
Packit 9795e1
{
Packit 9795e1
    int r;
Packit 9795e1
    uint8_t pkts_per_transfer = host->endpoint[EP2I(ep)].pkts_per_transfer;
Packit 9795e1
    uint8_t transfer_count    = host->endpoint[EP2I(ep)].transfer_count;
Packit 9795e1
    int pkt_size = host->endpoint[EP2I(ep)].transfer[0]->transfer->length /
Packit 9795e1
                   pkts_per_transfer;
Packit 9795e1
Packit 9795e1
    WARNING("buffered stream on endpoint %02X stalled, clearing stall", ep);
Packit 9795e1
Packit 9795e1
    usbredirhost_cancel_stream_unlocked(host, ep);
Packit 9795e1
    r = libusb_clear_halt(host->handle, ep);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        usbredirhost_send_stream_status(host, id, ep, usb_redir_stall);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
    usbredirhost_alloc_stream_unlocked(host, id, ep,
Packit 9795e1
                                       host->endpoint[EP2I(ep)].type,
Packit 9795e1
                                       pkts_per_transfer, pkt_size,
Packit 9795e1
                                       transfer_count, 0);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
/* Called from close and parser read callbacks */
Packit 9795e1
static int usbredirhost_cancel_pending_urbs(struct usbredirhost *host,
Packit 9795e1
                                            int notify_guest)
Packit 9795e1
{
Packit 9795e1
    struct usbredirtransfer *t;
Packit 9795e1
    int i, wait;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
    for (i = 0; i < MAX_ENDPOINTS; i++) {
Packit 9795e1
        if (notify_guest && host->endpoint[i].transfer_count)
Packit 9795e1
            usbredirhost_send_stream_status(host, 0, I2EP(i), usb_redir_stall);
Packit 9795e1
        usbredirhost_cancel_stream_unlocked(host, I2EP(i));
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    wait = host->cancels_pending;
Packit 9795e1
    for (t = host->transfers_head.next; t; t = t->next) {
Packit 9795e1
        libusb_cancel_transfer(t->transfer);
Packit 9795e1
        wait = 1;
Packit 9795e1
    }
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
Packit 9795e1
    if (notify_guest)
Packit 9795e1
        FLUSH(host);
Packit 9795e1
Packit 9795e1
    return wait;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Called from close and parser read callbacks */
Packit 9795e1
void usbredirhost_wait_for_cancel_completion(struct usbredirhost *host)
Packit 9795e1
{
Packit 9795e1
    int wait;
Packit 9795e1
    struct timeval tv;
Packit 9795e1
Packit 9795e1
    do {
Packit 9795e1
        memset(&tv, 0, sizeof(tv));
Packit 9795e1
        tv.tv_usec = 2500;
Packit 9795e1
        libusb_handle_events_timeout(host->ctx, &tv;;
Packit 9795e1
        LOCK(host);
Packit 9795e1
        wait = host->cancels_pending || host->transfers_head.next;
Packit 9795e1
        UNLOCK(host);
Packit 9795e1
    } while (wait);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Only called from read callbacks */
Packit 9795e1
static void usbredirhost_cancel_pending_urbs_on_interface(
Packit 9795e1
    struct usbredirhost *host, int i)
Packit 9795e1
{
Packit 9795e1
    struct usbredirtransfer *t;
Packit 9795e1
    const struct libusb_interface_descriptor *intf_desc;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
Packit 9795e1
    intf_desc = &host->config->interface[i].altsetting[host->alt_setting[i]];
Packit 9795e1
    for (i = 0; i < intf_desc->bNumEndpoints; i++) {
Packit 9795e1
        uint8_t ep = intf_desc->endpoint[i].bEndpointAddress;
Packit 9795e1
Packit 9795e1
        usbredirhost_cancel_stream_unlocked(host, ep);
Packit 9795e1
Packit 9795e1
        for (t = host->transfers_head.next; t; t = t->next) {
Packit 9795e1
            if (t->transfer->endpoint == ep)
Packit 9795e1
                libusb_cancel_transfer(t->transfer);
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Only called from read callbacks */
Packit 9795e1
static int usbredirhost_bInterfaceNumber_to_index(
Packit 9795e1
    struct usbredirhost *host, uint8_t bInterfaceNumber)
Packit 9795e1
{
Packit 9795e1
    int i, n;
Packit 9795e1
Packit 9795e1
    for (i = 0; host->config && i < host->config->bNumInterfaces; i++) {
Packit 9795e1
        n = host->config->interface[i].altsetting[0].bInterfaceNumber;
Packit 9795e1
        if (n == bInterfaceNumber) {
Packit 9795e1
            return i;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    ERROR("invalid bNumInterface: %d\n", (int)bInterfaceNumber);
Packit 9795e1
    return -1;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_log_data(struct usbredirhost *host, const char *desc,
Packit 9795e1
    const uint8_t *data, int len)
Packit 9795e1
{
Packit 9795e1
    if (usbredirparser_debug_data <= host->verbose) {
Packit 9795e1
        int i, j, n;
Packit 9795e1
Packit 9795e1
        for (i = 0; i < len; i += j) {
Packit 9795e1
            char buf[128];
Packit 9795e1
Packit 9795e1
            n = sprintf(buf, "%s", desc);
Packit 9795e1
            for (j = 0; j < 8 && i + j < len; j++){
Packit 9795e1
                 n += sprintf(buf + n, " %02X", data[i + j]);
Packit 9795e1
            }
Packit 9795e1
            va_log(host, usbredirparser_debug_data, "%s", buf);
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
void usbredirhost_set_buffered_output_size_cb(struct usbredirhost *host,
Packit 9795e1
    usbredirhost_buffered_output_size buffered_output_size_func)
Packit 9795e1
{
Packit 9795e1
    if (!host) {
Packit 9795e1
        fprintf(stderr, "%s: invalid usbredirhost", __func__);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->buffered_output_size_func = buffered_output_size_func;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/* Return value:
Packit 9795e1
    0 All ok
Packit 9795e1
    1 Packet borked, continue with next packet / urb
Packit 9795e1
    2 Stream borked, full stop, no resubmit, etc.
Packit 9795e1
   Note in the case of a return value of 2 this function takes care of
Packit 9795e1
   sending an iso status message to the usb-guest. */
Packit 9795e1
static int usbredirhost_handle_iso_status(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, uint8_t ep, int r)
Packit 9795e1
{
Packit 9795e1
    switch (r) {
Packit 9795e1
    case LIBUSB_TRANSFER_COMPLETED:
Packit 9795e1
    case -EXDEV: /* FIXlibusb: Passing regular error codes, bad libusb, bad! */
Packit 9795e1
        return 0;
Packit 9795e1
    case LIBUSB_TRANSFER_CANCELLED:
Packit 9795e1
        /* Stream was intentionally stopped */
Packit 9795e1
        return 2;
Packit 9795e1
    case LIBUSB_TRANSFER_STALL:
Packit 9795e1
        usbredirhost_clear_stream_stall_unlocked(host, id, ep);
Packit 9795e1
        return 2;
Packit 9795e1
    case LIBUSB_TRANSFER_NO_DEVICE:
Packit 9795e1
        usbredirhost_handle_disconnect(host);
Packit 9795e1
        return 2;
Packit 9795e1
    case LIBUSB_TRANSFER_OVERFLOW:
Packit 9795e1
    case LIBUSB_TRANSFER_ERROR:
Packit 9795e1
    case LIBUSB_TRANSFER_TIMED_OUT:
Packit 9795e1
    default:
Packit 9795e1
        ERROR("iso stream error on endpoint %02X: %d", ep, r);
Packit 9795e1
        return 1;
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void LIBUSB_CALL usbredirhost_iso_packet_complete(
Packit 9795e1
    struct libusb_transfer *libusb_transfer)
Packit 9795e1
{
Packit 9795e1
    struct usbredirtransfer *transfer = libusb_transfer->user_data;
Packit 9795e1
    uint8_t ep = libusb_transfer->endpoint;
Packit 9795e1
    struct usbredirhost *host = transfer->host;
Packit 9795e1
    int i, r, len, status;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
    if (transfer->cancelled) {
Packit 9795e1
        host->cancels_pending--;
Packit 9795e1
        usbredirhost_free_transfer(transfer);
Packit 9795e1
        goto unlock;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* Mark transfer completed (iow not submitted) */
Packit 9795e1
    transfer->packet_idx = 0;
Packit 9795e1
Packit 9795e1
    /* Check overal transfer status */
Packit 9795e1
    r = libusb_transfer->status;
Packit 9795e1
    switch (usbredirhost_handle_iso_status(host, transfer->id, ep, r)) {
Packit 9795e1
    case 0:
Packit 9795e1
        break;
Packit 9795e1
    case 1:
Packit 9795e1
        status = libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
        if (ep & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
            struct usb_redir_iso_packet_header iso_packet = {
Packit 9795e1
                .endpoint = ep,
Packit 9795e1
                .status   = status,
Packit 9795e1
                .length   = 0
Packit 9795e1
            };
Packit 9795e1
            usbredirparser_send_iso_packet(host->parser, transfer->id,
Packit 9795e1
                           &iso_packet, NULL, 0);
Packit 9795e1
            transfer->id += libusb_transfer->num_iso_packets;
Packit 9795e1
            goto resubmit;
Packit 9795e1
        } else {
Packit 9795e1
            usbredirhost_send_stream_status(host, transfer->id, ep, status);
Packit 9795e1
            goto unlock;
Packit 9795e1
        }
Packit 9795e1
        break;
Packit 9795e1
    case 2:
Packit 9795e1
        goto unlock;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* Check per packet status and send ok input packets to usb-guest */
Packit 9795e1
    for (i = 0; i < libusb_transfer->num_iso_packets; i++) {
Packit 9795e1
        r   = libusb_transfer->iso_packet_desc[i].status;
Packit 9795e1
        len = libusb_transfer->iso_packet_desc[i].actual_length;
Packit 9795e1
        status = libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
        switch (usbredirhost_handle_iso_status(host, transfer->id, ep, r)) {
Packit 9795e1
        case 0:
Packit 9795e1
            break;
Packit 9795e1
        case 1:
Packit 9795e1
            if (ep & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
                len = 0;
Packit 9795e1
            } else {
Packit 9795e1
                usbredirhost_send_stream_status(host, transfer->id, ep,
Packit 9795e1
                                                status);
Packit 9795e1
                goto unlock; /* We send max one iso status message per urb */
Packit 9795e1
            }
Packit 9795e1
            break;
Packit 9795e1
        case 2:
Packit 9795e1
            goto unlock;
Packit 9795e1
        }
Packit 9795e1
        if (ep & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
            usbredirhost_send_stream_data(host, transfer->id, ep, status,
Packit 9795e1
                   libusb_get_iso_packet_buffer(libusb_transfer, i), len);
Packit 9795e1
            transfer->id++;
Packit 9795e1
        } else {
Packit 9795e1
            DEBUG("iso-in complete ep %02X pkt %d len %d id %"PRIu64,
Packit 9795e1
                  ep, i, len, transfer->id);
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* And for input transfers resubmit the transfer (output transfers
Packit 9795e1
       get resubmitted when they have all their packets filled with data) */
Packit 9795e1
    if (ep & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
resubmit:
Packit 9795e1
        transfer->id += (host->endpoint[EP2I(ep)].transfer_count - 1) *
Packit 9795e1
                        libusb_transfer->num_iso_packets;
Packit 9795e1
        usbredirhost_submit_stream_transfer_unlocked(host, transfer);
Packit 9795e1
    } else {
Packit 9795e1
        for (i = 0; i < host->endpoint[EP2I(ep)].transfer_count; i++) {
Packit 9795e1
            transfer = host->endpoint[EP2I(ep)].transfer[i];
Packit 9795e1
            if (transfer->packet_idx == SUBMITTED_IDX)
Packit 9795e1
                break;
Packit 9795e1
        }
Packit 9795e1
        if (i == host->endpoint[EP2I(ep)].transfer_count) {
Packit 9795e1
            DEBUG("underflow of iso out queue on ep: %02X", ep);
Packit 9795e1
            /* Re-fill buffers before submitting urbs again */
Packit 9795e1
            for (i = 0; i < host->endpoint[EP2I(ep)].transfer_count; i++)
Packit 9795e1
                host->endpoint[EP2I(ep)].transfer[i]->packet_idx = 0;
Packit 9795e1
            host->endpoint[EP2I(ep)].out_idx = 0;
Packit 9795e1
            host->endpoint[EP2I(ep)].stream_started = 0;
Packit 9795e1
            host->endpoint[EP2I(ep)].drop_packets = 0;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
unlock:
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
static void LIBUSB_CALL usbredirhost_buffered_packet_complete(
Packit 9795e1
    struct libusb_transfer *libusb_transfer)
Packit 9795e1
{
Packit 9795e1
    struct usbredirtransfer *transfer = libusb_transfer->user_data;
Packit 9795e1
    uint8_t ep = libusb_transfer->endpoint;
Packit 9795e1
    struct usbredirhost *host = transfer->host;
Packit 9795e1
    int r, len = libusb_transfer->actual_length;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
Packit 9795e1
    if (transfer->cancelled) {
Packit 9795e1
        host->cancels_pending--;
Packit 9795e1
        usbredirhost_free_transfer(transfer);
Packit 9795e1
        goto unlock;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* Mark transfer completed (iow not submitted) */
Packit 9795e1
    transfer->packet_idx = 0;
Packit 9795e1
Packit 9795e1
    r = libusb_transfer->status;
Packit 9795e1
    switch (r) {
Packit 9795e1
    case LIBUSB_TRANSFER_COMPLETED:
Packit 9795e1
        break;
Packit 9795e1
    case LIBUSB_TRANSFER_STALL:
Packit 9795e1
        usbredirhost_clear_stream_stall_unlocked(host, transfer->id, ep);
Packit 9795e1
        goto unlock;
Packit 9795e1
    case LIBUSB_TRANSFER_NO_DEVICE:
Packit 9795e1
        usbredirhost_handle_disconnect(host);
Packit 9795e1
        goto unlock;
Packit 9795e1
    default:
Packit 9795e1
        ERROR("buffered in error on endpoint %02X: %d", ep, r);
Packit 9795e1
        len = 0;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_send_stream_data(host, transfer->id, ep,
Packit 9795e1
                           libusb_status_or_error_to_redir_status(host, r),
Packit 9795e1
                           transfer->transfer->buffer, len);
Packit 9795e1
    usbredirhost_log_data(host, "buffered data in:",
Packit 9795e1
                          transfer->transfer->buffer, len);
Packit 9795e1
Packit 9795e1
    transfer->id += host->endpoint[EP2I(ep)].transfer_count;
Packit 9795e1
    usbredirhost_submit_stream_transfer_unlocked(host, transfer);
Packit 9795e1
unlock:
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
static void usbredirhost_hello(void *priv, struct usb_redir_hello_header *h)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
Packit 9795e1
    if (host->connect_pending)
Packit 9795e1
        usbredirhost_send_device_connect(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_reset(void *priv)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    int r;
Packit 9795e1
Packit 9795e1
    if (host->disconnected || host->reset) {
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /*
Packit 9795e1
     * The guest should have cancelled any pending urbs already, but the
Packit 9795e1
     * cancellations may be awaiting completion, and if we then do a reset
Packit 9795e1
     * they will complete with an error code of LIBUSB_TRANSFER_NO_DEVICE.
Packit 9795e1
     *
Packit 9795e1
     * And we also need to cleanly shutdown any streams (and let the guest
Packit 9795e1
     * know they should be restarted after the reset).
Packit 9795e1
     */
Packit 9795e1
    if (usbredirhost_cancel_pending_urbs(host, 1))
Packit 9795e1
        usbredirhost_wait_for_cancel_completion(host);
Packit 9795e1
Packit 9795e1
    r = usbredirhost_reset_device(host);
Packit 9795e1
    if (r != 0) {
Packit 9795e1
        host->read_status = usbredirhost_read_device_lost;
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_set_configuration(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_set_configuration_header *set_config)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    int r, claim_status;
Packit 9795e1
    struct usb_redir_configuration_status_header status = {
Packit 9795e1
        .status = usb_redir_success,
Packit 9795e1
    };
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        status.status = usb_redir_ioerror;
Packit 9795e1
        goto exit;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->config &&
Packit 9795e1
            host->config->bConfigurationValue == set_config->configuration) {
Packit 9795e1
        goto exit;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->reset = 0;
Packit 9795e1
Packit 9795e1
    usbredirhost_cancel_pending_urbs(host, 0);
Packit 9795e1
    usbredirhost_release(host, 0);
Packit 9795e1
Packit 9795e1
    r = libusb_set_configuration(host->handle, set_config->configuration);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        ERROR("could not set active configuration to %d: %s",
Packit 9795e1
              (int)set_config->configuration, libusb_error_name(r));
Packit 9795e1
        status.status = usb_redir_ioerror;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    claim_status = usbredirhost_claim(host, 0);
Packit 9795e1
    if (claim_status != usb_redir_success) {
Packit 9795e1
        usbredirhost_clear_device(host);
Packit 9795e1
        host->read_status = usbredirhost_read_device_lost;
Packit 9795e1
        status.status = usb_redir_ioerror;
Packit 9795e1
        goto exit;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_send_interface_n_ep_info(host);
Packit 9795e1
Packit 9795e1
exit:
Packit 9795e1
    status.configuration = host->config ? host->config->bConfigurationValue:0;
Packit 9795e1
    usbredirparser_send_configuration_status(host->parser, id, &status);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_get_configuration(void *priv, uint64_t id)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    struct usb_redir_configuration_status_header status;
Packit 9795e1
Packit 9795e1
    if (host->disconnected)
Packit 9795e1
        status.status = usb_redir_ioerror;
Packit 9795e1
    else
Packit 9795e1
        status.status = usb_redir_success;
Packit 9795e1
    status.configuration = host->config ? host->config->bConfigurationValue:0;
Packit 9795e1
    usbredirparser_send_configuration_status(host->parser, id, &status);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_set_alt_setting(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_set_alt_setting_header *set_alt_setting)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    int i, j, r;
Packit 9795e1
    struct usb_redir_alt_setting_status_header status = {
Packit 9795e1
        .status = usb_redir_success,
Packit 9795e1
    };
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        status.status = usb_redir_ioerror;
Packit 9795e1
        status.alt = -1;
Packit 9795e1
        goto exit_unknown_interface;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    i = usbredirhost_bInterfaceNumber_to_index(host,
Packit 9795e1
                                               set_alt_setting->interface);
Packit 9795e1
    if (i == -1) {
Packit 9795e1
        status.status = usb_redir_inval;
Packit 9795e1
        status.alt = -1;
Packit 9795e1
        goto exit_unknown_interface;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->reset = 0;
Packit 9795e1
Packit 9795e1
    usbredirhost_cancel_pending_urbs_on_interface(host, i);
Packit 9795e1
Packit 9795e1
    r = libusb_set_interface_alt_setting(host->handle,
Packit 9795e1
                                         set_alt_setting->interface,
Packit 9795e1
                                         set_alt_setting->alt);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        ERROR("could not set alt setting for interface %d to %d: %s",
Packit 9795e1
              set_alt_setting->interface, set_alt_setting->alt,
Packit 9795e1
              libusb_error_name(r));
Packit 9795e1
        status.status = libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
        goto exit;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* The new alt setting may have lost endpoints compared to the old! ->
Packit 9795e1
       Clear settings for all endpoints which used to be part of the intf. */
Packit 9795e1
    for (j = 0; j < MAX_ENDPOINTS; j++) {
Packit 9795e1
        if (host->endpoint[j].interface != set_alt_setting->interface)
Packit 9795e1
            continue;
Packit 9795e1
Packit 9795e1
        if ((j & 0x0f) == 0) {
Packit 9795e1
            host->endpoint[j].type = usb_redir_type_control;
Packit 9795e1
        } else {
Packit 9795e1
            host->endpoint[j].type = usb_redir_type_invalid;
Packit 9795e1
        }
Packit 9795e1
        host->endpoint[j].interval = 0;
Packit 9795e1
        host->endpoint[j].interface = 0;
Packit 9795e1
        host->endpoint[j].max_packetsize = 0;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->alt_setting[i] = set_alt_setting->alt;
Packit 9795e1
    usbredirhost_parse_interface(host, i);
Packit 9795e1
    usbredirhost_send_interface_n_ep_info(host);
Packit 9795e1
Packit 9795e1
exit:
Packit 9795e1
    status.alt = host->alt_setting[i];
Packit 9795e1
exit_unknown_interface:
Packit 9795e1
    status.interface = set_alt_setting->interface;
Packit 9795e1
    usbredirparser_send_alt_setting_status(host->parser, id, &status);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_get_alt_setting(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_get_alt_setting_header *get_alt_setting)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    struct usb_redir_alt_setting_status_header status;
Packit 9795e1
    int i;
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        status.status = usb_redir_ioerror;
Packit 9795e1
        status.alt = -1;
Packit 9795e1
        goto exit;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    i = usbredirhost_bInterfaceNumber_to_index(host,
Packit 9795e1
                                               get_alt_setting->interface);
Packit 9795e1
    if (i >= 0) {
Packit 9795e1
        status.status = usb_redir_success;
Packit 9795e1
        status.alt = host->alt_setting[i];
Packit 9795e1
    } else {
Packit 9795e1
        status.status = usb_redir_inval;
Packit 9795e1
        status.alt = -1;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
exit:
Packit 9795e1
    status.interface = get_alt_setting->interface;
Packit 9795e1
    usbredirparser_send_alt_setting_status(host->parser, id, &status);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_start_iso_stream(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_start_iso_stream_header *start_iso_stream)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    uint8_t ep = start_iso_stream->endpoint;
Packit 9795e1
Packit 9795e1
    usbredirhost_alloc_stream(host, id, ep, usb_redir_type_iso,
Packit 9795e1
                              start_iso_stream->pkts_per_urb,
Packit 9795e1
                              host->endpoint[EP2I(ep)].max_packetsize,
Packit 9795e1
                              start_iso_stream->no_urbs, 1);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_stop_iso_stream(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_stop_iso_stream_header *stop_iso_stream)
Packit 9795e1
{
Packit 9795e1
    usbredirhost_stop_stream(priv, id, stop_iso_stream->endpoint);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_start_interrupt_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_start_interrupt_receiving_header *start_interrupt_receiving)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    uint8_t ep = start_interrupt_receiving->endpoint;
Packit 9795e1
Packit 9795e1
    usbredirhost_alloc_stream(host, id, ep, usb_redir_type_interrupt, 1,
Packit 9795e1
                              host->endpoint[EP2I(ep)].max_packetsize,
Packit 9795e1
                              INTERRUPT_TRANSFER_COUNT, 1);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_stop_interrupt_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_stop_interrupt_receiving_header *stop_interrupt_receiving)
Packit 9795e1
{
Packit 9795e1
    usbredirhost_stop_stream(priv, id, stop_interrupt_receiving->endpoint);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000103
Packit 9795e1
static int usbredirhost_ep_mask_to_eps(uint32_t ep_mask, unsigned char *eps)
Packit 9795e1
{
Packit 9795e1
    int i, j;
Packit 9795e1
Packit 9795e1
    for (i = 0, j = 0; i < MAX_ENDPOINTS; i++) {
Packit 9795e1
        if (ep_mask & (1 << i))
Packit 9795e1
            eps[j++] = I2EP(i);
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    return j;
Packit 9795e1
}
Packit 9795e1
#endif
Packit 9795e1
Packit 9795e1
static void usbredirhost_alloc_bulk_streams(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_alloc_bulk_streams_header *alloc_bulk_streams)
Packit 9795e1
{
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000103
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    unsigned char eps[MAX_ENDPOINTS];
Packit 9795e1
    int r, no_eps;
Packit 9795e1
    struct usb_redir_bulk_streams_status_header streams_status = {
Packit 9795e1
        .endpoints = alloc_bulk_streams->endpoints,
Packit 9795e1
        .no_streams = alloc_bulk_streams->no_streams,
Packit 9795e1
        .status = usb_redir_success,
Packit 9795e1
    };
Packit 9795e1
Packit 9795e1
    no_eps = usbredirhost_ep_mask_to_eps(alloc_bulk_streams->endpoints, eps);
Packit 9795e1
    r = libusb_alloc_streams(host->handle, alloc_bulk_streams->no_streams,
Packit 9795e1
                             eps, no_eps);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        ERROR("could not alloc bulk streams: %s", libusb_error_name(r));
Packit 9795e1
        streams_status.status =
Packit 9795e1
            libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
    } else if (r < alloc_bulk_streams->no_streams) {
Packit 9795e1
        ERROR("tried to alloc %u bulk streams but got only %d",
Packit 9795e1
              alloc_bulk_streams->no_streams, r);
Packit 9795e1
        streams_status.status = usb_redir_ioerror;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirparser_send_bulk_streams_status(host->parser, id, &streams_status);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
#endif
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_free_bulk_streams(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_free_bulk_streams_header *free_bulk_streams)
Packit 9795e1
{
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000103
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    unsigned char eps[MAX_ENDPOINTS];
Packit 9795e1
    int r, no_eps;
Packit 9795e1
    struct usb_redir_bulk_streams_status_header streams_status = {
Packit 9795e1
        .endpoints = free_bulk_streams->endpoints,
Packit 9795e1
        .no_streams = 0,
Packit 9795e1
        .status = usb_redir_success,
Packit 9795e1
    };
Packit 9795e1
Packit 9795e1
    no_eps = usbredirhost_ep_mask_to_eps(free_bulk_streams->endpoints, eps);
Packit 9795e1
    r = libusb_free_streams(host->handle, eps, no_eps);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        ERROR("could not free bulk streams: %s", libusb_error_name(r));
Packit 9795e1
        streams_status.status =
Packit 9795e1
            libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirparser_send_bulk_streams_status(host->parser, id, &streams_status);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
#endif
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_filter_reject(void *priv)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
Packit 9795e1
    if (host->disconnected)
Packit 9795e1
        return;
Packit 9795e1
Packit 9795e1
    INFO("device rejected");
Packit 9795e1
    host->read_status = usbredirhost_read_device_rejected;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_filter_filter(void *priv,
Packit 9795e1
    struct usbredirfilter_rule *rules, int rules_count)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
Packit 9795e1
    free(host->filter_rules);
Packit 9795e1
    host->filter_rules = rules;
Packit 9795e1
    host->filter_rules_count = rules_count;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_device_disconnect_ack(void *priv)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
Packit 9795e1
    if (!host->wait_disconnect) {
Packit 9795e1
        ERROR("error received disconnect ack without sending a disconnect");
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->wait_disconnect = 0;
Packit 9795e1
Packit 9795e1
    if (host->connect_pending)
Packit 9795e1
        usbredirhost_send_device_connect(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_start_bulk_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_start_bulk_receiving_header *start_bulk_receiving)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    uint8_t ep = start_bulk_receiving->endpoint;
Packit 9795e1
Packit 9795e1
    usbredirhost_alloc_stream(host, id, ep, usb_redir_type_bulk, 1,
Packit 9795e1
                              start_bulk_receiving->bytes_per_transfer,
Packit 9795e1
                              start_bulk_receiving->no_transfers, 1);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_stop_bulk_receiving(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_stop_bulk_receiving_header *stop_bulk_receiving)
Packit 9795e1
{
Packit 9795e1
    usbredirhost_stop_stream(priv, id, stop_bulk_receiving->endpoint);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
static void usbredirhost_cancel_data_packet(void *priv, uint64_t id)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    struct usbredirtransfer *t;
Packit 9795e1
    struct usb_redir_control_packet_header   control_packet;
Packit 9795e1
    struct usb_redir_bulk_packet_header      bulk_packet;
Packit 9795e1
    struct usb_redir_interrupt_packet_header interrupt_packet;
Packit 9795e1
Packit 9795e1
    /*
Packit 9795e1
     * This is a bit tricky, we are run from a parser read callback, while
Packit 9795e1
     * at the same time the packet completion callback may run from another
Packit 9795e1
     * thread.
Packit 9795e1
     *
Packit 9795e1
     * Since the completion handler will remove the transfer from our list,
Packit 9795e1
     * send it back to the usb-guest (which we don't want to do twice),
Packit 9795e1
     * and *free* the transfer, we must do the libusb_cancel_transfer()
Packit 9795e1
     * with the lock held to ensure that it is not freed while we try to
Packit 9795e1
     * cancel it.
Packit 9795e1
     *
Packit 9795e1
     * Doing this means libusb taking the transfer lock, while
Packit 9795e1
     * we are holding our own lock, this is ok, since libusb releases the
Packit 9795e1
     * transfer lock before calling the packet completion callback, so there
Packit 9795e1
     * is no deadlock here.
Packit 9795e1
     */
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
    for (t = host->transfers_head.next; t; t = t->next) {
Packit 9795e1
        /* After cancellation the guest may re-use the id, so skip already
Packit 9795e1
           cancelled packets */
Packit 9795e1
        if (!t->cancelled && t->id == id) {
Packit 9795e1
            break;
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /*
Packit 9795e1
     * Note not finding the transfer is not an error, the transfer may have
Packit 9795e1
     * completed by the time we receive the cancel.
Packit 9795e1
     */
Packit 9795e1
    if (t) {
Packit 9795e1
        t->cancelled = 1;
Packit 9795e1
        libusb_cancel_transfer(t->transfer);
Packit 9795e1
        switch(t->transfer->type) {
Packit 9795e1
        case LIBUSB_TRANSFER_TYPE_CONTROL:
Packit 9795e1
            control_packet = t->control_packet;
Packit 9795e1
            control_packet.status = usb_redir_cancelled;
Packit 9795e1
            control_packet.length = 0;
Packit 9795e1
            usbredirparser_send_control_packet(host->parser, t->id,
Packit 9795e1
                                               &control_packet, NULL, 0);
Packit 9795e1
            DEBUG("cancelled control packet ep %02x id %"PRIu64,
Packit 9795e1
                  control_packet.endpoint, id);
Packit 9795e1
            break;
Packit 9795e1
        case LIBUSB_TRANSFER_TYPE_BULK:
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000103
Packit 9795e1
        case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
Packit 9795e1
#endif
Packit 9795e1
            bulk_packet = t->bulk_packet;
Packit 9795e1
            bulk_packet.status = usb_redir_cancelled;
Packit 9795e1
            bulk_packet.length = 0;
Packit 9795e1
            bulk_packet.length_high = 0;
Packit 9795e1
            usbredirparser_send_bulk_packet(host->parser, t->id,
Packit 9795e1
                                               &bulk_packet, NULL, 0);
Packit 9795e1
            DEBUG("cancelled bulk packet ep %02x id %"PRIu64,
Packit 9795e1
                  bulk_packet.endpoint, id);
Packit 9795e1
            break;
Packit 9795e1
        case LIBUSB_TRANSFER_TYPE_INTERRUPT:
Packit 9795e1
            interrupt_packet = t->interrupt_packet;
Packit 9795e1
            interrupt_packet.status = usb_redir_cancelled;
Packit 9795e1
            interrupt_packet.length = 0;
Packit 9795e1
            usbredirparser_send_interrupt_packet(host->parser, t->id,
Packit 9795e1
                                                 &interrupt_packet, NULL, 0);
Packit 9795e1
            DEBUG("cancelled interrupt packet ep %02x id %"PRIu64,
Packit 9795e1
                  interrupt_packet.endpoint, id);
Packit 9795e1
            break;
Packit 9795e1
        }
Packit 9795e1
    } else
Packit 9795e1
        DEBUG("cancel packet id %"PRIu64" not found", id);
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void LIBUSB_CALL usbredirhost_control_packet_complete(
Packit 9795e1
    struct libusb_transfer *libusb_transfer)
Packit 9795e1
{
Packit 9795e1
    struct usb_redir_control_packet_header control_packet;
Packit 9795e1
    struct usbredirtransfer *transfer = libusb_transfer->user_data;
Packit 9795e1
    struct usbredirhost *host = transfer->host;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
Packit 9795e1
    control_packet = transfer->control_packet;
Packit 9795e1
    control_packet.status = libusb_status_or_error_to_redir_status(host,
Packit 9795e1
                                                  libusb_transfer->status);
Packit 9795e1
    control_packet.length = libusb_transfer->actual_length;
Packit 9795e1
Packit 9795e1
    DEBUG("control complete ep %02X status %d len %d id %"PRIu64,
Packit 9795e1
          control_packet.endpoint, control_packet.status,
Packit 9795e1
          control_packet.length, transfer->id);
Packit 9795e1
Packit 9795e1
    if (!transfer->cancelled) {
Packit 9795e1
        if (control_packet.endpoint & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
            usbredirhost_log_data(host, "ctrl data in:",
Packit 9795e1
                         libusb_transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
Packit 9795e1
                         libusb_transfer->actual_length);
Packit 9795e1
            usbredirparser_send_control_packet(host->parser, transfer->id,
Packit 9795e1
                                               &control_packet,
Packit 9795e1
                                               libusb_transfer->buffer +
Packit 9795e1
                                                   LIBUSB_CONTROL_SETUP_SIZE,
Packit 9795e1
                                               libusb_transfer->actual_length);
Packit 9795e1
        } else {
Packit 9795e1
            usbredirparser_send_control_packet(host->parser, transfer->id,
Packit 9795e1
                                               &control_packet, NULL, 0);
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_remove_and_free_transfer(transfer);
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_send_control_status(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, struct usb_redir_control_packet_header *control_packet,
Packit 9795e1
    uint8_t status)
Packit 9795e1
{
Packit 9795e1
    control_packet->status = status;
Packit 9795e1
    control_packet->length = 0;
Packit 9795e1
    usbredirparser_send_control_packet(host->parser, id, control_packet,
Packit 9795e1
                                       NULL, 0);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_control_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_control_packet_header *control_packet,
Packit 9795e1
    uint8_t *data, int data_len)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    uint8_t ep = control_packet->endpoint;
Packit 9795e1
    struct usbredirtransfer *transfer;
Packit 9795e1
    unsigned char *buffer;
Packit 9795e1
    int r;
Packit 9795e1
Packit 9795e1
    DEBUG("control submit ep %02X len %d id %"PRIu64, ep,
Packit 9795e1
          control_packet->length, id);
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        usbredirhost_send_control_status(host, id, control_packet,
Packit 9795e1
                                         usb_redir_ioerror);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* Verify endpoint type */
Packit 9795e1
    if (host->endpoint[EP2I(ep)].type != usb_redir_type_control) {
Packit 9795e1
        ERROR("error control packet on non control ep %02X", ep);
Packit 9795e1
        usbredirhost_send_control_status(host, id, control_packet,
Packit 9795e1
                                         usb_redir_inval);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->reset = 0;
Packit 9795e1
Packit 9795e1
    /* If it is a clear stall, we need to do an actual clear stall, rather then
Packit 9795e1
       just forward the control packet, so that the usbhost usbstack knows
Packit 9795e1
       the stall is cleared */
Packit 9795e1
    if (control_packet->requesttype == LIBUSB_RECIPIENT_ENDPOINT &&
Packit 9795e1
            control_packet->request == LIBUSB_REQUEST_CLEAR_FEATURE &&
Packit 9795e1
            control_packet->value == 0x00 && data_len == 0) {
Packit 9795e1
        r = libusb_clear_halt(host->handle, control_packet->index);
Packit 9795e1
        r = libusb_status_or_error_to_redir_status(host, r);
Packit 9795e1
        DEBUG("clear halt ep %02X status %d", control_packet->index, r);
Packit 9795e1
        usbredirhost_send_control_status(host, id, control_packet, r);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + control_packet->length);
Packit 9795e1
    if (!buffer) {
Packit 9795e1
        ERROR("out of memory allocating transfer buffer, dropping packet");
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    transfer = usbredirhost_alloc_transfer(host, 0);
Packit 9795e1
    if (!transfer) {
Packit 9795e1
        free(buffer);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    libusb_fill_control_setup(buffer,
Packit 9795e1
                              control_packet->requesttype,
Packit 9795e1
                              control_packet->request,
Packit 9795e1
                              control_packet->value,
Packit 9795e1
                              control_packet->index,
Packit 9795e1
                              control_packet->length);
Packit 9795e1
Packit 9795e1
    if (!(ep & LIBUSB_ENDPOINT_IN)) {
Packit 9795e1
        usbredirhost_log_data(host, "ctrl data out:", data, data_len);
Packit 9795e1
        memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, data_len);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    libusb_fill_control_transfer(transfer->transfer, host->handle, buffer,
Packit 9795e1
                                 usbredirhost_control_packet_complete,
Packit 9795e1
                                 transfer, CTRL_TIMEOUT);
Packit 9795e1
    transfer->id = id;
Packit 9795e1
    transfer->control_packet = *control_packet;
Packit 9795e1
Packit 9795e1
    usbredirhost_add_transfer(host, transfer);
Packit 9795e1
Packit 9795e1
    r = libusb_submit_transfer(transfer->transfer);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        ERROR("error submitting control transfer on ep %02X: %s",
Packit 9795e1
              ep, libusb_error_name(r));
Packit 9795e1
        transfer->transfer->actual_length = 0;
Packit 9795e1
        transfer->transfer->status = r;
Packit 9795e1
        usbredirhost_control_packet_complete(transfer->transfer);
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void LIBUSB_CALL usbredirhost_bulk_packet_complete(
Packit 9795e1
    struct libusb_transfer *libusb_transfer)
Packit 9795e1
{
Packit 9795e1
    struct usb_redir_bulk_packet_header bulk_packet;
Packit 9795e1
    struct usbredirtransfer *transfer = libusb_transfer->user_data;
Packit 9795e1
    struct usbredirhost *host = transfer->host;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
Packit 9795e1
    bulk_packet = transfer->bulk_packet;
Packit 9795e1
    bulk_packet.status = libusb_status_or_error_to_redir_status(host,
Packit 9795e1
                                                  libusb_transfer->status);
Packit 9795e1
    bulk_packet.length = libusb_transfer->actual_length;
Packit 9795e1
    bulk_packet.length_high = libusb_transfer->actual_length >> 16;
Packit 9795e1
Packit 9795e1
    DEBUG("bulk complete ep %02X status %d len %d id %"PRIu64,
Packit 9795e1
          bulk_packet.endpoint, bulk_packet.status,
Packit 9795e1
          libusb_transfer->actual_length, transfer->id);
Packit 9795e1
Packit 9795e1
    if (!transfer->cancelled) {
Packit 9795e1
        if (bulk_packet.endpoint & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
            usbredirhost_log_data(host, "bulk data in:",
Packit 9795e1
                                  libusb_transfer->buffer,
Packit 9795e1
                                  libusb_transfer->actual_length);
Packit 9795e1
            usbredirparser_send_bulk_packet(host->parser, transfer->id,
Packit 9795e1
                                            &bulk_packet,
Packit 9795e1
                                            libusb_transfer->buffer,
Packit 9795e1
                                            libusb_transfer->actual_length);
Packit 9795e1
        } else {
Packit 9795e1
            usbredirparser_send_bulk_packet(host->parser, transfer->id,
Packit 9795e1
                                            &bulk_packet, NULL, 0);
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_remove_and_free_transfer(transfer);
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_send_bulk_status(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, struct usb_redir_bulk_packet_header *bulk_packet,
Packit 9795e1
    uint8_t status)
Packit 9795e1
{
Packit 9795e1
    bulk_packet->status = status;
Packit 9795e1
    bulk_packet->length = 0;
Packit 9795e1
    bulk_packet->length_high = 0;
Packit 9795e1
    usbredirparser_send_bulk_packet(host->parser, id, bulk_packet, NULL, 0);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_bulk_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_bulk_packet_header *bulk_packet,
Packit 9795e1
    uint8_t *data, int data_len)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    uint8_t ep = bulk_packet->endpoint;
Packit 9795e1
    int len = (bulk_packet->length_high << 16) | bulk_packet->length;
Packit 9795e1
    struct usbredirtransfer *transfer;
Packit 9795e1
    int r;
Packit 9795e1
Packit 9795e1
    DEBUG("bulk submit ep %02X len %d id %"PRIu64, ep, len, id);
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        usbredirhost_send_bulk_status(host, id, bulk_packet,
Packit 9795e1
                                      usb_redir_ioerror);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].type != usb_redir_type_bulk) {
Packit 9795e1
        ERROR("error bulk packet on non bulk ep %02X", ep);
Packit 9795e1
        usbredirhost_send_bulk_status(host, id, bulk_packet, usb_redir_inval);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (ep & LIBUSB_ENDPOINT_IN) {
Packit 9795e1
        data = malloc(len);
Packit 9795e1
        if (!data) {
Packit 9795e1
            ERROR("out of memory allocating bulk buffer, dropping packet");
Packit 9795e1
            return;
Packit 9795e1
        }
Packit 9795e1
    } else {
Packit 9795e1
        usbredirhost_log_data(host, "bulk data out:", data, data_len);
Packit 9795e1
        /* Note no memcpy, we can re-use the data buffer the parser
Packit 9795e1
           malloc-ed for us and expects us to free */
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    transfer = usbredirhost_alloc_transfer(host, 0);
Packit 9795e1
    if (!transfer) {
Packit 9795e1
        free(data);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->reset = 0;
Packit 9795e1
Packit 9795e1
    if (bulk_packet->stream_id) {
Packit 9795e1
#if LIBUSBX_API_VERSION >= 0x01000103
Packit 9795e1
        libusb_fill_bulk_stream_transfer(transfer->transfer, host->handle, ep,
Packit 9795e1
                                         bulk_packet->stream_id, data, len,
Packit 9795e1
                                         usbredirhost_bulk_packet_complete,
Packit 9795e1
                                         transfer, BULK_TIMEOUT);
Packit 9795e1
#else
Packit 9795e1
        r = LIBUSB_ERROR_INVALID_PARAM;
Packit 9795e1
        free(data);
Packit 9795e1
        goto error;
Packit 9795e1
#endif
Packit 9795e1
    } else {
Packit 9795e1
        libusb_fill_bulk_transfer(transfer->transfer, host->handle, ep,
Packit 9795e1
                                  data, len, usbredirhost_bulk_packet_complete,
Packit 9795e1
                                  transfer, BULK_TIMEOUT);
Packit 9795e1
    }
Packit 9795e1
    transfer->id = id;
Packit 9795e1
    transfer->bulk_packet = *bulk_packet;
Packit 9795e1
Packit 9795e1
    usbredirhost_add_transfer(host, transfer);
Packit 9795e1
Packit 9795e1
    r = libusb_submit_transfer(transfer->transfer);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
#if LIBUSBX_API_VERSION < 0x01000103
Packit 9795e1
error:
Packit 9795e1
#endif
Packit 9795e1
        ERROR("error submitting bulk transfer on ep %02X: %s",
Packit 9795e1
              ep, libusb_error_name(r));
Packit 9795e1
        transfer->transfer->actual_length = 0;
Packit 9795e1
        transfer->transfer->status = r;
Packit 9795e1
        usbredirhost_bulk_packet_complete(transfer->transfer);
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_iso_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_iso_packet_header *iso_packet,
Packit 9795e1
    uint8_t *data, int data_len)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    uint8_t ep = iso_packet->endpoint;
Packit 9795e1
    struct usbredirtransfer *transfer;
Packit 9795e1
    int i, j, status = usb_redir_success;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        status = usb_redir_ioerror;
Packit 9795e1
        goto leave;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].type != usb_redir_type_iso) {
Packit 9795e1
        ERROR("error received iso packet for non iso ep %02X", ep);
Packit 9795e1
        status = usb_redir_inval;
Packit 9795e1
        goto leave;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].transfer_count == 0) {
Packit 9795e1
        ERROR("error received iso out packet for non started iso stream");
Packit 9795e1
        status = usb_redir_inval;
Packit 9795e1
        goto leave;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (data_len > host->endpoint[EP2I(ep)].max_packetsize) {
Packit 9795e1
        ERROR("error received iso out packet is larger than wMaxPacketSize");
Packit 9795e1
        status = usb_redir_inval;
Packit 9795e1
        goto leave;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].drop_packets) {
Packit 9795e1
        host->endpoint[EP2I(ep)].drop_packets--;
Packit 9795e1
        goto leave;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    i = host->endpoint[EP2I(ep)].out_idx;
Packit 9795e1
    transfer = host->endpoint[EP2I(ep)].transfer[i];
Packit 9795e1
    j = transfer->packet_idx;
Packit 9795e1
    if (j == SUBMITTED_IDX) {
Packit 9795e1
        DEBUG("overflow of iso out queue on ep: %02X, dropping packet", ep);
Packit 9795e1
        /* Since we're interupting the stream anyways, drop enough packets to
Packit 9795e1
           get back to our target buffer size */
Packit 9795e1
        host->endpoint[EP2I(ep)].drop_packets =
Packit 9795e1
                     (host->endpoint[EP2I(ep)].pkts_per_transfer *
Packit 9795e1
                      host->endpoint[EP2I(ep)].transfer_count) / 2;
Packit 9795e1
        goto leave;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    /* Store the id of the first packet in the urb */
Packit 9795e1
    if (j == 0) {
Packit 9795e1
        transfer->id = id;
Packit 9795e1
    }
Packit 9795e1
    memcpy(libusb_get_iso_packet_buffer(transfer->transfer, j),
Packit 9795e1
           data, data_len);
Packit 9795e1
    transfer->transfer->iso_packet_desc[j].length = data_len;
Packit 9795e1
    DEBUG("iso-in queue ep %02X urb %d pkt %d len %d id %"PRIu64,
Packit 9795e1
           ep, i, j, data_len, transfer->id);
Packit 9795e1
Packit 9795e1
    j++;
Packit 9795e1
    transfer->packet_idx = j;
Packit 9795e1
    if (j == host->endpoint[EP2I(ep)].pkts_per_transfer) {
Packit 9795e1
        i = (i + 1) % host->endpoint[EP2I(ep)].transfer_count;
Packit 9795e1
        host->endpoint[EP2I(ep)].out_idx = i;
Packit 9795e1
        j = 0;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].stream_started) {
Packit 9795e1
        if (transfer->packet_idx ==
Packit 9795e1
                host->endpoint[EP2I(ep)].pkts_per_transfer) {
Packit 9795e1
            usbredirhost_submit_stream_transfer_unlocked(host, transfer);
Packit 9795e1
        }
Packit 9795e1
    } else {
Packit 9795e1
        /* We've not started the stream (submitted some transfers) yet,
Packit 9795e1
           do so once we have half our buffers filled */
Packit 9795e1
        int available = i * host->endpoint[EP2I(ep)].pkts_per_transfer + j;
Packit 9795e1
        int needed = (host->endpoint[EP2I(ep)].pkts_per_transfer *
Packit 9795e1
                      host->endpoint[EP2I(ep)].transfer_count) / 2;
Packit 9795e1
        if (available == needed) {
Packit 9795e1
            DEBUG("iso-in starting stream on ep %02X", ep);
Packit 9795e1
            usbredirhost_start_stream_unlocked(host, ep);
Packit 9795e1
        }
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
leave:
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
    usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
    if (status != usb_redir_success) {
Packit 9795e1
        usbredirhost_send_stream_status(host, id, ep, status);
Packit 9795e1
    }
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void LIBUSB_CALL usbredirhost_interrupt_out_packet_complete(
Packit 9795e1
    struct libusb_transfer *libusb_transfer)
Packit 9795e1
{
Packit 9795e1
    struct usbredirtransfer *transfer = libusb_transfer->user_data;
Packit 9795e1
    struct usb_redir_interrupt_packet_header interrupt_packet;
Packit 9795e1
    struct usbredirhost *host = transfer->host;
Packit 9795e1
Packit 9795e1
    LOCK(host);
Packit 9795e1
Packit 9795e1
    interrupt_packet = transfer->interrupt_packet;
Packit 9795e1
    interrupt_packet.status = libusb_status_or_error_to_redir_status(host,
Packit 9795e1
                                                    libusb_transfer->status);
Packit 9795e1
    interrupt_packet.length = libusb_transfer->actual_length;
Packit 9795e1
Packit 9795e1
    DEBUG("interrupt out complete ep %02X status %d len %d id %"PRIu64,
Packit 9795e1
          interrupt_packet.endpoint, interrupt_packet.status,
Packit 9795e1
          interrupt_packet.length, transfer->id);
Packit 9795e1
Packit 9795e1
    if (!transfer->cancelled) {
Packit 9795e1
        usbredirparser_send_interrupt_packet(host->parser, transfer->id,
Packit 9795e1
                                             &interrupt_packet, NULL, 0);
Packit 9795e1
    }
Packit 9795e1
    usbredirhost_remove_and_free_transfer(transfer);
Packit 9795e1
    UNLOCK(host);
Packit 9795e1
    FLUSH(host);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_send_interrupt_status(struct usbredirhost *host,
Packit 9795e1
    uint64_t id, struct usb_redir_interrupt_packet_header *interrupt_packet,
Packit 9795e1
    uint8_t status)
Packit 9795e1
{
Packit 9795e1
    interrupt_packet->status = status;
Packit 9795e1
    interrupt_packet->length = 0;
Packit 9795e1
    usbredirparser_send_interrupt_packet(host->parser, id, interrupt_packet,
Packit 9795e1
                                         NULL, 0);
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
static void usbredirhost_interrupt_packet(void *priv, uint64_t id,
Packit 9795e1
    struct usb_redir_interrupt_packet_header *interrupt_packet,
Packit 9795e1
    uint8_t *data, int data_len)
Packit 9795e1
{
Packit 9795e1
    struct usbredirhost *host = priv;
Packit 9795e1
    uint8_t ep = interrupt_packet->endpoint;
Packit 9795e1
    struct usbredirtransfer *transfer;
Packit 9795e1
    int r;
Packit 9795e1
Packit 9795e1
    DEBUG("interrupt submit ep %02X len %d id %"PRIu64, ep,
Packit 9795e1
          interrupt_packet->length, id);
Packit 9795e1
Packit 9795e1
    if (host->disconnected) {
Packit 9795e1
        usbredirhost_send_interrupt_status(host, id, interrupt_packet,
Packit 9795e1
                                           usb_redir_ioerror);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (host->endpoint[EP2I(ep)].type != usb_redir_type_interrupt) {
Packit 9795e1
        ERROR("error received interrupt packet for non interrupt ep %02X", ep);
Packit 9795e1
        usbredirhost_send_interrupt_status(host, id, interrupt_packet,
Packit 9795e1
                                           usb_redir_inval);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    if (data_len > host->endpoint[EP2I(ep)].max_packetsize) {
Packit 9795e1
        ERROR("error received interrupt out packet is larger than wMaxPacketSize");
Packit 9795e1
        usbredirhost_send_interrupt_status(host, id, interrupt_packet,
Packit 9795e1
                                           usb_redir_inval);
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        FLUSH(host);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    usbredirhost_log_data(host, "interrupt data out:", data, data_len);
Packit 9795e1
Packit 9795e1
    /* Note no memcpy, we can re-use the data buffer the parser
Packit 9795e1
       malloc-ed for us and expects us to free */
Packit 9795e1
Packit 9795e1
    transfer = usbredirhost_alloc_transfer(host, 0);
Packit 9795e1
    if (!transfer) {
Packit 9795e1
        usbredirparser_free_packet_data(host->parser, data);
Packit 9795e1
        return;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    host->reset = 0;
Packit 9795e1
Packit 9795e1
    libusb_fill_interrupt_transfer(transfer->transfer, host->handle, ep,
Packit 9795e1
        data, data_len, usbredirhost_interrupt_out_packet_complete,
Packit 9795e1
        transfer, INTERRUPT_TIMEOUT);
Packit 9795e1
    transfer->id = id;
Packit 9795e1
    transfer->interrupt_packet = *interrupt_packet;
Packit 9795e1
Packit 9795e1
    usbredirhost_add_transfer(host, transfer);
Packit 9795e1
Packit 9795e1
    r = libusb_submit_transfer(transfer->transfer);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        ERROR("error submitting interrupt transfer on ep %02X: %s",
Packit 9795e1
              ep, libusb_error_name(r));
Packit 9795e1
        transfer->transfer->actual_length = 0;
Packit 9795e1
        transfer->transfer->status = r;
Packit 9795e1
        usbredirhost_interrupt_out_packet_complete(transfer->transfer);
Packit 9795e1
    }
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
/**************************************************************************/
Packit 9795e1
Packit 9795e1
void usbredirhost_get_guest_filter(struct usbredirhost *host,
Packit 9795e1
    const struct usbredirfilter_rule **rules_ret, int *rules_count_ret)
Packit 9795e1
{
Packit 9795e1
    *rules_ret = host->filter_rules;
Packit 9795e1
    *rules_count_ret = host->filter_rules_count;
Packit 9795e1
}
Packit 9795e1
Packit 9795e1
int usbredirhost_check_device_filter(const struct usbredirfilter_rule *rules,
Packit 9795e1
    int rules_count, libusb_device *dev, int flags)
Packit 9795e1
{
Packit 9795e1
    int i, r, num_interfaces;
Packit 9795e1
    struct libusb_device_descriptor dev_desc;
Packit 9795e1
    struct libusb_config_descriptor *config = NULL;
Packit 9795e1
    uint8_t interface_class[MAX_INTERFACES];
Packit 9795e1
    uint8_t interface_subclass[MAX_INTERFACES];
Packit 9795e1
    uint8_t interface_protocol[MAX_INTERFACES];
Packit 9795e1
Packit 9795e1
    r = libusb_get_device_descriptor(dev, &dev_desc);
Packit 9795e1
    if (r < 0) {
Packit 9795e1
        if (r == LIBUSB_ERROR_NO_MEM)
Packit 9795e1
            return -ENOMEM;
Packit 9795e1
        return -EIO;
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    r = libusb_get_active_config_descriptor(dev, &config);
Packit 9795e1
    if (r < 0 && r != LIBUSB_ERROR_NOT_FOUND) {
Packit 9795e1
        if (r == LIBUSB_ERROR_NO_MEM)
Packit 9795e1
            return -ENOMEM;
Packit 9795e1
        return -EIO;
Packit 9795e1
    }
Packit 9795e1
    if (config == NULL) {
Packit 9795e1
        return usbredirfilter_check(rules, rules_count, dev_desc.bDeviceClass,
Packit 9795e1
                    dev_desc.bDeviceSubClass, dev_desc.bDeviceProtocol,
Packit 9795e1
                    NULL, NULL, NULL, 0,
Packit 9795e1
                    dev_desc.idVendor, dev_desc.idProduct,
Packit 9795e1
                    dev_desc.bcdDevice, flags);
Packit 9795e1
    }
Packit 9795e1
Packit 9795e1
    num_interfaces = config->bNumInterfaces;
Packit 9795e1
    for (i = 0; i < num_interfaces; i++) {
Packit 9795e1
        const struct libusb_interface_descriptor *intf_desc =
Packit 9795e1
            config->interface[i].altsetting;
Packit 9795e1
        interface_class[i] = intf_desc->bInterfaceClass;
Packit 9795e1
        interface_subclass[i] = intf_desc->bInterfaceSubClass;
Packit 9795e1
        interface_protocol[i] = intf_desc->bInterfaceProtocol;
Packit 9795e1
    }
Packit 9795e1
    libusb_free_config_descriptor(config);
Packit 9795e1
Packit 9795e1
    return usbredirfilter_check(rules, rules_count, dev_desc.bDeviceClass,
Packit 9795e1
                dev_desc.bDeviceSubClass, dev_desc.bDeviceProtocol,
Packit 9795e1
                interface_class, interface_subclass, interface_protocol,
Packit 9795e1
                num_interfaces, dev_desc.idVendor, dev_desc.idProduct,
Packit 9795e1
                dev_desc.bcdDevice, flags);
Packit 9795e1
}