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