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