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