• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *------------------------------------------------------------------------*/
42 struct usb_descriptor *
usb_desc_foreach(struct usb_config_descriptor * cd,struct usb_descriptor * _desc)43 usb_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  *------------------------------------------------------------------------*/
94 struct usb_interface_descriptor *
usb_idesc_foreach(struct usb_config_descriptor * cd,struct usb_idesc_parse_state * ps)95 usb_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  *------------------------------------------------------------------------*/
167 struct usb_endpoint_descriptor *
usb_edesc_foreach(struct usb_config_descriptor * cd,struct usb_endpoint_descriptor * ped)168 usb_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  *------------------------------------------------------------------------*/
202 struct usb_endpoint_ss_comp_descriptor *
usb_ed_comp_foreach(struct usb_config_descriptor * cd,struct usb_endpoint_ss_comp_descriptor * ped)203 usb_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  *------------------------------------------------------------------------*/
232 uint8_t
usbd_get_no_descriptors(struct usb_config_descriptor * cd,uint8_t type)233 usbd_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  *------------------------------------------------------------------------*/
256 uint8_t
usbd_get_no_alts(struct usb_config_descriptor * cd,struct usb_interface_descriptor * id)257 usbd_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