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