2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
29 #include LIBUSB_GLOBAL_INCLUDE_FILE
35 #include <sys/queue.h>
39 #include "libusb20_desc.h"
40 #include "libusb20_int.h"
42 static const uint32_t libusb20_me_encode_empty[2]; /* dummy */
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_CONFIG_DESC);
48 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP);
49 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC);
50 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC);
51 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC);
52 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_BOS_DESCRIPTOR);
54 /*------------------------------------------------------------------------*
55 * libusb20_parse_config_desc
58 * NULL: Out of memory.
59 * Else: A valid config structure pointer which must be passed to "free()"
60 *------------------------------------------------------------------------*/
61 struct libusb20_config *
62 libusb20_parse_config_desc(const void *config_desc)
64 struct libusb20_config *lub_config;
65 struct libusb20_interface *lub_interface;
66 struct libusb20_interface *lub_alt_interface;
67 struct libusb20_interface *last_if;
68 struct libusb20_endpoint *lub_endpoint;
69 struct libusb20_endpoint *last_ep;
71 struct libusb20_me_struct pcdesc;
74 uint16_t niface_no_alt;
80 if (ptr[1] != LIBUSB20_DT_CONFIG) {
81 return (NULL); /* not config descriptor */
85 * The first "bInterfaceNumber" cannot start at 0xFFFF
86 * because the field is 8-bit.
94 /* get "wTotalLength" and setup "pcdesc" */
95 pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0);
97 ((const uint8_t *)config_desc)[2] |
98 (((const uint8_t *)config_desc)[3] << 8);
99 pcdesc.type = LIBUSB20_ME_IS_RAW;
101 /* descriptor pre-scan */
102 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
103 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
105 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
107 /* check "bInterfaceNumber" */
108 if (ptr[2] != iface_no) {
115 /* sanity checking */
117 return (NULL); /* corrupt */
119 if (nendpoint >= 256) {
120 return (NULL); /* corrupt */
122 size = sizeof(*lub_config) +
123 (niface * sizeof(*lub_interface)) +
124 (nendpoint * sizeof(*lub_endpoint)) +
127 lub_config = malloc(size);
128 if (lub_config == NULL) {
129 return (NULL); /* out of memory */
131 /* make sure memory is initialised */
132 memset(lub_config, 0, size);
134 lub_interface = (void *)(lub_config + 1);
135 lub_alt_interface = (void *)(lub_interface + niface_no_alt);
136 lub_endpoint = (void *)(lub_interface + niface);
139 * Make a copy of the config descriptor, so that the caller can free
140 * the initial config descriptor pointer!
142 memcpy((void *)(lub_endpoint + nendpoint), config_desc, pcdesc.len);
144 ptr = (const void *)(lub_endpoint + nendpoint);
145 pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0);
147 /* init config structure */
149 LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc);
151 if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) {
154 lub_config->num_interface = 0;
155 lub_config->interface = lub_interface;
156 lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
157 lub_config->extra.len = -ptr[0];
158 lub_config->extra.type = LIBUSB20_ME_IS_RAW;
169 /* descriptor pre-scan */
170 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
171 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
174 last_ep = lub_endpoint;
175 last_if->num_endpoints++;
177 LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc);
179 if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) {
182 last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
183 last_ep->extra.len = 0;
184 last_ep->extra.type = LIBUSB20_ME_IS_RAW;
186 lub_config->extra.len += ptr[0];
189 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
190 if (ptr[2] != iface_no) {
194 lub_config->num_interface++;
195 last_if = lub_interface;
198 /* one more alternate setting */
199 lub_interface->num_altsetting++;
200 last_if = lub_alt_interface;
204 LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc);
206 if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) {
210 /* detect broken USB descriptors when USB debugging is enabled */
211 if (last_if->desc.bInterfaceNumber != (uint8_t)(niface - 1)) {
212 const char *str = getenv("LIBUSB_DEBUG");
213 if (str != NULL && str[0] != '\0' && str[0] != '0') {
214 printf("LIBUSB_DEBUG: bInterfaceNumber(%u) is not sequential(%u)\n",
215 last_if->desc.bInterfaceNumber, niface - 1);
218 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
219 last_if->extra.len = 0;
220 last_if->extra.type = LIBUSB20_ME_IS_RAW;
221 last_if->endpoints = lub_endpoint + 1;
222 last_if->altsetting = lub_alt_interface;
223 last_if->num_altsetting = 0;
224 last_if->num_endpoints = 0;
227 /* unknown descriptor */
230 last_ep->extra.len += ptr[0];
232 last_if->extra.len += ptr[0];
235 lub_config->extra.len += ptr[0];
242 /*------------------------------------------------------------------------*
243 * libusb20_desc_foreach
245 * Safe traversal of USB descriptors.
248 * NULL: End of descriptors
249 * Else: Pointer to next descriptor
250 *------------------------------------------------------------------------*/
252 libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
253 const uint8_t *psubdesc)
255 const uint8_t *start;
257 const uint8_t *desc_next;
263 start = (const uint8_t *)pdesc->ptr;
264 end = LIBUSB20_ADD_BYTES(start, pdesc->len);
266 /* get start of next descriptor */
267 if (psubdesc == NULL)
270 psubdesc = psubdesc + psubdesc[0];
272 /* check that the next USB descriptor is within the range */
273 if ((psubdesc < start) || (psubdesc >= end))
274 return (NULL); /* out of range, or EOD */
276 /* check start of the second next USB descriptor, if any */
277 desc_next = psubdesc + psubdesc[0];
278 if ((desc_next < start) || (desc_next > end))
279 return (NULL); /* out of range */
281 /* check minimum descriptor length */
283 return (NULL); /* too short descriptor */
285 return (psubdesc); /* return start of next descriptor */
288 /*------------------------------------------------------------------------*
289 * libusb20_me_get_1 - safety wrapper to read out one byte
290 *------------------------------------------------------------------------*/
292 libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
294 if (offset < ie->len) {
295 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
300 /*------------------------------------------------------------------------*
301 * libusb20_me_get_2 - safety wrapper to read out one word
302 *------------------------------------------------------------------------*/
304 libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
306 return (libusb20_me_get_1(ie, offset) |
307 (libusb20_me_get_1(ie, offset + 1) << 8));
310 /*------------------------------------------------------------------------*
311 * libusb20_me_encode - encode a message structure
313 * Description of parameters:
314 * "len" - maximum length of output buffer
315 * "ptr" - pointer to output buffer. If NULL, no data will be written
316 * "pd" - source structure
319 * 0..65535 - Number of bytes used, limited by the "len" input parameter.
320 *------------------------------------------------------------------------*/
322 libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
324 const uint8_t *pf; /* pointer to format data */
325 uint8_t *buf; /* pointer to output buffer */
327 uint32_t pd_offset; /* decoded structure offset */
328 uint16_t len_old; /* old length */
329 uint16_t pd_count; /* decoded element count */
330 uint8_t me; /* message element */
336 pd_offset = sizeof(void *);
337 pf = (*((struct libusb20_me_format *const *)pd))->format;
343 /* get information element */
345 me = (pf[0]) & LIBUSB20_ME_MASK;
346 pd_count = pf[1] | (pf[2] << 8);
349 /* encode the message element */
352 case LIBUSB20_ME_INT8:
356 if (len < 1) /* overflow */
359 temp = *((const uint8_t *)
360 LIBUSB20_ADD_BYTES(pd, pd_offset));
369 case LIBUSB20_ME_INT16:
370 pd_offset = -((-pd_offset) & ~1); /* align */
374 if (len < 2) /* overflow */
378 temp = *((const uint16_t *)
379 LIBUSB20_ADD_BYTES(pd, pd_offset));
380 buf[1] = (temp >> 8) & 0xFF;
381 buf[0] = temp & 0xFF;
389 case LIBUSB20_ME_INT32:
390 pd_offset = -((-pd_offset) & ~3); /* align */
394 if (len < 4) /* overflow */
397 temp = *((const uint32_t *)
398 LIBUSB20_ADD_BYTES(pd, pd_offset));
399 buf[3] = (temp >> 24) & 0xFF;
400 buf[2] = (temp >> 16) & 0xFF;
401 buf[1] = (temp >> 8) & 0xFF;
402 buf[0] = temp & 0xFF;
410 case LIBUSB20_ME_INT64:
411 pd_offset = -((-pd_offset) & ~7); /* align */
415 if (len < 8) /* overflow */
419 temp = *((const uint64_t *)
420 LIBUSB20_ADD_BYTES(pd, pd_offset));
421 buf[7] = (temp >> 56) & 0xFF;
422 buf[6] = (temp >> 48) & 0xFF;
423 buf[5] = (temp >> 40) & 0xFF;
424 buf[4] = (temp >> 32) & 0xFF;
425 buf[3] = (temp >> 24) & 0xFF;
426 buf[2] = (temp >> 16) & 0xFF;
427 buf[1] = (temp >> 8) & 0xFF;
428 buf[0] = temp & 0xFF;
436 case LIBUSB20_ME_STRUCT:
437 pd_offset = -((-pd_offset) &
438 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
442 struct libusb20_me_struct *ps;
444 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
447 case LIBUSB20_ME_IS_RAW:
452 case LIBUSB20_ME_IS_ENCODED:
462 src_len = libusb20_me_get_1(pd, 0);
463 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
464 if (src_len == 0xFF) {
465 /* length is escaped */
466 src_len = libusb20_me_get_2(pd, 1);
468 LIBUSB20_ADD_BYTES(ps->ptr, 3);
472 case LIBUSB20_ME_IS_DECODED:
473 /* reserve 3 length bytes */
474 src_len = libusb20_me_encode(NULL,
475 0xFFFF - 3, ps->ptr);
479 default: /* empty structure */
485 if (src_len > 0xFE) {
486 if (src_len > (0xFFFF - 3))
490 if (len < (src_len + 3))
496 buf[1] = (src_len & 0xFF);
497 buf[2] = (src_len >> 8) & 0xFF;
500 len -= (src_len + 3);
502 if (len < (src_len + 1))
507 buf[0] = (src_len & 0xFF);
510 len -= (src_len + 1);
513 /* check for buffer and non-zero length */
515 if (buf && src_len) {
516 if (ps->type == LIBUSB20_ME_IS_DECODED) {
519 * procedure - we have
521 * complete structure:
523 (void) libusb20_me_encode(buf,
524 0xFFFF - 3, ps->ptr);
526 bcopy(src_ptr, buf, src_len);
530 pd_offset += sizeof(struct libusb20_me_struct);
539 return (len_old - len);
542 /*------------------------------------------------------------------------*
543 * libusb20_me_decode - decode a message into a decoded structure
545 * Description of parameters:
546 * "ptr" - message pointer
547 * "len" - message length
548 * "pd" - pointer to decoded structure
551 * "0..65535" - number of bytes decoded, limited by "len"
552 *------------------------------------------------------------------------*/
554 libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
556 const uint8_t *pf; /* pointer to format data */
557 const uint8_t *buf; /* pointer to input buffer */
559 uint32_t pd_offset; /* decoded structure offset */
560 uint16_t len_old; /* old length */
561 uint16_t pd_count; /* decoded element count */
562 uint8_t me; /* message element */
568 pd_offset = sizeof(void *);
569 pf = (*((struct libusb20_me_format **)pd))->format;
575 /* get information element */
577 me = (pf[0]) & LIBUSB20_ME_MASK;
578 pd_count = pf[1] | (pf[2] << 8);
581 /* decode the message element by type */
584 case LIBUSB20_ME_INT8:
596 *((uint8_t *)LIBUSB20_ADD_BYTES(pd,
602 case LIBUSB20_ME_INT16:
603 pd_offset = -((-pd_offset) & ~1); /* align */
616 *((uint16_t *)LIBUSB20_ADD_BYTES(pd,
622 case LIBUSB20_ME_INT32:
623 pd_offset = -((-pd_offset) & ~3); /* align */
633 temp |= buf[2] << 16;
639 *((uint32_t *)LIBUSB20_ADD_BYTES(pd,
645 case LIBUSB20_ME_INT64:
646 pd_offset = -((-pd_offset) & ~7); /* align */
655 temp = ((uint64_t)buf[7]) << 56;
656 temp |= ((uint64_t)buf[6]) << 48;
657 temp |= ((uint64_t)buf[5]) << 40;
658 temp |= ((uint64_t)buf[4]) << 32;
659 temp |= buf[3] << 24;
660 temp |= buf[2] << 16;
666 *((uint64_t *)LIBUSB20_ADD_BYTES(pd,
672 case LIBUSB20_ME_STRUCT:
673 pd_offset = -((-pd_offset) &
674 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
677 struct libusb20_me_struct *ps;
679 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
681 if (ps->type == LIBUSB20_ME_IS_ENCODED) {
683 * Pre-store a de-constified
687 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
690 * Get the correct number of
694 if (buf[0] == 0xFF) {
703 /* get the structure length */
706 if (buf[0] == 0xFF) {
725 /* check for invalid length */
731 /* check wanted structure type */
734 case LIBUSB20_ME_IS_ENCODED:
735 /* check for zero length */
741 ps->ptr = LIBUSB20_ADD_BYTES(
742 libusb20_me_encode_empty, 0);
749 case LIBUSB20_ME_IS_RAW:
750 /* update length and pointer */
752 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
755 case LIBUSB20_ME_IS_EMPTY:
756 case LIBUSB20_ME_IS_DECODED:
757 /* check for non-zero length */
760 ps->type = LIBUSB20_ME_IS_DECODED;
766 (void) libusb20_me_decode(buf,
770 ps->type = LIBUSB20_ME_IS_EMPTY;
777 * nothing to do - should
786 pd_offset += sizeof(struct libusb20_me_struct);
795 return (len_old - len);