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