Index: sys/dev/usb/uaudio.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/uaudio.c,v retrieving revision 1.168 diff -u -r1.168 uaudio.c --- sys/dev/usb/uaudio.c 10 Jan 2021 15:50:16 -0000 1.168 +++ sys/dev/usb/uaudio.c 29 Jan 2021 19:36:18 -0000 @@ -1532,52 +1532,63 @@ int size, const usb_interface_descriptor_t *id) #define offs (*offsp) { - const struct usb_audio_streaming_interface_descriptor *asid; - const struct usb_audio_streaming_type1_descriptor *asf1d; - const usb_endpoint_descriptor_audio_t *ed; - const usb_endpoint_descriptor_audio_t *epdesc1; - const struct usb_audio_streaming_endpoint_descriptor *sed; + const struct usb_audio_streaming_interface_descriptor *asid = NULL; + const struct usb_audio_streaming_type1_descriptor *asf1d = NULL; + const usb_endpoint_descriptor_audio_t *ed = NULL; + const usb_endpoint_descriptor_audio_t *epdesc1 = NULL; + const struct usb_audio_streaming_endpoint_descriptor *sed = NULL; + const usb_descriptor_t *desc = NULL; int format, chan __unused, prec, enc; int dir, type, sync; struct as_info ai; const char *format_str __unused; - asid = (const void *)(tbuf + offs); - if (asid->bDescriptorType != UDESC_CS_INTERFACE || - asid->bDescriptorSubtype != AS_GENERAL) + while (offs < size) { + desc = (const void *)(tbuf + offs); + + if (desc->bDescriptorType == UDESC_CS_INTERFACE && + desc->bDescriptorSubtype == AS_GENERAL) { + asid = (const void *)desc; + offs += asid->bLength; + } else if (desc->bDescriptorType == UDESC_CS_INTERFACE && + desc->bDescriptorSubtype == FORMAT_TYPE) { + asf1d = (const void *)desc; + offs += asf1d->bLength; + } else if (desc->bDescriptorType == UDESC_ENDPOINT) { + ed = (const void *)desc; + offs += ed->bLength; + } else if (desc->bDescriptorType == UDESC_CS_ENDPOINT && + desc->bDescriptorSubtype == AS_GENERAL) { + sed = (const void *)desc; + offs += sed->bLength; + } else if (ed != NULL && id->bNumEndpoints > 1 && + desc->bDescriptorType == UDESC_ENDPOINT) { + epdesc1 = (const void*)desc; + offs += epdesc1->bLength; + } else + break; + } + + if (asid == NULL || asf1d == NULL || ed == NULL || sed == NULL || + (id->bNumEndpoints > 1 && epdesc1 == NULL)) return USBD_INVAL; + + format = UGETW(asid->wFormatTag); DPRINTF("asid: bTerminalLink=%d wFormatTag=%d\n", asid->bTerminalLink, UGETW(asid->wFormatTag)); - offs += asid->bLength; - if (offs > size) - return USBD_INVAL; - - asf1d = (const void *)(tbuf + offs); - if (asf1d->bDescriptorType != UDESC_CS_INTERFACE || - asf1d->bDescriptorSubtype != FORMAT_TYPE) - return USBD_INVAL; - offs += asf1d->bLength; - if (offs > size) - return USBD_INVAL; if (asf1d->bFormatType != FORMAT_TYPE_I) { aprint_normal_dev(sc->sc_dev, - "ignored setting with type %d format\n", UGETW(asid->wFormatTag)); + "ignored setting with type %d format\n", format); return USBD_NORMAL_COMPLETION; } - ed = (const void *)(tbuf + offs); - if (ed->bDescriptorType != UDESC_ENDPOINT) - return USBD_INVAL; DPRINTF("endpoint[0] bLength=%d bDescriptorType=%d " "bEndpointAddress=%d bmAttributes=%#x wMaxPacketSize=%d " "bInterval=%d bRefresh=%d bSynchAddress=%d\n", ed->bLength, ed->bDescriptorType, ed->bEndpointAddress, ed->bmAttributes, UGETW(ed->wMaxPacketSize), ed->bInterval, ed->bRefresh, ed->bSynchAddress); - offs += ed->bLength; - if (offs > size) - return USBD_INVAL; if (UE_GET_XFERTYPE(ed->bmAttributes) != UE_ISOCHRONOUS) return USBD_INVAL; @@ -1606,14 +1617,7 @@ #endif } - sed = (const void *)(tbuf + offs); - if (sed->bDescriptorType != UDESC_CS_ENDPOINT || - sed->bDescriptorSubtype != AS_GENERAL) - return USBD_INVAL; DPRINTF(" streadming_endpoint: offset=%d bLength=%d\n", offs, sed->bLength); - offs += sed->bLength; - if (offs > size) - return USBD_INVAL; #ifdef UAUDIO_MULTIPLE_ENDPOINTS if (sync && id->bNumEndpoints <= 1) { @@ -1627,11 +1631,7 @@ "non sync-pipe endpoint but multiple endpoints\n"); return USBD_INVAL; } - epdesc1 = NULL; if (id->bNumEndpoints > 1) { - epdesc1 = (const void*)(tbuf + offs); - if (epdesc1->bDescriptorType != UDESC_ENDPOINT) - return USBD_INVAL; DPRINTF("endpoint[1] bLength=%d " "bDescriptorType=%d bEndpointAddress=%d " "bmAttributes=%#x wMaxPacketSize=%d bInterval=%d " @@ -1640,9 +1640,6 @@ epdesc1->bEndpointAddress, epdesc1->bmAttributes, UGETW(epdesc1->wMaxPacketSize), epdesc1->bInterval, epdesc1->bRefresh, epdesc1->bSynchAddress); - offs += epdesc1->bLength; - if (offs > size) - return USBD_INVAL; if (epdesc1->bSynchAddress != 0) { aprint_error_dev(sc->sc_dev, "invalid endpoint: bSynchAddress=0\n"); @@ -1665,7 +1662,6 @@ /* UE_GET_ADDR(epdesc1->bEndpointAddress), and epdesc1->bRefresh */ } - format = UGETW(asid->wFormatTag); chan = asf1d->bNrChannels; prec = asf1d->bBitResolution; if (prec != 8 && prec != 16 && prec != 24) {