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