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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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