Blame 0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch

1b1995
From bcc4748db3e991fbaa032fe9c0726288a8f1008d Mon Sep 17 00:00:00 2001
1b1995
From: Hans de Goede <hdegoede@redhat.com>
1b1995
Date: Thu, 12 Jan 2012 16:54:04 +0100
1b1995
Subject: [PATCH 120/140] usb-redir: Add the posibility to filter out certain
1b1995
 devices from redirecion
1b1995
1b1995
This patch adds the posibility to filter out certain devices from redirecion.
1b1995
To use this pass the filter property to -device usb-redir.  The filter
1b1995
property takes a string consisting of filter rules, the format for a rule is:
1b1995
<class>:<vendor>:<product>:<version>:<allow>
1b1995
1b1995
-1 can be used to allow any value for a field.
1b1995
1b1995
Muliple rules can be concatonated using | as a separator. Note that if
1b1995
a device matches none of the passed in rules, redirecting it will not be
1b1995
allowed!
1b1995
1b1995
Example:
1b1995
-device usb-redir,filter='-1:0x0781:0x5567:-1:0|0x08:-1:-1:-1:1'
1b1995
1b1995
This example will deny the Sandisk Cruzer Blade being redirected, as it
1b1995
has a usb id of 0781:5567, it will allow any other usb mass storage devices,
1b1995
and it will deny any other devices (the default for devices not matching any
1b1995
of the rules.
1b1995
1b1995
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1b1995
---
1b1995
 configure   |    2 +-
1b1995
 usb-redir.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
1b1995
 2 files changed, 106 insertions(+), 11 deletions(-)
1b1995
1b1995
diff --git a/configure b/configure
1b1995
index 7ecf44e..c7e37df 100755
1b1995
--- a/configure
1b1995
+++ b/configure
1b1995
@@ -2541,7 +2541,7 @@ fi
1b1995
 
1b1995
 # check for usbredirparser for usb network redirection support
1b1995
 if test "$usb_redir" != "no" ; then
1b1995
-    if $pkg_config libusbredirparser >/dev/null 2>&1 ; then
1b1995
+    if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then
1b1995
         usb_redir="yes"
1b1995
         usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
1b1995
         usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
1b1995
diff --git a/usb-redir.c b/usb-redir.c
1b1995
index 6e92f14..85f40d6 100644
1b1995
--- a/usb-redir.c
1b1995
+++ b/usb-redir.c
1b1995
@@ -34,6 +34,7 @@
1b1995
 #include <sys/ioctl.h>
1b1995
 #include <signal.h>
1b1995
 #include <usbredirparser.h>
1b1995
+#include <usbredirfilter.h>
1b1995
 
1b1995
 #include "hw/usb.h"
1b1995
 
1b1995
@@ -72,6 +73,7 @@ struct USBRedirDevice {
1b1995
     /* Properties */
1b1995
     CharDriverState *cs;
1b1995
     uint8_t debug;
1b1995
+    char *filter_str;
1b1995
     /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
1b1995
     const uint8_t *read_buf;
1b1995
     int read_buf_size;
1b1995
@@ -84,6 +86,11 @@ struct USBRedirDevice {
1b1995
     struct endp_data endpoint[MAX_ENDPOINTS];
1b1995
     uint32_t packet_id;
1b1995
     QTAILQ_HEAD(, AsyncURB) asyncq;
1b1995
+    /* Data for device filtering */
1b1995
+    struct usb_redir_device_connect_header device_info;
1b1995
+    struct usb_redir_interface_info_header interface_info;
1b1995
+    struct usbredirfilter_rule *filter_rules;
1b1995
+    int filter_rules_count;
1b1995
 };
1b1995
 
1b1995
 struct AsyncURB {
1b1995
@@ -790,6 +797,7 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
1b1995
 static void usbredir_open_close_bh(void *opaque)
1b1995
 {
1b1995
     USBRedirDevice *dev = opaque;
1b1995
+    uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
1b1995
 
1b1995
     usbredir_device_disconnect(dev);
1b1995
 
1b1995
@@ -820,7 +828,9 @@ static void usbredir_open_close_bh(void *opaque)
1b1995
         dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
1b1995
         dev->read_buf = NULL;
1b1995
         dev->read_buf_size = 0;
1b1995
-        usbredirparser_init(dev->parser, VERSION, NULL, 0, 0);
1b1995
+
1b1995
+        usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
1b1995
+        usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
1b1995
         usbredirparser_do_write(dev->parser);
1b1995
     }
1b1995
 }
1b1995
@@ -908,6 +918,17 @@ static int usbredir_initfn(USBDevice *udev)
1b1995
         return -1;
1b1995
     }
1b1995
 
1b1995
+    if (dev->filter_str) {
1b1995
+        i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|",
1b1995
+                                           &dev->filter_rules,
1b1995
+                                           &dev->filter_rules_count);
1b1995
+        if (i) {
1b1995
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter",
1b1995
+                          "a usb device filter string");
1b1995
+            return -1;
1b1995
+        }
1b1995
+    }
1b1995
+
1b1995
     dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev);
1b1995
     dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
1b1995
 
1b1995
@@ -956,6 +977,44 @@ static void usbredir_handle_destroy(USBDevice *udev)
1b1995
     if (dev->parser) {
1b1995
         usbredirparser_destroy(dev->parser);
1b1995
     }
1b1995
+
1b1995
+    free(dev->filter_rules);
1b1995
+}
1b1995
+
1b1995
+static int usbredir_check_filter(USBRedirDevice *dev)
1b1995
+{
1b1995
+    if (dev->interface_info.interface_count == 0) {
1b1995
+        ERROR("No interface info for device\n");
1b1995
+        return -1;
1b1995
+    }
1b1995
+
1b1995
+    if (dev->filter_rules) {
1b1995
+        if (!usbredirparser_peer_has_cap(dev->parser,
1b1995
+                                    usb_redir_cap_connect_device_version)) {
1b1995
+            ERROR("Device filter specified and peer does not have the "
1b1995
+                  "connect_device_version capability\n");
1b1995
+            return -1;
1b1995
+        }
1b1995
+
1b1995
+        if (usbredirfilter_check(
1b1995
+                dev->filter_rules,
1b1995
+                dev->filter_rules_count,
1b1995
+                dev->device_info.device_class,
1b1995
+                dev->device_info.device_subclass,
1b1995
+                dev->device_info.device_protocol,
1b1995
+                dev->interface_info.interface_class,
1b1995
+                dev->interface_info.interface_subclass,
1b1995
+                dev->interface_info.interface_protocol,
1b1995
+                dev->interface_info.interface_count,
1b1995
+                dev->device_info.vendor_id,
1b1995
+                dev->device_info.product_id,
1b1995
+                dev->device_info.device_version_bcd,
1b1995
+                0) != 0) {
1b1995
+            return -1;
1b1995
+        }
1b1995
+    }
1b1995
+
1b1995
+    return 0;
1b1995
 }
1b1995
 
1b1995
 /*
1b1995
@@ -984,6 +1043,7 @@ static void usbredir_device_connect(void *priv,
1b1995
     struct usb_redir_device_connect_header *device_connect)
1b1995
 {
1b1995
     USBRedirDevice *dev = priv;
1b1995
+    const char *speed;
1b1995
 
1b1995
     if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
1b1995
         ERROR("Received device connect while already connected\n");
1b1995
@@ -992,26 +1052,48 @@ static void usbredir_device_connect(void *priv,
1b1995
 
1b1995
     switch (device_connect->speed) {
1b1995
     case usb_redir_speed_low:
1b1995
-        DPRINTF("attaching low speed device\n");
1b1995
+        speed = "low speed";
1b1995
         dev->dev.speed = USB_SPEED_LOW;
1b1995
         break;
1b1995
     case usb_redir_speed_full:
1b1995
-        DPRINTF("attaching full speed device\n");
1b1995
+        speed = "full speed";
1b1995
         dev->dev.speed = USB_SPEED_FULL;
1b1995
         break;
1b1995
     case usb_redir_speed_high:
1b1995
-        DPRINTF("attaching high speed device\n");
1b1995
+        speed = "high speed";
1b1995
         dev->dev.speed = USB_SPEED_HIGH;
1b1995
         break;
1b1995
     case usb_redir_speed_super:
1b1995
-        DPRINTF("attaching super speed device\n");
1b1995
+        speed = "super speed";
1b1995
         dev->dev.speed = USB_SPEED_SUPER;
1b1995
         break;
1b1995
     default:
1b1995
-        DPRINTF("attaching unknown speed device, assuming full speed\n");
1b1995
+        speed = "unknown speed";
1b1995
         dev->dev.speed = USB_SPEED_FULL;
1b1995
     }
1b1995
+
1b1995
+    if (usbredirparser_peer_has_cap(dev->parser,
1b1995
+                                    usb_redir_cap_connect_device_version)) {
1b1995
+        INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
1b1995
+             speed, device_connect->vendor_id, device_connect->product_id,
1b1995
+             device_connect->device_version_bcd >> 8,
1b1995
+             device_connect->device_version_bcd & 0xff,
1b1995
+             device_connect->device_class);
1b1995
+    } else {
1b1995
+        INFO("attaching %s device %04x:%04x class %02x\n", speed,
1b1995
+             device_connect->vendor_id, device_connect->product_id,
1b1995
+             device_connect->device_class);
1b1995
+    }
1b1995
+
1b1995
     dev->dev.speedmask = (1 << dev->dev.speed);
1b1995
+    dev->device_info = *device_connect;
1b1995
+
1b1995
+    if (usbredir_check_filter(dev)) {
1b1995
+        WARNING("Device %04x:%04x rejected by device filter, not attaching\n",
1b1995
+                device_connect->vendor_id, device_connect->product_id);
1b1995
+        return;
1b1995
+    }
1b1995
+
1b1995
     qemu_mod_timer(dev->attach_timer, dev->next_attach_time);
1b1995
 }
1b1995
 
1b1995
@@ -1038,15 +1120,27 @@ static void usbredir_device_disconnect(void *priv)
1b1995
     for (i = 0; i < MAX_ENDPOINTS; i++) {
1b1995
         QTAILQ_INIT(&dev->endpoint[i].bufpq);
1b1995
     }
1b1995
+    dev->interface_info.interface_count = 0;
1b1995
 }
1b1995
 
1b1995
 static void usbredir_interface_info(void *priv,
1b1995
     struct usb_redir_interface_info_header *interface_info)
1b1995
 {
1b1995
-    /* The intention is to allow specifying acceptable interface classes
1b1995
-       for redirection on the cmdline and in the future verify this here,
1b1995
-       and disconnect (or never connect) the device if a not accepted
1b1995
-       interface class is detected */
1b1995
+    USBRedirDevice *dev = priv;
1b1995
+
1b1995
+    dev->interface_info = *interface_info;
1b1995
+
1b1995
+    /*
1b1995
+     * If we receive interface info after the device has already been
1b1995
+     * connected (ie on a set_config), re-check the filter.
1b1995
+     */
1b1995
+    if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
1b1995
+        if (usbredir_check_filter(dev)) {
1b1995
+            ERROR("Device no longer matches filter after interface info "
1b1995
+                  "change, disconnecting!\n");
1b1995
+            usbredir_device_disconnect(dev);
1b1995
+        }
1b1995
+    }
1b1995
 }
1b1995
 
1b1995
 static void usbredir_ep_info(void *priv,
1b1995
@@ -1356,6 +1450,7 @@ static struct USBDeviceInfo usbredir_dev_info = {
1b1995
     .qdev.props     = (Property[]) {
1b1995
         DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
1b1995
         DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
1b1995
+        DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
1b1995
         DEFINE_PROP_END_OF_LIST(),
1b1995
     },
1b1995
 };
1b1995
-- 
1b1995
1.7.9.3
1b1995