libusb20_desc.c revision 186730
1/* $FreeBSD: head/lib/libusb20/libusb20_desc.c 186730 2009-01-04 00:12:01Z 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	    ((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	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	const uint8_t *start;
242	const uint8_t *end;
243	const uint8_t *desc_next;
244
245	/* be NULL safe */
246	if (pdesc == NULL)
247		return (NULL);
248
249	start = (const uint8_t *)pdesc->ptr;
250	end = LIBUSB20_ADD_BYTES(start, pdesc->len);
251
252	/* get start of next descriptor */
253	if (psubdesc == NULL)
254		psubdesc = start;
255	else
256		psubdesc = psubdesc + psubdesc[0];
257
258	/* check that the next USB descriptor is within the range */
259	if ((psubdesc < start) || (psubdesc >= end))
260		return (NULL);		/* out of range, or EOD */
261
262	/* check start of the second next USB descriptor, if any */
263	desc_next = psubdesc + psubdesc[0];
264	if ((desc_next < start) || (desc_next > end))
265		return (NULL);		/* out of range */
266
267	/* check minimum descriptor length */
268	if (psubdesc[0] < 3)
269		return (NULL);		/* too short descriptor */
270
271	return (psubdesc);		/* return start of next descriptor */
272}
273
274/*------------------------------------------------------------------------*
275 *	libusb20_me_get_1 - safety wrapper to read out one byte
276 *------------------------------------------------------------------------*/
277uint8_t
278libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
279{
280	if (offset < ie->len) {
281		return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
282	}
283	return (0);
284}
285
286/*------------------------------------------------------------------------*
287 *	libusb20_me_get_2 - safety wrapper to read out one word
288 *------------------------------------------------------------------------*/
289uint16_t
290libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
291{
292	return (libusb20_me_get_1(ie, offset) |
293	    (libusb20_me_get_1(ie, offset + 1) << 8));
294}
295
296/*------------------------------------------------------------------------*
297 *	libusb20_me_encode - encode a message structure
298 *
299 * Description of parameters:
300 * "len" - maximum length of output buffer
301 * "ptr" - pointer to output buffer. If NULL, no data will be written
302 * "pd" - source structure
303 *
304 * Return values:
305 * 0..65535 - Number of bytes used, limited by the "len" input parameter.
306 *------------------------------------------------------------------------*/
307uint16_t
308libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
309{
310	const uint8_t *pf;		/* pointer to format data */
311	uint8_t *buf;			/* pointer to output buffer */
312
313	uint32_t pd_offset;		/* decoded structure offset */
314	uint16_t len_old;		/* old length */
315	uint16_t pd_count;		/* decoded element count */
316	uint8_t me;			/* message element */
317
318	/* initialise */
319
320	len_old = len;
321	buf = ptr;
322	pd_offset = sizeof(void *);
323	pf = (*((struct libusb20_me_format *const *)pd))->format;
324
325	/* scan */
326
327	while (1) {
328
329		/* get information element */
330
331		me = (pf[0]) & LIBUSB20_ME_MASK;
332		pd_count = pf[1] | (pf[2] << 8);
333		pf += 3;
334
335		/* encode the message element */
336
337		switch (me) {
338		case LIBUSB20_ME_INT8:
339			while (pd_count--) {
340				uint8_t temp;
341
342				if (len < 1)	/* overflow */
343					goto done;
344				if (buf) {
345					temp = *((const uint8_t *)
346					    LIBUSB20_ADD_BYTES(pd, pd_offset));
347					buf[0] = temp;
348					buf += 1;
349				}
350				pd_offset += 1;
351				len -= 1;
352			}
353			break;
354
355		case LIBUSB20_ME_INT16:
356			pd_offset = -((-pd_offset) & ~1);	/* align */
357			while (pd_count--) {
358				uint16_t temp;
359
360				if (len < 2)	/* overflow */
361					goto done;
362
363				if (buf) {
364					temp = *((const uint16_t *)
365					    LIBUSB20_ADD_BYTES(pd, pd_offset));
366					buf[1] = (temp >> 8) & 0xFF;
367					buf[0] = temp & 0xFF;
368					buf += 2;
369				}
370				pd_offset += 2;
371				len -= 2;
372			}
373			break;
374
375		case LIBUSB20_ME_INT32:
376			pd_offset = -((-pd_offset) & ~3);	/* align */
377			while (pd_count--) {
378				uint32_t temp;
379
380				if (len < 4)	/* overflow */
381					goto done;
382				if (buf) {
383					temp = *((const uint32_t *)
384					    LIBUSB20_ADD_BYTES(pd, pd_offset));
385					buf[3] = (temp >> 24) & 0xFF;
386					buf[2] = (temp >> 16) & 0xFF;
387					buf[1] = (temp >> 8) & 0xFF;
388					buf[0] = temp & 0xFF;
389					buf += 4;
390				}
391				pd_offset += 4;
392				len -= 4;
393			}
394			break;
395
396		case LIBUSB20_ME_INT64:
397			pd_offset = -((-pd_offset) & ~7);	/* align */
398			while (pd_count--) {
399				uint64_t temp;
400
401				if (len < 8)	/* overflow */
402					goto done;
403				if (buf) {
404
405					temp = *((const uint64_t *)
406					    LIBUSB20_ADD_BYTES(pd, pd_offset));
407					buf[7] = (temp >> 56) & 0xFF;
408					buf[6] = (temp >> 48) & 0xFF;
409					buf[5] = (temp >> 40) & 0xFF;
410					buf[4] = (temp >> 32) & 0xFF;
411					buf[3] = (temp >> 24) & 0xFF;
412					buf[2] = (temp >> 16) & 0xFF;
413					buf[1] = (temp >> 8) & 0xFF;
414					buf[0] = temp & 0xFF;
415					buf += 8;
416				}
417				pd_offset += 8;
418				len -= 8;
419			}
420			break;
421
422		case LIBUSB20_ME_STRUCT:
423			pd_offset = -((-pd_offset) &
424			    ~(LIBUSB20_ME_STRUCT_ALIGN - 1));	/* align */
425			while (pd_count--) {
426				void *src_ptr;
427				uint16_t src_len;
428				struct libusb20_me_struct *ps;
429
430				ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
431
432				switch (ps->type) {
433				case LIBUSB20_ME_IS_RAW:
434					src_len = ps->len;
435					src_ptr = ps->ptr;
436					break;
437
438				case LIBUSB20_ME_IS_ENCODED:
439					if (ps->len == 0) {
440						/*
441						 * Length is encoded
442						 * in the data itself
443						 * and should be
444						 * correct:
445						 */
446						ps->len = 0 - 1;
447					}
448					src_len = libusb20_me_get_1(pd, 0);
449					src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
450					if (src_len == 0xFF) {
451						/* length is escaped */
452						src_len = libusb20_me_get_2(pd, 1);
453						src_ptr =
454						    LIBUSB20_ADD_BYTES(ps->ptr, 3);
455					}
456					break;
457
458				case LIBUSB20_ME_IS_DECODED:
459					/* reserve 3 length bytes */
460					src_len = libusb20_me_encode(NULL,
461					    0 - 1 - 3, ps->ptr);
462					src_ptr = NULL;
463					break;
464
465				default:	/* empty structure */
466					src_len = 0;
467					src_ptr = NULL;
468					break;
469				}
470
471				if (src_len > 0xFE) {
472					if (src_len > (uint16_t)(0 - 1 - 3))
473						/* overflow */
474						goto done;
475
476					if (len < (src_len + 3))
477						/* overflow */
478						goto done;
479
480					if (buf) {
481						buf[0] = 0xFF;
482						buf[1] = (src_len & 0xFF);
483						buf[2] = (src_len >> 8) & 0xFF;
484						buf += 3;
485					}
486					len -= (src_len + 3);
487				} else {
488					if (len < (src_len + 1))
489						/* overflow */
490						goto done;
491
492					if (buf) {
493						buf[0] = (src_len & 0xFF);
494						buf += 1;
495					}
496					len -= (src_len + 1);
497				}
498
499				/* check for buffer and non-zero length */
500
501				if (buf && src_len) {
502					if (ps->type == LIBUSB20_ME_IS_DECODED) {
503						/*
504						 * Repeat encode
505						 * procedure - we have
506						 * room for the
507						 * complete structure:
508						 */
509						uint16_t dummy;
510
511						dummy = libusb20_me_encode(buf,
512						    0 - 1 - 3, ps->ptr);
513					} else {
514						bcopy(src_ptr, buf, src_len);
515					}
516					buf += src_len;
517				}
518				pd_offset += sizeof(struct libusb20_me_struct);
519			}
520			break;
521
522		default:
523			goto done;
524		}
525	}
526done:
527	return (len_old - len);
528}
529
530/*------------------------------------------------------------------------*
531 *	libusb20_me_decode - decode a message into a decoded structure
532 *
533 * Description of parameters:
534 * "ptr" - message pointer
535 * "len" - message length
536 * "pd" - pointer to decoded structure
537 *
538 * Returns:
539 * "0..65535" - number of bytes decoded, limited by "len"
540 *------------------------------------------------------------------------*/
541uint16_t
542libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
543{
544	const uint8_t *pf;		/* pointer to format data */
545	const uint8_t *buf;		/* pointer to input buffer */
546
547	uint32_t pd_offset;		/* decoded structure offset */
548	uint16_t len_old;		/* old length */
549	uint16_t pd_count;		/* decoded element count */
550	uint8_t me;			/* message element */
551
552	/* initialise */
553
554	len_old = len;
555	buf = ptr;
556	pd_offset = sizeof(void *);
557	pf = (*((struct libusb20_me_format **)pd))->format;
558
559	/* scan */
560
561	while (1) {
562
563		/* get information element */
564
565		me = (pf[0]) & LIBUSB20_ME_MASK;
566		pd_count = pf[1] | (pf[2] << 8);
567		pf += 3;
568
569		/* decode the message element by type */
570
571		switch (me) {
572		case LIBUSB20_ME_INT8:
573			while (pd_count--) {
574				uint8_t temp;
575
576				if (len < 1) {
577					len = 0;
578					temp = 0;
579				} else {
580					len -= 1;
581					temp = buf[0];
582					buf++;
583				}
584				*((uint8_t *)LIBUSB20_ADD_BYTES(pd,
585				    pd_offset)) = temp;
586				pd_offset += 1;
587			}
588			break;
589
590		case LIBUSB20_ME_INT16:
591			pd_offset = -((-pd_offset) & ~1);	/* align */
592			while (pd_count--) {
593				uint16_t temp;
594
595				if (len < 2) {
596					len = 0;
597					temp = 0;
598				} else {
599					len -= 2;
600					temp = buf[1] << 8;
601					temp |= buf[0];
602					buf += 2;
603				}
604				*((uint16_t *)LIBUSB20_ADD_BYTES(pd,
605				    pd_offset)) = temp;
606				pd_offset += 2;
607			}
608			break;
609
610		case LIBUSB20_ME_INT32:
611			pd_offset = -((-pd_offset) & ~3);	/* align */
612			while (pd_count--) {
613				uint32_t temp;
614
615				if (len < 4) {
616					len = 0;
617					temp = 0;
618				} else {
619					len -= 4;
620					temp = buf[3] << 24;
621					temp |= buf[2] << 16;
622					temp |= buf[1] << 8;
623					temp |= buf[0];
624					buf += 4;
625				}
626
627				*((uint32_t *)LIBUSB20_ADD_BYTES(pd,
628				    pd_offset)) = temp;
629				pd_offset += 4;
630			}
631			break;
632
633		case LIBUSB20_ME_INT64:
634			pd_offset = -((-pd_offset) & ~7);	/* align */
635			while (pd_count--) {
636				uint64_t temp;
637
638				if (len < 8) {
639					len = 0;
640					temp = 0;
641				} else {
642					len -= 8;
643					temp = ((uint64_t)buf[7]) << 56;
644					temp |= ((uint64_t)buf[6]) << 48;
645					temp |= ((uint64_t)buf[5]) << 40;
646					temp |= ((uint64_t)buf[4]) << 32;
647					temp |= buf[3] << 24;
648					temp |= buf[2] << 16;
649					temp |= buf[1] << 8;
650					temp |= buf[0];
651					buf += 8;
652				}
653
654				*((uint64_t *)LIBUSB20_ADD_BYTES(pd,
655				    pd_offset)) = temp;
656				pd_offset += 8;
657			}
658			break;
659
660		case LIBUSB20_ME_STRUCT:
661			pd_offset = -((-pd_offset) &
662			    ~(LIBUSB20_ME_STRUCT_ALIGN - 1));	/* align */
663			while (pd_count--) {
664				uint16_t temp;
665				uint16_t dummy;
666				struct libusb20_me_struct *ps;
667
668				ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
669
670				if (ps->type == LIBUSB20_ME_IS_ENCODED) {
671					/*
672					 * Pre-store a de-constified
673					 * pointer to the raw
674					 * structure:
675					 */
676					ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
677
678					/*
679					 * Get the correct number of
680					 * length bytes:
681					 */
682					if (len != 0) {
683						if (buf[0] == 0xFF) {
684							ps->len = 3;
685						} else {
686							ps->len = 1;
687						}
688					} else {
689						ps->len = 0;
690					}
691				}
692				/* get the structure length */
693
694				if (len != 0) {
695					if (buf[0] == 0xFF) {
696						if (len < 3) {
697							len = 0;
698							temp = 0;
699						} else {
700							len -= 3;
701							temp = buf[1] |
702							    (buf[2] << 8);
703							buf += 3;
704						}
705					} else {
706						len -= 1;
707						temp = buf[0];
708						buf += 1;
709					}
710				} else {
711					len = 0;
712					temp = 0;
713				}
714				/* check for invalid length */
715
716				if (temp > len) {
717					len = 0;
718					temp = 0;
719				}
720				/* check wanted structure type */
721
722				switch (ps->type) {
723				case LIBUSB20_ME_IS_ENCODED:
724					/* check for zero length */
725					if (temp == 0) {
726						/*
727						 * The pointer must
728						 * be valid:
729						 */
730						ps->ptr = LIBUSB20_ADD_BYTES(
731						    libusb20_me_encode_empty, 0);
732						ps->len = 1;
733					} else {
734						ps->len += temp;
735					}
736					break;
737
738				case LIBUSB20_ME_IS_RAW:
739					/* update length and pointer */
740					ps->len = temp;
741					ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
742					break;
743
744				case LIBUSB20_ME_IS_EMPTY:
745				case LIBUSB20_ME_IS_DECODED:
746					/* check for non-zero length */
747					if (temp != 0) {
748						/* update type */
749						ps->type = LIBUSB20_ME_IS_DECODED;
750						ps->len = 0;
751						/*
752						 * Recursivly decode
753						 * the next structure
754						 */
755						dummy = libusb20_me_decode(buf,
756						    temp, ps->ptr);
757					} else {
758						/* update type */
759						ps->type = LIBUSB20_ME_IS_EMPTY;
760						ps->len = 0;
761					}
762					break;
763
764				default:
765					/*
766					 * nothing to do - should
767					 * not happen
768					 */
769					ps->ptr = NULL;
770					ps->len = 0;
771					break;
772				}
773				buf += temp;
774				len -= temp;
775				pd_offset += sizeof(struct libusb20_me_struct);
776			}
777			break;
778
779		default:
780			goto done;
781		}
782	}
783done:
784	return (len_old - len);
785}
786