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