xref: /freebsd/sys/dev/usb/usb_parse.c (revision 71625ec9)
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 #ifdef USB_GLOBAL_INCLUDE_FILE
29 #include USB_GLOBAL_INCLUDE_FILE
30 #else
31 #include <sys/stdint.h>
32 #include <sys/stddef.h>
33 #include <sys/param.h>
34 #include <sys/queue.h>
35 #include <sys/types.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/bus.h>
39 #include <sys/module.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/condvar.h>
43 #include <sys/sysctl.h>
44 #include <sys/sx.h>
45 #include <sys/unistd.h>
46 #include <sys/callout.h>
47 #include <sys/malloc.h>
48 #include <sys/priv.h>
49 
50 #include <dev/usb/usb.h>
51 #include <dev/usb/usbdi.h>
52 #include <dev/usb/usbdi_util.h>
53 
54 #define	USB_DEBUG_VAR usb_debug
55 
56 #include <dev/usb/usb_core.h>
57 #include <dev/usb/usb_debug.h>
58 #endif			/* USB_GLOBAL_INCLUDE_FILE */
59 
60 /*------------------------------------------------------------------------*
61  *	usb_desc_foreach
62  *
63  * This function is the safe way to iterate across the USB config
64  * descriptor. It contains several checks against invalid
65  * descriptors. If the "desc" argument passed to this function is
66  * "NULL" the first descriptor, if any, will be returned.
67  *
68  * Return values:
69  *   NULL: End of descriptors
70  *   Else: Next descriptor after "desc"
71  *------------------------------------------------------------------------*/
72 struct usb_descriptor *
usb_desc_foreach(struct usb_config_descriptor * cd,struct usb_descriptor * _desc)73 usb_desc_foreach(struct usb_config_descriptor *cd,
74     struct usb_descriptor *_desc)
75 {
76 	uint8_t *desc_next;
77 	uint8_t *start;
78 	uint8_t *end;
79 	uint8_t *desc;
80 
81 	/* be NULL safe */
82 	if (cd == NULL)
83 		return (NULL);
84 
85 	/* We assume that the "wTotalLength" has been checked. */
86 	start = (uint8_t *)cd;
87 	end = start + UGETW(cd->wTotalLength);
88 	desc = (uint8_t *)_desc;
89 
90 	/* Get start of next USB descriptor. */
91 	if (desc == NULL)
92 		desc = start;
93 	else
94 		desc = desc + desc[0];
95 
96 	/* Check that the next USB descriptor is within the range. */
97 	if ((desc < start) || (desc >= end))
98 		return (NULL);		/* out of range, or EOD */
99 
100 	/* Check that the second next USB descriptor is within range. */
101 	desc_next = desc + desc[0];
102 	if ((desc_next < start) || (desc_next > end))
103 		return (NULL);		/* out of range */
104 
105 	/* Check minimum descriptor length. */
106 	if (desc[0] < 3)
107 		return (NULL);		/* too short descriptor */
108 
109 	/* Return start of next descriptor. */
110 	return ((struct usb_descriptor *)desc);
111 }
112 
113 /*------------------------------------------------------------------------*
114  *	usb_idesc_foreach
115  *
116  * This function will iterate the interface descriptors in the config
117  * descriptor. The parse state structure should be zeroed before
118  * calling this function the first time.
119  *
120  * Return values:
121  *   NULL: End of descriptors
122  *   Else: A valid interface descriptor
123  *------------------------------------------------------------------------*/
124 struct usb_interface_descriptor *
usb_idesc_foreach(struct usb_config_descriptor * cd,struct usb_idesc_parse_state * ps)125 usb_idesc_foreach(struct usb_config_descriptor *cd,
126     struct usb_idesc_parse_state *ps)
127 {
128 	struct usb_interface_descriptor *id;
129 	uint8_t new_iface;
130 
131 	/* retrieve current descriptor */
132 	id = (struct usb_interface_descriptor *)ps->desc;
133 	/* default is to start a new interface */
134 	new_iface = 1;
135 
136 	while (1) {
137 		id = (struct usb_interface_descriptor *)
138 		    usb_desc_foreach(cd, (struct usb_descriptor *)id);
139 		if (id == NULL)
140 			break;
141 		if ((id->bDescriptorType == UDESC_INTERFACE) &&
142 		    (id->bLength >= sizeof(*id))) {
143 			if (ps->iface_no_last == id->bInterfaceNumber) {
144 				/*
145 				 * Don't allow more than 256 alternate
146 				 * settings to avoid overflowing the
147 				 * alternate index which is a 8-bit
148 				 * variable.
149 				 */
150 				if (ps->iface_index_alt == 255) {
151 					DPRINTF("Interface(%u) has more than 256 alternate settings\n",
152 					    id->bInterfaceNumber);
153 					continue;
154 				}
155 				new_iface = 0;
156 			}
157 			ps->iface_no_last = id->bInterfaceNumber;
158 			break;
159 		}
160 	}
161 
162 	if (ps->desc == NULL) {
163 		/* first time or zero descriptors */
164 	} else if (new_iface) {
165 		/* new interface */
166 		ps->iface_index ++;
167 		ps->iface_index_alt = 0;
168 	} else {
169 		/* new alternate interface */
170 		ps->iface_index_alt ++;
171 	}
172 #if (USB_IFACE_MAX <= 0)
173 #error "USB_IFACE_MAX must be defined greater than zero"
174 #endif
175 	/* check for too many interfaces */
176 	if (ps->iface_index >= USB_IFACE_MAX) {
177 		DPRINTF("Interface limit reached\n");
178 		id = NULL;
179 	}
180 
181 	/* store and return current descriptor */
182 	ps->desc = (struct usb_descriptor *)id;
183 	return (id);
184 }
185 
186 /*------------------------------------------------------------------------*
187  *	usb_edesc_foreach
188  *
189  * This function will iterate all the endpoint descriptors within an
190  * interface descriptor. Starting value for the "ped" argument should
191  * be a valid interface descriptor.
192  *
193  * Return values:
194  *   NULL: End of descriptors
195  *   Else: A valid endpoint descriptor
196  *------------------------------------------------------------------------*/
197 struct usb_endpoint_descriptor *
usb_edesc_foreach(struct usb_config_descriptor * cd,struct usb_endpoint_descriptor * ped)198 usb_edesc_foreach(struct usb_config_descriptor *cd,
199     struct usb_endpoint_descriptor *ped)
200 {
201 	struct usb_descriptor *desc;
202 
203 	desc = ((struct usb_descriptor *)ped);
204 
205 	while ((desc = usb_desc_foreach(cd, desc))) {
206 		if (desc->bDescriptorType == UDESC_INTERFACE) {
207 			break;
208 		}
209 		if (desc->bDescriptorType == UDESC_ENDPOINT) {
210 			if (desc->bLength < sizeof(*ped)) {
211 				/* endpoint descriptor is invalid */
212 				break;
213 			}
214 			return ((struct usb_endpoint_descriptor *)desc);
215 		}
216 	}
217 	return (NULL);
218 }
219 
220 /*------------------------------------------------------------------------*
221  *	usb_ed_comp_foreach
222  *
223  * This function will iterate all the endpoint companion descriptors
224  * within an endpoint descriptor in an interface descriptor. Starting
225  * value for the "ped" argument should be a valid endpoint companion
226  * descriptor.
227  *
228  * Return values:
229  *   NULL: End of descriptors
230  *   Else: A valid endpoint companion descriptor
231  *------------------------------------------------------------------------*/
232 struct usb_endpoint_ss_comp_descriptor *
usb_ed_comp_foreach(struct usb_config_descriptor * cd,struct usb_endpoint_ss_comp_descriptor * ped)233 usb_ed_comp_foreach(struct usb_config_descriptor *cd,
234     struct usb_endpoint_ss_comp_descriptor *ped)
235 {
236 	struct usb_descriptor *desc;
237 
238 	desc = ((struct usb_descriptor *)ped);
239 
240 	while ((desc = usb_desc_foreach(cd, desc))) {
241 		if (desc->bDescriptorType == UDESC_INTERFACE)
242 			break;
243 		if (desc->bDescriptorType == UDESC_ENDPOINT)
244 			break;
245 		if (desc->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
246 			if (desc->bLength < sizeof(*ped)) {
247 				/* endpoint companion descriptor is invalid */
248 				break;
249 			}
250 			return ((struct usb_endpoint_ss_comp_descriptor *)desc);
251 		}
252 	}
253 	return (NULL);
254 }
255 
256 /*------------------------------------------------------------------------*
257  *	usbd_get_no_descriptors
258  *
259  * This function will count the total number of descriptors in the
260  * configuration descriptor of type "type".
261  *------------------------------------------------------------------------*/
262 uint8_t
usbd_get_no_descriptors(struct usb_config_descriptor * cd,uint8_t type)263 usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type)
264 {
265 	struct usb_descriptor *desc = NULL;
266 	uint8_t count = 0;
267 
268 	while ((desc = usb_desc_foreach(cd, desc))) {
269 		if (desc->bDescriptorType == type) {
270 			count++;
271 			if (count == 0xFF)
272 				break;			/* crazy */
273 		}
274 	}
275 	return (count);
276 }
277 
278 /*------------------------------------------------------------------------*
279  *	usbd_get_no_alts
280  *
281  * Return value:
282  *   Number of alternate settings for the given interface descriptor
283  *   pointer. If the USB descriptor is corrupt, the returned value can
284  *   be greater than the actual number of alternate settings.
285  *------------------------------------------------------------------------*/
286 uint8_t
usbd_get_no_alts(struct usb_config_descriptor * cd,struct usb_interface_descriptor * id)287 usbd_get_no_alts(struct usb_config_descriptor *cd,
288     struct usb_interface_descriptor *id)
289 {
290 	struct usb_descriptor *desc;
291 	uint8_t n;
292 	uint8_t ifaceno;
293 
294 	/* Reset interface count */
295 
296 	n = 0;
297 
298 	/* Get the interface number */
299 
300 	ifaceno = id->bInterfaceNumber;
301 
302 	/* Iterate all the USB descriptors */
303 
304 	desc = NULL;
305 	while ((desc = usb_desc_foreach(cd, desc))) {
306 		if ((desc->bDescriptorType == UDESC_INTERFACE) &&
307 		    (desc->bLength >= sizeof(*id))) {
308 			id = (struct usb_interface_descriptor *)desc;
309 			if (id->bInterfaceNumber == ifaceno) {
310 				n++;
311 				if (n == 0xFF)
312 					break;		/* crazy */
313 			}
314 		}
315 	}
316 	return (n);
317 }
318