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 * The first "bInterfaceNumber" should never have the value 0xff. 86 * Then it is corrupt. 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 * Sometimes USB devices have corrupt interface 211 * descriptors and we need to overwrite the provided 212 * interface number! 213 */ 214 last_if->desc.bInterfaceNumber = niface - 1; 215 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]); 216 last_if->extra.len = 0; 217 last_if->extra.type = LIBUSB20_ME_IS_RAW; 218 last_if->endpoints = lub_endpoint + 1; 219 last_if->altsetting = lub_alt_interface; 220 last_if->num_altsetting = 0; 221 last_if->num_endpoints = 0; 222 last_ep = NULL; 223 } else { 224 /* unknown descriptor */ 225 if (last_if) { 226 if (last_ep) { 227 last_ep->extra.len += ptr[0]; 228 } else { 229 last_if->extra.len += ptr[0]; 230 } 231 } else { 232 lub_config->extra.len += ptr[0]; 233 } 234 } 235 } 236 return (lub_config); 237 } 238 239 /*------------------------------------------------------------------------* 240 * libusb20_desc_foreach 241 * 242 * Safe traversal of USB descriptors. 243 * 244 * Return values: 245 * NULL: End of descriptors 246 * Else: Pointer to next descriptor 247 *------------------------------------------------------------------------*/ 248 const uint8_t * 249 libusb20_desc_foreach(const struct libusb20_me_struct *pdesc, 250 const uint8_t *psubdesc) 251 { 252 const uint8_t *start; 253 const uint8_t *end; 254 const uint8_t *desc_next; 255 256 /* be NULL safe */ 257 if (pdesc == NULL) 258 return (NULL); 259 260 start = (const uint8_t *)pdesc->ptr; 261 end = LIBUSB20_ADD_BYTES(start, pdesc->len); 262 263 /* get start of next descriptor */ 264 if (psubdesc == NULL) 265 psubdesc = start; 266 else 267 psubdesc = psubdesc + psubdesc[0]; 268 269 /* check that the next USB descriptor is within the range */ 270 if ((psubdesc < start) || (psubdesc >= end)) 271 return (NULL); /* out of range, or EOD */ 272 273 /* check start of the second next USB descriptor, if any */ 274 desc_next = psubdesc + psubdesc[0]; 275 if ((desc_next < start) || (desc_next > end)) 276 return (NULL); /* out of range */ 277 278 /* check minimum descriptor length */ 279 if (psubdesc[0] < 3) 280 return (NULL); /* too short descriptor */ 281 282 return (psubdesc); /* return start of next descriptor */ 283 } 284 285 /*------------------------------------------------------------------------* 286 * libusb20_me_get_1 - safety wrapper to read out one byte 287 *------------------------------------------------------------------------*/ 288 uint8_t 289 libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset) 290 { 291 if (offset < ie->len) { 292 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset))); 293 } 294 return (0); 295 } 296 297 /*------------------------------------------------------------------------* 298 * libusb20_me_get_2 - safety wrapper to read out one word 299 *------------------------------------------------------------------------*/ 300 uint16_t 301 libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset) 302 { 303 return (libusb20_me_get_1(ie, offset) | 304 (libusb20_me_get_1(ie, offset + 1) << 8)); 305 } 306 307 /*------------------------------------------------------------------------* 308 * libusb20_me_encode - encode a message structure 309 * 310 * Description of parameters: 311 * "len" - maximum length of output buffer 312 * "ptr" - pointer to output buffer. If NULL, no data will be written 313 * "pd" - source structure 314 * 315 * Return values: 316 * 0..65535 - Number of bytes used, limited by the "len" input parameter. 317 *------------------------------------------------------------------------*/ 318 uint16_t 319 libusb20_me_encode(void *ptr, uint16_t len, const void *pd) 320 { 321 const uint8_t *pf; /* pointer to format data */ 322 uint8_t *buf; /* pointer to output buffer */ 323 324 uint32_t pd_offset; /* decoded structure offset */ 325 uint16_t len_old; /* old length */ 326 uint16_t pd_count; /* decoded element count */ 327 uint8_t me; /* message element */ 328 329 /* initialise */ 330 331 len_old = len; 332 buf = ptr; 333 pd_offset = sizeof(void *); 334 pf = (*((struct libusb20_me_format *const *)pd))->format; 335 336 /* scan */ 337 338 while (1) { 339 340 /* get information element */ 341 342 me = (pf[0]) & LIBUSB20_ME_MASK; 343 pd_count = pf[1] | (pf[2] << 8); 344 pf += 3; 345 346 /* encode the message element */ 347 348 switch (me) { 349 case LIBUSB20_ME_INT8: 350 while (pd_count--) { 351 uint8_t temp; 352 353 if (len < 1) /* overflow */ 354 goto done; 355 if (buf) { 356 temp = *((const uint8_t *) 357 LIBUSB20_ADD_BYTES(pd, pd_offset)); 358 buf[0] = temp; 359 buf += 1; 360 } 361 pd_offset += 1; 362 len -= 1; 363 } 364 break; 365 366 case LIBUSB20_ME_INT16: 367 pd_offset = -((-pd_offset) & ~1); /* align */ 368 while (pd_count--) { 369 uint16_t temp; 370 371 if (len < 2) /* overflow */ 372 goto done; 373 374 if (buf) { 375 temp = *((const uint16_t *) 376 LIBUSB20_ADD_BYTES(pd, pd_offset)); 377 buf[1] = (temp >> 8) & 0xFF; 378 buf[0] = temp & 0xFF; 379 buf += 2; 380 } 381 pd_offset += 2; 382 len -= 2; 383 } 384 break; 385 386 case LIBUSB20_ME_INT32: 387 pd_offset = -((-pd_offset) & ~3); /* align */ 388 while (pd_count--) { 389 uint32_t temp; 390 391 if (len < 4) /* overflow */ 392 goto done; 393 if (buf) { 394 temp = *((const uint32_t *) 395 LIBUSB20_ADD_BYTES(pd, pd_offset)); 396 buf[3] = (temp >> 24) & 0xFF; 397 buf[2] = (temp >> 16) & 0xFF; 398 buf[1] = (temp >> 8) & 0xFF; 399 buf[0] = temp & 0xFF; 400 buf += 4; 401 } 402 pd_offset += 4; 403 len -= 4; 404 } 405 break; 406 407 case LIBUSB20_ME_INT64: 408 pd_offset = -((-pd_offset) & ~7); /* align */ 409 while (pd_count--) { 410 uint64_t temp; 411 412 if (len < 8) /* overflow */ 413 goto done; 414 if (buf) { 415 416 temp = *((const uint64_t *) 417 LIBUSB20_ADD_BYTES(pd, pd_offset)); 418 buf[7] = (temp >> 56) & 0xFF; 419 buf[6] = (temp >> 48) & 0xFF; 420 buf[5] = (temp >> 40) & 0xFF; 421 buf[4] = (temp >> 32) & 0xFF; 422 buf[3] = (temp >> 24) & 0xFF; 423 buf[2] = (temp >> 16) & 0xFF; 424 buf[1] = (temp >> 8) & 0xFF; 425 buf[0] = temp & 0xFF; 426 buf += 8; 427 } 428 pd_offset += 8; 429 len -= 8; 430 } 431 break; 432 433 case LIBUSB20_ME_STRUCT: 434 pd_offset = -((-pd_offset) & 435 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */ 436 while (pd_count--) { 437 void *src_ptr; 438 uint16_t src_len; 439 struct libusb20_me_struct *ps; 440 441 ps = LIBUSB20_ADD_BYTES(pd, pd_offset); 442 443 switch (ps->type) { 444 case LIBUSB20_ME_IS_RAW: 445 src_len = ps->len; 446 src_ptr = ps->ptr; 447 break; 448 449 case LIBUSB20_ME_IS_ENCODED: 450 if (ps->len == 0) { 451 /* 452 * Length is encoded 453 * in the data itself 454 * and should be 455 * correct: 456 */ 457 ps->len = 0xFFFF; 458 } 459 src_len = libusb20_me_get_1(pd, 0); 460 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1); 461 if (src_len == 0xFF) { 462 /* length is escaped */ 463 src_len = libusb20_me_get_2(pd, 1); 464 src_ptr = 465 LIBUSB20_ADD_BYTES(ps->ptr, 3); 466 } 467 break; 468 469 case LIBUSB20_ME_IS_DECODED: 470 /* reserve 3 length bytes */ 471 src_len = libusb20_me_encode(NULL, 472 0xFFFF - 3, ps->ptr); 473 src_ptr = NULL; 474 break; 475 476 default: /* empty structure */ 477 src_len = 0; 478 src_ptr = NULL; 479 break; 480 } 481 482 if (src_len > 0xFE) { 483 if (src_len > (0xFFFF - 3)) 484 /* overflow */ 485 goto done; 486 487 if (len < (src_len + 3)) 488 /* overflow */ 489 goto done; 490 491 if (buf) { 492 buf[0] = 0xFF; 493 buf[1] = (src_len & 0xFF); 494 buf[2] = (src_len >> 8) & 0xFF; 495 buf += 3; 496 } 497 len -= (src_len + 3); 498 } else { 499 if (len < (src_len + 1)) 500 /* overflow */ 501 goto done; 502 503 if (buf) { 504 buf[0] = (src_len & 0xFF); 505 buf += 1; 506 } 507 len -= (src_len + 1); 508 } 509 510 /* check for buffer and non-zero length */ 511 512 if (buf && src_len) { 513 if (ps->type == LIBUSB20_ME_IS_DECODED) { 514 /* 515 * Repeat encode 516 * procedure - we have 517 * room for the 518 * complete structure: 519 */ 520 (void) libusb20_me_encode(buf, 521 0xFFFF - 3, ps->ptr); 522 } else { 523 bcopy(src_ptr, buf, src_len); 524 } 525 buf += src_len; 526 } 527 pd_offset += sizeof(struct libusb20_me_struct); 528 } 529 break; 530 531 default: 532 goto done; 533 } 534 } 535 done: 536 return (len_old - len); 537 } 538 539 /*------------------------------------------------------------------------* 540 * libusb20_me_decode - decode a message into a decoded structure 541 * 542 * Description of parameters: 543 * "ptr" - message pointer 544 * "len" - message length 545 * "pd" - pointer to decoded structure 546 * 547 * Returns: 548 * "0..65535" - number of bytes decoded, limited by "len" 549 *------------------------------------------------------------------------*/ 550 uint16_t 551 libusb20_me_decode(const void *ptr, uint16_t len, void *pd) 552 { 553 const uint8_t *pf; /* pointer to format data */ 554 const uint8_t *buf; /* pointer to input buffer */ 555 556 uint32_t pd_offset; /* decoded structure offset */ 557 uint16_t len_old; /* old length */ 558 uint16_t pd_count; /* decoded element count */ 559 uint8_t me; /* message element */ 560 561 /* initialise */ 562 563 len_old = len; 564 buf = ptr; 565 pd_offset = sizeof(void *); 566 pf = (*((struct libusb20_me_format **)pd))->format; 567 568 /* scan */ 569 570 while (1) { 571 572 /* get information element */ 573 574 me = (pf[0]) & LIBUSB20_ME_MASK; 575 pd_count = pf[1] | (pf[2] << 8); 576 pf += 3; 577 578 /* decode the message element by type */ 579 580 switch (me) { 581 case LIBUSB20_ME_INT8: 582 while (pd_count--) { 583 uint8_t temp; 584 585 if (len < 1) { 586 len = 0; 587 temp = 0; 588 } else { 589 len -= 1; 590 temp = buf[0]; 591 buf++; 592 } 593 *((uint8_t *)LIBUSB20_ADD_BYTES(pd, 594 pd_offset)) = temp; 595 pd_offset += 1; 596 } 597 break; 598 599 case LIBUSB20_ME_INT16: 600 pd_offset = -((-pd_offset) & ~1); /* align */ 601 while (pd_count--) { 602 uint16_t temp; 603 604 if (len < 2) { 605 len = 0; 606 temp = 0; 607 } else { 608 len -= 2; 609 temp = buf[1] << 8; 610 temp |= buf[0]; 611 buf += 2; 612 } 613 *((uint16_t *)LIBUSB20_ADD_BYTES(pd, 614 pd_offset)) = temp; 615 pd_offset += 2; 616 } 617 break; 618 619 case LIBUSB20_ME_INT32: 620 pd_offset = -((-pd_offset) & ~3); /* align */ 621 while (pd_count--) { 622 uint32_t temp; 623 624 if (len < 4) { 625 len = 0; 626 temp = 0; 627 } else { 628 len -= 4; 629 temp = buf[3] << 24; 630 temp |= buf[2] << 16; 631 temp |= buf[1] << 8; 632 temp |= buf[0]; 633 buf += 4; 634 } 635 636 *((uint32_t *)LIBUSB20_ADD_BYTES(pd, 637 pd_offset)) = temp; 638 pd_offset += 4; 639 } 640 break; 641 642 case LIBUSB20_ME_INT64: 643 pd_offset = -((-pd_offset) & ~7); /* align */ 644 while (pd_count--) { 645 uint64_t temp; 646 647 if (len < 8) { 648 len = 0; 649 temp = 0; 650 } else { 651 len -= 8; 652 temp = ((uint64_t)buf[7]) << 56; 653 temp |= ((uint64_t)buf[6]) << 48; 654 temp |= ((uint64_t)buf[5]) << 40; 655 temp |= ((uint64_t)buf[4]) << 32; 656 temp |= buf[3] << 24; 657 temp |= buf[2] << 16; 658 temp |= buf[1] << 8; 659 temp |= buf[0]; 660 buf += 8; 661 } 662 663 *((uint64_t *)LIBUSB20_ADD_BYTES(pd, 664 pd_offset)) = temp; 665 pd_offset += 8; 666 } 667 break; 668 669 case LIBUSB20_ME_STRUCT: 670 pd_offset = -((-pd_offset) & 671 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */ 672 while (pd_count--) { 673 uint16_t temp; 674 struct libusb20_me_struct *ps; 675 676 ps = LIBUSB20_ADD_BYTES(pd, pd_offset); 677 678 if (ps->type == LIBUSB20_ME_IS_ENCODED) { 679 /* 680 * Pre-store a de-constified 681 * pointer to the raw 682 * structure: 683 */ 684 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0); 685 686 /* 687 * Get the correct number of 688 * length bytes: 689 */ 690 if (len != 0) { 691 if (buf[0] == 0xFF) { 692 ps->len = 3; 693 } else { 694 ps->len = 1; 695 } 696 } else { 697 ps->len = 0; 698 } 699 } 700 /* get the structure length */ 701 702 if (len != 0) { 703 if (buf[0] == 0xFF) { 704 if (len < 3) { 705 len = 0; 706 temp = 0; 707 } else { 708 len -= 3; 709 temp = buf[1] | 710 (buf[2] << 8); 711 buf += 3; 712 } 713 } else { 714 len -= 1; 715 temp = buf[0]; 716 buf += 1; 717 } 718 } else { 719 len = 0; 720 temp = 0; 721 } 722 /* check for invalid length */ 723 724 if (temp > len) { 725 len = 0; 726 temp = 0; 727 } 728 /* check wanted structure type */ 729 730 switch (ps->type) { 731 case LIBUSB20_ME_IS_ENCODED: 732 /* check for zero length */ 733 if (temp == 0) { 734 /* 735 * The pointer must 736 * be valid: 737 */ 738 ps->ptr = LIBUSB20_ADD_BYTES( 739 libusb20_me_encode_empty, 0); 740 ps->len = 1; 741 } else { 742 ps->len += temp; 743 } 744 break; 745 746 case LIBUSB20_ME_IS_RAW: 747 /* update length and pointer */ 748 ps->len = temp; 749 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0); 750 break; 751 752 case LIBUSB20_ME_IS_EMPTY: 753 case LIBUSB20_ME_IS_DECODED: 754 /* check for non-zero length */ 755 if (temp != 0) { 756 /* update type */ 757 ps->type = LIBUSB20_ME_IS_DECODED; 758 ps->len = 0; 759 /* 760 * Recursivly decode 761 * the next structure 762 */ 763 (void) libusb20_me_decode(buf, 764 temp, ps->ptr); 765 } else { 766 /* update type */ 767 ps->type = LIBUSB20_ME_IS_EMPTY; 768 ps->len = 0; 769 } 770 break; 771 772 default: 773 /* 774 * nothing to do - should 775 * not happen 776 */ 777 ps->ptr = NULL; 778 ps->len = 0; 779 break; 780 } 781 buf += temp; 782 len -= temp; 783 pd_offset += sizeof(struct libusb20_me_struct); 784 } 785 break; 786 787 default: 788 goto done; 789 } 790 } 791 done: 792 return (len_old - len); 793 } 794