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
26
27 /*
28 * Descriptor parsing functions
29 */
30 #define USBA_FRAMEWORK
31 #include <sys/usb/usba/usba_impl.h>
32 #include <sys/strsun.h>
33
34 #define INCREMENT_BUF(buf) \
35 if ((buf)[0] == 0) { \
36 break; \
37 } else { \
38 (buf) += (buf)[0]; \
39 }
40 #define isdigit(ch) ((ch >= '0') && (ch <= '9'))
41
42 extern usba_cfg_pwr_descr_t default_cfg_power;
43 extern usba_if_pwr_descr_t default_if_power;
44
45 size_t
usb_parse_data(char * format,uchar_t * data,size_t datalen,void * structure,size_t structlen)46 usb_parse_data(char *format,
47 uchar_t *data,
48 size_t datalen,
49 void *structure,
50 size_t structlen)
51 {
52 int fmt;
53 int counter = 1;
54 int multiplier = 0;
55 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
usb_parse_CV_descr(char * format,uchar_t * data,size_t datalen,void * structure,size_t structlen)171 usb_parse_CV_descr(char *format,
172 uchar_t *data,
173 size_t datalen,
174 void *structure,
175 size_t structlen)
176 {
177 return (usb_parse_data(format, data, datalen, structure,
178 structlen));
179 }
180
181
182 /*
183 * Helper function: returns pointer to n-th descriptor of
184 * type descr_type, unless the end of the buffer or a descriptor
185 * of type stop_descr_type1 or stop_descr_type2 is encountered first.
186 */
187 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)188 usb_nth_descr(uchar_t *buf,
189 size_t buflen,
190 int descr_type,
191 uint_t n,
192 int stop_descr_type1,
193 int stop_descr_type2)
194 {
195 uchar_t *bufstart = buf;
196 uchar_t *bufend = buf + buflen;
197
198 if (buf == NULL) {
199
200 return (NULL);
201 }
202
203 while (buf + 2 <= bufend) {
204 if ((buf != bufstart) && ((buf[1] == stop_descr_type1) ||
205 (buf[1] == stop_descr_type2))) {
206
207 return (NULL);
208 }
209
210 if ((descr_type == USB_DESCR_TYPE_ANY) ||
211 (buf[1] == descr_type)) {
212 if (n-- == 0) {
213
214 return (buf);
215 }
216 }
217
218 /*
219 * Check for a bad buffer.
220 * If buf[0] is 0, then this will be an infite loop
221 */
222 INCREMENT_BUF(buf);
223 }
224
225 return (NULL);
226 }
227
228
229 size_t
usb_parse_dev_descr(uchar_t * buf,size_t buflen,usb_dev_descr_t * ret_descr,size_t ret_buf_len)230 usb_parse_dev_descr(uchar_t *buf, /* from GET_DESCRIPTOR(DEVICE) */
231 size_t buflen,
232 usb_dev_descr_t *ret_descr,
233 size_t ret_buf_len)
234 {
235 if ((buf == NULL) || (ret_descr == NULL) ||
236 (buflen < 2) || (buf[1] != USB_DESCR_TYPE_DEV)) {
237
238 return (USB_PARSE_ERROR);
239 }
240
241 return (usb_parse_data("ccsccccssscccc",
242 buf, buflen, ret_descr, ret_buf_len));
243 }
244
245
246 size_t
usb_parse_cfg_descr(uchar_t * buf,size_t buflen,usb_cfg_descr_t * ret_descr,size_t ret_buf_len)247 usb_parse_cfg_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
248 size_t buflen,
249 usb_cfg_descr_t *ret_descr,
250 size_t ret_buf_len)
251 {
252 if ((buf == NULL) || (ret_descr == NULL) ||
253 (buflen < 2) || (buf[1] != USB_DESCR_TYPE_CFG)) {
254
255 return (USB_PARSE_ERROR);
256 }
257
258 return (usb_parse_data("ccsccccc",
259 buf, buflen, ret_descr, ret_buf_len));
260 }
261
262
263 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)264 usba_parse_cfg_pwr_descr(
265 uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
266 size_t buflen,
267 usba_cfg_pwr_descr_t *ret_descr,
268 size_t ret_buf_len)
269 {
270 uchar_t *bufend = buf + buflen;
271
272 if ((buf == NULL) || (ret_descr == NULL)) {
273
274 return (USB_PARSE_ERROR);
275 }
276 while (buf + 2 <= bufend) {
277
278 if (buf[1] == USBA_DESCR_TYPE_CFG_PWR_1_1) {
279 return (usb_parse_data("ccsccccccccsss",
280 buf, buflen, ret_descr, ret_buf_len));
281 }
282
283 /*
284 * Check for a bad buffer.
285 * If buf[0] is 0, then this will be an infinite loop
286 */
287 INCREMENT_BUF(buf);
288 }
289
290 /* return the default configuration power descriptor */
291 bcopy(&default_cfg_power, ret_descr, USBA_CFG_PWR_DESCR_SIZE);
292
293 return (ret_descr->bLength);
294
295 }
296
297
298 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)299 usb_parse_ia_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
300 size_t buflen,
301 size_t first_if,
302 usb_ia_descr_t *ret_descr,
303 size_t ret_buf_len)
304 {
305 uchar_t *bufend = buf + buflen;
306
307 if ((buf == NULL) || (ret_descr == NULL)) {
308
309 return (USB_PARSE_ERROR);
310 }
311
312 while (buf + USB_IA_DESCR_SIZE <= bufend) {
313 if ((buf[1] == USB_DESCR_TYPE_IA) &&
314 (buf[2] == first_if)) {
315
316 return (usb_parse_data("cccccccc",
317 buf, _PTRDIFF(bufend, buf),
318 ret_descr, ret_buf_len));
319 }
320
321 /*
322 * Check for a bad buffer.
323 * If buf[0] is 0, then this will be an infinite loop
324 */
325 INCREMENT_BUF(buf);
326 }
327
328 return (USB_PARSE_ERROR);
329 }
330
331
332 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)333 usb_parse_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
334 size_t buflen,
335 uint_t if_number,
336 uint_t alt_if_setting,
337 usb_if_descr_t *ret_descr,
338 size_t ret_buf_len)
339 {
340 uchar_t *bufend = buf + buflen;
341
342 if ((buf == NULL) || (ret_descr == NULL)) {
343
344 return (USB_PARSE_ERROR);
345 }
346
347 while (buf + 4 <= bufend) {
348 if ((buf[1] == USB_DESCR_TYPE_IF) &&
349 (buf[2] == if_number) &&
350 (buf[3] == alt_if_setting)) {
351
352 return (usb_parse_data("ccccccccc",
353 buf, _PTRDIFF(bufend, buf),
354 ret_descr, ret_buf_len));
355 }
356
357 /*
358 * Check for a bad buffer.
359 * If buf[0] is 0, then this will be an infinite loop
360 */
361 INCREMENT_BUF(buf);
362 }
363
364 return (USB_PARSE_ERROR);
365 }
366
367 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)368 usba_parse_if_pwr_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
369 size_t buflen,
370 uint_t if_number,
371 uint_t alt_if_setting,
372 usba_if_pwr_descr_t *ret_descr,
373 size_t ret_buf_len)
374 {
375 uchar_t *bufend = buf + buflen;
376
377 if ((buf == NULL) || (ret_descr == NULL)) {
378
379 return (USB_PARSE_ERROR);
380 }
381
382 while (buf + 4 <= bufend) {
383 if ((buf[1] == USB_DESCR_TYPE_IF) &&
384 (buf[2] == if_number) &&
385 (buf[3] == alt_if_setting)) {
386
387 buf += buf[0];
388
389 if (buf + 2 <= bufend) {
390 if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) {
391
392 return (
393 usb_parse_data("cccccccccsss", buf,
394 _PTRDIFF(bufend, buf), ret_descr,
395 ret_buf_len));
396 } else {
397 break;
398 }
399 } else {
400 break;
401 }
402 }
403
404 /*
405 * Check for a bad buffer.
406 * If buf[0] is 0, then this will be an infinite loop
407 */
408 INCREMENT_BUF(buf);
409 }
410
411 /* return the default interface power descriptor */
412 bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE);
413
414 return (ret_descr->bLength);
415 }
416
417
418 /*
419 * the endpoint index is relative to the interface. index 0 is
420 * the first endpoint
421 */
422 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)423 usb_parse_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
424 size_t buflen,
425 uint_t if_number,
426 uint_t alt_if_setting,
427 uint_t ep_index,
428 usb_ep_descr_t *ret_descr,
429 size_t ret_buf_len)
430 {
431 uchar_t *bufend = buf + buflen;
432
433 if ((buf == NULL) || (ret_descr == NULL)) {
434
435 return (USB_PARSE_ERROR);
436 }
437
438 while ((buf + 4) <= bufend) {
439 if (buf[1] == USB_DESCR_TYPE_IF &&
440 buf[2] == if_number &&
441 buf[3] == alt_if_setting) {
442 if ((buf = usb_nth_descr(buf,
443 _PTRDIFF(bufend, buf),
444 USB_DESCR_TYPE_EP, ep_index,
445 USB_DESCR_TYPE_IF, -1)) == NULL) {
446
447 break;
448 }
449
450 return (usb_parse_data("ccccsc",
451 buf, _PTRDIFF(bufend, buf),
452 ret_descr, ret_buf_len));
453 }
454
455 /*
456 * Check for a bad buffer.
457 * If buf[0] is 0, then this will be an infinite loop
458 */
459 INCREMENT_BUF(buf);
460 }
461
462 return (USB_PARSE_ERROR);
463 }
464
465
466 /*
467 * Returns (at ret_descr) a null-terminated string. Null termination is
468 * guaranteed, even if the string is longer than the buffer. Thus, a
469 * maximum of (ret_buf_len - 1) characters are returned.
470 * Stops silently on first character not in UNICODE format.
471 */
472 /*ARGSUSED*/
473 size_t
usba_ascii_string_descr(uchar_t * buf,size_t buflen,char * ret_descr,size_t ret_buf_len)474 usba_ascii_string_descr(uchar_t *buf, /* from GET_DESCRIPTOR(STRING) */
475 size_t buflen,
476 char *ret_descr,
477 size_t ret_buf_len)
478 {
479 int i = 1;
480 char *retstart = ret_descr;
481 uchar_t *bufend = buf + buflen;
482
483 if ((buf == NULL) || (ret_descr == NULL) ||
484 (ret_buf_len == 0) || (buflen < 2) ||
485 (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) {
486
487 return (USB_PARSE_ERROR);
488 }
489
490 for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 &&
491 buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) {
492 *ret_descr++ = buf[0];
493 }
494
495 *ret_descr++ = 0;
496
497 return (_PTRDIFF(ret_descr, retstart));
498 }
499
500
501 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)502 usb_parse_CV_cfg_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
503 size_t buflen,
504 char *fmt,
505 uint_t descr_type,
506 uint_t descr_index,
507 void *ret_descr,
508 size_t ret_buf_len)
509 {
510 uchar_t *bufend = buf + buflen;
511
512 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL) ||
513 (buflen < 2) || ((buf = usb_nth_descr(buf, buflen, descr_type,
514 descr_index, -1, -1)) == NULL)) {
515
516 return (USB_PARSE_ERROR);
517 }
518
519 return (usb_parse_data(fmt, buf,
520 _PTRDIFF(bufend, buf), ret_descr,
521 ret_buf_len));
522 }
523
524
525 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)526 usb_parse_CV_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
527 size_t buflen,
528 char *fmt,
529 uint_t if_number,
530 uint_t alt_if_setting,
531 uint_t descr_type,
532 uint_t descr_index,
533 void *ret_descr,
534 size_t ret_buf_len)
535 {
536 uchar_t *bufend = buf + buflen;
537
538 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
539
540 return (USB_PARSE_ERROR);
541 }
542
543 while (buf + 4 <= bufend) {
544 if ((buf[1] == USB_DESCR_TYPE_IF) &&
545 (buf[2] == if_number) &&
546 (buf[3] == alt_if_setting)) {
547 if ((buf = usb_nth_descr(buf,
548 _PTRDIFF(bufend, buf), descr_type,
549 descr_index, USB_DESCR_TYPE_IF, -1)) ==
550 NULL) {
551 break;
552 }
553
554 return (usb_parse_data(fmt, buf,
555 _PTRDIFF(bufend, buf),
556 ret_descr, ret_buf_len));
557 }
558
559 /*
560 * Check for a bad buffer.
561 * If buf[0] is 0, then this will be an infinite loop
562 */
563 INCREMENT_BUF(buf);
564 }
565
566 return (USB_PARSE_ERROR);
567 }
568
569
570 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)571 usb_parse_CV_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
572 size_t buflen,
573 char *fmt,
574 uint_t if_number,
575 uint_t alt_if_setting,
576 uint_t ep_index,
577 uint_t descr_type,
578 uint_t descr_index,
579 void *ret_descr,
580 size_t ret_buf_len)
581 {
582 uchar_t *bufend = buf + buflen;
583
584 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) {
585
586 return (USB_PARSE_ERROR);
587 }
588
589 while (buf + 4 <= bufend) {
590 if ((buf[1] == USB_DESCR_TYPE_IF) &&
591 (buf[2] == if_number) &&
592 (buf[3] == alt_if_setting)) {
593 if ((buf = usb_nth_descr(buf,
594 _PTRDIFF(bufend, buf),
595 USB_DESCR_TYPE_EP, ep_index,
596 USB_DESCR_TYPE_IF, -1)) == NULL) {
597
598 break;
599 }
600
601 if ((buf = usb_nth_descr(buf,
602 _PTRDIFF(bufend, buf),
603 descr_type, descr_index,
604 USB_DESCR_TYPE_EP,
605 USB_DESCR_TYPE_IF)) == NULL) {
606
607 break;
608 }
609
610 return (usb_parse_data(fmt, buf,
611 _PTRDIFF(bufend, buf),
612 ret_descr, ret_buf_len));
613 }
614
615 /*
616 * Check for a bad buffer.
617 * If buf[0] is 0, then this will be an infite loop
618 */
619 INCREMENT_BUF(buf);
620 }
621
622 return (USB_PARSE_ERROR);
623 }
624
625 size_t
usb_parse_bos_descr(uchar_t * buf,size_t buflen,usb_bos_descr_t * ret_descr,size_t ret_buf_len)626 usb_parse_bos_descr(uchar_t *buf, /* from GET_DESCRIPTOR(BOS) */
627 size_t buflen,
628 usb_bos_descr_t *ret_descr,
629 size_t ret_buf_len)
630 {
631 if ((buf == NULL) || (ret_descr == NULL) ||
632 (buflen < 2) || (buf[1] != USB_DESCR_TYPE_BOS)) {
633
634 return (USB_PARSE_ERROR);
635 }
636
637 return (usb_parse_data("ccsc",
638 buf, buflen, ret_descr, ret_buf_len));
639 }
640
641 size_t
usb_parse_uwb_bos_descr(uchar_t * buf,size_t buflen,usb_uwb_cap_descr_t * ret_descr,size_t ret_buf_len)642 usb_parse_uwb_bos_descr(uchar_t *buf, /* from GET_DESCRIPTOR(BOS) */
643 size_t buflen,
644 usb_uwb_cap_descr_t *ret_descr,
645 size_t ret_buf_len)
646 {
647 uchar_t *bufend = buf + buflen;
648
649 if ((buf == NULL) || (ret_descr == NULL)) {
650
651 return (USB_PARSE_ERROR);
652 }
653
654 while (buf + 3 <= bufend) {
655 if ((buf[1] == USB_DESCR_TYPE_DEV_CAPABILITY) &&
656 (buf[2] == USB_CAP_TYPE_WUSB)) {
657
658 return (usb_parse_data("ccccsccsc",
659 buf, _PTRDIFF(bufend, buf), ret_descr,
660 ret_buf_len));
661 }
662
663 INCREMENT_BUF(buf);
664 }
665
666 return (USB_PARSE_ERROR);
667 }
668
669 size_t
usb_parse_comp_ep_descr(uchar_t * buf,size_t buflen,uint_t if_number,uint_t alt_if_setting,uint_t ep_index,usb_ep_comp_descr_t * ret_descr,size_t ret_buf_len)670 usb_parse_comp_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */
671 size_t buflen,
672 uint_t if_number,
673 uint_t alt_if_setting,
674 uint_t ep_index,
675 usb_ep_comp_descr_t *ret_descr,
676 size_t ret_buf_len)
677 {
678 return (usb_parse_CV_ep_descr(buf, buflen, "ccccsscc",
679 if_number, alt_if_setting, ep_index,
680 USB_DESCR_TYPE_WIRELESS_EP_COMP, 0,
681 ret_descr, ret_buf_len));
682 }
683