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