libusb20_desc.c revision 286333
1/* $FreeBSD: stable/10/lib/libusb/libusb20_desc.c 286333 2015-08-05 18:52:40Z pfg $ */
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
41static const uint32_t libusb20_me_encode_empty[2];	/* dummy */
42
43LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
44LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
45LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC);
46LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC);
47LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP);
48LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC);
49LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC);
50LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC);
51LIBUSB20_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 *------------------------------------------------------------------------*/
60struct libusb20_config *
61libusb20_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	 * The first "bInterfaceNumber" should never have the value 0xff.
84	 * Then it is corrupt.
85	 */
86	niface_no_alt = 0;
87	nendpoint = 0;
88	niface = 0;
89	iface_no = 0xFFFF;
90	ptr = NULL;
91
92	/* get "wTotalLength" and setup "pcdesc" */
93	pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0);
94	pcdesc.len =
95	    ((const uint8_t *)config_desc)[2] |
96	    (((const uint8_t *)config_desc)[3] << 8);
97	pcdesc.type = LIBUSB20_ME_IS_RAW;
98
99	/* descriptor pre-scan */
100	while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
101		if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
102			nendpoint++;
103		} else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
104			niface++;
105			/* check "bInterfaceNumber" */
106			if (ptr[2] != iface_no) {
107				iface_no = ptr[2];
108				niface_no_alt++;
109			}
110		}
111	}
112
113	/* sanity checking */
114	if (niface >= 256) {
115		return (NULL);		/* corrupt */
116	}
117	if (nendpoint >= 256) {
118		return (NULL);		/* corrupt */
119	}
120	size = sizeof(*lub_config) +
121	    (niface * sizeof(*lub_interface)) +
122	    (nendpoint * sizeof(*lub_endpoint)) +
123	    pcdesc.len;
124
125	lub_config = malloc(size);
126	if (lub_config == NULL) {
127		return (NULL);		/* out of memory */
128	}
129	/* make sure memory is initialised */
130	memset(lub_config, 0, size);
131
132	lub_interface = (void *)(lub_config + 1);
133	lub_alt_interface = (void *)(lub_interface + niface_no_alt);
134	lub_endpoint = (void *)(lub_interface + niface);
135
136	/*
137	 * Make a copy of the config descriptor, so that the caller can free
138	 * the inital config descriptor pointer!
139	 */
140	memcpy((void *)(lub_endpoint + nendpoint), config_desc, pcdesc.len);
141
142	ptr = (const void *)(lub_endpoint + nendpoint);
143	pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0);
144
145	/* init config structure */
146
147	LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc);
148
149	if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) {
150		/* ignore */
151	}
152	lub_config->num_interface = 0;
153	lub_config->interface = lub_interface;
154	lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
155	lub_config->extra.len = -ptr[0];
156	lub_config->extra.type = LIBUSB20_ME_IS_RAW;
157
158	/* reset states */
159	niface = 0;
160	iface_no = 0xFFFF;
161	ptr = NULL;
162	lub_interface--;
163	lub_endpoint--;
164	last_if = NULL;
165	last_ep = NULL;
166
167	/* descriptor pre-scan */
168	while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
169		if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
170			if (last_if) {
171				lub_endpoint++;
172				last_ep = lub_endpoint;
173				last_if->num_endpoints++;
174
175				LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc);
176
177				if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) {
178					/* ignore */
179				}
180				last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
181				last_ep->extra.len = 0;
182				last_ep->extra.type = LIBUSB20_ME_IS_RAW;
183			} else {
184				lub_config->extra.len += ptr[0];
185			}
186
187		} else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
188			if (ptr[2] != iface_no) {
189				/* new interface */
190				iface_no = ptr[2];
191				lub_interface++;
192				lub_config->num_interface++;
193				last_if = lub_interface;
194				niface++;
195			} else {
196				/* one more alternate setting */
197				lub_interface->num_altsetting++;
198				last_if = lub_alt_interface;
199				lub_alt_interface++;
200			}
201
202			LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc);
203
204			if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) {
205				/* ignore */
206			}
207			/*
208			 * Sometimes USB devices have corrupt interface
209			 * descriptors and we need to overwrite the provided
210			 * interface number!
211			 */
212			last_if->desc.bInterfaceNumber = niface - 1;
213			last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
214			last_if->extra.len = 0;
215			last_if->extra.type = LIBUSB20_ME_IS_RAW;
216			last_if->endpoints = lub_endpoint + 1;
217			last_if->altsetting = lub_alt_interface;
218			last_if->num_altsetting = 0;
219			last_if->num_endpoints = 0;
220			last_ep = NULL;
221		} else {
222			/* unknown descriptor */
223			if (last_if) {
224				if (last_ep) {
225					last_ep->extra.len += ptr[0];
226				} else {
227					last_if->extra.len += ptr[0];
228				}
229			} else {
230				lub_config->extra.len += ptr[0];
231			}
232		}
233	}
234	return (lub_config);
235}
236
237/*------------------------------------------------------------------------*
238 *	libusb20_desc_foreach
239 *
240 * Safe traversal of USB descriptors.
241 *
242 * Return values:
243 * NULL: End of descriptors
244 * Else: Pointer to next descriptor
245 *------------------------------------------------------------------------*/
246const uint8_t *
247libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
248    const uint8_t *psubdesc)
249{
250	const uint8_t *start;
251	const uint8_t *end;
252	const uint8_t *desc_next;
253
254	/* be NULL safe */
255	if (pdesc == NULL)
256		return (NULL);
257
258	start = (const uint8_t *)pdesc->ptr;
259	end = LIBUSB20_ADD_BYTES(start, pdesc->len);
260
261	/* get start of next descriptor */
262	if (psubdesc == NULL)
263		psubdesc = start;
264	else
265		psubdesc = psubdesc + psubdesc[0];
266
267	/* check that the next USB descriptor is within the range */
268	if ((psubdesc < start) || (psubdesc >= end))
269		return (NULL);		/* out of range, or EOD */
270
271	/* check start of the second next USB descriptor, if any */
272	desc_next = psubdesc + psubdesc[0];
273	if ((desc_next < start) || (desc_next > end))
274		return (NULL);		/* out of range */
275
276	/* check minimum descriptor length */
277	if (psubdesc[0] < 3)
278		return (NULL);		/* too short descriptor */
279
280	return (psubdesc);		/* return start of next descriptor */
281}
282
283/*------------------------------------------------------------------------*
284 *	libusb20_me_get_1 - safety wrapper to read out one byte
285 *------------------------------------------------------------------------*/
286uint8_t
287libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
288{
289	if (offset < ie->len) {
290		return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
291	}
292	return (0);
293}
294
295/*------------------------------------------------------------------------*
296 *	libusb20_me_get_2 - safety wrapper to read out one word
297 *------------------------------------------------------------------------*/
298uint16_t
299libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
300{
301	return (libusb20_me_get_1(ie, offset) |
302	    (libusb20_me_get_1(ie, offset + 1) << 8));
303}
304
305/*------------------------------------------------------------------------*
306 *	libusb20_me_encode - encode a message structure
307 *
308 * Description of parameters:
309 * "len" - maximum length of output buffer
310 * "ptr" - pointer to output buffer. If NULL, no data will be written
311 * "pd" - source structure
312 *
313 * Return values:
314 * 0..65535 - Number of bytes used, limited by the "len" input parameter.
315 *------------------------------------------------------------------------*/
316uint16_t
317libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
318{
319	const uint8_t *pf;		/* pointer to format data */
320	uint8_t *buf;			/* pointer to output buffer */
321
322	uint32_t pd_offset;		/* decoded structure offset */
323	uint16_t len_old;		/* old length */
324	uint16_t pd_count;		/* decoded element count */
325	uint8_t me;			/* message element */
326
327	/* initialise */
328
329	len_old = len;
330	buf = ptr;
331	pd_offset = sizeof(void *);
332	pf = (*((struct libusb20_me_format *const *)pd))->format;
333
334	/* scan */
335
336	while (1) {
337
338		/* get information element */
339
340		me = (pf[0]) & LIBUSB20_ME_MASK;
341		pd_count = pf[1] | (pf[2] << 8);
342		pf += 3;
343
344		/* encode the message element */
345
346		switch (me) {
347		case LIBUSB20_ME_INT8:
348			while (pd_count--) {
349				uint8_t temp;
350
351				if (len < 1)	/* overflow */
352					goto done;
353				if (buf) {
354					temp = *((const uint8_t *)
355					    LIBUSB20_ADD_BYTES(pd, pd_offset));
356					buf[0] = temp;
357					buf += 1;
358				}
359				pd_offset += 1;
360				len -= 1;
361			}
362			break;
363
364		case LIBUSB20_ME_INT16:
365			pd_offset = -((-pd_offset) & ~1);	/* align */
366			while (pd_count--) {
367				uint16_t temp;
368
369				if (len < 2)	/* overflow */
370					goto done;
371
372				if (buf) {
373					temp = *((const uint16_t *)
374					    LIBUSB20_ADD_BYTES(pd, pd_offset));
375					buf[1] = (temp >> 8) & 0xFF;
376					buf[0] = temp & 0xFF;
377					buf += 2;
378				}
379				pd_offset += 2;
380				len -= 2;
381			}
382			break;
383
384		case LIBUSB20_ME_INT32:
385			pd_offset = -((-pd_offset) & ~3);	/* align */
386			while (pd_count--) {
387				uint32_t temp;
388
389				if (len < 4)	/* overflow */
390					goto done;
391				if (buf) {
392					temp = *((const uint32_t *)
393					    LIBUSB20_ADD_BYTES(pd, pd_offset));
394					buf[3] = (temp >> 24) & 0xFF;
395					buf[2] = (temp >> 16) & 0xFF;
396					buf[1] = (temp >> 8) & 0xFF;
397					buf[0] = temp & 0xFF;
398					buf += 4;
399				}
400				pd_offset += 4;
401				len -= 4;
402			}
403			break;
404
405		case LIBUSB20_ME_INT64:
406			pd_offset = -((-pd_offset) & ~7);	/* align */
407			while (pd_count--) {
408				uint64_t temp;
409
410				if (len < 8)	/* overflow */
411					goto done;
412				if (buf) {
413
414					temp = *((const uint64_t *)
415					    LIBUSB20_ADD_BYTES(pd, pd_offset));
416					buf[7] = (temp >> 56) & 0xFF;
417					buf[6] = (temp >> 48) & 0xFF;
418					buf[5] = (temp >> 40) & 0xFF;
419					buf[4] = (temp >> 32) & 0xFF;
420					buf[3] = (temp >> 24) & 0xFF;
421					buf[2] = (temp >> 16) & 0xFF;
422					buf[1] = (temp >> 8) & 0xFF;
423					buf[0] = temp & 0xFF;
424					buf += 8;
425				}
426				pd_offset += 8;
427				len -= 8;
428			}
429			break;
430
431		case LIBUSB20_ME_STRUCT:
432			pd_offset = -((-pd_offset) &
433			    ~(LIBUSB20_ME_STRUCT_ALIGN - 1));	/* align */
434			while (pd_count--) {
435				void *src_ptr;
436				uint16_t src_len;
437				struct libusb20_me_struct *ps;
438
439				ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
440
441				switch (ps->type) {
442				case LIBUSB20_ME_IS_RAW:
443					src_len = ps->len;
444					src_ptr = ps->ptr;
445					break;
446
447				case LIBUSB20_ME_IS_ENCODED:
448					if (ps->len == 0) {
449						/*
450						 * Length is encoded
451						 * in the data itself
452						 * and should be
453						 * correct:
454						 */
455						ps->len = 0xFFFF;
456					}
457					src_len = libusb20_me_get_1(pd, 0);
458					src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
459					if (src_len == 0xFF) {
460						/* length is escaped */
461						src_len = libusb20_me_get_2(pd, 1);
462						src_ptr =
463						    LIBUSB20_ADD_BYTES(ps->ptr, 3);
464					}
465					break;
466
467				case LIBUSB20_ME_IS_DECODED:
468					/* reserve 3 length bytes */
469					src_len = libusb20_me_encode(NULL,
470					    0xFFFF - 3, ps->ptr);
471					src_ptr = NULL;
472					break;
473
474				default:	/* empty structure */
475					src_len = 0;
476					src_ptr = NULL;
477					break;
478				}
479
480				if (src_len > 0xFE) {
481					if (src_len > (0xFFFF - 3))
482						/* overflow */
483						goto done;
484
485					if (len < (src_len + 3))
486						/* overflow */
487						goto done;
488
489					if (buf) {
490						buf[0] = 0xFF;
491						buf[1] = (src_len & 0xFF);
492						buf[2] = (src_len >> 8) & 0xFF;
493						buf += 3;
494					}
495					len -= (src_len + 3);
496				} else {
497					if (len < (src_len + 1))
498						/* overflow */
499						goto done;
500
501					if (buf) {
502						buf[0] = (src_len & 0xFF);
503						buf += 1;
504					}
505					len -= (src_len + 1);
506				}
507
508				/* check for buffer and non-zero length */
509
510				if (buf && src_len) {
511					if (ps->type == LIBUSB20_ME_IS_DECODED) {
512						/*
513						 * Repeat encode
514						 * procedure - we have
515						 * room for the
516						 * complete structure:
517						 */
518						uint16_t dummy;
519
520						dummy = 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	}
535done:
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 *------------------------------------------------------------------------*/
550uint16_t
551libusb20_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				uint16_t dummy;
675				struct libusb20_me_struct *ps;
676
677				ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
678
679				if (ps->type == LIBUSB20_ME_IS_ENCODED) {
680					/*
681					 * Pre-store a de-constified
682					 * pointer to the raw
683					 * structure:
684					 */
685					ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
686
687					/*
688					 * Get the correct number of
689					 * length bytes:
690					 */
691					if (len != 0) {
692						if (buf[0] == 0xFF) {
693							ps->len = 3;
694						} else {
695							ps->len = 1;
696						}
697					} else {
698						ps->len = 0;
699					}
700				}
701				/* get the structure length */
702
703				if (len != 0) {
704					if (buf[0] == 0xFF) {
705						if (len < 3) {
706							len = 0;
707							temp = 0;
708						} else {
709							len -= 3;
710							temp = buf[1] |
711							    (buf[2] << 8);
712							buf += 3;
713						}
714					} else {
715						len -= 1;
716						temp = buf[0];
717						buf += 1;
718					}
719				} else {
720					len = 0;
721					temp = 0;
722				}
723				/* check for invalid length */
724
725				if (temp > len) {
726					len = 0;
727					temp = 0;
728				}
729				/* check wanted structure type */
730
731				switch (ps->type) {
732				case LIBUSB20_ME_IS_ENCODED:
733					/* check for zero length */
734					if (temp == 0) {
735						/*
736						 * The pointer must
737						 * be valid:
738						 */
739						ps->ptr = LIBUSB20_ADD_BYTES(
740						    libusb20_me_encode_empty, 0);
741						ps->len = 1;
742					} else {
743						ps->len += temp;
744					}
745					break;
746
747				case LIBUSB20_ME_IS_RAW:
748					/* update length and pointer */
749					ps->len = temp;
750					ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
751					break;
752
753				case LIBUSB20_ME_IS_EMPTY:
754				case LIBUSB20_ME_IS_DECODED:
755					/* check for non-zero length */
756					if (temp != 0) {
757						/* update type */
758						ps->type = LIBUSB20_ME_IS_DECODED;
759						ps->len = 0;
760						/*
761						 * Recursivly decode
762						 * the next structure
763						 */
764						dummy = libusb20_me_decode(buf,
765						    temp, ps->ptr);
766					} else {
767						/* update type */
768						ps->type = LIBUSB20_ME_IS_EMPTY;
769						ps->len = 0;
770					}
771					break;
772
773				default:
774					/*
775					 * nothing to do - should
776					 * not happen
777					 */
778					ps->ptr = NULL;
779					ps->len = 0;
780					break;
781				}
782				buf += temp;
783				len -= temp;
784				pd_offset += sizeof(struct libusb20_me_struct);
785			}
786			break;
787
788		default:
789			goto done;
790		}
791	}
792done:
793	return (len_old - len);
794}
795