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