diff options
Diffstat (limited to 'core/usbh_core.c')
| -rw-r--r-- | core/usbh_core.c | 133 |
1 files changed, 94 insertions, 39 deletions
diff --git a/core/usbh_core.c b/core/usbh_core.c index ba00d8f8..0457a7c5 100644 --- a/core/usbh_core.c +++ b/core/usbh_core.c @@ -27,6 +27,7 @@ struct usbh_bus g_usbhost_bus[CONFIG_USBHOST_MAX_BUS]; #define DESC_bLength 0 /** Length offset */ #define DESC_bDescriptorType 1 /** Descriptor type offset */ +#define USB_DEV_ADDR_MIN 2 #define USB_DEV_ADDR_MAX 0x7f #define USB_DEV_ADDR_MARK_OFFSET 5 #define USB_DEV_ADDR_MARK_MASK 0x1f @@ -43,17 +44,19 @@ static void dummy_event_handler(uint8_t busid, uint8_t hub_index, uint8_t hub_po static int usbh_allocate_devaddr(struct usbh_devaddr_map *devgen) { uint8_t lastaddr = devgen->last; - uint8_t devaddr = lastaddr; + uint8_t devaddr; int index; int bitno; + if (lastaddr < USB_DEV_ADDR_MIN || lastaddr > USB_DEV_ADDR_MAX) { + lastaddr = USB_DEV_ADDR_MAX; + } + devaddr = lastaddr; + for (;;) { devaddr++; - if (devaddr > 0x7f) { - devaddr = 2; - } - if (devaddr == lastaddr) { - return -USB_ERR_NOMEM; + if (devaddr > USB_DEV_ADDR_MAX) { + devaddr = USB_DEV_ADDR_MIN; } index = devaddr >> 5; @@ -63,6 +66,10 @@ static int usbh_allocate_devaddr(struct usbh_devaddr_map *devgen) devgen->last = devaddr; return (int)devaddr; } + + if (devaddr == lastaddr) { + return -USB_ERR_NOMEM; + } } } @@ -71,7 +78,7 @@ static int __usbh_free_devaddr(struct usbh_devaddr_map *devgen, uint8_t devaddr) int index; int bitno; - if ((devaddr > 0) && (devaddr < USB_DEV_ADDR_MAX)) { + if ((devaddr > 0) && (devaddr <= USB_DEV_ADDR_MAX)) { index = devaddr >> USB_DEV_ADDR_MARK_OFFSET; bitno = devaddr & USB_DEV_ADDR_MARK_MASK; @@ -132,6 +139,10 @@ static const struct usbh_class_driver *usbh_find_class_driver(uint8_t class, uin static int parse_device_descriptor(struct usbh_hubport *hport, struct usb_device_descriptor *desc, uint16_t length) { + if (length < 8) { + return -USB_ERR_INVAL; + } + if (desc->bLength != USB_SIZEOF_DEVICE_DESC) { USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength); return -USB_ERR_INVAL; @@ -139,6 +150,16 @@ static int parse_device_descriptor(struct usbh_hubport *hport, struct usb_device USB_LOG_ERR("unexpected device descriptor 0x%02x\r\n", desc->bDescriptorType); return -USB_ERR_INVAL; } else { + if ((hport->speed >= USB_SPEED_SUPER && desc->bMaxPacketSize0 != 9) || + (hport->speed == USB_SPEED_HIGH && desc->bMaxPacketSize0 != 64) || + (hport->speed == USB_SPEED_LOW && desc->bMaxPacketSize0 != 8) || + (hport->speed == USB_SPEED_FULL && + desc->bMaxPacketSize0 != 8 && desc->bMaxPacketSize0 != 16 && + desc->bMaxPacketSize0 != 32 && desc->bMaxPacketSize0 != 64)) { + USB_LOG_ERR("invalid bMaxPacketSize0 %d\r\n", desc->bMaxPacketSize0); + return -USB_ERR_INVAL; + } + if (length <= 8) { return 0; } @@ -188,6 +209,9 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config uint32_t desc_len = 0; uint8_t *p; + if (length < USB_SIZEOF_CONFIG_DESC) { + return -USB_ERR_INVAL; + } if (desc->bLength != USB_SIZEOF_CONFIG_DESC) { USB_LOG_ERR("invalid config bLength 0x%02x\r\n", desc->bLength); return -USB_ERR_INVAL; @@ -195,9 +219,17 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config USB_LOG_ERR("unexpected config descriptor 0x%02x\r\n", desc->bDescriptorType); return -USB_ERR_INVAL; } else { + if (desc->bNumInterfaces > CONFIG_USBHOST_MAX_INTERFACES) { + return -USB_ERR_NOMEM; + } + if (length <= USB_SIZEOF_CONFIG_DESC) { return 0; } + + if (desc->wTotalLength != length) { + return -USB_ERR_INVAL; + } #if 0 USB_LOG_DBG("Config Descriptor:\r\n"); USB_LOG_DBG("bLength: 0x%02x \r\n", desc->bLength); @@ -225,9 +257,14 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config memset(hport->config.intf, 0, sizeof(struct usbh_interface) * CONFIG_USBHOST_MAX_INTERFACES); - while (p[DESC_bLength]) { + while ((desc_len < length) && + (p[DESC_bLength] >= 2) && + (p[DESC_bLength] <= length - desc_len)) { switch (p[DESC_bDescriptorType]) { case USB_DESCRIPTOR_TYPE_INTERFACE: + if (cur_ep != cur_ep_num) { + return -USB_ERR_INVAL; + } if (p[DESC_bLength] < USB_SIZEOF_INTERFACE_DESC) { return -USB_ERR_INVAL; } @@ -242,16 +279,19 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config return -USB_ERR_NOMEM; } - if (cur_ep_num > CONFIG_USBHOST_MAX_ENDPOINTS) { - USB_LOG_ERR("Endpoint num %d overflow\r\n", cur_ep_num); + if (cur_alt_setting >= CONFIG_USBHOST_MAX_INTF_ALTSETTINGS) { + USB_LOG_ERR("Interface altsetting num %d overflow\r\n", cur_alt_setting); return -USB_ERR_NOMEM; } - if (cur_alt_setting >= CONFIG_USBHOST_MAX_INTF_ALTSETTINGS) { - USB_LOG_ERR("Interface altsetting num %d overflow\r\n", cur_alt_setting); + if (cur_ep_num > CONFIG_USBHOST_MAX_ENDPOINTS) { + USB_LOG_ERR("Endpoint num %d overflow\r\n", cur_ep_num); return -USB_ERR_NOMEM; } + if (cur_alt_setting != hport->config.intf[cur_iface].altsetting_num) { + return -USB_ERR_INVAL; + } #if 0 USB_LOG_DBG("Interface Descriptor:\r\n"); USB_LOG_DBG("bLength: 0x%02x \r\n", intf_desc->bLength); @@ -264,8 +304,9 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config USB_LOG_DBG("bInterfaceProtocol: 0x%02x \r\n", intf_desc->bInterfaceProtocol); USB_LOG_DBG("iInterface: 0x%02x \r\n", intf_desc->iInterface); #endif - memcpy(&hport->config.intf[cur_iface].altsetting[cur_alt_setting].intf_desc, intf_desc, 9); - hport->config.intf[cur_iface].altsetting_num = cur_alt_setting + 1; + + memcpy(&hport->config.intf[cur_iface].altsetting[cur_alt_setting].intf_desc, intf_desc, USB_SIZEOF_INTERFACE_DESC); + hport->config.intf[cur_iface].altsetting_num++; break; case USB_DESCRIPTOR_TYPE_ENDPOINT: if (p[DESC_bLength] < USB_SIZEOF_ENDPOINT_DESC) { @@ -273,12 +314,29 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config } ep_desc = (struct usb_endpoint_descriptor *)p; - if (cur_ep >= CONFIG_USBHOST_MAX_ENDPOINTS) { + if (USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize) == 0) { + return -USB_ERR_INVAL; + } + + if ((ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT || + (ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS) { + if (ep_desc->bInterval == 0 || + (hport->speed >= USB_SPEED_HIGH && ep_desc->bInterval > 16)) { + return -USB_ERR_INVAL; + } + } + + if (cur_iface >= CONFIG_USBHOST_MAX_INTERFACES) { + USB_LOG_ERR("Interface num %d overflow\r\n", cur_iface); + return -USB_ERR_NOMEM; + } + + if (cur_ep >= cur_ep_num) { USB_LOG_ERR("Endpoint num %d overflow\r\n", cur_ep); return -USB_ERR_NOMEM; } - memcpy(&hport->config.intf[cur_iface].altsetting[cur_alt_setting].ep[cur_ep].ep_desc, ep_desc, 7); + memcpy(&hport->config.intf[cur_iface].altsetting[cur_alt_setting].ep[cur_ep].ep_desc, ep_desc, USB_SIZEOF_ENDPOINT_DESC); cur_ep++; break; @@ -288,10 +346,10 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config /* skip to next descriptor */ desc_len += p[DESC_bLength]; p += p[DESC_bLength]; + } - if (desc_len > length) { - return -USB_ERR_INVAL; - } + if (cur_ep != cur_ep_num) { + return -USB_ERR_INVAL; } if (desc_len != length) { @@ -379,8 +437,8 @@ int usbh_enumerate(struct usbh_hubport *hport) /* Extract the correct max packetsize from the device descriptor */ dev_desc = (struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid]; - if (dev_desc->bcdUSB >= USB_3_0) { - ep_mps = 1 << dev_desc->bMaxPacketSize0; + if (hport->speed >= USB_SPEED_SUPER) { + ep_mps = 1U << dev_desc->bMaxPacketSize0; } else { ep_mps = dev_desc->bMaxPacketSize0; } @@ -395,6 +453,7 @@ int usbh_enumerate(struct usbh_hubport *hport) /* Assign a function address to the device connected to this port */ dev_addr = usbh_allocate_devaddr(&hport->bus->devgen); if (dev_addr < 0) { + ret = dev_addr; USB_LOG_ERR("Failed to allocate devaddr,errorcode:%d\r\n", ret); goto errout; } @@ -409,6 +468,7 @@ int usbh_enumerate(struct usbh_hubport *hport) ret = usbh_control_transfer(hport, setup, NULL); if (ret < 0) { USB_LOG_ERR("Failed to set devaddr,errorcode:%d\r\n", ret); + __usbh_free_devaddr(&hport->bus->devgen, (uint8_t)dev_addr); goto errout; } @@ -431,7 +491,12 @@ int usbh_enumerate(struct usbh_hubport *hport) goto errout; } - parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid], USB_SIZEOF_DEVICE_DESC); + ret = parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid], USB_SIZEOF_DEVICE_DESC); + if (ret < 0) { + USB_LOG_ERR("Parse full device descriptor fail\r\n"); + goto errout; + } + USB_LOG_INFO("New device found,idVendor:%04x,idProduct:%04x,bcdDevice:%04x\r\n", ((struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid])->idVendor, ((struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid])->idProduct, @@ -748,17 +813,14 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out struct usb_setup_packet *setup = hport->setup; int ret; uint8_t *src; - uint8_t *dst; uint16_t len; - uint16_t i = 2; - uint16_t j = 0; /* Get Manufacturer string */ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE; setup->bRequest = USB_REQUEST_GET_DESCRIPTOR; setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_STRING << 8) | index); setup->wIndex = 0x0409; - setup->wLength = 255; + setup->wLength = MIN(255, CONFIG_USBHOST_REQUEST_BUFFER_LEN); ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]); if (ret < 0) { @@ -766,26 +828,19 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out } src = ep0_request_buffer[hport->bus->busid]; - dst = output; - len = src[0]; - - if (ret != len) { - USB_LOG_ERR("Get string descriptor failed, expect %d, actual %d\r\n", len, ret); + if (ret < 2 || src[1] != USB_DESCRIPTOR_TYPE_STRING || src[0] != ret || (src[0] & 1)) { return -USB_ERR_IO; } - memset(output, 0, output_len); - - if (((len - 2) / 2) > output_len) { + len = (src[0] - 2) / 2; + if (len > output_len) { return -USB_ERR_NOMEM; } - while (i < len) { - dst[j] = src[i]; - i += 2; - j++; + memset(output, 0, output_len); + for (uint16_t i = 0; i < len; i++) { + output[i] = src[2 + 2 * i]; } - return 0; } |
