1184610Salfred/* $FreeBSD: stable/11/sys/dev/usb/usb_parse.c 368826 2020-12-30 01:11:08Z hselasky $ */ 2184610Salfred/*- 3368826Shselasky * Copyright (c) 2008-2020 Hans Petter Selasky. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 28246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 29246122Shselasky#else 30194677Sthompsa#include <sys/stdint.h> 31194677Sthompsa#include <sys/stddef.h> 32194677Sthompsa#include <sys/param.h> 33194677Sthompsa#include <sys/queue.h> 34194677Sthompsa#include <sys/types.h> 35194677Sthompsa#include <sys/systm.h> 36194677Sthompsa#include <sys/kernel.h> 37194677Sthompsa#include <sys/bus.h> 38194677Sthompsa#include <sys/module.h> 39194677Sthompsa#include <sys/lock.h> 40194677Sthompsa#include <sys/mutex.h> 41194677Sthompsa#include <sys/condvar.h> 42194677Sthompsa#include <sys/sysctl.h> 43194677Sthompsa#include <sys/sx.h> 44194677Sthompsa#include <sys/unistd.h> 45194677Sthompsa#include <sys/callout.h> 46194677Sthompsa#include <sys/malloc.h> 47194677Sthompsa#include <sys/priv.h> 48194677Sthompsa 49188942Sthompsa#include <dev/usb/usb.h> 50194677Sthompsa#include <dev/usb/usbdi.h> 51194677Sthompsa#include <dev/usb/usbdi_util.h> 52250204Shselasky 53250204Shselasky#define USB_DEBUG_VAR usb_debug 54250204Shselasky 55250204Shselasky#include <dev/usb/usb_core.h> 56250204Shselasky#include <dev/usb/usb_debug.h> 57246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 58184610Salfred 59184610Salfred/*------------------------------------------------------------------------* 60194228Sthompsa * usb_desc_foreach 61184610Salfred * 62184610Salfred * This function is the safe way to iterate across the USB config 63184610Salfred * descriptor. It contains several checks against invalid 64184610Salfred * descriptors. If the "desc" argument passed to this function is 65184610Salfred * "NULL" the first descriptor, if any, will be returned. 66184610Salfred * 67184610Salfred * Return values: 68184610Salfred * NULL: End of descriptors 69184610Salfred * Else: Next descriptor after "desc" 70184610Salfred *------------------------------------------------------------------------*/ 71192984Sthompsastruct usb_descriptor * 72194228Sthompsausb_desc_foreach(struct usb_config_descriptor *cd, 73192984Sthompsa struct usb_descriptor *_desc) 74184610Salfred{ 75187178Sthompsa uint8_t *desc_next; 76187178Sthompsa uint8_t *start; 77187178Sthompsa uint8_t *end; 78187178Sthompsa uint8_t *desc; 79184610Salfred 80187178Sthompsa /* be NULL safe */ 81187178Sthompsa if (cd == NULL) 82184610Salfred return (NULL); 83184610Salfred 84187178Sthompsa /* We assume that the "wTotalLength" has been checked. */ 85187178Sthompsa start = (uint8_t *)cd; 86187178Sthompsa end = start + UGETW(cd->wTotalLength); 87187178Sthompsa desc = (uint8_t *)_desc; 88187178Sthompsa 89187178Sthompsa /* Get start of next USB descriptor. */ 90187178Sthompsa if (desc == NULL) 91187178Sthompsa desc = start; 92187178Sthompsa else 93187178Sthompsa desc = desc + desc[0]; 94187178Sthompsa 95187178Sthompsa /* Check that the next USB descriptor is within the range. */ 96187178Sthompsa if ((desc < start) || (desc >= end)) 97187178Sthompsa return (NULL); /* out of range, or EOD */ 98187178Sthompsa 99187178Sthompsa /* Check that the second next USB descriptor is within range. */ 100187178Sthompsa desc_next = desc + desc[0]; 101187178Sthompsa if ((desc_next < start) || (desc_next > end)) 102187178Sthompsa return (NULL); /* out of range */ 103187178Sthompsa 104187178Sthompsa /* Check minimum descriptor length. */ 105187178Sthompsa if (desc[0] < 3) 106187178Sthompsa return (NULL); /* too short descriptor */ 107187178Sthompsa 108187178Sthompsa /* Return start of next descriptor. */ 109192984Sthompsa return ((struct usb_descriptor *)desc); 110184610Salfred} 111184610Salfred 112184610Salfred/*------------------------------------------------------------------------* 113194228Sthompsa * usb_idesc_foreach 114184610Salfred * 115190730Sthompsa * This function will iterate the interface descriptors in the config 116190730Sthompsa * descriptor. The parse state structure should be zeroed before 117190730Sthompsa * calling this function the first time. 118184610Salfred * 119184610Salfred * Return values: 120184610Salfred * NULL: End of descriptors 121184610Salfred * Else: A valid interface descriptor 122184610Salfred *------------------------------------------------------------------------*/ 123192984Sthompsastruct usb_interface_descriptor * 124194228Sthompsausb_idesc_foreach(struct usb_config_descriptor *cd, 125192984Sthompsa struct usb_idesc_parse_state *ps) 126184610Salfred{ 127192984Sthompsa struct usb_interface_descriptor *id; 128190730Sthompsa uint8_t new_iface; 129184610Salfred 130190730Sthompsa /* retrieve current descriptor */ 131192984Sthompsa id = (struct usb_interface_descriptor *)ps->desc; 132190730Sthompsa /* default is to start a new interface */ 133190730Sthompsa new_iface = 1; 134184610Salfred 135190730Sthompsa while (1) { 136192984Sthompsa id = (struct usb_interface_descriptor *) 137194228Sthompsa usb_desc_foreach(cd, (struct usb_descriptor *)id); 138190730Sthompsa if (id == NULL) 139190730Sthompsa break; 140190730Sthompsa if ((id->bDescriptorType == UDESC_INTERFACE) && 141190730Sthompsa (id->bLength >= sizeof(*id))) { 142368826Shselasky if (ps->iface_no_last == id->bInterfaceNumber) { 143368826Shselasky /* 144368826Shselasky * Don't allow more than 256 alternate 145368826Shselasky * settings to avoid overflowing the 146368826Shselasky * alternate index which is a 8-bit 147368826Shselasky * variable. 148368826Shselasky */ 149368826Shselasky if (ps->iface_index_alt == 255) { 150368826Shselasky DPRINTF("Interface(%u) has more than 256 alternate settings\n", 151368826Shselasky id->bInterfaceNumber); 152368826Shselasky continue; 153368826Shselasky } 154190730Sthompsa new_iface = 0; 155368826Shselasky } 156190730Sthompsa ps->iface_no_last = id->bInterfaceNumber; 157190730Sthompsa break; 158190730Sthompsa } 159190730Sthompsa } 160184610Salfred 161190730Sthompsa if (ps->desc == NULL) { 162250204Shselasky /* first time or zero descriptors */ 163190730Sthompsa } else if (new_iface) { 164190730Sthompsa /* new interface */ 165190730Sthompsa ps->iface_index ++; 166190730Sthompsa ps->iface_index_alt = 0; 167190730Sthompsa } else { 168190730Sthompsa /* new alternate interface */ 169190730Sthompsa ps->iface_index_alt ++; 170190730Sthompsa } 171250204Shselasky#if (USB_IFACE_MAX <= 0) 172250204Shselasky#error "USB_IFACE_MAX must be defined greater than zero" 173250204Shselasky#endif 174250204Shselasky /* check for too many interfaces */ 175250204Shselasky if (ps->iface_index >= USB_IFACE_MAX) { 176250204Shselasky DPRINTF("Interface limit reached\n"); 177250204Shselasky id = NULL; 178250204Shselasky } 179184610Salfred 180190730Sthompsa /* store and return current descriptor */ 181192984Sthompsa ps->desc = (struct usb_descriptor *)id; 182190730Sthompsa return (id); 183184610Salfred} 184184610Salfred 185184610Salfred/*------------------------------------------------------------------------* 186194228Sthompsa * usb_edesc_foreach 187184610Salfred * 188190730Sthompsa * This function will iterate all the endpoint descriptors within an 189190730Sthompsa * interface descriptor. Starting value for the "ped" argument should 190190730Sthompsa * be a valid interface descriptor. 191184610Salfred * 192184610Salfred * Return values: 193184610Salfred * NULL: End of descriptors 194184610Salfred * Else: A valid endpoint descriptor 195184610Salfred *------------------------------------------------------------------------*/ 196192984Sthompsastruct usb_endpoint_descriptor * 197194228Sthompsausb_edesc_foreach(struct usb_config_descriptor *cd, 198192984Sthompsa struct usb_endpoint_descriptor *ped) 199184610Salfred{ 200192984Sthompsa struct usb_descriptor *desc; 201184610Salfred 202192984Sthompsa desc = ((struct usb_descriptor *)ped); 203184610Salfred 204194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 205184610Salfred if (desc->bDescriptorType == UDESC_INTERFACE) { 206184610Salfred break; 207184610Salfred } 208184610Salfred if (desc->bDescriptorType == UDESC_ENDPOINT) { 209190730Sthompsa if (desc->bLength < sizeof(*ped)) { 210213435Shselasky /* endpoint descriptor is invalid */ 211190730Sthompsa break; 212184610Salfred } 213192984Sthompsa return ((struct usb_endpoint_descriptor *)desc); 214184610Salfred } 215184610Salfred } 216184610Salfred return (NULL); 217184610Salfred} 218184610Salfred 219184610Salfred/*------------------------------------------------------------------------* 220213435Shselasky * usb_ed_comp_foreach 221213435Shselasky * 222213435Shselasky * This function will iterate all the endpoint companion descriptors 223213435Shselasky * within an endpoint descriptor in an interface descriptor. Starting 224213435Shselasky * value for the "ped" argument should be a valid endpoint companion 225213435Shselasky * descriptor. 226213435Shselasky * 227213435Shselasky * Return values: 228213435Shselasky * NULL: End of descriptors 229213435Shselasky * Else: A valid endpoint companion descriptor 230213435Shselasky *------------------------------------------------------------------------*/ 231213435Shselaskystruct usb_endpoint_ss_comp_descriptor * 232213435Shselaskyusb_ed_comp_foreach(struct usb_config_descriptor *cd, 233213435Shselasky struct usb_endpoint_ss_comp_descriptor *ped) 234213435Shselasky{ 235213435Shselasky struct usb_descriptor *desc; 236213435Shselasky 237213435Shselasky desc = ((struct usb_descriptor *)ped); 238213435Shselasky 239213435Shselasky while ((desc = usb_desc_foreach(cd, desc))) { 240213435Shselasky if (desc->bDescriptorType == UDESC_INTERFACE) 241213435Shselasky break; 242213435Shselasky if (desc->bDescriptorType == UDESC_ENDPOINT) 243213435Shselasky break; 244213435Shselasky if (desc->bDescriptorType == UDESC_ENDPOINT_SS_COMP) { 245213435Shselasky if (desc->bLength < sizeof(*ped)) { 246213435Shselasky /* endpoint companion descriptor is invalid */ 247213435Shselasky break; 248213435Shselasky } 249213435Shselasky return ((struct usb_endpoint_ss_comp_descriptor *)desc); 250213435Shselasky } 251213435Shselasky } 252213435Shselasky return (NULL); 253213435Shselasky} 254213435Shselasky 255213435Shselasky/*------------------------------------------------------------------------* 256194228Sthompsa * usbd_get_no_descriptors 257184610Salfred * 258190730Sthompsa * This function will count the total number of descriptors in the 259190730Sthompsa * configuration descriptor of type "type". 260184610Salfred *------------------------------------------------------------------------*/ 261190730Sthompsauint8_t 262194228Sthompsausbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type) 263184610Salfred{ 264192984Sthompsa struct usb_descriptor *desc = NULL; 265190730Sthompsa uint8_t count = 0; 266184610Salfred 267194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 268190730Sthompsa if (desc->bDescriptorType == type) { 269184610Salfred count++; 270190730Sthompsa if (count == 0xFF) 271190730Sthompsa break; /* crazy */ 272184610Salfred } 273184610Salfred } 274184610Salfred return (count); 275184610Salfred} 276184610Salfred 277184610Salfred/*------------------------------------------------------------------------* 278194228Sthompsa * usbd_get_no_alts 279184610Salfred * 280184610Salfred * Return value: 281195963Salfred * Number of alternate settings for the given interface descriptor 282195963Salfred * pointer. If the USB descriptor is corrupt, the returned value can 283195963Salfred * be greater than the actual number of alternate settings. 284184610Salfred *------------------------------------------------------------------------*/ 285190730Sthompsauint8_t 286194228Sthompsausbd_get_no_alts(struct usb_config_descriptor *cd, 287192984Sthompsa struct usb_interface_descriptor *id) 288184610Salfred{ 289192984Sthompsa struct usb_descriptor *desc; 290195963Salfred uint8_t n; 291190730Sthompsa uint8_t ifaceno; 292184610Salfred 293195963Salfred /* Reset interface count */ 294195963Salfred 295195963Salfred n = 0; 296195963Salfred 297195963Salfred /* Get the interface number */ 298195963Salfred 299190730Sthompsa ifaceno = id->bInterfaceNumber; 300190730Sthompsa 301195963Salfred /* Iterate all the USB descriptors */ 302190730Sthompsa 303195963Salfred desc = NULL; 304194228Sthompsa while ((desc = usb_desc_foreach(cd, desc))) { 305184610Salfred if ((desc->bDescriptorType == UDESC_INTERFACE) && 306184610Salfred (desc->bLength >= sizeof(*id))) { 307192984Sthompsa id = (struct usb_interface_descriptor *)desc; 308184610Salfred if (id->bInterfaceNumber == ifaceno) { 309184610Salfred n++; 310190730Sthompsa if (n == 0xFF) 311190730Sthompsa break; /* crazy */ 312195963Salfred } 313184610Salfred } 314184610Salfred } 315184610Salfred return (n); 316184610Salfred} 317