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
43static const uint32_t libusb20_me_encode_empty[2];	/* dummy */
44
45LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
46LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
47LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC);
48LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC);
49LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP);
50LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC);
51LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC);
52LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC);
53LIBUSB20_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 *------------------------------------------------------------------------*/
62struct libusb20_config *
63libusb20_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 *------------------------------------------------------------------------*/
252const uint8_t *
253libusb20_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 *------------------------------------------------------------------------*/
292uint8_t
293libusb20_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 *------------------------------------------------------------------------*/
304uint16_t
305libusb20_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 *------------------------------------------------------------------------*/
322uint16_t
323libusb20_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	}
539done:
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 *------------------------------------------------------------------------*/
554uint16_t
555libusb20_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	}
795done:
796	return (len_old - len);
797}
798