1 /* $FreeBSD: releng/12.2/sys/dev/usb/usb_parse.c 326255 2017-11-27 14:52:40Z pfg $ */
2 /*-
3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 *
5 * Copyright (c) 2008 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 new_iface = 0;
116 ps->iface_no_last = id->bInterfaceNumber;
117 break;
118 }
119 }
120
121 if (ps->desc == NULL) {
122 /* first time or zero descriptors */
123 } else if (new_iface) {
124 /* new interface */
125 ps->iface_index ++;
126 ps->iface_index_alt = 0;
127 } else {
128 /* new alternate interface */
129 ps->iface_index_alt ++;
130 }
131 #if (USB_IFACE_MAX <= 0)
132 #error "USB_IFACE_MAX must be defined greater than zero"
133 #endif
134 /* check for too many interfaces */
135 if (ps->iface_index >= USB_IFACE_MAX) {
136 DPRINTF("Interface limit reached\n");
137 id = NULL;
138 }
139
140 /* store and return current descriptor */
141 ps->desc = (struct usb_descriptor *)id;
142 return (id);
143 }
144
145 /*------------------------------------------------------------------------*
146 * usb_edesc_foreach
147 *
148 * This function will iterate all the endpoint descriptors within an
149 * interface descriptor. Starting value for the "ped" argument should
150 * be a valid interface descriptor.
151 *
152 * Return values:
153 * NULL: End of descriptors
154 * Else: A valid endpoint descriptor
155 *------------------------------------------------------------------------*/
156 struct usb_endpoint_descriptor *
usb_edesc_foreach(struct usb_config_descriptor * cd,struct usb_endpoint_descriptor * ped)157 usb_edesc_foreach(struct usb_config_descriptor *cd,
158 struct usb_endpoint_descriptor *ped)
159 {
160 struct usb_descriptor *desc;
161
162 desc = ((struct usb_descriptor *)ped);
163
164 while ((desc = usb_desc_foreach(cd, desc))) {
165 if (desc->bDescriptorType == UDESC_INTERFACE) {
166 break;
167 }
168 if (desc->bDescriptorType == UDESC_ENDPOINT) {
169 if (desc->bLength < sizeof(*ped)) {
170 /* endpoint descriptor is invalid */
171 break;
172 }
173 return ((struct usb_endpoint_descriptor *)desc);
174 }
175 }
176 return (NULL);
177 }
178
179 /*------------------------------------------------------------------------*
180 * usb_ed_comp_foreach
181 *
182 * This function will iterate all the endpoint companion descriptors
183 * within an endpoint descriptor in an interface descriptor. Starting
184 * value for the "ped" argument should be a valid endpoint companion
185 * descriptor.
186 *
187 * Return values:
188 * NULL: End of descriptors
189 * Else: A valid endpoint companion descriptor
190 *------------------------------------------------------------------------*/
191 struct usb_endpoint_ss_comp_descriptor *
usb_ed_comp_foreach(struct usb_config_descriptor * cd,struct usb_endpoint_ss_comp_descriptor * ped)192 usb_ed_comp_foreach(struct usb_config_descriptor *cd,
193 struct usb_endpoint_ss_comp_descriptor *ped)
194 {
195 struct usb_descriptor *desc;
196
197 desc = ((struct usb_descriptor *)ped);
198
199 while ((desc = usb_desc_foreach(cd, desc))) {
200 if (desc->bDescriptorType == UDESC_INTERFACE)
201 break;
202 if (desc->bDescriptorType == UDESC_ENDPOINT)
203 break;
204 if (desc->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
205 if (desc->bLength < sizeof(*ped)) {
206 /* endpoint companion descriptor is invalid */
207 break;
208 }
209 return ((struct usb_endpoint_ss_comp_descriptor *)desc);
210 }
211 }
212 return (NULL);
213 }
214
215 /*------------------------------------------------------------------------*
216 * usbd_get_no_descriptors
217 *
218 * This function will count the total number of descriptors in the
219 * configuration descriptor of type "type".
220 *------------------------------------------------------------------------*/
221 uint8_t
usbd_get_no_descriptors(struct usb_config_descriptor * cd,uint8_t type)222 usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type)
223 {
224 struct usb_descriptor *desc = NULL;
225 uint8_t count = 0;
226
227 while ((desc = usb_desc_foreach(cd, desc))) {
228 if (desc->bDescriptorType == type) {
229 count++;
230 if (count == 0xFF)
231 break; /* crazy */
232 }
233 }
234 return (count);
235 }
236
237 /*------------------------------------------------------------------------*
238 * usbd_get_no_alts
239 *
240 * Return value:
241 * Number of alternate settings for the given interface descriptor
242 * pointer. If the USB descriptor is corrupt, the returned value can
243 * be greater than the actual number of alternate settings.
244 *------------------------------------------------------------------------*/
245 uint8_t
usbd_get_no_alts(struct usb_config_descriptor * cd,struct usb_interface_descriptor * id)246 usbd_get_no_alts(struct usb_config_descriptor *cd,
247 struct usb_interface_descriptor *id)
248 {
249 struct usb_descriptor *desc;
250 uint8_t n;
251 uint8_t ifaceno;
252
253 /* Reset interface count */
254
255 n = 0;
256
257 /* Get the interface number */
258
259 ifaceno = id->bInterfaceNumber;
260
261 /* Iterate all the USB descriptors */
262
263 desc = NULL;
264 while ((desc = usb_desc_foreach(cd, desc))) {
265 if ((desc->bDescriptorType == UDESC_INTERFACE) &&
266 (desc->bLength >= sizeof(*id))) {
267 id = (struct usb_interface_descriptor *)desc;
268 if (id->bInterfaceNumber == ifaceno) {
269 n++;
270 if (n == 0xFF)
271 break; /* crazy */
272 }
273 }
274 }
275 return (n);
276 }
277