1/*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2008-2020 Hans Petter Selasky. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include "implementation/global_implementation.h" 29 30/*------------------------------------------------------------------------* 31 * usb_desc_foreach 32 * 33 * This function is the safe way to iterate across the USB config 34 * descriptor. It contains several checks against invalid 35 * descriptors. If the "desc" argument passed to this function is 36 * "NULL" the first descriptor, if any, will be returned. 37 * 38 * Return values: 39 * NULL: End of descriptors 40 * Else: Next descriptor after "desc" 41 *------------------------------------------------------------------------*/ 42struct usb_descriptor * 43usb_desc_foreach(struct usb_config_descriptor *cd, 44 struct usb_descriptor *_desc) 45{ 46 uint8_t *desc_next; 47 uint8_t *start; 48 uint8_t *end; 49 uint8_t *desc; 50 51 /* be NULL safe */ 52 if (cd == NULL) 53 return (NULL); 54 55 /* We assume that the "wTotalLength" has been checked. */ 56 start = (uint8_t *)cd; 57 end = start + UGETW(cd->wTotalLength); 58 desc = (uint8_t *)_desc; 59 60 /* Get start of next USB descriptor. */ 61 if (desc == NULL) 62 desc = start; 63 else 64 desc = desc + desc[0]; 65 66 /* Check that the next USB descriptor is within the range. */ 67 if ((desc < start) || (desc >= end)) 68 return (NULL); /* out of range, or EOD */ 69 70 /* Check that the second next USB descriptor is within range. */ 71 desc_next = desc + desc[0]; 72 if ((desc_next < start) || (desc_next > end)) 73 return (NULL); /* out of range */ 74 75 /* Check minimum descriptor length. */ 76 if (desc[0] < 3) 77 return (NULL); /* too short descriptor */ 78 79 /* Return start of next descriptor. */ 80 return ((struct usb_descriptor *)desc); 81} 82 83/*------------------------------------------------------------------------* 84 * usb_idesc_foreach 85 * 86 * This function will iterate the interface descriptors in the config 87 * descriptor. The parse state structure should be zeroed before 88 * calling this function the first time. 89 * 90 * Return values: 91 * NULL: End of descriptors 92 * Else: A valid interface descriptor 93 *------------------------------------------------------------------------*/ 94struct usb_interface_descriptor * 95usb_idesc_foreach(struct usb_config_descriptor *cd, 96 struct usb_idesc_parse_state *ps) 97{ 98 struct usb_interface_descriptor *id; 99 uint8_t new_iface; 100 101 /* retrieve current descriptor */ 102 id = (struct usb_interface_descriptor *)ps->desc; 103 /* default is to start a new interface */ 104 new_iface = 1; 105 106 while (1) { 107 id = (struct usb_interface_descriptor *) 108 usb_desc_foreach(cd, (struct usb_descriptor *)id); 109 if (id == NULL) 110 break; 111 if ((id->bDescriptorType == UDESC_INTERFACE) && 112 (id->bLength >= sizeof(*id))) { 113 if (ps->iface_no_last == id->bInterfaceNumber) { 114 /* 115 * Don't allow more than 256 alternate 116 * settings to avoid overflowing the 117 * alternate index which is a 8-bit 118 * variable. 119 */ 120 if (ps->iface_index_alt == 255) { 121 DPRINTF("Interface(%u) has more than 256 alternate settings\n", 122 id->bInterfaceNumber); 123 continue; 124 } 125 new_iface = 0; 126 } 127 ps->iface_no_last = id->bInterfaceNumber; 128 break; 129 } 130 } 131 132 if (ps->desc == NULL) { 133 /* first time or zero descriptors */ 134 } else if (new_iface) { 135 /* new interface */ 136 ps->iface_index ++; 137 ps->iface_index_alt = 0; 138 } else { 139 /* new alternate interface */ 140 ps->iface_index_alt ++; 141 } 142#if (USB_IFACE_MAX <= 0) 143#error "USB_IFACE_MAX must be defined greater than zero" 144#endif 145 /* check for too many interfaces */ 146 if (ps->iface_index >= USB_IFACE_MAX) { 147 DPRINTF("Interface limit reached\n"); 148 id = NULL; 149 } 150 151 /* store and return current descriptor */ 152 ps->desc = (struct usb_descriptor *)id; 153 return (id); 154} 155 156/*------------------------------------------------------------------------* 157 * usb_edesc_foreach 158 * 159 * This function will iterate all the endpoint descriptors within an 160 * interface descriptor. Starting value for the "ped" argument should 161 * be a valid interface descriptor. 162 * 163 * Return values: 164 * NULL: End of descriptors 165 * Else: A valid endpoint descriptor 166 *------------------------------------------------------------------------*/ 167struct usb_endpoint_descriptor * 168usb_edesc_foreach(struct usb_config_descriptor *cd, 169 struct usb_endpoint_descriptor *ped) 170{ 171 struct usb_descriptor *desc; 172 173 desc = ((struct usb_descriptor *)ped); 174 175 while ((desc = usb_desc_foreach(cd, desc))) { 176 if (desc->bDescriptorType == UDESC_INTERFACE) { 177 break; 178 } 179 if (desc->bDescriptorType == UDESC_ENDPOINT) { 180 if (desc->bLength < sizeof(*ped)) { 181 /* endpoint descriptor is invalid */ 182 break; 183 } 184 return ((struct usb_endpoint_descriptor *)desc); 185 } 186 } 187 return (NULL); 188} 189 190/*------------------------------------------------------------------------* 191 * usb_ed_comp_foreach 192 * 193 * This function will iterate all the endpoint companion descriptors 194 * within an endpoint descriptor in an interface descriptor. Starting 195 * value for the "ped" argument should be a valid endpoint companion 196 * descriptor. 197 * 198 * Return values: 199 * NULL: End of descriptors 200 * Else: A valid endpoint companion descriptor 201 *------------------------------------------------------------------------*/ 202struct usb_endpoint_ss_comp_descriptor * 203usb_ed_comp_foreach(struct usb_config_descriptor *cd, 204 struct usb_endpoint_ss_comp_descriptor *ped) 205{ 206 struct usb_descriptor *desc; 207 208 desc = ((struct usb_descriptor *)ped); 209 210 while ((desc = usb_desc_foreach(cd, desc))) { 211 if (desc->bDescriptorType == UDESC_INTERFACE) 212 break; 213 if (desc->bDescriptorType == UDESC_ENDPOINT) 214 break; 215 if (desc->bDescriptorType == UDESC_ENDPOINT_SS_COMP) { 216 if (desc->bLength < sizeof(*ped)) { 217 /* endpoint companion descriptor is invalid */ 218 break; 219 } 220 return ((struct usb_endpoint_ss_comp_descriptor *)desc); 221 } 222 } 223 return (NULL); 224} 225 226/*------------------------------------------------------------------------* 227 * usbd_get_no_descriptors 228 * 229 * This function will count the total number of descriptors in the 230 * configuration descriptor of type "type". 231 *------------------------------------------------------------------------*/ 232uint8_t 233usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type) 234{ 235 struct usb_descriptor *desc = NULL; 236 uint8_t count = 0; 237 238 while ((desc = usb_desc_foreach(cd, desc))) { 239 if (desc->bDescriptorType == type) { 240 count++; 241 if (count == 0xFF) 242 break; /* crazy */ 243 } 244 } 245 return (count); 246} 247 248/*------------------------------------------------------------------------* 249 * usbd_get_no_alts 250 * 251 * Return value: 252 * Number of alternate settings for the given interface descriptor 253 * pointer. If the USB descriptor is corrupt, the returned value can 254 * be greater than the actual number of alternate settings. 255 *------------------------------------------------------------------------*/ 256uint8_t 257usbd_get_no_alts(struct usb_config_descriptor *cd, 258 struct usb_interface_descriptor *id) 259{ 260 struct usb_descriptor *desc; 261 uint8_t n; 262 uint8_t ifaceno; 263 264 /* Reset interface count */ 265 266 n = 0; 267 268 /* Get the interface number */ 269 270 ifaceno = id->bInterfaceNumber; 271 272 /* Iterate all the USB descriptors */ 273 274 desc = NULL; 275 while ((desc = usb_desc_foreach(cd, desc))) { 276 if ((desc->bDescriptorType == UDESC_INTERFACE) && 277 (desc->bLength >= sizeof(*id))) { 278 id = (struct usb_interface_descriptor *)desc; 279 if (id->bInterfaceNumber == ifaceno) { 280 n++; 281 if (n == 0xFF) 282 break; /* crazy */ 283 } 284 } 285 } 286 return (n); 287} 288