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
usb_parse_data(char * format,const uchar_t * data,size_t datalen,void * structure,size_t structlen)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
usb_parse_CV_descr(char * format,const uchar_t * data,size_t datalen,void * structure,size_t structlen)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 *
usb_nth_descr(const uchar_t * buf,size_t buflen,int descr_type,uint_t n,int stop_descr_type1,int stop_descr_type2)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
usb_parse_dev_descr(const uchar_t * buf,size_t buflen,usb_dev_descr_t * ret_descr,size_t ret_buf_len)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
usb_parse_cfg_descr(const uchar_t * buf,size_t buflen,usb_cfg_descr_t * ret_descr,size_t ret_buf_len)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
usba_parse_cfg_pwr_descr(const uchar_t * buf,size_t buflen,usba_cfg_pwr_descr_t * ret_descr,size_t ret_buf_len)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
usb_parse_ia_descr(const uchar_t * buf,size_t buflen,size_t first_if,usb_ia_descr_t * ret_descr,size_t ret_buf_len)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
usb_parse_if_descr(const 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)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
usba_parse_if_pwr_descr(const 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)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
usb_parse_ep_descr(const 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)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
usba_ascii_string_descr(const uchar_t * buf,size_t buflen,char * ret_descr,size_t ret_buf_len)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
usb_parse_CV_cfg_descr(const uchar_t * buf,size_t buflen,char * fmt,uint_t descr_type,uint_t descr_index,void * ret_descr,size_t ret_buf_len)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
usb_parse_CV_if_descr(const 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)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
usb_parse_CV_ep_descr(const 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)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