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