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