static int copy_interface(struct usb_interface *dest, const struct libusb_interface *src) { int i; int num_altsetting = src->num_altsetting; size_t alloc_size = sizeof(struct usb_interface_descriptor) * num_altsetting; dest->num_altsetting = num_altsetting; dest->altsetting = malloc(alloc_size); if (!dest->altsetting) return -ENOMEM; memset(dest->altsetting, 0, alloc_size); for (i = 0; i < num_altsetting; i++) { int r = copy_interface_descriptor(dest->altsetting + i, &src->altsetting[i]); if (r < 0) { clear_interface(dest); return r; } } return 0; }
static void clear_config_descriptor(struct usb_config_descriptor *config) { if (config->extra) free(config->extra); if (config->interface) { int i; for (i = 0; i < config->bNumInterfaces; i++) clear_interface(config->interface + i); free(config->interface); } }
static void clear_configuration(struct libusb_config_descriptor *config) { if (config->interface) { int i; for (i = 0; i < config->bNumInterfaces; i++) clear_interface((struct libusb_interface *) config->interface + i); free((void *) config->interface); } if (config->extra) free((void *) config->extra); }
static int parse_interface(libusb_context *ctx, struct libusb_interface *usb_interface, unsigned char *buffer, int size, int host_endian) { int i; int len; int r; int parsed = 0; int tmp; struct usb_descriptor_header header; struct libusb_interface_descriptor *ifp; unsigned char *begin; usb_interface->num_altsetting = 0; while (size >= INTERFACE_DESC_LENGTH) { struct libusb_interface_descriptor *altsetting = (struct libusb_interface_descriptor *) usb_interface->altsetting; altsetting = realloc(altsetting, sizeof(struct libusb_interface_descriptor) * (usb_interface->num_altsetting + 1)); if (!altsetting) { r = LIBUSB_ERROR_NO_MEM; goto err; } usb_interface->altsetting = altsetting; ifp = altsetting + usb_interface->num_altsetting; usb_interface->num_altsetting++; usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0); ifp->extra = NULL; ifp->extra_length = 0; ifp->endpoint = NULL; /* Skip over the interface */ buffer += ifp->bLength; parsed += ifp->bLength; size -= ifp->bLength; begin = buffer; /* Skip over any interface, class or vendor descriptors */ while (size >= DESC_HEADER_LENGTH) { usbi_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength < 2) { usbi_err(ctx, "invalid descriptor of length %d", header.bLength); r = LIBUSB_ERROR_IO; goto err; } /* If we find another "proper" descriptor then we're done */ if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || (header.bDescriptorType == LIBUSB_DT_ENDPOINT) || (header.bDescriptorType == LIBUSB_DT_CONFIG) || (header.bDescriptorType == LIBUSB_DT_DEVICE)) break; buffer += header.bLength; parsed += header.bLength; size -= header.bLength; } /* Copy any unknown descriptors into a storage area for */ /* drivers to later parse */ len = (int)(buffer - begin); if (len) { ifp->extra = malloc(len); if (!ifp->extra) { r = LIBUSB_ERROR_NO_MEM; goto err; } memcpy((unsigned char *) ifp->extra, begin, len); ifp->extra_length = len; } /* Did we hit an unexpected descriptor? */ usbi_parse_descriptor(buffer, "bb", &header, 0); if ((size >= DESC_HEADER_LENGTH) && ((header.bDescriptorType == LIBUSB_DT_CONFIG) || (header.bDescriptorType == LIBUSB_DT_DEVICE))) return parsed; if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints); r = LIBUSB_ERROR_IO; goto err; } if (ifp->bNumEndpoints > 0) { struct libusb_endpoint_descriptor *endpoint; tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor); endpoint = malloc(tmp); ifp->endpoint = endpoint; if (!endpoint) { r = LIBUSB_ERROR_NO_MEM; goto err; } memset(endpoint, 0, tmp); for (i = 0; i < ifp->bNumEndpoints; i++) { usbi_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength > size) { usbi_err(ctx, "ran out of descriptors parsing"); r = LIBUSB_ERROR_IO; goto err; } r = parse_endpoint(ctx, endpoint + i, buffer, size, host_endian); if (r < 0) goto err; buffer += r; parsed += r; size -= r; } } /* We check to see if it's an alternate to this one */ ifp = (struct libusb_interface_descriptor *) buffer; if (size < LIBUSB_DT_INTERFACE_SIZE || ifp->bDescriptorType != LIBUSB_DT_INTERFACE || !ifp->bAlternateSetting) return parsed; } return parsed; err: clear_interface(usb_interface); return r; }