|
@@ -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] */
|