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