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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Descriptor parsing functions 31 */ 32 #define USBA_FRAMEWORK 33 #include <sys/usb/usba/usba_impl.h> 34 35 #define INCREMENT_BUF(buf) \ 36 if ((buf)[0] == 0) { \ 37 break; \ 38 } else { \ 39 (buf) += (buf)[0]; \ 40 } 41 #define isdigit(ch) ((ch >= '0') && (ch <= '9')) 42 43 extern usba_cfg_pwr_descr_t default_cfg_power; 44 extern usba_if_pwr_descr_t default_if_power; 45 46 size_t 47 usb_parse_data(char *format, 48 uchar_t *data, 49 size_t datalen, 50 void *structure, 51 size_t structlen) 52 { 53 int fmt; 54 int counter = 1; 55 int multiplier = 0; 56 uchar_t *dataend = data + datalen; 57 char *structstart = (char *)structure; 58 void *structend = (void *)((intptr_t)structstart + structlen); 59 60 if ((format == NULL) || (data == NULL) || (structure == NULL)) { 61 62 return (USB_PARSE_ERROR); 63 } 64 65 while ((fmt = *format) != '\0') { 66 67 /* 68 * Could some one pass a "format" that is greater than 69 * the structlen? Conversely, one could pass a ret_buf_len 70 * that is less than the "format" length. 71 * If so, we need to protect against writing over memory. 72 */ 73 if (counter++ > structlen) { 74 break; 75 } 76 77 if (fmt == 'c') { 78 uint8_t *cp = (uint8_t *)structure; 79 80 cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) & 81 ~(_CHAR_ALIGNMENT - 1)); 82 if (((data + 1) > dataend) || 83 ((cp + 1) > (uint8_t *)structend)) 84 break; 85 86 *cp++ = *data++; 87 structure = (void *)cp; 88 if (multiplier) { 89 multiplier--; 90 } 91 if (multiplier == 0) { 92 format++; 93 } 94 } else if (fmt == 's') { 95 uint16_t *sp = (uint16_t *)structure; 96 97 sp = (uint16_t *) 98 (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) & 99 ~(_SHORT_ALIGNMENT - 1)); 100 if (((data + 2) > dataend) || 101 ((sp + 1) > (uint16_t *)structend)) 102 break; 103 104 *sp++ = (data[1] << 8) + data[0]; 105 data += 2; 106 structure = (void *)sp; 107 if (multiplier) { 108 multiplier--; 109 } 110 if (multiplier == 0) { 111 format++; 112 } 113 } else if (fmt == 'l') { 114 uint32_t *lp = (uint32_t *)structure; 115 116 lp = (uint32_t *) 117 (((uintptr_t)lp + _INT_ALIGNMENT - 1) & 118 ~(_INT_ALIGNMENT - 1)); 119 if (((data + 4) > dataend) || 120 ((lp + 1) > (uint32_t *)structend)) 121 break; 122 123 *lp++ = ((((( 124 (uint32_t)data[3] << 8) | data[2]) << 8) | 125 data[1]) << 8) | data[0]; 126 data += 4; 127 structure = (void *)lp; 128 if (multiplier) { 129 multiplier--; 130 } 131 if (multiplier == 0) { 132 format++; 133 } 134 } else if (fmt == 'L') { 135 uint64_t *llp = (uint64_t *)structure; 136 137 llp = (uint64_t *) 138 (((uintptr_t)llp + _LONG_LONG_ALIGNMENT - 1) & 139 ~(_LONG_LONG_ALIGNMENT - 1)); 140 if (((data + 8) > dataend) || 141 ((llp + 1) >= (uint64_t *)structend)) 142 break; 143 144 *llp++ = (((((((((((((data[7] << 8) | 145 data[6]) << 8) | data[5]) << 8) | 146 data[4]) << 8) | data[3]) << 8) | 147 data[2]) << 8) | data[1]) << 8) | 148 data[0]; 149 data += 8; 150 structure = (void *)llp; 151 if (multiplier) { 152 multiplier--; 153 } 154 if (multiplier == 0) { 155 format++; 156 } 157 } else if (isdigit(fmt)) { 158 multiplier = (multiplier * 10) + (fmt - '0'); 159 format++; 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_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */ 300 size_t buflen, 301 uint_t if_number, 302 uint_t alt_if_setting, 303 usb_if_descr_t *ret_descr, 304 size_t ret_buf_len) 305 { 306 uchar_t *bufend = buf + buflen; 307 308 if ((buf == NULL) || (ret_descr == NULL)) { 309 310 return (USB_PARSE_ERROR); 311 } 312 313 while (buf + 4 <= bufend) { 314 if ((buf[1] == USB_DESCR_TYPE_IF) && 315 (buf[2] == if_number) && 316 (buf[3] == alt_if_setting)) { 317 318 return (usb_parse_data("ccccccccc", 319 buf, bufend - buf, ret_descr, ret_buf_len)); 320 } 321 322 /* 323 * Check for a bad buffer. 324 * If buf[0] is 0, then this will be an infinite loop 325 */ 326 INCREMENT_BUF(buf); 327 } 328 329 return (USB_PARSE_ERROR); 330 } 331 332 size_t 333 usba_parse_if_pwr_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */ 334 size_t buflen, 335 uint_t if_number, 336 uint_t alt_if_setting, 337 usba_if_pwr_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 buf += buf[0]; 353 354 if (buf + 2 <= bufend) { 355 if (buf[1] == USBA_DESCR_TYPE_IF_PWR_1_1) { 356 357 return ( 358 usb_parse_data("cccccccccsss", 359 buf, bufend - buf, ret_descr, 360 ret_buf_len)); 361 } else { 362 break; 363 } 364 } else { 365 break; 366 } 367 } 368 369 /* 370 * Check for a bad buffer. 371 * If buf[0] is 0, then this will be an infinite loop 372 */ 373 INCREMENT_BUF(buf); 374 } 375 376 /* return the default interface power descriptor */ 377 bcopy(&default_if_power, ret_descr, USBA_IF_PWR_DESCR_SIZE); 378 379 return (ret_descr->bLength); 380 } 381 382 383 /* 384 * the endpoint index is relative to the interface. index 0 is 385 * the first endpoint 386 */ 387 size_t 388 usb_parse_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */ 389 size_t buflen, 390 uint_t if_number, 391 uint_t alt_if_setting, 392 uint_t ep_index, 393 usb_ep_descr_t *ret_descr, 394 size_t ret_buf_len) 395 { 396 uchar_t *bufend = buf + buflen; 397 398 if ((buf == NULL) || (ret_descr == NULL)) { 399 400 return (USB_PARSE_ERROR); 401 } 402 403 while ((buf + 4) <= bufend) { 404 if (buf[1] == USB_DESCR_TYPE_IF && 405 buf[2] == if_number && 406 buf[3] == alt_if_setting) { 407 if ((buf = usb_nth_descr(buf, bufend - buf, 408 USB_DESCR_TYPE_EP, ep_index, 409 USB_DESCR_TYPE_IF, -1)) == NULL) { 410 411 break; 412 } 413 414 return (usb_parse_data("ccccsc", 415 buf, bufend - buf, 416 ret_descr, ret_buf_len)); 417 } 418 419 /* 420 * Check for a bad buffer. 421 * If buf[0] is 0, then this will be an infinite loop 422 */ 423 INCREMENT_BUF(buf); 424 } 425 426 return (USB_PARSE_ERROR); 427 } 428 429 430 /* 431 * Returns (at ret_descr) a null-terminated string. Null termination is 432 * guaranteed, even if the string is longer than the buffer. Thus, a 433 * maximum of (ret_buf_len - 1) characters are returned. 434 * Stops silently on first character not in UNICODE format. 435 */ 436 /*ARGSUSED*/ 437 size_t 438 usba_ascii_string_descr(uchar_t *buf, /* from GET_DESCRIPTOR(STRING) */ 439 size_t buflen, 440 char *ret_descr, 441 size_t ret_buf_len) 442 { 443 int i = 1; 444 char *retstart = ret_descr; 445 uchar_t *bufend = buf + buflen; 446 447 if ((buf == NULL) || (ret_descr == NULL) || 448 (ret_buf_len == 0) || (buflen < 2) || 449 (buf[0] < 2) || (buf[1] != USB_DESCR_TYPE_STRING)) { 450 451 return (USB_PARSE_ERROR); 452 } 453 454 for (buf = buf + 2; buf+1 < bufend && ret_buf_len > 1 && 455 buf[0] != 0 && buf[1] == 0 && (i < ret_buf_len); buf += 2, i++) { 456 *ret_descr++ = buf[0]; 457 } 458 459 *ret_descr++ = 0; 460 461 return (ret_descr - retstart); 462 } 463 464 465 size_t 466 usb_parse_CV_cfg_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */ 467 size_t buflen, 468 char *fmt, 469 uint_t descr_type, 470 uint_t descr_index, 471 void *ret_descr, 472 size_t ret_buf_len) 473 { 474 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, bufend - buf, ret_descr, 484 ret_buf_len)); 485 } 486 487 488 size_t 489 usb_parse_CV_if_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */ 490 size_t buflen, 491 char *fmt, 492 uint_t if_number, 493 uint_t alt_if_setting, 494 uint_t descr_type, 495 uint_t descr_index, 496 void *ret_descr, 497 size_t ret_buf_len) 498 { 499 uchar_t *bufend = buf + buflen; 500 501 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) { 502 503 return (USB_PARSE_ERROR); 504 } 505 506 while (buf + 4 <= bufend) { 507 if ((buf[1] == USB_DESCR_TYPE_IF) && 508 (buf[2] == if_number) && 509 (buf[3] == alt_if_setting)) { 510 if ((buf = usb_nth_descr(buf, bufend - buf, descr_type, 511 descr_index, USB_DESCR_TYPE_IF, -1)) == 512 NULL) { 513 break; 514 } 515 516 return (usb_parse_data(fmt, 517 buf, bufend - buf, ret_descr, ret_buf_len)); 518 } 519 520 /* 521 * Check for a bad buffer. 522 * If buf[0] is 0, then this will be an infinite loop 523 */ 524 INCREMENT_BUF(buf); 525 } 526 527 return (USB_PARSE_ERROR); 528 } 529 530 531 size_t 532 usb_parse_CV_ep_descr(uchar_t *buf, /* from GET_DESCRIPTOR(CONFIGURATION) */ 533 size_t buflen, 534 char *fmt, 535 uint_t if_number, 536 uint_t alt_if_setting, 537 uint_t ep_index, 538 uint_t descr_type, 539 uint_t descr_index, 540 void *ret_descr, 541 size_t ret_buf_len) 542 { 543 uchar_t *bufend = buf + buflen; 544 545 if ((buf == NULL) || (ret_descr == NULL) || (fmt == NULL)) { 546 547 return (USB_PARSE_ERROR); 548 } 549 550 while (buf + 4 <= bufend) { 551 if ((buf[1] == USB_DESCR_TYPE_IF) && 552 (buf[2] == if_number) && 553 (buf[3] == alt_if_setting)) { 554 if ((buf = usb_nth_descr(buf, bufend - buf, 555 USB_DESCR_TYPE_EP, ep_index, 556 USB_DESCR_TYPE_IF, -1)) == NULL) { 557 558 break; 559 } 560 561 if ((buf = usb_nth_descr(buf, bufend - buf, 562 descr_type, descr_index, 563 USB_DESCR_TYPE_EP, 564 USB_DESCR_TYPE_IF)) == NULL) { 565 566 break; 567 } 568 569 return (usb_parse_data(fmt, buf, bufend - buf, 570 ret_descr, ret_buf_len)); 571 } 572 573 /* 574 * Check for a bad buffer. 575 * If buf[0] is 0, then this will be an infite loop 576 */ 577 INCREMENT_BUF(buf); 578 } 579 580 return (USB_PARSE_ERROR); 581 } 582