3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
30 #include LIBUSB_GLOBAL_INCLUDE_FILE
36 #include <sys/queue.h>
40 #include "libusb20_desc.h"
41 #include "libusb20_int.h"
43 static const uint32_t libusb20_me_encode_empty[2]; /* dummy */
45 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
46 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
47 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_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);
55 /*------------------------------------------------------------------------*
56 * libusb20_parse_config_desc
59 * NULL: Out of memory.
60 * Else: A valid config structure pointer which must be passed to "free()"
61 *------------------------------------------------------------------------*/
62 struct libusb20_config *
63 libusb20_parse_config_desc(const void *config_desc)
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;
72 struct libusb20_me_struct pcdesc;
75 uint16_t niface_no_alt;
81 if (ptr[1] != LIBUSB20_DT_CONFIG) {
82 return (NULL); /* not config descriptor */
86 * The first "bInterfaceNumber" cannot start at 0xFFFF
87 * because the field is 8-bit.
95 /* get "wTotalLength" and setup "pcdesc" */
96 pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0);
98 ((const uint8_t *)config_desc)[2] |
99 (((const uint8_t *)config_desc)[3] << 8);
100 pcdesc.type = LIBUSB20_ME_IS_RAW;
102 /* descriptor pre-scan */
103 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
104 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
106 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
108 /* check "bInterfaceNumber" */
109 if (ptr[2] != iface_no) {
116 /* sanity checking */
118 return (NULL); /* corrupt */
120 if (nendpoint >= 256) {
121 return (NULL); /* corrupt */
123 size = sizeof(*lub_config) +
124 (niface * sizeof(*lub_interface)) +
125 (nendpoint * sizeof(*lub_endpoint)) +
128 lub_config = malloc(size);
129 if (lub_config == NULL) {
130 return (NULL); /* out of memory */
132 /* make sure memory is initialised */
133 memset(lub_config, 0, size);
135 lub_interface = (void *)(lub_config + 1);
136 lub_alt_interface = (void *)(lub_interface + niface_no_alt);
137 lub_endpoint = (void *)(lub_interface + niface);
140 * Make a copy of the config descriptor, so that the caller can free
141 * the initial config descriptor pointer!
143 memcpy((void *)(lub_endpoint + nendpoint), config_desc, pcdesc.len);
145 ptr = (const void *)(lub_endpoint + nendpoint);
146 pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0);
148 /* init config structure */
150 LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc);
152 if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) {
155 lub_config->num_interface = 0;
156 lub_config->interface = lub_interface;
157 lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
158 lub_config->extra.len = -ptr[0];
159 lub_config->extra.type = LIBUSB20_ME_IS_RAW;
170 /* descriptor pre-scan */
171 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
172 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
175 last_ep = lub_endpoint;
176 last_if->num_endpoints++;
178 LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc);
180 if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) {
183 last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
184 last_ep->extra.len = 0;
185 last_ep->extra.type = LIBUSB20_ME_IS_RAW;
187 lub_config->extra.len += ptr[0];
190 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
191 if (ptr[2] != iface_no) {
195 lub_config->num_interface++;
196 last_if = lub_interface;
199 /* one more alternate setting */
200 lub_interface->num_altsetting++;
201 last_if = lub_alt_interface;
205 LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc);
207 if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) {
211 /* detect broken USB descriptors when USB debugging is enabled */
212 if (last_if->desc.bInterfaceNumber != (uint8_t)(niface - 1)) {
213 const char *str = getenv("LIBUSB_DEBUG");
214 if (str != NULL && str[0] != '\0' && str[0] != '0') {
215 printf("LIBUSB_DEBUG: bInterfaceNumber(%u) is not sequential(%u)\n",
216 last_if->desc.bInterfaceNumber, niface - 1);
219 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
220 last_if->extra.len = 0;
221 last_if->extra.type = LIBUSB20_ME_IS_RAW;
222 last_if->endpoints = lub_endpoint + 1;
223 last_if->altsetting = lub_alt_interface;
224 last_if->num_altsetting = 0;
225 last_if->num_endpoints = 0;
228 /* unknown descriptor */
231 last_ep->extra.len += ptr[0];
233 last_if->extra.len += ptr[0];
236 lub_config->extra.len += ptr[0];
243 /*------------------------------------------------------------------------*
244 * libusb20_desc_foreach
246 * Safe traversal of USB descriptors.
249 * NULL: End of descriptors
250 * Else: Pointer to next descriptor
251 *------------------------------------------------------------------------*/
253 libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
254 const uint8_t *psubdesc)
256 const uint8_t *start;
258 const uint8_t *desc_next;
264 start = (const uint8_t *)pdesc->ptr;
265 end = LIBUSB20_ADD_BYTES(start, pdesc->len);
267 /* get start of next descriptor */
268 if (psubdesc == NULL)
271 psubdesc = psubdesc + psubdesc[0];
273 /* check that the next USB descriptor is within the range */
274 if ((psubdesc < start) || (psubdesc >= end))
275 return (NULL); /* out of range, or EOD */
277 /* check start of the second next USB descriptor, if any */
278 desc_next = psubdesc + psubdesc[0];
279 if ((desc_next < start) || (desc_next > end))
280 return (NULL); /* out of range */
282 /* check minimum descriptor length */
284 return (NULL); /* too short descriptor */
286 return (psubdesc); /* return start of next descriptor */
289 /*------------------------------------------------------------------------*
290 * libusb20_me_get_1 - safety wrapper to read out one byte
291 *------------------------------------------------------------------------*/
293 libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
295 if (offset < ie->len) {
296 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
301 /*------------------------------------------------------------------------*
302 * libusb20_me_get_2 - safety wrapper to read out one word
303 *------------------------------------------------------------------------*/
305 libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
307 return (libusb20_me_get_1(ie, offset) |
308 (libusb20_me_get_1(ie, offset + 1) << 8));
311 /*------------------------------------------------------------------------*
312 * libusb20_me_encode - encode a message structure
314 * Description of parameters:
315 * "len" - maximum length of output buffer
316 * "ptr" - pointer to output buffer. If NULL, no data will be written
317 * "pd" - source structure
320 * 0..65535 - Number of bytes used, limited by the "len" input parameter.
321 *------------------------------------------------------------------------*/
323 libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
325 const uint8_t *pf; /* pointer to format data */
326 uint8_t *buf; /* pointer to output buffer */
328 uint32_t pd_offset; /* decoded structure offset */
329 uint16_t len_old; /* old length */
330 uint16_t pd_count; /* decoded element count */
331 uint8_t me; /* message element */
337 pd_offset = sizeof(void *);
338 pf = (*((struct libusb20_me_format *const *)pd))->format;
344 /* get information element */
346 me = (pf[0]) & LIBUSB20_ME_MASK;
347 pd_count = pf[1] | (pf[2] << 8);
350 /* encode the message element */
353 case LIBUSB20_ME_INT8:
357 if (len < 1) /* overflow */
360 temp = *((const uint8_t *)
361 LIBUSB20_ADD_BYTES(pd, pd_offset));
370 case LIBUSB20_ME_INT16:
371 pd_offset = -((-pd_offset) & ~1); /* align */
375 if (len < 2) /* overflow */
379 temp = *((const uint16_t *)
380 LIBUSB20_ADD_BYTES(pd, pd_offset));
381 buf[1] = (temp >> 8) & 0xFF;
382 buf[0] = temp & 0xFF;
390 case LIBUSB20_ME_INT32:
391 pd_offset = -((-pd_offset) & ~3); /* align */
395 if (len < 4) /* overflow */
398 temp = *((const uint32_t *)
399 LIBUSB20_ADD_BYTES(pd, pd_offset));
400 buf[3] = (temp >> 24) & 0xFF;
401 buf[2] = (temp >> 16) & 0xFF;
402 buf[1] = (temp >> 8) & 0xFF;
403 buf[0] = temp & 0xFF;
411 case LIBUSB20_ME_INT64:
412 pd_offset = -((-pd_offset) & ~7); /* align */
416 if (len < 8) /* overflow */
420 temp = *((const uint64_t *)
421 LIBUSB20_ADD_BYTES(pd, pd_offset));
422 buf[7] = (temp >> 56) & 0xFF;
423 buf[6] = (temp >> 48) & 0xFF;
424 buf[5] = (temp >> 40) & 0xFF;
425 buf[4] = (temp >> 32) & 0xFF;
426 buf[3] = (temp >> 24) & 0xFF;
427 buf[2] = (temp >> 16) & 0xFF;
428 buf[1] = (temp >> 8) & 0xFF;
429 buf[0] = temp & 0xFF;
437 case LIBUSB20_ME_STRUCT:
438 pd_offset = -((-pd_offset) &
439 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
443 struct libusb20_me_struct *ps;
445 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
448 case LIBUSB20_ME_IS_RAW:
453 case LIBUSB20_ME_IS_ENCODED:
463 src_len = libusb20_me_get_1(pd, 0);
464 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
465 if (src_len == 0xFF) {
466 /* length is escaped */
467 src_len = libusb20_me_get_2(pd, 1);
469 LIBUSB20_ADD_BYTES(ps->ptr, 3);
473 case LIBUSB20_ME_IS_DECODED:
474 /* reserve 3 length bytes */
475 src_len = libusb20_me_encode(NULL,
476 0xFFFF - 3, ps->ptr);
480 default: /* empty structure */
486 if (src_len > 0xFE) {
487 if (src_len > (0xFFFF - 3))
491 if (len < (src_len + 3))
497 buf[1] = (src_len & 0xFF);
498 buf[2] = (src_len >> 8) & 0xFF;
501 len -= (src_len + 3);
503 if (len < (src_len + 1))
508 buf[0] = (src_len & 0xFF);
511 len -= (src_len + 1);
514 /* check for buffer and non-zero length */
516 if (buf && src_len) {
517 if (ps->type == LIBUSB20_ME_IS_DECODED) {
520 * procedure - we have
522 * complete structure:
524 (void) libusb20_me_encode(buf,
525 0xFFFF - 3, ps->ptr);
527 bcopy(src_ptr, buf, src_len);
531 pd_offset += sizeof(struct libusb20_me_struct);
540 return (len_old - len);
543 /*------------------------------------------------------------------------*
544 * libusb20_me_decode - decode a message into a decoded structure
546 * Description of parameters:
547 * "ptr" - message pointer
548 * "len" - message length
549 * "pd" - pointer to decoded structure
552 * "0..65535" - number of bytes decoded, limited by "len"
553 *------------------------------------------------------------------------*/
555 libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
557 const uint8_t *pf; /* pointer to format data */
558 const uint8_t *buf; /* pointer to input buffer */
560 uint32_t pd_offset; /* decoded structure offset */
561 uint16_t len_old; /* old length */
562 uint16_t pd_count; /* decoded element count */
563 uint8_t me; /* message element */
569 pd_offset = sizeof(void *);
570 pf = (*((struct libusb20_me_format **)pd))->format;
576 /* get information element */
578 me = (pf[0]) & LIBUSB20_ME_MASK;
579 pd_count = pf[1] | (pf[2] << 8);
582 /* decode the message element by type */
585 case LIBUSB20_ME_INT8:
597 *((uint8_t *)LIBUSB20_ADD_BYTES(pd,
603 case LIBUSB20_ME_INT16:
604 pd_offset = -((-pd_offset) & ~1); /* align */
617 *((uint16_t *)LIBUSB20_ADD_BYTES(pd,
623 case LIBUSB20_ME_INT32:
624 pd_offset = -((-pd_offset) & ~3); /* align */
634 temp |= buf[2] << 16;
640 *((uint32_t *)LIBUSB20_ADD_BYTES(pd,
646 case LIBUSB20_ME_INT64:
647 pd_offset = -((-pd_offset) & ~7); /* align */
656 temp = ((uint64_t)buf[7]) << 56;
657 temp |= ((uint64_t)buf[6]) << 48;
658 temp |= ((uint64_t)buf[5]) << 40;
659 temp |= ((uint64_t)buf[4]) << 32;
660 temp |= buf[3] << 24;
661 temp |= buf[2] << 16;
667 *((uint64_t *)LIBUSB20_ADD_BYTES(pd,
673 case LIBUSB20_ME_STRUCT:
674 pd_offset = -((-pd_offset) &
675 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
678 struct libusb20_me_struct *ps;
680 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
682 if (ps->type == LIBUSB20_ME_IS_ENCODED) {
684 * Pre-store a de-constified
688 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
691 * Get the correct number of
695 if (buf[0] == 0xFF) {
704 /* get the structure length */
707 if (buf[0] == 0xFF) {
726 /* check for invalid length */
732 /* check wanted structure type */
735 case LIBUSB20_ME_IS_ENCODED:
736 /* check for zero length */
742 ps->ptr = LIBUSB20_ADD_BYTES(
743 libusb20_me_encode_empty, 0);
750 case LIBUSB20_ME_IS_RAW:
751 /* update length and pointer */
753 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
756 case LIBUSB20_ME_IS_EMPTY:
757 case LIBUSB20_ME_IS_DECODED:
758 /* check for non-zero length */
761 ps->type = LIBUSB20_ME_IS_DECODED;
767 (void) libusb20_me_decode(buf,
771 ps->type = LIBUSB20_ME_IS_EMPTY;
778 * nothing to do - should
787 pd_offset += sizeof(struct libusb20_me_struct);
796 return (len_old - len);