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