Commit c3d3c472 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: Code improvements for core/config.c

This patch makes some improvements to the code in config.c.

	Create a subroutine to handle the repeated task of skipping
	forward to the next descriptor of a certain type.

	Remove some fairly useless debugging messages (they could
	never even have been enabled in the pre-as221 code).

	Verify that endpoint descriptors don't have an address
	equal to 0 (as well as not being above 15).

	Rename some local variables so they are a little more
	consistent and meaningful.

Despite all the changes, the functionality should remain the same.
Please apply.
parent e51bf644
...@@ -17,14 +17,38 @@ ...@@ -17,14 +17,38 @@
#define USB_MAXCONFIG 8 /* Arbitrary limit */ #define USB_MAXCONFIG 8 /* Arbitrary limit */
static int find_next_descriptor(unsigned char *buffer, int size,
int dt1, int dt2, int *num_skipped)
{
struct usb_descriptor_header *h;
int n = 0;
unsigned char *buffer0 = buffer;
/* Find the next descriptor of type dt1 or dt2 */
while (size >= sizeof(struct usb_descriptor_header)) {
h = (struct usb_descriptor_header *) buffer;
if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2)
break;
buffer += h->bLength;
size -= h->bLength;
++n;
}
/* Store the number of descriptors skipped and return the
* number of bytes skipped */
if (num_skipped)
*num_skipped = n;
return buffer - buffer0;
}
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
int asnum, struct usb_host_endpoint *endpoint, int asnum, struct usb_host_endpoint *endpoint,
unsigned char *buffer, int size) unsigned char *buffer, int size)
{ {
unsigned char *buffer0 = buffer; unsigned char *buffer0 = buffer;
struct usb_descriptor_header *header; struct usb_descriptor_header *header;
unsigned char *begin; int n, i;
int numskipped;
header = (struct usb_descriptor_header *)buffer; header = (struct usb_descriptor_header *)buffer;
if (header->bDescriptorType != USB_DT_ENDPOINT) { if (header->bDescriptorType != USB_DT_ENDPOINT) {
...@@ -47,7 +71,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -47,7 +71,8 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
return -EINVAL; return -EINVAL;
} }
if ((endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK) >= 16) { i = endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;
if (i >= 16 || i == 0) {
dev_err(ddev, "config %d interface %d altsetting %d has an " dev_err(ddev, "config %d interface %d altsetting %d has an "
"invalid endpoint with address 0x%X\n", "invalid endpoint with address 0x%X\n",
cfgno, inum, asnum, endpoint->desc.bEndpointAddress); cfgno, inum, asnum, endpoint->desc.bEndpointAddress);
...@@ -59,32 +84,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -59,32 +84,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
buffer += header->bLength; buffer += header->bLength;
size -= header->bLength; size -= header->bLength;
/* Skip over any Class Specific or Vendor Specific descriptors */ /* Skip over any Class Specific or Vendor Specific descriptors;
begin = buffer; * find the next endpoint or interface descriptor */
numskipped = 0; endpoint->extra = buffer;
while (size >= sizeof(struct usb_descriptor_header)) { i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
header = (struct usb_descriptor_header *)buffer; USB_DT_INTERFACE, &n);
endpoint->extralen = i;
/* If we find another "proper" descriptor then we're done */ if (n > 0)
if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE))
break;
dev_dbg(ddev, "skipping descriptor 0x%X\n",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped) {
dev_dbg(ddev, "skipped %d class/vendor specific endpoint " dev_dbg(ddev, "skipped %d class/vendor specific endpoint "
"descriptors\n", numskipped); "descriptors\n", n);
endpoint->extra = begin; return buffer - buffer0 + i;
endpoint->extralen = buffer - begin;
}
return buffer - buffer0;
} }
static void usb_free_intf(struct usb_interface *intf) static void usb_free_intf(struct usb_interface *intf)
...@@ -93,9 +102,9 @@ static void usb_free_intf(struct usb_interface *intf) ...@@ -93,9 +102,9 @@ static void usb_free_intf(struct usb_interface *intf)
if (intf->altsetting) { if (intf->altsetting) {
for (j = 0; j < intf->num_altsetting; j++) { for (j = 0; j < intf->num_altsetting; j++) {
struct usb_host_interface *as = &intf->altsetting[j]; struct usb_host_interface *alt = &intf->altsetting[j];
kfree(as->endpoint); kfree(alt->endpoint);
} }
kfree(intf->altsetting); kfree(intf->altsetting);
} }
...@@ -109,13 +118,14 @@ static int usb_parse_interface(struct device *ddev, int cfgno, ...@@ -109,13 +118,14 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
struct usb_interface_descriptor *d; struct usb_interface_descriptor *d;
int inum, asnum; int inum, asnum;
struct usb_interface *interface; struct usb_interface *interface;
struct usb_host_interface *ifp; struct usb_host_interface *alt;
int len, numskipped; int i, n;
struct usb_descriptor_header *header; int len, retval;
unsigned char *begin;
int i, retval;
d = (struct usb_interface_descriptor *) buffer; d = (struct usb_interface_descriptor *) buffer;
buffer += d->bLength;
size -= d->bLength;
if (d->bDescriptorType != USB_DT_INTERFACE) { if (d->bDescriptorType != USB_DT_INTERFACE) {
dev_err(ddev, "config %d has an unexpected descriptor of type " dev_err(ddev, "config %d has an unexpected descriptor of type "
"0x%X, expecting interface type 0x%X\n", "0x%X, expecting interface type 0x%X\n",
...@@ -124,21 +134,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno, ...@@ -124,21 +134,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
} }
inum = d->bInterfaceNumber; inum = d->bInterfaceNumber;
if (inum >= config->desc.bNumInterfaces) { if (inum >= config->desc.bNumInterfaces)
goto skip_to_next_interface_descriptor;
/* Skip to the next interface descriptor */
buffer += d->bLength;
size -= d->bLength;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *) buffer;
if (header->bDescriptorType == USB_DT_INTERFACE)
break;
buffer += header->bLength;
size -= header->bLength;
}
return buffer - buffer0;
}
interface = config->interface[inum]; interface = config->interface[inum];
asnum = d->bAlternateSetting; asnum = d->bAlternateSetting;
...@@ -149,57 +146,41 @@ static int usb_parse_interface(struct device *ddev, int cfgno, ...@@ -149,57 +146,41 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
return -EINVAL; return -EINVAL;
} }
ifp = &interface->altsetting[asnum]; alt = &interface->altsetting[asnum];
if (ifp->desc.bLength) { if (alt->desc.bLength) {
dev_err(ddev, "Duplicate descriptor for config %d " dev_err(ddev, "Duplicate descriptor for config %d "
"interface %d altsetting %d\n", cfgno, inum, asnum); "interface %d altsetting %d\n", cfgno, inum, asnum);
return -EINVAL; return -EINVAL;
} }
memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE);
buffer += d->bLength; /* Skip over any Class Specific or Vendor Specific descriptors;
size -= d->bLength; * find the first endpoint or interface descriptor */
alt->extra = buffer;
/* Skip over any Class Specific or Vendor Specific descriptors */ i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
begin = buffer; USB_DT_INTERFACE, &n);
numskipped = 0; alt->extralen = i;
while (size >= sizeof(struct usb_descriptor_header)) { if (n > 0)
header = (struct usb_descriptor_header *)buffer;
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_ENDPOINT))
break;
dev_dbg(ddev, "skipping descriptor 0x%X\n",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped) {
dev_dbg(ddev, "skipped %d class/vendor specific " dev_dbg(ddev, "skipped %d class/vendor specific "
"interface descriptors\n", numskipped); "interface descriptors\n", n);
ifp->extra = begin; buffer += i;
ifp->extralen = buffer - begin; size -= i;
}
if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) { if (alt->desc.bNumEndpoints > USB_MAXENDPOINTS) {
dev_err(ddev, "too many endpoints for config %d interface %d " dev_err(ddev, "too many endpoints for config %d interface %d "
"altsetting %d: %d, maximum allowed: %d\n", "altsetting %d: %d, maximum allowed: %d\n",
cfgno, inum, asnum, ifp->desc.bNumEndpoints, cfgno, inum, asnum, alt->desc.bNumEndpoints,
USB_MAXENDPOINTS); USB_MAXENDPOINTS);
return -EINVAL; return -EINVAL;
} }
len = ifp->desc.bNumEndpoints * sizeof(struct usb_host_endpoint); len = alt->desc.bNumEndpoints * sizeof(struct usb_host_endpoint);
ifp->endpoint = kmalloc(len, GFP_KERNEL); alt->endpoint = kmalloc(len, GFP_KERNEL);
if (!ifp->endpoint) if (!alt->endpoint)
return -ENOMEM; return -ENOMEM;
memset(ifp->endpoint, 0, len); memset(alt->endpoint, 0, len);
for (i = 0; i < ifp->desc.bNumEndpoints; i++) { for (i = 0; i < alt->desc.bNumEndpoints; i++) {
if (size < USB_DT_ENDPOINT_SIZE) { if (size < USB_DT_ENDPOINT_SIZE) {
dev_err(ddev, "too few endpoint descriptors for " dev_err(ddev, "too few endpoint descriptors for "
"config %d interface %d altsetting %d\n", "config %d interface %d altsetting %d\n",
...@@ -208,15 +189,19 @@ static int usb_parse_interface(struct device *ddev, int cfgno, ...@@ -208,15 +189,19 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
} }
retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, retval = usb_parse_endpoint(ddev, cfgno, inum, asnum,
ifp->endpoint + i, buffer, size); alt->endpoint + i, buffer, size);
if (retval < 0) if (retval < 0)
return retval; return retval;
buffer += retval; buffer += retval;
size -= retval; size -= retval;
} }
return buffer - buffer0; return buffer - buffer0;
skip_to_next_interface_descriptor:
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
USB_DT_INTERFACE, NULL);
return buffer - buffer0 + i;
} }
int usb_parse_configuration(struct device *ddev, int cfgidx, int usb_parse_configuration(struct device *ddev, int cfgidx,
...@@ -224,14 +209,12 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -224,14 +209,12 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
{ {
int cfgno; int cfgno;
int nintf, nintf_orig; int nintf, nintf_orig;
int i, j; int i, j, n;
struct usb_interface *interface; struct usb_interface *interface;
unsigned char *buffer2; unsigned char *buffer2;
int size2; int size2;
struct usb_descriptor_header *header; struct usb_descriptor_header *header;
int numskipped, len; int len, retval;
unsigned char *begin;
int retval;
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
if (config->desc.bDescriptorType != USB_DT_CONFIG || if (config->desc.bDescriptorType != USB_DT_CONFIG ||
...@@ -244,6 +227,9 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -244,6 +227,9 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
config->desc.wTotalLength = size; config->desc.wTotalLength = size;
cfgno = config->desc.bConfigurationValue; cfgno = config->desc.bConfigurationValue;
buffer += config->desc.bLength;
size -= config->desc.bLength;
nintf = nintf_orig = config->desc.bNumInterfaces; nintf = nintf_orig = config->desc.bNumInterfaces;
if (nintf > USB_MAXINTERFACES) { if (nintf > USB_MAXINTERFACES) {
dev_warn(ddev, "config %d has too many interfaces: %d, " dev_warn(ddev, "config %d has too many interfaces: %d, "
...@@ -255,7 +241,6 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -255,7 +241,6 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
for (i = 0; i < nintf; ++i) { for (i = 0; i < nintf; ++i) {
interface = config->interface[i] = interface = config->interface[i] =
kmalloc(sizeof(struct usb_interface), GFP_KERNEL); kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
dev_dbg(ddev, "kmalloc IF %p, numif %i\n", interface, i);
if (!interface) if (!interface)
return -ENOMEM; return -ENOMEM;
memset(interface, 0, sizeof(struct usb_interface)); memset(interface, 0, sizeof(struct usb_interface));
...@@ -263,10 +248,10 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -263,10 +248,10 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
/* Go through the descriptors, checking their length and counting the /* Go through the descriptors, checking their length and counting the
* number of altsettings for each interface */ * number of altsettings for each interface */
buffer2 = buffer; for ((buffer2 = buffer, size2 = size);
size2 = size; size2 >= sizeof(struct usb_descriptor_header);
j = 0; (buffer2 += header->bLength, size2 -= header->bLength)) {
while (size2 >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *) buffer2; header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) { if ((header->bLength > size2) || (header->bLength < 2)) {
dev_err(ddev, "config %d has an invalid descriptor " dev_err(ddev, "config %d has an invalid descriptor "
...@@ -277,13 +262,14 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -277,13 +262,14 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
if (header->bDescriptorType == USB_DT_INTERFACE) { if (header->bDescriptorType == USB_DT_INTERFACE) {
struct usb_interface_descriptor *d; struct usb_interface_descriptor *d;
if (header->bLength < USB_DT_INTERFACE_SIZE) { d = (struct usb_interface_descriptor *) header;
if (d->bLength < USB_DT_INTERFACE_SIZE) {
dev_err(ddev, "config %d has an invalid " dev_err(ddev, "config %d has an invalid "
"interface descriptor of length %d\n", "interface descriptor of length %d\n",
cfgno, header->bLength); cfgno, d->bLength);
return -EINVAL; return -EINVAL;
} }
d = (struct usb_interface_descriptor *) header;
i = d->bInterfaceNumber; i = d->bInterfaceNumber;
if (i >= nintf_orig) { if (i >= nintf_orig) {
dev_err(ddev, "config %d has an invalid " dev_err(ddev, "config %d has an invalid "
...@@ -294,21 +280,18 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -294,21 +280,18 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
if (i < nintf) if (i < nintf)
++config->interface[i]->num_altsetting; ++config->interface[i]->num_altsetting;
} else if ((header->bDescriptorType == USB_DT_DEVICE || } else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG) && j) { header->bDescriptorType == USB_DT_CONFIG) {
dev_err(ddev, "config %d contains an unexpected " dev_err(ddev, "config %d contains an unexpected "
"descriptor of type 0x%X\n", "descriptor of type 0x%X\n",
cfgno, header->bDescriptorType); cfgno, header->bDescriptorType);
return -EINVAL; return -EINVAL;
} }
j = 1; } /* for ((buffer2 = buffer, size2 = size); ...) */
buffer2 += header->bLength;
size2 -= header->bLength;
}
/* Allocate the altsetting arrays */ /* Allocate the altsetting arrays */
for (i = 0; i < config->desc.bNumInterfaces; ++i) { for (i = 0; i < nintf; ++i) {
interface = config->interface[i]; interface = config->interface[i];
if (interface->num_altsetting > USB_MAXALTSETTING) { if (interface->num_altsetting > USB_MAXALTSETTING) {
dev_err(ddev, "too many alternate settings for " dev_err(ddev, "too many alternate settings for "
...@@ -332,33 +315,17 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -332,33 +315,17 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
memset(interface->altsetting, 0, len); memset(interface->altsetting, 0, len);
} }
buffer += config->desc.bLength; /* Skip over any Class Specific or Vendor Specific descriptors;
size -= config->desc.bLength; * find the first interface descriptor */
config->extra = buffer;
/* Skip over any Class Specific or Vendor Specific descriptors */ i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
begin = buffer; USB_DT_INTERFACE, &n);
numskipped = 0; config->extralen = i;
while (size >= sizeof(struct usb_descriptor_header)) { if (n > 0)
header = (struct usb_descriptor_header *)buffer; dev_dbg(ddev, "skipped %d class/vendor specific "
"configuration descriptors\n", n);
/* If we find another "proper" descriptor then we're done */ buffer += i;
if ((header->bDescriptorType == USB_DT_ENDPOINT) || size -= i;
(header->bDescriptorType == USB_DT_INTERFACE))
break;
dev_dbg(ddev, "skipping descriptor 0x%X\n",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped) {
dev_dbg(ddev, "skipped %d class/vendor specific configuration "
"descriptors\n", numskipped);
config->extra = begin;
config->extralen = buffer - begin;
}
/* Parse all the interface/altsetting descriptors */ /* Parse all the interface/altsetting descriptors */
while (size >= sizeof(struct usb_descriptor_header)) { while (size >= sizeof(struct usb_descriptor_header)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment