summaryrefslogtreecommitdiff
path: root/class/audio
diff options
context:
space:
mode:
Diffstat (limited to 'class/audio')
-rw-r--r--class/audio/usbh_audio.c71
1 files changed, 49 insertions, 22 deletions
diff --git a/class/audio/usbh_audio.c b/class/audio/usbh_audio.c
index 5ef08c90..53fbcaa8 100644
--- a/class/audio/usbh_audio.c
+++ b/class/audio/usbh_audio.c
@@ -37,7 +37,8 @@ static int16_t volume_float2hex(float volume_db)
return (int16_t)(volume_db * 256);
}
-static float volume_roundf(float x) {
+static float volume_roundf(float x)
+{
if (x >= 0.0f) {
int intpart = (int)x;
float frac = x - (float)intpart;
@@ -367,12 +368,12 @@ intf_found:
}
static int usbh_audio_get_volume_info(struct usbh_audio *audio_class,
- uint8_t ch,
- int16_t *volume_cur,
- int16_t *volume_min,
- int16_t *volume_max,
- int16_t *volume_res,
- bool is_tx)
+ uint8_t ch,
+ int16_t *volume_cur,
+ int16_t *volume_min,
+ int16_t *volume_max,
+ int16_t *volume_res,
+ bool is_tx)
{
struct usb_setup_packet *setup;
int ret;
@@ -496,6 +497,10 @@ feature_found:
return ret;
}
+ if (volume_res <= 0 || volume_min > volume_max) {
+ return -USB_ERR_INVAL;
+ }
+
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = AUDIO_REQUEST_SET_CUR;
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
@@ -660,10 +665,15 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
hport->config.intf[intf].priv = audio_class;
p = hport->raw_config_desc;
- while (p[DESC_bLength]) {
+ while (desc_len < hport->config.config_desc.wTotalLength) {
switch (p[DESC_bDescriptorType]) {
case USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION:
cur_iface_count = p[3];
+
+ if ((cur_iface_count - 1) > CONFIG_USBHOST_AUDIO_MAX_STREAMS) {
+ USB_LOG_ERR("Audio stream %u exceeds max %u\r\n", (cur_iface_count - 1), CONFIG_USBHOST_AUDIO_MAX_STREAMS);
+ return -USB_ERR_INVAL;
+ }
break;
case USB_DESCRIPTOR_TYPE_INTERFACE:
cur_iface = p[INTF_DESC_bInterfaceNumber];
@@ -671,6 +681,7 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
break;
case USB_DESCRIPTOR_TYPE_ENDPOINT:
if (cur_iface == audio_class->ctrl_intf) {
+ /* ignore endpoint descriptor for control interface */
} else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
struct usb_endpoint_descriptor *ep_desc = (struct usb_endpoint_descriptor *)p;
if (ep_desc->bEndpointAddress & 0x80) {
@@ -682,14 +693,13 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
}
break;
case AUDIO_INTERFACE_DESCRIPTOR_TYPE:
- if (cur_iface_count == 0xff) {
- USB_LOG_ERR("Audio descriptor must have iad descriptor\r\n");
- return -USB_ERR_INVAL;
- }
-
if (cur_iface == audio_class->ctrl_intf) {
switch (p[DESC_bDescriptorSubType]) {
case AUDIO_CONTROL_HEADER: {
+ if (p[DESC_bLength] < sizeof(struct audio_cs_if_ac_header_descriptor)) {
+ return -USB_ERR_INVAL;
+ }
+
struct audio_cs_if_ac_header_descriptor *desc = (struct audio_cs_if_ac_header_descriptor *)p;
audio_class->bcdADC = desc->bcdADC;
audio_class->bInCollection = desc->bInCollection;
@@ -704,6 +714,10 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
} else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
switch (p[DESC_bDescriptorSubType]) {
case AUDIO_STREAMING_GENERAL: {
+ if (p[DESC_bLength] < sizeof(struct audio_cs_if_as_general_descriptor)) {
+ return -USB_ERR_INVAL;
+ }
+
struct audio_cs_if_as_general_descriptor *desc = (struct audio_cs_if_as_general_descriptor *)p;
/* all altsetting have the same general */
@@ -711,11 +725,18 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].bTerminalLink = desc->bTerminalLink;
} break;
case AUDIO_STREAMING_FORMAT_TYPE: {
+ if (p[DESC_bLength] < 8) {
+ return -USB_ERR_INVAL;
+ }
+
struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
- USB_ASSERT(desc->bSamFreqType <= CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM && desc->bSamFreqType > 0);
- USB_ASSERT(desc->bNrChannels <= CONFIG_USBHOST_AUDIO_MAX_CHANNELS);
- USB_ASSERT(cur_alt_setting < CONFIG_USBHOST_MAX_INTF_ALTSETTINGS);
+ if (desc->bSamFreqType == 0 ||
+ desc->bSamFreqType > CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM ||
+ desc->bNrChannels == 0 || desc->bNrChannels > CONFIG_USBHOST_AUDIO_MAX_CHANNELS ||
+ cur_alt_setting >= CONFIG_USBHOST_MAX_INTF_ALTSETTINGS) {
+ return -USB_ERR_INVAL;
+ }
audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].bNrChannels = desc->bNrChannels;
memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, AUDIO_SIZEOF_FORMAT_TYPE_DESC(desc->bSamFreqType));
@@ -728,6 +749,10 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
case AUDIO_ENDPOINT_DESCRIPTOR_TYPE:
if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
if (p[DESC_bDescriptorSubType] == AUDIO_ENDPOINT_GENERAL) {
+ if (p[DESC_bLength] < sizeof(struct audio_cs_ep_ep_general_descriptor)) {
+ return -USB_ERR_INVAL;
+ }
+
struct audio_cs_ep_ep_general_descriptor *desc = (struct audio_cs_ep_ep_general_descriptor *)p;
audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].ep_attr = desc->bmAttributes;
@@ -740,10 +765,6 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
/* skip to next descriptor */
desc_len += p[DESC_bLength];
p += p[DESC_bLength];
-
- if (desc_len > hport->config.config_desc.wTotalLength) {
- return -USB_ERR_INVAL;
- }
}
if (p_ac_desc == NULL) {
@@ -757,11 +778,17 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
USB_LOG_ERR("Fail to find feature unit for stream %s\r\n", audio_class->as_msg_table[i].is_tx ? "tx" : "rx");
return -USB_ERR_INVAL;
}
+
+ if ((feature_desc->bLength < 7) ||
+ (feature_desc->bLength > sizeof(struct audio_cs_if_ac_feature_unit_descriptor)) ||
+ (feature_desc->bControlSize != 1) ||
+ (feature_desc->bLength != (7 + feature_desc->bControlSize * (feature_desc->bNrChannels + 1)))) {
+ return -USB_ERR_INVAL;
+ }
+
audio_class->as_msg_table[i].feature_unit_id = feature_desc->bUnitID;
audio_class->as_msg_table[i].bControlSize = feature_desc->bControlSize;
- USB_ASSERT(feature_desc->bLength > 7);
- USB_ASSERT((feature_desc->bLength - 7) <= sizeof(audio_class->as_msg_table[i].bmaControls));
usb_memcpy(&audio_class->as_msg_table[i].bmaControls[0], feature_desc->bmaControls, feature_desc->bLength - 7);
ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].is_tx);