static int usb_parse_configuration(struct device *ddev, int cfgidx, struct usb_host_config *config, unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; int cfgno; int nintf, nintf_orig; int i, j, n; struct usb_interface_cache *intfc; unsigned char *buffer2; int size2; struct usb_descriptor_header *header; int len, retval; u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; unsigned iad_num = 0; memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); if (config->desc.bDescriptorType != USB_DT_CONFIG || config->desc.bLength < USB_DT_CONFIG_SIZE) { dev_err(ddev, "invalid descriptor for config index %d: " "type = 0x%X, length = %d\n", cfgidx, config->desc.bDescriptorType, config->desc.bLength); return -EINVAL; } cfgno = config->desc.bConfigurationValue; buffer += config->desc.bLength; size -= config->desc.bLength; nintf = nintf_orig = config->desc.bNumInterfaces; if (nintf > USB_MAXINTERFACES) { dev_warn(ddev, "config %d has too many interfaces: %d, " "using maximum allowed: %d\n", cfgno, nintf, USB_MAXINTERFACES); nintf = USB_MAXINTERFACES; } /* Go through the descriptors, checking their length and counting the * number of altsettings for each interface */ n = 0; for ((buffer2 = buffer, size2 = size); size2 > 0; (buffer2 += header->bLength, size2 -= header->bLength)) { if (size2 < sizeof(struct usb_descriptor_header)) { dev_warn(ddev, "config %d descriptor has %d excess " "byte%s, ignoring\n", cfgno, size2, plural(size2)); break; } header = (struct usb_descriptor_header *) buffer2; if ((header->bLength > size2) || (header->bLength < 2)) { dev_warn(ddev, "config %d has an invalid descriptor " "of length %d, skipping remainder of the config\n", cfgno, header->bLength); break; } if (header->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *d; int inum; d = (struct usb_interface_descriptor *) header; if (d->bLength < USB_DT_INTERFACE_SIZE) { dev_warn(ddev, "config %d has an invalid " "interface descriptor of length %d, " "skipping\n", cfgno, d->bLength); continue; } inum = d->bInterfaceNumber; if (inum >= nintf_orig) dev_warn(ddev, "config %d has an invalid " "interface number: %d but max is %d\n", cfgno, inum, nintf_orig - 1); /* Have we already encountered this interface? * Count its altsettings */ for (i = 0; i < n; ++i) { if (inums[i] == inum) break; } if (i < n) { if (nalts[i] < 255) ++nalts[i]; } else if (n < USB_MAXINTERFACES) { inums[n] = inum; nalts[n] = 1; ++n; } } else if (header->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) { if (iad_num == USB_MAXIADS) { dev_warn(ddev, "found more Interface " "Association Descriptors " "than allocated for in " "configuration %d\n", cfgno); } else { config->intf_assoc[iad_num] = (struct usb_interface_assoc_descriptor *)header; iad_num++; } } else if (header->bDescriptorType == USB_DT_DEVICE || header->bDescriptorType == USB_DT_CONFIG) dev_warn(ddev, "config %d contains an unexpected " "descriptor of type 0x%X, skipping\n", cfgno, header->bDescriptorType); } /* for ((buffer2 = buffer, size2 = size); ...) */ size = buffer2 - buffer; config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0); if (n != nintf) dev_warn(ddev, "config %d has %d interface%s, different from " "the descriptor's value: %d\n", cfgno, n, plural(n), nintf_orig); else if (n == 0) dev_warn(ddev, "config %d has no interfaces?\n", cfgno); config->desc.bNumInterfaces = nintf = n; /* Check for missing interface numbers */ for (i = 0; i < nintf; ++i) { for (j = 0; j < nintf; ++j) { if (inums[j] == i) break; } if (j >= nintf) dev_warn(ddev, "config %d has no interface number " "%d\n", cfgno, i); } /* Allocate the usb_interface_caches and altsetting arrays */ for (i = 0; i < nintf; ++i) { j = nalts[i]; if (j > USB_MAXALTSETTING) { dev_warn(ddev, "too many alternate settings for " "config %d interface %d: %d, " "using maximum allowed: %d\n", cfgno, inums[i], j, USB_MAXALTSETTING); nalts[i] = j = USB_MAXALTSETTING; } len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); if (!intfc) return -ENOMEM; kref_init(&intfc->ref); } /* Skip over any Class Specific or Vendor Specific descriptors; * find the first interface descriptor */ config->extra = buffer; i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, USB_DT_INTERFACE, &n); config->extralen = i; if (n > 0) dev_dbg(ddev, "skipped %d descriptor%s after %s\n", n, plural(n), "configuration"); buffer += i; size -= i; /* Parse all the interface/altsetting descriptors */ while (size > 0) { retval = usb_parse_interface(ddev, cfgno, config, buffer, size, inums, nalts); if (retval < 0) return retval; buffer += retval; size -= retval; } /* Check for missing altsettings */ for (i = 0; i < nintf; ++i) { intfc = config->intf_cache[i]; for (j = 0; j < intfc->num_altsetting; ++j) { for (n = 0; n < intfc->num_altsetting; ++n) { if (intfc->altsetting[n].desc. bAlternateSetting == j) break; } if (n >= intfc->num_altsetting) dev_warn(ddev, "config %d interface %d has no " "altsetting %d\n", cfgno, inums[i], j); } } return 0; }
int usb_parse_configuration( usb_config_descriptor *config, char *buffer) { int i; int retval; int size; usb_descriptor_header *header; memcpy( config, buffer, USB_DT_CONFIG_SIZE); size = config->wTotalLength; if (config->bNumInterfaces > USB_MAXINTERFACES) { printf( "too many interfaces\n"); return -1; } config->interface = (usb_interface *) malloc( config->bNumInterfaces * sizeof(usb_interface)); if (!config->interface) { printf( "malloc\n"); return -1; } memset( config->interface, 0, config->bNumInterfaces * sizeof(usb_interface)); buffer += config->bLength; size -= config->bLength; // Skip over the rest of the Class or Vendor Specific descriptors for (i = 0; i < config->bNumInterfaces; i++) { char *begin; begin = buffer; while (size >= sizeof(usb_descriptor_header)) { header = (usb_descriptor_header *)buffer; if ((header->bLength > size) || (header->bLength < 2)) { printf( "invalid descriptor length of %d\n", header->bLength); return -1; } // If we find another "proper" descriptor then we're done if ((header->bDescriptorType == USB_DT_ENDPOINT) || (header->bDescriptorType == USB_DT_INTERFACE) || (header->bDescriptorType == USB_DT_CONFIG) || (header->bDescriptorType == USB_DT_DEVICE)) break; buffer += header->bLength; size -= header->bLength; } retval = usb_parse_interface(config->interface + i, buffer, size); if (retval < 0) return retval; buffer += retval; size -= retval; } return size; }
int usb_parse_configuration(struct usb_host_config *config, char *buffer) { int i, retval, size; struct usb_descriptor_header *header; memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); le16_to_cpus(&config->desc.wTotalLength); size = config->desc.wTotalLength; if (config->desc.bNumInterfaces > USB_MAXINTERFACES) { warn("too many interfaces"); return -1; } config->interface = (struct usb_interface *) kmalloc(config->desc.bNumInterfaces * sizeof(struct usb_interface), GFP_KERNEL); dbg("kmalloc IF %p, numif %i", config->interface, config->desc.bNumInterfaces); if (!config->interface) { err("out of memory"); return -1; } memset(config->interface, 0, config->desc.bNumInterfaces * sizeof(struct usb_interface)); buffer += config->desc.bLength; size -= config->desc.bLength; config->extra = NULL; config->extralen = 0; for (i = 0; i < config->desc.bNumInterfaces; i++) { int numskipped, len; char *begin; /* Skip over the rest of the Class Specific or Vendor */ /* Specific descriptors */ begin = buffer; numskipped = 0; while (size >= sizeof(struct usb_descriptor_header)) { header = (struct usb_descriptor_header *)buffer; if ((header->bLength > size) || (header->bLength < 2)) { err("invalid descriptor length of %d", header->bLength); return -1; } /* If we find another "proper" descriptor then we're done */ if ((header->bDescriptorType == USB_DT_ENDPOINT) || (header->bDescriptorType == USB_DT_INTERFACE) || (header->bDescriptorType == USB_DT_CONFIG) || (header->bDescriptorType == USB_DT_DEVICE)) break; dbg("skipping descriptor 0x%X", header->bDescriptorType); numskipped++; buffer += header->bLength; size -= header->bLength; } if (numskipped) dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); if (len) { if (config->extralen) { warn("extra config descriptor"); } else { config->extra = kmalloc(len, GFP_KERNEL); if (!config->extra) { err("couldn't allocate memory for config extra descriptors"); config->extralen = 0; return -1; } memcpy(config->extra, begin, len); config->extralen = len; } } retval = usb_parse_interface(config->interface + i, buffer, size); if (retval < 0) return retval; buffer += retval; size -= retval; } return size; }
int usb_parse_configuration(struct usb_config_descriptor *config, unsigned char *buffer) { int i, retval, size; struct usb_descriptor_header header; usb_parse_descriptor(buffer, "bbwbbbbb", config); size = config->wTotalLength; if (config->bNumInterfaces > USB_MAXINTERFACES) { if (usb_debug >= 1) fprintf(stderr, "too many interfaces\n"); return -1; } config->interface = (struct usb_interface *) malloc(config->bNumInterfaces * sizeof(struct usb_interface)); if (!config->interface) { if (usb_debug >= 1) fprintf(stderr, "out of memory\n"); return -1; } memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface)); buffer += config->bLength; size -= config->bLength; config->extra = NULL; config->extralen = 0; for (i = 0; i < config->bNumInterfaces; i++) { int numskipped, len; unsigned char *begin; /* Skip over the rest of the Class Specific or Vendor */ /* Specific descriptors */ begin = buffer; numskipped = 0; while (size >= DESC_HEADER_LENGTH) { usb_parse_descriptor(buffer, "bb", &header); if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { if (usb_debug >= 1) fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); return -1; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == USB_DT_ENDPOINT) || (header.bDescriptorType == USB_DT_INTERFACE) || (header.bDescriptorType == USB_DT_CONFIG) || (header.bDescriptorType == USB_DT_DEVICE)) break; if (usb_debug >= 2) fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); numskipped++; buffer += header.bLength; size -= header.bLength; } if (numskipped && usb_debug >= 2) fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); if (len) { /* FIXME: We should realloc and append here */ if (!config->extralen) { config->extra = malloc(len); if (!config->extra) { if (usb_debug >= 1) fprintf(stderr, "couldn't allocate memory for config extra descriptors\n"); config->extralen = 0; return -1; } memcpy(config->extra, begin, len); config->extralen = len; } } retval = usb_parse_interface(config->interface + i, buffer, size); if (retval < 0) return retval; buffer += retval; size -= retval; } return size; }