1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE 29 #include LIBUSB_GLOBAL_INCLUDE_FILE 30 #else 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <time.h> 35 #include <sys/queue.h> 36 #endif 37 38 #include "libusb20.h" 39 #include "libusb20_desc.h" 40 #include "libusb20_int.h" 41 42 static const uint32_t libusb20_me_encode_empty[2]; /* dummy */ 43 44 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC); 45 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC); 46 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC); 47 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC); 48 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP); 49 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC); 50 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC); 51 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC); 52 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_BOS_DESCRIPTOR); 53 54 /*------------------------------------------------------------------------* 55 * libusb20_parse_config_desc 56 * 57 * Return values: 58 * NULL: Out of memory. 59 * Else: A valid config structure pointer which must be passed to "free()" 60 *------------------------------------------------------------------------*/ 61 struct libusb20_config * 62 libusb20_parse_config_desc(const void *config_desc) 63 { 64 struct libusb20_config *lub_config; 65 struct libusb20_interface *lub_interface; 66 struct libusb20_interface *lub_alt_interface; 67 struct libusb20_interface *last_if; 68 struct libusb20_endpoint *lub_endpoint; 69 struct libusb20_endpoint *last_ep; 70 71 struct libusb20_me_struct pcdesc; 72 const uint8_t *ptr; 73 uint32_t size; 74 uint16_t niface_no_alt; 75 uint16_t niface; 76 uint16_t nendpoint; 77 uint16_t iface_no; 78 79 ptr = config_desc; 80 if (ptr[1] != LIBUSB20_DT_CONFIG) { 81 return (NULL); /* not config descriptor */ 82 } 83 84 /* 85 * The first "bInterfaceNumber" cannot start at 0xFFFF 86 * because the field is 8-bit. 87 */ 88 niface_no_alt = 0; 89 nendpoint = 0; 90 niface = 0; 91 iface_no = 0xFFFF; 92 ptr = NULL; 93 94 /* get "wTotalLength" and setup "pcdesc" */ 95 pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0); 96 pcdesc.len = 97 ((const uint8_t *)config_desc)[2] | 98 (((const uint8_t *)config_desc)[3] << 8); 99 pcdesc.type = LIBUSB20_ME_IS_RAW; 100 101 /* descriptor pre-scan */ 102 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) { 103 if (ptr[1] == LIBUSB20_DT_ENDPOINT) { 104 nendpoint++; 105 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) { 106 niface++; 107 /* check "bInterfaceNumber" */ 108 if (ptr[2] != iface_no) { 109 iface_no = ptr[2]; 110 niface_no_alt++; 111 } 112 } 113 } 114 115 /* sanity checking */ 116 if (niface >= 256) { 117 return (NULL); /* corrupt */ 118 } 119 if (nendpoint >= 256) { 120 return (NULL); /* corrupt */ 121 } 122 size = sizeof(*lub_config) + 123 (niface * sizeof(*lub_interface)) + 124 (nendpoint * sizeof(*lub_endpoint)) + 125 pcdesc.len; 126 127 lub_config = malloc(size); 128 if (lub_config == NULL) { 129 return (NULL); /* out of memory */ 130 } 131 /* make sure memory is initialised */ 132 memset(lub_config, 0, size); 133 134 lub_interface = (void *)(lub_config + 1); 135 lub_alt_interface = (void *)(lub_interface + niface_no_alt); 136 lub_endpoint = (void *)(lub_interface + niface); 137 138 /* 139 * Make a copy of the config descriptor, so that the caller can free 140 * the initial config descriptor pointer! 141 */ 142 memcpy((void *)(lub_endpoint + nendpoint), config_desc, pcdesc.len); 143 144 ptr = (const void *)(lub_endpoint + nendpoint); 145 pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0); 146 147 /* init config structure */ 148 149 LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc); 150 151 if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) { 152 /* ignore */ 153 } 154 lub_config->num_interface = 0; 155 lub_config->interface = lub_interface; 156 lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]); 157 lub_config->extra.len = -ptr[0]; 158 lub_config->extra.type = LIBUSB20_ME_IS_RAW; 159 160 /* reset states */ 161 niface = 0; 162 iface_no = 0xFFFF; 163 ptr = NULL; 164 lub_interface--; 165 lub_endpoint--; 166 last_if = NULL; 167 last_ep = NULL; 168 169 /* descriptor pre-scan */ 170 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) { 171 if (ptr[1] == LIBUSB20_DT_ENDPOINT) { 172 if (last_if) { 173 lub_endpoint++; 174 last_ep = lub_endpoint; 175 last_if->num_endpoints++; 176 177 LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc); 178 179 if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) { 180 /* ignore */ 181 } 182 last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]); 183 last_ep->extra.len = 0; 184 last_ep->extra.type = LIBUSB20_ME_IS_RAW; 185 } else { 186 lub_config->extra.len += ptr[0]; 187 } 188 189 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) { 190 if (ptr[2] != iface_no) { 191 /* new interface */ 192 iface_no = ptr[2]; 193 lub_interface++; 194 lub_config->num_interface++; 195 last_if = lub_interface; 196 niface++; 197 } else { 198 /* one more alternate setting */ 199 lub_interface->num_altsetting++; 200 last_if = lub_alt_interface; 201 lub_alt_interface++; 202 } 203 204 LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc); 205 206 if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) { 207 /* ignore */ 208 } 209 210 /* detect broken USB descriptors when USB debugging is enabled */ 211 if (last_if->desc.bInterfaceNumber != (uint8_t)(niface - 1)) { 212 const char *str = getenv("LIBUSB_DEBUG"); 213 if (str != NULL && str[0] != '\0' && str[0] != '0') { 214 printf("LIBUSB_DEBUG: bInterfaceNumber(%u) is not sequential(%u)\n", 215 last_if->desc.bInterfaceNumber, niface - 1); 216 } 217 } 218 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]); 219 last_if->extra.len = 0; 220 last_if->extra.type = LIBUSB20_ME_IS_RAW; 221 last_if->endpoints = lub_endpoint + 1; 222 last_if->altsetting = lub_alt_interface; 223 last_if->num_altsetting = 0; 224 last_if->num_endpoints = 0; 225 last_ep = NULL; 226 } else { 227 /* unknown descriptor */ 228 if (last_if) { 229 if (last_ep) { 230 last_ep->extra.len += ptr[0]; 231 } else { 232 last_if->extra.len += ptr[0]; 233 } 234 } else { 235 lub_config->extra.len += ptr[0]; 236 } 237 } 238 } 239 return (lub_config); 240 } 241 242 /*------------------------------------------------------------------------* 243 * libusb20_desc_foreach 244 * 245 * Safe traversal of USB descriptors. 246 * 247 * Return values: 248 * NULL: End of descriptors 249 * Else: Pointer to next descriptor 250 *------------------------------------------------------------------------*/ 251 const uint8_t * 252 libusb20_desc_foreach(const struct libusb20_me_struct *pdesc, 253 const uint8_t *psubdesc) 254 { 255 const uint8_t *start; 256 const uint8_t *end; 257 const uint8_t *desc_next; 258 259 /* be NULL safe */ 260 if (pdesc == NULL) 261 return (NULL); 262 263 start = (const uint8_t *)pdesc->ptr; 264 end = LIBUSB20_ADD_BYTES(start, pdesc->len); 265 266 /* get start of next descriptor */ 267 if (psubdesc == NULL) 268 psubdesc = start; 269 else 270 psubdesc = psubdesc + psubdesc[0]; 271 272 /* check that the next USB descriptor is within the range */ 273 if ((psubdesc < start) || (psubdesc >= end)) 274 return (NULL); /* out of range, or EOD */ 275 276 /* check start of the second next USB descriptor, if any */ 277 desc_next = psubdesc + psubdesc[0]; 278 if ((desc_next < start) || (desc_next > end)) 279 return (NULL); /* out of range */ 280 281 /* check minimum descriptor length */ 282 if (psubdesc[0] < 3) 283 return (NULL); /* too short descriptor */ 284 285 return (psubdesc); /* return start of next descriptor */ 286 } 287 288 /*------------------------------------------------------------------------* 289 * libusb20_me_get_1 - safety wrapper to read out one byte 290 *------------------------------------------------------------------------*/ 291 uint8_t 292 libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset) 293 { 294 if (offset < ie->len) { 295 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset))); 296 } 297 return (0); 298 } 299 300 /*------------------------------------------------------------------------* 301 * libusb20_me_get_2 - safety wrapper to read out one word 302 *------------------------------------------------------------------------*/ 303 uint16_t 304 libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset) 305 { 306 return (libusb20_me_get_1(ie, offset) | 307 (libusb20_me_get_1(ie, offset + 1) << 8)); 308 } 309 310 /*------------------------------------------------------------------------* 311 * libusb20_me_encode - encode a message structure 312 * 313 * Description of parameters: 314 * "len" - maximum length of output buffer 315 * "ptr" - pointer to output buffer. If NULL, no data will be written 316 * "pd" - source structure 317 * 318 * Return values: 319 * 0..65535 - Number of bytes used, limited by the "len" input parameter. 320 *------------------------------------------------------------------------*/ 321 uint16_t 322 libusb20_me_encode(void *ptr, uint16_t len, const void *pd) 323 { 324 const uint8_t *pf; /* pointer to format data */ 325 uint8_t *buf; /* pointer to output buffer */ 326 327 uint32_t pd_offset; /* decoded structure offset */ 328 uint16_t len_old; /* old length */ 329 uint16_t pd_count; /* decoded element count */ 330 uint8_t me; /* message element */ 331 332 /* initialise */ 333 334 len_old = len; 335 buf = ptr; 336 pd_offset = sizeof(void *); 337 pf = (*((struct libusb20_me_format *const *)pd))->format; 338 339 /* scan */ 340 341 while (1) { 342 343 /* get information element */ 344 345 me = (pf[0]) & LIBUSB20_ME_MASK; 346 pd_count = pf[1] | (pf[2] << 8); 347 pf += 3; 348 349 /* encode the message element */ 350 351 switch (me) { 352 case LIBUSB20_ME_INT8: 353 while (pd_count--) { 354 uint8_t temp; 355 356 if (len < 1) /* overflow */ 357 goto done; 358 if (buf) { 359 temp = *((const uint8_t *) 360 LIBUSB20_ADD_BYTES(pd, pd_offset)); 361 buf[0] = temp; 362 buf += 1; 363 } 364 pd_offset += 1; 365 len -= 1; 366 } 367 break; 368 369 case LIBUSB20_ME_INT16: 370 pd_offset = -((-pd_offset) & ~1); /* align */ 371 while (pd_count--) { 372 uint16_t temp; 373 374 if (len < 2) /* overflow */ 375 goto done; 376 377 if (buf) { 378 temp = *((const uint16_t *) 379 LIBUSB20_ADD_BYTES(pd, pd_offset)); 380 buf[1] = (temp >> 8) & 0xFF; 381 buf[0] = temp & 0xFF; 382 buf += 2; 383 } 384 pd_offset += 2; 385 len -= 2; 386 } 387 break; 388 389 case LIBUSB20_ME_INT32: 390 pd_offset = -((-pd_offset) & ~3); /* align */ 391 while (pd_count--) { 392 uint32_t temp; 393 394 if (len < 4) /* overflow */ 395 goto done; 396 if (buf) { 397 temp = *((const uint32_t *) 398 LIBUSB20_ADD_BYTES(pd, pd_offset)); 399 buf[3] = (temp >> 24) & 0xFF; 400 buf[2] = (temp >> 16) & 0xFF; 401 buf[1] = (temp >> 8) & 0xFF; 402 buf[0] = temp & 0xFF; 403 buf += 4; 404 } 405 pd_offset += 4; 406 len -= 4; 407 } 408 break; 409 410 case LIBUSB20_ME_INT64: 411 pd_offset = -((-pd_offset) & ~7); /* align */ 412 while (pd_count--) { 413 uint64_t temp; 414 415 if (len < 8) /* overflow */ 416 goto done; 417 if (buf) { 418 419 temp = *((const uint64_t *) 420 LIBUSB20_ADD_BYTES(pd, pd_offset)); 421 buf[7] = (temp >> 56) & 0xFF; 422 buf[6] = (temp >> 48) & 0xFF; 423 buf[5] = (temp >> 40) & 0xFF; 424 buf[4] = (temp >> 32) & 0xFF; 425 buf[3] = (temp >> 24) & 0xFF; 426 buf[2] = (temp >> 16) & 0xFF; 427 buf[1] = (temp >> 8) & 0xFF; 428 buf[0] = temp & 0xFF; 429 buf += 8; 430 } 431 pd_offset += 8; 432 len -= 8; 433 } 434 break; 435 436 case LIBUSB20_ME_STRUCT: 437 pd_offset = -((-pd_offset) & 438 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */ 439 while (pd_count--) { 440 void *src_ptr; 441 uint16_t src_len; 442 struct libusb20_me_struct *ps; 443 444 ps = LIBUSB20_ADD_BYTES(pd, pd_offset); 445 446 switch (ps->type) { 447 case LIBUSB20_ME_IS_RAW: 448 src_len = ps->len; 449 src_ptr = ps->ptr; 450 break; 451 452 case LIBUSB20_ME_IS_ENCODED: 453 if (ps->len == 0) { 454 /* 455 * Length is encoded 456 * in the data itself 457 * and should be 458 * correct: 459 */ 460 ps->len = 0xFFFF; 461 } 462 src_len = libusb20_me_get_1(pd, 0); 463 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1); 464 if (src_len == 0xFF) { 465 /* length is escaped */ 466 src_len = libusb20_me_get_2(pd, 1); 467 src_ptr = 468 LIBUSB20_ADD_BYTES(ps->ptr, 3); 469 } 470 break; 471 472 case LIBUSB20_ME_IS_DECODED: 473 /* reserve 3 length bytes */ 474 src_len = libusb20_me_encode(NULL, 475 0xFFFF - 3, ps->ptr); 476 src_ptr = NULL; 477 break; 478 479 default: /* empty structure */ 480 src_len = 0; 481 src_ptr = NULL; 482 break; 483 } 484 485 if (src_len > 0xFE) { 486 if (src_len > (0xFFFF - 3)) 487 /* overflow */ 488 goto done; 489 490 if (len < (src_len + 3)) 491 /* overflow */ 492 goto done; 493 494 if (buf) { 495 buf[0] = 0xFF; 496 buf[1] = (src_len & 0xFF); 497 buf[2] = (src_len >> 8) & 0xFF; 498 buf += 3; 499 } 500 len -= (src_len + 3); 501 } else { 502 if (len < (src_len + 1)) 503 /* overflow */ 504 goto done; 505 506 if (buf) { 507 buf[0] = (src_len & 0xFF); 508 buf += 1; 509 } 510 len -= (src_len + 1); 511 } 512 513 /* check for buffer and non-zero length */ 514 515 if (buf && src_len) { 516 if (ps->type == LIBUSB20_ME_IS_DECODED) { 517 /* 518 * Repeat encode 519 * procedure - we have 520 * room for the 521 * complete structure: 522 */ 523 (void) libusb20_me_encode(buf, 524 0xFFFF - 3, ps->ptr); 525 } else { 526 bcopy(src_ptr, buf, src_len); 527 } 528 buf += src_len; 529 } 530 pd_offset += sizeof(struct libusb20_me_struct); 531 } 532 break; 533 534 default: 535 goto done; 536 } 537 } 538 done: 539 return (len_old - len); 540 } 541 542 /*------------------------------------------------------------------------* 543 * libusb20_me_decode - decode a message into a decoded structure 544 * 545 * Description of parameters: 546 * "ptr" - message pointer 547 * "len" - message length 548 * "pd" - pointer to decoded structure 549 * 550 * Returns: 551 * "0..65535" - number of bytes decoded, limited by "len" 552 *------------------------------------------------------------------------*/ 553 uint16_t 554 libusb20_me_decode(const void *ptr, uint16_t len, void *pd) 555 { 556 const uint8_t *pf; /* pointer to format data */ 557 const uint8_t *buf; /* pointer to input buffer */ 558 559 uint32_t pd_offset; /* decoded structure offset */ 560 uint16_t len_old; /* old length */ 561 uint16_t pd_count; /* decoded element count */ 562 uint8_t me; /* message element */ 563 564 /* initialise */ 565 566 len_old = len; 567 buf = ptr; 568 pd_offset = sizeof(void *); 569 pf = (*((struct libusb20_me_format **)pd))->format; 570 571 /* scan */ 572 573 while (1) { 574 575 /* get information element */ 576 577 me = (pf[0]) & LIBUSB20_ME_MASK; 578 pd_count = pf[1] | (pf[2] << 8); 579 pf += 3; 580 581 /* decode the message element by type */ 582 583 switch (me) { 584 case LIBUSB20_ME_INT8: 585 while (pd_count--) { 586 uint8_t temp; 587 588 if (len < 1) { 589 len = 0; 590 temp = 0; 591 } else { 592 len -= 1; 593 temp = buf[0]; 594 buf++; 595 } 596 *((uint8_t *)LIBUSB20_ADD_BYTES(pd, 597 pd_offset)) = temp; 598 pd_offset += 1; 599 } 600 break; 601 602 case LIBUSB20_ME_INT16: 603 pd_offset = -((-pd_offset) & ~1); /* align */ 604 while (pd_count--) { 605 uint16_t temp; 606 607 if (len < 2) { 608 len = 0; 609 temp = 0; 610 } else { 611 len -= 2; 612 temp = buf[1] << 8; 613 temp |= buf[0]; 614 buf += 2; 615 } 616 *((uint16_t *)LIBUSB20_ADD_BYTES(pd, 617 pd_offset)) = temp; 618 pd_offset += 2; 619 } 620 break; 621 622 case LIBUSB20_ME_INT32: 623 pd_offset = -((-pd_offset) & ~3); /* align */ 624 while (pd_count--) { 625 uint32_t temp; 626 627 if (len < 4) { 628 len = 0; 629 temp = 0; 630 } else { 631 len -= 4; 632 temp = buf[3] << 24; 633 temp |= buf[2] << 16; 634 temp |= buf[1] << 8; 635 temp |= buf[0]; 636 buf += 4; 637 } 638 639 *((uint32_t *)LIBUSB20_ADD_BYTES(pd, 640 pd_offset)) = temp; 641 pd_offset += 4; 642 } 643 break; 644 645 case LIBUSB20_ME_INT64: 646 pd_offset = -((-pd_offset) & ~7); /* align */ 647 while (pd_count--) { 648 uint64_t temp; 649 650 if (len < 8) { 651 len = 0; 652 temp = 0; 653 } else { 654 len -= 8; 655 temp = ((uint64_t)buf[7]) << 56; 656 temp |= ((uint64_t)buf[6]) << 48; 657 temp |= ((uint64_t)buf[5]) << 40; 658 temp |= ((uint64_t)buf[4]) << 32; 659 temp |= buf[3] << 24; 660 temp |= buf[2] << 16; 661 temp |= buf[1] << 8; 662 temp |= buf[0]; 663 buf += 8; 664 } 665 666 *((uint64_t *)LIBUSB20_ADD_BYTES(pd, 667 pd_offset)) = temp; 668 pd_offset += 8; 669 } 670 break; 671 672 case LIBUSB20_ME_STRUCT: 673 pd_offset = -((-pd_offset) & 674 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */ 675 while (pd_count--) { 676 uint16_t temp; 677 struct libusb20_me_struct *ps; 678 679 ps = LIBUSB20_ADD_BYTES(pd, pd_offset); 680 681 if (ps->type == LIBUSB20_ME_IS_ENCODED) { 682 /* 683 * Pre-store a de-constified 684 * pointer to the raw 685 * structure: 686 */ 687 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0); 688 689 /* 690 * Get the correct number of 691 * length bytes: 692 */ 693 if (len != 0) { 694 if (buf[0] == 0xFF) { 695 ps->len = 3; 696 } else { 697 ps->len = 1; 698 } 699 } else { 700 ps->len = 0; 701 } 702 } 703 /* get the structure length */ 704 705 if (len != 0) { 706 if (buf[0] == 0xFF) { 707 if (len < 3) { 708 len = 0; 709 temp = 0; 710 } else { 711 len -= 3; 712 temp = buf[1] | 713 (buf[2] << 8); 714 buf += 3; 715 } 716 } else { 717 len -= 1; 718 temp = buf[0]; 719 buf += 1; 720 } 721 } else { 722 len = 0; 723 temp = 0; 724 } 725 /* check for invalid length */ 726 727 if (temp > len) { 728 len = 0; 729 temp = 0; 730 } 731 /* check wanted structure type */ 732 733 switch (ps->type) { 734 case LIBUSB20_ME_IS_ENCODED: 735 /* check for zero length */ 736 if (temp == 0) { 737 /* 738 * The pointer must 739 * be valid: 740 */ 741 ps->ptr = LIBUSB20_ADD_BYTES( 742 libusb20_me_encode_empty, 0); 743 ps->len = 1; 744 } else { 745 ps->len += temp; 746 } 747 break; 748 749 case LIBUSB20_ME_IS_RAW: 750 /* update length and pointer */ 751 ps->len = temp; 752 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0); 753 break; 754 755 case LIBUSB20_ME_IS_EMPTY: 756 case LIBUSB20_ME_IS_DECODED: 757 /* check for non-zero length */ 758 if (temp != 0) { 759 /* update type */ 760 ps->type = LIBUSB20_ME_IS_DECODED; 761 ps->len = 0; 762 /* 763 * Recursivly decode 764 * the next structure 765 */ 766 (void) libusb20_me_decode(buf, 767 temp, ps->ptr); 768 } else { 769 /* update type */ 770 ps->type = LIBUSB20_ME_IS_EMPTY; 771 ps->len = 0; 772 } 773 break; 774 775 default: 776 /* 777 * nothing to do - should 778 * not happen 779 */ 780 ps->ptr = NULL; 781 ps->len = 0; 782 break; 783 } 784 buf += temp; 785 len -= temp; 786 pd_offset += sizeof(struct libusb20_me_struct); 787 } 788 break; 789 790 default: 791 goto done; 792 } 793 } 794 done: 795 return (len_old - len); 796 } 797