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