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