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