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