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