xref: /illumos-gate/usr/src/uts/common/io/usb/usba/parser.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
26  * Copyright 2019, Joyent, Inc.
27  */
28 
29 
30 /*
31  * Descriptor parsing functions
32  */
33 #define	USBA_FRAMEWORK
34 #include <sys/usb/usba/usba_impl.h>
35 #include <sys/strsun.h>
36 
37 #define	INCREMENT_BUF(buf) \
38 		if ((buf)[0] == 0) { \
39 			break; \
40 		} else { \
41 			(buf) += (buf)[0]; \
42 		}
43 #define	isdigit(ch) ((ch >= '0') && (ch <= '9'))
44 
45 extern usba_cfg_pwr_descr_t default_cfg_power;
46 extern usba_if_pwr_descr_t default_if_power;
47 
48 size_t
49 usb_parse_data(char *format, const uchar_t  *data, size_t datalen,
50     void *structure, size_t structlen)
51 {
52 	int	fmt;
53 	int	counter = 1;
54 	int	multiplier = 0;
55 	const uchar_t	*dataend = data + datalen;
56 	char	*structstart = (char *)structure;
57 	void	*structend = (void *)((intptr_t)structstart + structlen);
58 
59 	if ((format == NULL) || (data == NULL) || (structure == NULL)) {
60 
61 		return (USB_PARSE_ERROR);
62 	}
63 
64 	while ((fmt = *format) != '\0') {
65 
66 		/*
67 		 * Could some one pass a "format" that is greater than
68 		 * the structlen? Conversely, one could pass a ret_buf_len
69 		 * that is less than the "format" length.
70 		 * If so, we need to protect against writing over memory.
71 		 */
72 		if (counter++ > structlen) {
73 			break;
74 		}
75 
76 		if (fmt == 'c') {
77 			uint8_t	*cp = (uint8_t *)structure;
78 
79 			cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
80 			    ~(_CHAR_ALIGNMENT - 1));
81 			if (((data + 1) > dataend) ||
82 			    ((cp + 1) > (uint8_t *)structend))
83 				break;
84 
85 			*cp++ = *data++;
86 			structure = (void *)cp;
87 			if (multiplier) {
88 				multiplier--;
89 			}
90 			if (multiplier == 0) {
91 				format++;
92 			}
93 		} else if (fmt == 's') {
94 			uint16_t	*sp = (uint16_t *)structure;
95 
96 			sp = (uint16_t *)
97 			    (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
98 			    ~(_SHORT_ALIGNMENT - 1));
99 			if (((data + 2) > dataend) ||
100 			    ((sp + 1) > (uint16_t *)structend))
101 				break;
102 
103 			*sp++ = (data[1] << 8) + data[0];
104 			data += 2;
105 			structure = (void *)sp;
106 			if (multiplier) {
107 				multiplier--;
108 			}
109 			if (multiplier == 0) {
110 				format++;
111 			}
112 		} else if (fmt == 'l') {
113 			uint32_t	*lp = (uint32_t *)structure;
114 
115 			lp = (uint32_t *)
116 			    (((uintptr_t)lp + _INT_ALIGNMENT - 1) &
117 			    ~(_INT_ALIGNMENT - 1));
118 			if (((data + 4) > dataend) ||
119 			    ((lp + 1) > (uint32_t *)structend))
120 				break;
121 
122 			*lp++ = (((((
123 			    (uint32_t)data[3] << 8) | data[2]) << 8) |
124 			    data[1]) << 8) | data[0];
125 			data += 4;
126 			structure = (void *)lp;
127 			if (multiplier) {
128 				multiplier--;
129 			}
130 			if (multiplier == 0) {
131 				format++;
132 			}
133 		} else if (fmt == 'L') {
134 			uint64_t	*llp = (uint64_t *)structure;
135 
136 			llp = (uint64_t *)
137 			    (((uintptr_t)llp + _LONG_LONG_ALIGNMENT - 1) &
138 			    ~(_LONG_LONG_ALIGNMENT - 1));
139 			if (((data + 8) > dataend) ||
140 			    ((llp + 1) >= (uint64_t *)structend))
141 				break;
142 
143 			*llp++ = (((((((((((((data[7] << 8) |
144 			    data[6]) << 8) | data[5]) << 8) |
145 			    data[4]) << 8) | data[3]) << 8) |
146 			    data[2]) << 8) | data[1]) << 8) |
147 			    data[0];
148 			data += 8;
149 			structure = (void *)llp;
150 			if (multiplier) {
151 				multiplier--;
152 			}
153 			if (multiplier == 0) {
154 				format++;
155 			}
156 		} else if (isdigit(fmt)) {
157 			multiplier = (multiplier * 10) + (fmt - '0');
158 			format++;
159 			counter--;
160 		} else {
161 			multiplier = 0;
162 			break;
163 		}
164 	}
165 
166 	return ((intptr_t)structure - (intptr_t)structstart);
167 }
168 
169 
170 size_t
171 usb_parse_CV_descr(char *format, const uchar_t *data, size_t datalen,
172     void *structure, size_t structlen)
173 {
174 	return (usb_parse_data(format, data, datalen, structure,
175 	    structlen));
176 }
177 
178 
179 /*
180  *	Helper function: returns pointer to n-th descriptor of
181  *	type descr_type, unless the end of the buffer or a descriptor
182  *	of type	stop_descr_type1 or stop_descr_type2 is encountered first.
183  */
184 static const uchar_t *
185 usb_nth_descr(const uchar_t *buf, size_t buflen, int descr_type, uint_t n,
186     int stop_descr_type1, int stop_descr_type2)
187 {
188 	const uchar_t	*bufstart = buf;
189 	const uchar_t *bufend = buf + buflen;
190 
191 	if (buf == NULL) {
192 
193 		return (NULL);
194 	}
195 
196 	while (buf + 2 <= bufend) {
197 		if ((buf != bufstart) && ((buf[1] == stop_descr_type1) ||
198 		    (buf[1] == stop_descr_type2))) {
199 
200 			return (NULL);
201 		}
202 
203 		if ((descr_type == USB_DESCR_TYPE_ANY) ||
204 		    (buf[1] == descr_type)) {
205 			if (n-- == 0) {
206 
207 				return (buf);
208 			}
209 		}
210 
211 		/*
212 		 * Check for a bad buffer.
213 		 * If buf[0] is 0, then this will be an infite loop
214 		 */
215 		INCREMENT_BUF(buf);
216 	}
217 
218 	return (NULL);
219 }
220 
221 
222 size_t
223 usb_parse_dev_descr(const uchar_t *buf, size_t buflen,
224     usb_dev_descr_t *ret_descr, size_t ret_buf_len)
225 {
226 	if ((buf == NULL) || (ret_descr == NULL) ||
227 	    (buflen < 2) || (buf[1] != USB_DESCR_TYPE_DEV)) {
228 
229 		return (USB_PARSE_ERROR);
230 	}
231 
232 	return (usb_parse_data("ccsccccssscccc",
233 	    buf, buflen, ret_descr, ret_buf_len));
234 }
235 
236 
237 size_t
238 usb_parse_cfg_descr(const uchar_t *buf, size_t buflen,
239     usb_cfg_descr_t *ret_descr, size_t ret_buf_len)
240 {
241 	if ((buf == NULL) || (ret_descr == NULL) ||
242 	    (buflen < 2) || (buf[1] != USB_DESCR_TYPE_CFG)) {
243 
244 		return (USB_PARSE_ERROR);
245 	}
246 
247 	return (usb_parse_data("ccsccccc",
248 	    buf, buflen, ret_descr, ret_buf_len));
249 }
250 
251 
252 size_t
253 usba_parse_cfg_pwr_descr(const uchar_t *buf, size_t buflen,
254     usba_cfg_pwr_descr_t *ret_descr, size_t ret_buf_len)
255 {
256 	const uchar_t *bufend = buf + buflen;
257 
258 	if ((buf == NULL) || (ret_descr == NULL)) {
259 
260 		return (USB_PARSE_ERROR);
261 	}
262 	while (buf + 2 <= bufend) {
263 
264 		if (buf[1] == USBA_DESCR_TYPE_CFG_PWR_1_1) {
265 			return (usb_parse_data("ccsccccccccsss",
266 			    buf, buflen, ret_descr, ret_buf_len));
267 		}
268 
269 		/*
270 		 * Check for a bad buffer.
271 		 * If buf[0] is 0, then this will be an infinite loop
272 		 */
273 		INCREMENT_BUF(buf);
274 	}
275 
276 	/* return the default configuration power descriptor */
277 	bcopy(&default_cfg_power, ret_descr, USBA_CFG_PWR_DESCR_SIZE);
278 
279 	return (ret_descr->bLength);
280 
281 }
282 
283 
284 size_t
285 usb_parse_ia_descr(const uchar_t *buf, size_t buflen, size_t first_if,
286     usb_ia_descr_t *ret_descr, size_t ret_buf_len)
287 {
288 	const uchar_t *bufend = buf + buflen;
289 
290 	if ((buf == NULL) || (ret_descr == NULL)) {
291 
292 		return (USB_PARSE_ERROR);
293 	}
294 
295 	while (buf + USB_IA_DESCR_SIZE <= bufend) {
296 		if ((buf[1] == USB_DESCR_TYPE_IA) &&
297 		    (buf[2] == first_if)) {
298 
299 			return (usb_parse_data("cccccccc",
300 			    buf, _PTRDIFF(bufend, buf),
301 			    ret_descr, ret_buf_len));
302 		}
303 
304 		/*
305 		 * Check for a bad buffer.
306 		 * If buf[0] is 0, then this will be an infinite loop
307 		 */
308 		INCREMENT_BUF(buf);
309 	}
310 
311 	return (USB_PARSE_ERROR);
312 }
313 
314 
315 size_t
316 usb_parse_if_descr(const uchar_t *buf, size_t buflen, uint_t if_number,
317     uint_t alt_if_setting, usb_if_descr_t *ret_descr, size_t ret_buf_len)
318 {
319 	const uchar_t *bufend = buf + buflen;
320 
321 	if ((buf == NULL) || (ret_descr == NULL)) {
322 
323 		return (USB_PARSE_ERROR);
324 	}
325 
326 	while (buf + 4 <= bufend) {
327 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
328 		    (buf[2] == if_number) &&
329 		    (buf[3] == alt_if_setting)) {
330 
331 			return (usb_parse_data("ccccccccc",
332 			    buf, _PTRDIFF(bufend, buf),
333 			    ret_descr, ret_buf_len));
334 		}
335 
336 		/*
337 		 * Check for a bad buffer.
338 		 * If buf[0] is 0, then this will be an infinite loop
339 		 */
340 		INCREMENT_BUF(buf);
341 	}
342 
343 	return (USB_PARSE_ERROR);
344 }
345 
346 size_t
347 usba_parse_if_pwr_descr(const uchar_t *buf, size_t buflen, uint_t if_number,
348     uint_t alt_if_setting, usba_if_pwr_descr_t *ret_descr, size_t ret_buf_len)
349 {
350 	const uchar_t *bufend = buf + buflen;
351 
352 	if ((buf == NULL) || (ret_descr == NULL)) {
353 
354 		return (USB_PARSE_ERROR);
355 	}
356 
357 	while (buf + 4 <= bufend) {
358 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
359 		    (buf[2] == if_number) &&
360 		    (buf[3] == alt_if_setting)) {
361 
362 			buf += buf[0];
363 
364 			if (buf + 2 <= bufend) {
365 				if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) {
366 
367 					return (
368 					    usb_parse_data("cccccccccsss", buf,
369 					    _PTRDIFF(bufend, buf), ret_descr,
370 					    ret_buf_len));
371 				} else {
372 					break;
373 				}
374 			} else {
375 				break;
376 			}
377 		}
378 
379 		/*
380 		 * Check for a bad buffer.
381 		 * If buf[0] is 0, then this will be an infinite loop
382 		 */
383 		INCREMENT_BUF(buf);
384 	}
385 
386 	/* return the default interface power descriptor */
387 	bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE);
388 
389 	return (ret_descr->bLength);
390 }
391 
392 
393 /*
394  * the endpoint index is relative to the interface. index 0 is
395  * the first endpoint
396  */
397 size_t
398 usb_parse_ep_descr(const uchar_t *buf, size_t buflen, uint_t if_number,
399     uint_t alt_if_setting, uint_t ep_index, usb_ep_descr_t *ret_descr,
400     size_t ret_buf_len)
401 {
402 	const uchar_t *bufend = buf + buflen;
403 
404 	if ((buf == NULL) || (ret_descr == NULL)) {
405 
406 		return (USB_PARSE_ERROR);
407 	}
408 
409 	while ((buf + 4) <= bufend) {
410 		if (buf[1] == USB_DESCR_TYPE_IF &&
411 		    buf[2] == if_number &&
412 		    buf[3] == alt_if_setting) {
413 			if ((buf = usb_nth_descr(buf,
414 			    _PTRDIFF(bufend, buf),
415 			    USB_DESCR_TYPE_EP, ep_index,
416 			    USB_DESCR_TYPE_IF, -1)) == NULL) {
417 
418 				break;
419 			}
420 
421 			return (usb_parse_data("ccccsc",
422 			    buf, _PTRDIFF(bufend, buf),
423 			    ret_descr, ret_buf_len));
424 		}
425 
426 		/*
427 		 * Check for a bad buffer.
428 		 * If buf[0] is 0, then this will be an infinite loop
429 		 */
430 		INCREMENT_BUF(buf);
431 	}
432 
433 	return (USB_PARSE_ERROR);
434 }
435 
436 
437 /*
438  * Returns (at ret_descr) a null-terminated string.  Null termination is
439  * guaranteed, even if the string is longer than the buffer.  Thus, a
440  * maximum of (ret_buf_len - 1) characters are returned.
441  * Stops silently on first character not in UNICODE format.
442  */
443 /*ARGSUSED*/
444 size_t
445 usba_ascii_string_descr(const uchar_t *buf, size_t buflen, char *ret_descr,
446     size_t ret_buf_len)
447 {
448 	int		i = 1;
449 	char		*retstart = ret_descr;
450 	const uchar_t	*bufend = buf + buflen;
451 
452 	if ((buf == NULL) || (ret_descr == NULL) ||
453 	    (ret_buf_len == 0) || (buflen < 2) ||
454 	    (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) {
455 
456 		return (USB_PARSE_ERROR);
457 	}
458 
459 	for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 &&
460 	    buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) {
461 		*ret_descr++ = buf[0];
462 	}
463 
464 	*ret_descr++ = 0;
465 
466 	return (_PTRDIFF(ret_descr, retstart));
467 }
468 
469 
470 size_t
471 usb_parse_CV_cfg_descr(const uchar_t *buf, size_t buflen, char *fmt,
472     uint_t descr_type, uint_t descr_index, void *ret_descr, size_t ret_buf_len)
473 {
474 	const uchar_t *bufend = buf + buflen;
475 
476 	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL) ||
477 	    (buflen < 2) || ((buf = usb_nth_descr(buf, buflen, descr_type,
478 	    descr_index, -1, -1)) == NULL)) {
479 
480 		return (USB_PARSE_ERROR);
481 	}
482 
483 	return (usb_parse_data(fmt, buf,
484 	    _PTRDIFF(bufend, buf), ret_descr,
485 	    ret_buf_len));
486 }
487 
488 
489 size_t
490 usb_parse_CV_if_descr(const uchar_t *buf, size_t buflen, char *fmt,
491     uint_t if_number, uint_t alt_if_setting, uint_t descr_type,
492     uint_t descr_index, void *ret_descr, size_t ret_buf_len)
493 {
494 	const uchar_t *bufend = buf + buflen;
495 
496 	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
497 
498 		return (USB_PARSE_ERROR);
499 	}
500 
501 	while (buf + 4 <= bufend) {
502 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
503 		    (buf[2] == if_number) &&
504 		    (buf[3] == alt_if_setting)) {
505 			if ((buf = usb_nth_descr(buf,
506 			    _PTRDIFF(bufend, buf), descr_type,
507 			    descr_index, USB_DESCR_TYPE_IF, -1)) ==
508 			    NULL) {
509 				break;
510 			}
511 
512 			return (usb_parse_data(fmt, buf,
513 			    _PTRDIFF(bufend, buf),
514 			    ret_descr, ret_buf_len));
515 		}
516 
517 		/*
518 		 * Check for a bad buffer.
519 		 * If buf[0] is 0, then this will be an infinite loop
520 		 */
521 		INCREMENT_BUF(buf);
522 	}
523 
524 	return (USB_PARSE_ERROR);
525 }
526 
527 
528 size_t
529 usb_parse_CV_ep_descr(const uchar_t *buf, size_t buflen, char *fmt,
530     uint_t if_number, uint_t alt_if_setting, uint_t ep_index, uint_t descr_type,
531     uint_t descr_index, void *ret_descr, size_t ret_buf_len)
532 {
533 	const uchar_t *bufend = buf + buflen;
534 
535 	if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
536 
537 		return (USB_PARSE_ERROR);
538 	}
539 
540 	while (buf + 4 <= bufend) {
541 		if ((buf[1] == USB_DESCR_TYPE_IF) &&
542 		    (buf[2] == if_number) &&
543 		    (buf[3] == alt_if_setting)) {
544 			if ((buf = usb_nth_descr(buf,
545 			    _PTRDIFF(bufend, buf),
546 			    USB_DESCR_TYPE_EP, ep_index,
547 			    USB_DESCR_TYPE_IF, -1)) == NULL) {
548 
549 				break;
550 			}
551 
552 			if ((buf = usb_nth_descr(buf,
553 			    _PTRDIFF(bufend, buf),
554 			    descr_type, descr_index,
555 			    USB_DESCR_TYPE_EP,
556 			    USB_DESCR_TYPE_IF)) == NULL) {
557 
558 				break;
559 			}
560 
561 			return (usb_parse_data(fmt, buf,
562 			    _PTRDIFF(bufend, buf),
563 			    ret_descr, ret_buf_len));
564 		}
565 
566 		/*
567 		 * Check for a bad buffer.
568 		 * If buf[0] is 0, then this will be an infite loop
569 		 */
570 		INCREMENT_BUF(buf);
571 	}
572 
573 	return (USB_PARSE_ERROR);
574 }
575