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