• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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