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