diff options
-rw-r--r-- | drivers/usb/misc/usbtest.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index e7235d5cce85..1c78e747f72b 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -606,6 +606,28 @@ static int is_good_config(struct usbtest_dev *tdev, int len) return 0; } +static int is_good_ext(struct usbtest_dev *tdev, u8 *buf) +{ + struct usb_ext_cap_descriptor *ext; + u32 attr; + + ext = (struct usb_ext_cap_descriptor *) buf; + + if (ext->bLength != USB_DT_USB_EXT_CAP_SIZE) { + ERROR(tdev, "bogus usb 2.0 extension descriptor length\n"); + return 0; + } + + attr = le32_to_cpu(ext->bmAttributes); + /* bits[1:4] is used and others are reserved */ + if (attr & ~0x1e) { /* reserved == 0 */ + ERROR(tdev, "reserved bits set\n"); + return 0; + } + + return 1; +} + /* sanity test for standard requests working with usb_control_mesg() and some * of the utility functions which use it. * @@ -694,12 +716,67 @@ static int ch9_postconfig(struct usbtest_dev *dev) * 3.0 spec */ if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0300) { + struct usb_bos_descriptor *bos = NULL; + struct usb_dev_cap_header *header = NULL; + unsigned total, num, length; + u8 *buf; + retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf, sizeof(*udev->bos->desc)); if (retval != sizeof(*udev->bos->desc)) { dev_err(&iface->dev, "bos descriptor --> %d\n", retval); return (retval < 0) ? retval : -EDOM; } + + bos = (struct usb_bos_descriptor *)dev->buf; + total = le16_to_cpu(bos->wTotalLength); + num = bos->bNumDeviceCaps; + + if (total > TBUF_SIZE) + total = TBUF_SIZE; + + /* + * get generic device-level capability descriptors [9.6.2] + * in USB 3.0 spec + */ + retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf, + total); + if (retval != total) { + dev_err(&iface->dev, "bos descriptor set --> %d\n", + retval); + return (retval < 0) ? retval : -EDOM; + } + + length = sizeof(*udev->bos->desc); + buf = dev->buf; + for (i = 0; i < num; i++) { + buf += length; + if (buf + sizeof(struct usb_dev_cap_header) > + dev->buf + total) + break; + + header = (struct usb_dev_cap_header *)buf; + length = header->bLength; + + if (header->bDescriptorType != + USB_DT_DEVICE_CAPABILITY) { + dev_warn(&udev->dev, "not device capability descriptor, skip\n"); + continue; + } + + switch (header->bDevCapabilityType) { + case USB_CAP_TYPE_EXT: + if (buf + USB_DT_USB_EXT_CAP_SIZE > + dev->buf + total || + !is_good_ext(dev, buf)) { + dev_err(&iface->dev, "bogus usb 2.0 extension descriptor\n"); + return -EDOM; + } + break; + default: + break; + } + } } /* there's always [9.4.3] at least one config descriptor [9.6.3] */ |