enum For string descriptor (langid, manufacturer product, serila): always get the first 2 bytes to determine the length first. otherwise, some device may have buffer overflow.

This commit is contained in:
hathach
2025-04-14 16:09:32 +07:00
parent edbea218b9
commit e8a84f9076
4 changed files with 76 additions and 58 deletions

View File

@@ -36,7 +36,7 @@
extern "C" { extern "C" {
#endif #endif
#define NEOPIXEL_PIN 48 #define NEOPIXEL_PIN 38
#define BUTTON_PIN 0 #define BUTTON_PIN 0
#define BUTTON_STATE_ACTIVE 0 #define BUTTON_STATE_ACTIVE 0

View File

@@ -34,6 +34,6 @@ endif ()
set(EXTRA_COMPONENT_DIRS "src" "${CMAKE_CURRENT_LIST_DIR}/boards" "${CMAKE_CURRENT_LIST_DIR}/components") set(EXTRA_COMPONENT_DIRS "src" "${CMAKE_CURRENT_LIST_DIR}/boards" "${CMAKE_CURRENT_LIST_DIR}/components")
# set SDKCONFIG for each IDF Target # set SDKCONFIG for each IDF Target
set(SDKCONFIG ${CMAKE_SOURCE_DIR}/sdkconfig.${IDF_TARGET}) set(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)

View File

@@ -108,15 +108,13 @@ typedef struct {
} tu_lookup_table_t; } tu_lookup_table_t;
static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) {
tu_static char not_found[11];
for(uint16_t i=0; i<p_table->count; i++) { for(uint16_t i=0; i<p_table->count; i++) {
if (p_table->items[i].key == key) return p_table->items[i].data; if (p_table->items[i].key == key) { return p_table->items[i].data; }
} }
// not found return the key value in hex // not found return the key value in hex
static char not_found[11];
snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key); snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
return not_found; return not_found;
} }

View File

@@ -1372,9 +1372,13 @@ enum {
ENUM_HUB_CLEAR_RESET_2, ENUM_HUB_CLEAR_RESET_2,
ENUM_SET_ADDR, ENUM_SET_ADDR,
ENUM_GET_DEVICE_DESC, ENUM_GET_DEVICE_DESC,
ENUM_GET_STRING_LANGUAGE_ID_LEN,
ENUM_GET_STRING_LANGUAGE_ID, ENUM_GET_STRING_LANGUAGE_ID,
ENUM_GET_STRING_MANUFACTURER_LEN,
ENUM_GET_STRING_MANUFACTURER, ENUM_GET_STRING_MANUFACTURER,
ENUM_GET_STRING_PRODUCT_LEN,
ENUM_GET_STRING_PRODUCT, ENUM_GET_STRING_PRODUCT,
ENUM_GET_STRING_SERIAL_LEN,
ENUM_GET_STRING_SERIAL, ENUM_GET_STRING_SERIAL,
ENUM_GET_9BYTE_CONFIG_DESC, ENUM_GET_9BYTE_CONFIG_DESC,
ENUM_GET_FULL_CONFIG_DESC, ENUM_GET_FULL_CONFIG_DESC,
@@ -1416,6 +1420,9 @@ static void process_enumeration(tuh_xfer_t* xfer) {
uint8_t const daddr = xfer->daddr; uint8_t const daddr = xfer->daddr;
uintptr_t const state = xfer->user_data; uintptr_t const state = xfer->user_data;
usbh_device_t* dev = get_device(daddr); usbh_device_t* dev = get_device(daddr);
if (daddr > 0) {
TU_ASSERT(dev,);
}
uint16_t langid = 0x0409; // default is English uint16_t langid = 0x0409; // default is English
switch (state) { switch (state) {
@@ -1474,30 +1481,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
break; break;
} }
#if 0
case ENUM_RESET_2:
// TODO not used by now, but may be needed for some devices !?
// Reset device again before Set Address
TU_LOG_USBH("Port reset2 \r\n");
if (_dev0.hub_addr == 0) {
// connected directly to roothub
hcd_port_reset( _dev0.rhport );
tusb_time_delay_ms_api(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
// sof of controller may not running while resetting
hcd_port_reset_end(_dev0.rhport);
// TODO: fall through to SET ADDRESS, refactor later
}
#if CFG_TUH_HUB
else {
// after RESET_DELAY the hub_port_reset() already complete
TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port,
process_enumeration, ENUM_HUB_GET_STATUS_2), );
break;
}
#endif
TU_ATTR_FALLTHROUGH;
#endif
case ENUM_SET_ADDR: case ENUM_SET_ADDR:
enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl); enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl);
break; break;
@@ -1520,14 +1503,15 @@ static void process_enumeration(tuh_xfer_t* xfer) {
// Get full device descriptor // Get full device descriptor
TU_LOG_USBH("Get Device Descriptor\r\n"); TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),); process_enumeration, ENUM_GET_STRING_LANGUAGE_ID_LEN),);
break; break;
} }
case ENUM_GET_STRING_LANGUAGE_ID: { // For string descriptor (langid, manufacturer, product, serila): always get the first 2 bytes
// to determine the length first. otherwise, some device may have buffer overflow.
case ENUM_GET_STRING_LANGUAGE_ID_LEN: {
// save the received device descriptor // save the received device descriptor
TU_ASSERT(dev,); tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl;
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
dev->vid = desc_device->idVendor; dev->vid = desc_device->idVendor;
dev->pid = desc_device->idProduct; dev->pid = desc_device->idProduct;
dev->i_manufacturer = desc_device->iManufacturer; dev->i_manufacturer = desc_device->iManufacturer;
@@ -1535,50 +1519,88 @@ static void process_enumeration(tuh_xfer_t* xfer) {
dev->i_serial = desc_device->iSerialNumber; dev->i_serial = desc_device->iSerialNumber;
dev->bNumConfigurations = desc_device->bNumConfigurations; dev->bNumConfigurations = desc_device->bNumConfigurations;
tuh_enum_descriptor_device_cb(daddr, desc_device); // callback tuh_enum_descriptor_device_cb(daddr, desc_device);// callback
tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_MANUFACTURER); process_enumeration, ENUM_GET_STRING_LANGUAGE_ID);
break; break;
} }
case ENUM_GET_STRING_MANUFACTURER: { case ENUM_GET_STRING_LANGUAGE_ID: {
TU_ASSERT(dev,); const uint8_t str_len = xfer->buffer[0];
const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl; tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN);
break;
}
case ENUM_GET_STRING_MANUFACTURER_LEN: {
const tusb_desc_string_t* desc_langid = (const tusb_desc_string_t *) _usbh_epbuf.ctrl;
if (desc_langid->bLength >= 4) { if (desc_langid->bLength >= 4) {
langid = tu_le16toh(desc_langid->utf16le[0]); langid = tu_le16toh(desc_langid->utf16le[0]); // previous request is langid
} }
if (dev->i_manufacturer != 0) { if (dev->i_manufacturer != 0) {
tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_MANUFACTURER);
break;
}else {
TU_ATTR_FALLTHROUGH;
}
}
case ENUM_GET_STRING_MANUFACTURER: {
if (dev->i_manufacturer != 0) {
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_STRING_PRODUCT_LEN);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
}
case ENUM_GET_STRING_PRODUCT_LEN:
if (dev->i_product != 0) {
if (state == ENUM_GET_STRING_PRODUCT_LEN) {
langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
}
tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_PRODUCT); process_enumeration, ENUM_GET_STRING_PRODUCT);
break; break;
} else { } else {
TU_ATTR_FALLTHROUGH; TU_ATTR_FALLTHROUGH;
} }
}
case ENUM_GET_STRING_PRODUCT: { case ENUM_GET_STRING_PRODUCT: {
TU_ASSERT(dev,);
if (state == ENUM_GET_STRING_PRODUCT) {
langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
}
if (dev->i_product != 0) { if (dev->i_product != 0) {
tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
process_enumeration, ENUM_GET_STRING_SERIAL); const uint8_t str_len = xfer->buffer[0];
tuh_descriptor_get_string(daddr, dev->i_product, langid, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_STRING_SERIAL_LEN);
break; break;
} else { } else {
TU_ATTR_FALLTHROUGH; TU_ATTR_FALLTHROUGH;
} }
} }
case ENUM_GET_STRING_SERIAL: { case ENUM_GET_STRING_SERIAL_LEN:
TU_ASSERT(dev,);
if (state == ENUM_GET_STRING_SERIAL) {
langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
}
if (dev->i_serial != 0) { if (dev->i_serial != 0) {
tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, if (state == ENUM_GET_STRING_SERIAL_LEN) {
process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
}
tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, 2,
process_enumeration, ENUM_GET_STRING_SERIAL);
break;
} else {
TU_ATTR_FALLTHROUGH;
}
case ENUM_GET_STRING_SERIAL: {
if (dev->i_serial != 0) {
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, str_len,
process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
break; break;
} else { } else {
TU_ATTR_FALLTHROUGH; TU_ATTR_FALLTHROUGH;
@@ -1627,8 +1649,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
case ENUM_CONFIG_DRIVER: { case ENUM_CONFIG_DRIVER: {
TU_LOG_USBH("Device configured\r\n"); TU_LOG_USBH("Device configured\r\n");
TU_ASSERT(dev,);
dev->configured = 1; dev->configured = 1;
// Parse configuration & set up drivers // Parse configuration & set up drivers