1 /* $FreeBSD$ */
2 /*-
3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 *
5 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
30 #include LIBUSB_GLOBAL_INCLUDE_FILE
31 #else
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <sys/queue.h>
37 #endif
38
39 #include "libusb20.h"
40 #include "libusb20_desc.h"
41 #include "libusb20_int.h"
42
43 static const uint32_t libusb20_me_encode_empty[2]; /* dummy */
44
45 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
46 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
47 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_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 *
libusb20_parse_config_desc(const void * config_desc)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
72 struct libusb20_me_struct pcdesc;
73 const uint8_t *ptr;
74 uint32_t size;
75 uint16_t niface_no_alt;
76 uint16_t niface;
77 uint16_t nendpoint;
78 uint16_t iface_no;
79
80 ptr = config_desc;
81 if (ptr[1] != LIBUSB20_DT_CONFIG) {
82 return (NULL); /* not config descriptor */
83 }
84 /*
85 * The first "bInterfaceNumber" should never have the value 0xff.
86 * Then it is corrupt.
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 * Sometimes USB devices have corrupt interface
211 * descriptors and we need to overwrite the provided
212 * interface number!
213 */
214 last_if->desc.bInterfaceNumber = niface - 1;
215 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
216 last_if->extra.len = 0;
217 last_if->extra.type = LIBUSB20_ME_IS_RAW;
218 last_if->endpoints = lub_endpoint + 1;
219 last_if->altsetting = lub_alt_interface;
220 last_if->num_altsetting = 0;
221 last_if->num_endpoints = 0;
222 last_ep = NULL;
223 } else {
224 /* unknown descriptor */
225 if (last_if) {
226 if (last_ep) {
227 last_ep->extra.len += ptr[0];
228 } else {
229 last_if->extra.len += ptr[0];
230 }
231 } else {
232 lub_config->extra.len += ptr[0];
233 }
234 }
235 }
236 return (lub_config);
237 }
238
239 /*------------------------------------------------------------------------*
240 * libusb20_desc_foreach
241 *
242 * Safe traversal of USB descriptors.
243 *
244 * Return values:
245 * NULL: End of descriptors
246 * Else: Pointer to next descriptor
247 *------------------------------------------------------------------------*/
248 const uint8_t *
libusb20_desc_foreach(const struct libusb20_me_struct * pdesc,const uint8_t * psubdesc)249 libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
250 const uint8_t *psubdesc)
251 {
252 const uint8_t *start;
253 const uint8_t *end;
254 const uint8_t *desc_next;
255
256 /* be NULL safe */
257 if (pdesc == NULL)
258 return (NULL);
259
260 start = (const uint8_t *)pdesc->ptr;
261 end = LIBUSB20_ADD_BYTES(start, pdesc->len);
262
263 /* get start of next descriptor */
264 if (psubdesc == NULL)
265 psubdesc = start;
266 else
267 psubdesc = psubdesc + psubdesc[0];
268
269 /* check that the next USB descriptor is within the range */
270 if ((psubdesc < start) || (psubdesc >= end))
271 return (NULL); /* out of range, or EOD */
272
273 /* check start of the second next USB descriptor, if any */
274 desc_next = psubdesc + psubdesc[0];
275 if ((desc_next < start) || (desc_next > end))
276 return (NULL); /* out of range */
277
278 /* check minimum descriptor length */
279 if (psubdesc[0] < 3)
280 return (NULL); /* too short descriptor */
281
282 return (psubdesc); /* return start of next descriptor */
283 }
284
285 /*------------------------------------------------------------------------*
286 * libusb20_me_get_1 - safety wrapper to read out one byte
287 *------------------------------------------------------------------------*/
288 uint8_t
libusb20_me_get_1(const struct libusb20_me_struct * ie,uint16_t offset)289 libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
290 {
291 if (offset < ie->len) {
292 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
293 }
294 return (0);
295 }
296
297 /*------------------------------------------------------------------------*
298 * libusb20_me_get_2 - safety wrapper to read out one word
299 *------------------------------------------------------------------------*/
300 uint16_t
libusb20_me_get_2(const struct libusb20_me_struct * ie,uint16_t offset)301 libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
302 {
303 return (libusb20_me_get_1(ie, offset) |
304 (libusb20_me_get_1(ie, offset + 1) << 8));
305 }
306
307 /*------------------------------------------------------------------------*
308 * libusb20_me_encode - encode a message structure
309 *
310 * Description of parameters:
311 * "len" - maximum length of output buffer
312 * "ptr" - pointer to output buffer. If NULL, no data will be written
313 * "pd" - source structure
314 *
315 * Return values:
316 * 0..65535 - Number of bytes used, limited by the "len" input parameter.
317 *------------------------------------------------------------------------*/
318 uint16_t
libusb20_me_encode(void * ptr,uint16_t len,const void * pd)319 libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
320 {
321 const uint8_t *pf; /* pointer to format data */
322 uint8_t *buf; /* pointer to output buffer */
323
324 uint32_t pd_offset; /* decoded structure offset */
325 uint16_t len_old; /* old length */
326 uint16_t pd_count; /* decoded element count */
327 uint8_t me; /* message element */
328
329 /* initialise */
330
331 len_old = len;
332 buf = ptr;
333 pd_offset = sizeof(void *);
334 pf = (*((struct libusb20_me_format *const *)pd))->format;
335
336 /* scan */
337
338 while (1) {
339
340 /* get information element */
341
342 me = (pf[0]) & LIBUSB20_ME_MASK;
343 pd_count = pf[1] | (pf[2] << 8);
344 pf += 3;
345
346 /* encode the message element */
347
348 switch (me) {
349 case LIBUSB20_ME_INT8:
350 while (pd_count--) {
351 uint8_t temp;
352
353 if (len < 1) /* overflow */
354 goto done;
355 if (buf) {
356 temp = *((const uint8_t *)
357 LIBUSB20_ADD_BYTES(pd, pd_offset));
358 buf[0] = temp;
359 buf += 1;
360 }
361 pd_offset += 1;
362 len -= 1;
363 }
364 break;
365
366 case LIBUSB20_ME_INT16:
367 pd_offset = -((-pd_offset) & ~1); /* align */
368 while (pd_count--) {
369 uint16_t temp;
370
371 if (len < 2) /* overflow */
372 goto done;
373
374 if (buf) {
375 temp = *((const uint16_t *)
376 LIBUSB20_ADD_BYTES(pd, pd_offset));
377 buf[1] = (temp >> 8) & 0xFF;
378 buf[0] = temp & 0xFF;
379 buf += 2;
380 }
381 pd_offset += 2;
382 len -= 2;
383 }
384 break;
385
386 case LIBUSB20_ME_INT32:
387 pd_offset = -((-pd_offset) & ~3); /* align */
388 while (pd_count--) {
389 uint32_t temp;
390
391 if (len < 4) /* overflow */
392 goto done;
393 if (buf) {
394 temp = *((const uint32_t *)
395 LIBUSB20_ADD_BYTES(pd, pd_offset));
396 buf[3] = (temp >> 24) & 0xFF;
397 buf[2] = (temp >> 16) & 0xFF;
398 buf[1] = (temp >> 8) & 0xFF;
399 buf[0] = temp & 0xFF;
400 buf += 4;
401 }
402 pd_offset += 4;
403 len -= 4;
404 }
405 break;
406
407 case LIBUSB20_ME_INT64:
408 pd_offset = -((-pd_offset) & ~7); /* align */
409 while (pd_count--) {
410 uint64_t temp;
411
412 if (len < 8) /* overflow */
413 goto done;
414 if (buf) {
415
416 temp = *((const uint64_t *)
417 LIBUSB20_ADD_BYTES(pd, pd_offset));
418 buf[7] = (temp >> 56) & 0xFF;
419 buf[6] = (temp >> 48) & 0xFF;
420 buf[5] = (temp >> 40) & 0xFF;
421 buf[4] = (temp >> 32) & 0xFF;
422 buf[3] = (temp >> 24) & 0xFF;
423 buf[2] = (temp >> 16) & 0xFF;
424 buf[1] = (temp >> 8) & 0xFF;
425 buf[0] = temp & 0xFF;
426 buf += 8;
427 }
428 pd_offset += 8;
429 len -= 8;
430 }
431 break;
432
433 case LIBUSB20_ME_STRUCT:
434 pd_offset = -((-pd_offset) &
435 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
436 while (pd_count--) {
437 void *src_ptr;
438 uint16_t src_len;
439 struct libusb20_me_struct *ps;
440
441 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
442
443 switch (ps->type) {
444 case LIBUSB20_ME_IS_RAW:
445 src_len = ps->len;
446 src_ptr = ps->ptr;
447 break;
448
449 case LIBUSB20_ME_IS_ENCODED:
450 if (ps->len == 0) {
451 /*
452 * Length is encoded
453 * in the data itself
454 * and should be
455 * correct:
456 */
457 ps->len = 0xFFFF;
458 }
459 src_len = libusb20_me_get_1(pd, 0);
460 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
461 if (src_len == 0xFF) {
462 /* length is escaped */
463 src_len = libusb20_me_get_2(pd, 1);
464 src_ptr =
465 LIBUSB20_ADD_BYTES(ps->ptr, 3);
466 }
467 break;
468
469 case LIBUSB20_ME_IS_DECODED:
470 /* reserve 3 length bytes */
471 src_len = libusb20_me_encode(NULL,
472 0xFFFF - 3, ps->ptr);
473 src_ptr = NULL;
474 break;
475
476 default: /* empty structure */
477 src_len = 0;
478 src_ptr = NULL;
479 break;
480 }
481
482 if (src_len > 0xFE) {
483 if (src_len > (0xFFFF - 3))
484 /* overflow */
485 goto done;
486
487 if (len < (src_len + 3))
488 /* overflow */
489 goto done;
490
491 if (buf) {
492 buf[0] = 0xFF;
493 buf[1] = (src_len & 0xFF);
494 buf[2] = (src_len >> 8) & 0xFF;
495 buf += 3;
496 }
497 len -= (src_len + 3);
498 } else {
499 if (len < (src_len + 1))
500 /* overflow */
501 goto done;
502
503 if (buf) {
504 buf[0] = (src_len & 0xFF);
505 buf += 1;
506 }
507 len -= (src_len + 1);
508 }
509
510 /* check for buffer and non-zero length */
511
512 if (buf && src_len) {
513 if (ps->type == LIBUSB20_ME_IS_DECODED) {
514 /*
515 * Repeat encode
516 * procedure - we have
517 * room for the
518 * complete structure:
519 */
520 (void) libusb20_me_encode(buf,
521 0xFFFF - 3, ps->ptr);
522 } else {
523 bcopy(src_ptr, buf, src_len);
524 }
525 buf += src_len;
526 }
527 pd_offset += sizeof(struct libusb20_me_struct);
528 }
529 break;
530
531 default:
532 goto done;
533 }
534 }
535 done:
536 return (len_old - len);
537 }
538
539 /*------------------------------------------------------------------------*
540 * libusb20_me_decode - decode a message into a decoded structure
541 *
542 * Description of parameters:
543 * "ptr" - message pointer
544 * "len" - message length
545 * "pd" - pointer to decoded structure
546 *
547 * Returns:
548 * "0..65535" - number of bytes decoded, limited by "len"
549 *------------------------------------------------------------------------*/
550 uint16_t
libusb20_me_decode(const void * ptr,uint16_t len,void * pd)551 libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
552 {
553 const uint8_t *pf; /* pointer to format data */
554 const uint8_t *buf; /* pointer to input buffer */
555
556 uint32_t pd_offset; /* decoded structure offset */
557 uint16_t len_old; /* old length */
558 uint16_t pd_count; /* decoded element count */
559 uint8_t me; /* message element */
560
561 /* initialise */
562
563 len_old = len;
564 buf = ptr;
565 pd_offset = sizeof(void *);
566 pf = (*((struct libusb20_me_format **)pd))->format;
567
568 /* scan */
569
570 while (1) {
571
572 /* get information element */
573
574 me = (pf[0]) & LIBUSB20_ME_MASK;
575 pd_count = pf[1] | (pf[2] << 8);
576 pf += 3;
577
578 /* decode the message element by type */
579
580 switch (me) {
581 case LIBUSB20_ME_INT8:
582 while (pd_count--) {
583 uint8_t temp;
584
585 if (len < 1) {
586 len = 0;
587 temp = 0;
588 } else {
589 len -= 1;
590 temp = buf[0];
591 buf++;
592 }
593 *((uint8_t *)LIBUSB20_ADD_BYTES(pd,
594 pd_offset)) = temp;
595 pd_offset += 1;
596 }
597 break;
598
599 case LIBUSB20_ME_INT16:
600 pd_offset = -((-pd_offset) & ~1); /* align */
601 while (pd_count--) {
602 uint16_t temp;
603
604 if (len < 2) {
605 len = 0;
606 temp = 0;
607 } else {
608 len -= 2;
609 temp = buf[1] << 8;
610 temp |= buf[0];
611 buf += 2;
612 }
613 *((uint16_t *)LIBUSB20_ADD_BYTES(pd,
614 pd_offset)) = temp;
615 pd_offset += 2;
616 }
617 break;
618
619 case LIBUSB20_ME_INT32:
620 pd_offset = -((-pd_offset) & ~3); /* align */
621 while (pd_count--) {
622 uint32_t temp;
623
624 if (len < 4) {
625 len = 0;
626 temp = 0;
627 } else {
628 len -= 4;
629 temp = buf[3] << 24;
630 temp |= buf[2] << 16;
631 temp |= buf[1] << 8;
632 temp |= buf[0];
633 buf += 4;
634 }
635
636 *((uint32_t *)LIBUSB20_ADD_BYTES(pd,
637 pd_offset)) = temp;
638 pd_offset += 4;
639 }
640 break;
641
642 case LIBUSB20_ME_INT64:
643 pd_offset = -((-pd_offset) & ~7); /* align */
644 while (pd_count--) {
645 uint64_t temp;
646
647 if (len < 8) {
648 len = 0;
649 temp = 0;
650 } else {
651 len -= 8;
652 temp = ((uint64_t)buf[7]) << 56;
653 temp |= ((uint64_t)buf[6]) << 48;
654 temp |= ((uint64_t)buf[5]) << 40;
655 temp |= ((uint64_t)buf[4]) << 32;
656 temp |= buf[3] << 24;
657 temp |= buf[2] << 16;
658 temp |= buf[1] << 8;
659 temp |= buf[0];
660 buf += 8;
661 }
662
663 *((uint64_t *)LIBUSB20_ADD_BYTES(pd,
664 pd_offset)) = temp;
665 pd_offset += 8;
666 }
667 break;
668
669 case LIBUSB20_ME_STRUCT:
670 pd_offset = -((-pd_offset) &
671 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
672 while (pd_count--) {
673 uint16_t temp;
674 struct libusb20_me_struct *ps;
675
676 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
677
678 if (ps->type == LIBUSB20_ME_IS_ENCODED) {
679 /*
680 * Pre-store a de-constified
681 * pointer to the raw
682 * structure:
683 */
684 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
685
686 /*
687 * Get the correct number of
688 * length bytes:
689 */
690 if (len != 0) {
691 if (buf[0] == 0xFF) {
692 ps->len = 3;
693 } else {
694 ps->len = 1;
695 }
696 } else {
697 ps->len = 0;
698 }
699 }
700 /* get the structure length */
701
702 if (len != 0) {
703 if (buf[0] == 0xFF) {
704 if (len < 3) {
705 len = 0;
706 temp = 0;
707 } else {
708 len -= 3;
709 temp = buf[1] |
710 (buf[2] << 8);
711 buf += 3;
712 }
713 } else {
714 len -= 1;
715 temp = buf[0];
716 buf += 1;
717 }
718 } else {
719 len = 0;
720 temp = 0;
721 }
722 /* check for invalid length */
723
724 if (temp > len) {
725 len = 0;
726 temp = 0;
727 }
728 /* check wanted structure type */
729
730 switch (ps->type) {
731 case LIBUSB20_ME_IS_ENCODED:
732 /* check for zero length */
733 if (temp == 0) {
734 /*
735 * The pointer must
736 * be valid:
737 */
738 ps->ptr = LIBUSB20_ADD_BYTES(
739 libusb20_me_encode_empty, 0);
740 ps->len = 1;
741 } else {
742 ps->len += temp;
743 }
744 break;
745
746 case LIBUSB20_ME_IS_RAW:
747 /* update length and pointer */
748 ps->len = temp;
749 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
750 break;
751
752 case LIBUSB20_ME_IS_EMPTY:
753 case LIBUSB20_ME_IS_DECODED:
754 /* check for non-zero length */
755 if (temp != 0) {
756 /* update type */
757 ps->type = LIBUSB20_ME_IS_DECODED;
758 ps->len = 0;
759 /*
760 * Recursivly decode
761 * the next structure
762 */
763 (void) libusb20_me_decode(buf,
764 temp, ps->ptr);
765 } else {
766 /* update type */
767 ps->type = LIBUSB20_ME_IS_EMPTY;
768 ps->len = 0;
769 }
770 break;
771
772 default:
773 /*
774 * nothing to do - should
775 * not happen
776 */
777 ps->ptr = NULL;
778 ps->len = 0;
779 break;
780 }
781 buf += temp;
782 len -= temp;
783 pd_offset += sizeof(struct libusb20_me_struct);
784 }
785 break;
786
787 default:
788 goto done;
789 }
790 }
791 done:
792 return (len_old - len);
793 }
794