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