3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/queue.h>
34 #include "libusb20_desc.h"
35 #include "libusb20_int.h"
37 static const uint32_t libusb20_me_encode_empty[2]; /* dummy */
39 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
40 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
41 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC);
42 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC);
43 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP);
45 /*------------------------------------------------------------------------*
46 * libusb20_parse_config_desc
49 * NULL: Out of memory.
50 * Else: A valid config structure pointer which must be passed to "free()"
51 *------------------------------------------------------------------------*/
52 struct libusb20_config *
53 libusb20_parse_config_desc(const void *config_desc)
55 struct libusb20_config *lub_config;
56 struct libusb20_interface *lub_interface;
57 struct libusb20_interface *lub_alt_interface;
58 struct libusb20_interface *last_if;
59 struct libusb20_endpoint *lub_endpoint;
60 struct libusb20_endpoint *last_ep;
62 struct libusb20_me_struct pcdesc;
65 uint16_t niface_no_alt;
71 if (ptr[1] != LIBUSB20_DT_CONFIG) {
72 return (NULL); /* not config descriptor */
75 * The first "bInterfaceNumber" should never have the value 0xff.
84 /* get "wTotalLength" and setup "pcdesc" */
85 pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0);
87 ((const uint8_t *)config_desc)[2] |
88 (((const uint8_t *)config_desc)[3] << 8);
89 pcdesc.type = LIBUSB20_ME_IS_RAW;
91 /* descriptor pre-scan */
92 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
93 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
95 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
97 /* check "bInterfaceNumber" */
98 if (ptr[2] != iface_no) {
105 /* sanity checking */
107 return (NULL); /* corrupt */
109 if (nendpoint >= 256) {
110 return (NULL); /* corrupt */
112 size = sizeof(*lub_config) +
113 (niface * sizeof(*lub_interface)) +
114 (nendpoint * sizeof(*lub_endpoint)) +
117 lub_config = malloc(size);
118 if (lub_config == NULL) {
119 return (NULL); /* out of memory */
121 lub_interface = (void *)(lub_config + 1);
122 lub_alt_interface = (void *)(lub_interface + niface_no_alt);
123 lub_endpoint = (void *)(lub_interface + niface);
126 * Make a copy of the config descriptor, so that the caller can free
127 * the inital config descriptor pointer!
129 ptr = (void *)(lub_endpoint + nendpoint);
130 memcpy(LIBUSB20_ADD_BYTES(ptr, 0), config_desc, pcdesc.len);
131 pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0);
132 config_desc = LIBUSB20_ADD_BYTES(ptr, 0);
134 /* init config structure */
138 LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc);
140 if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) {
143 lub_config->num_interface = 0;
144 lub_config->interface = lub_interface;
145 lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
146 lub_config->extra.len = -ptr[0];
147 lub_config->extra.type = LIBUSB20_ME_IS_RAW;
158 /* descriptor pre-scan */
159 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
160 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
163 last_ep = lub_endpoint;
164 last_if->num_endpoints++;
166 LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc);
168 if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) {
171 last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
172 last_ep->extra.len = 0;
173 last_ep->extra.type = LIBUSB20_ME_IS_RAW;
175 lub_config->extra.len += ptr[0];
178 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
179 if (ptr[2] != iface_no) {
183 lub_config->num_interface++;
184 last_if = lub_interface;
187 /* one more alternate setting */
188 lub_interface->num_altsetting++;
189 last_if = lub_alt_interface;
193 LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc);
195 if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) {
199 * Sometimes USB devices have corrupt interface
200 * descriptors and we need to overwrite the provided
203 last_if->desc.bInterfaceNumber = niface - 1;
204 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
205 last_if->extra.len = 0;
206 last_if->extra.type = LIBUSB20_ME_IS_RAW;
207 last_if->endpoints = lub_endpoint + 1;
208 last_if->altsetting = lub_alt_interface;
209 last_if->num_altsetting = 0;
210 last_if->num_endpoints = 0;
213 /* unknown descriptor */
216 last_ep->extra.len += ptr[0];
218 last_if->extra.len += ptr[0];
221 lub_config->extra.len += ptr[0];
228 /*------------------------------------------------------------------------*
229 * libusb20_desc_foreach
231 * Safe traversal of USB descriptors.
234 * NULL: End of descriptors
235 * Else: Pointer to next descriptor
236 *------------------------------------------------------------------------*/
238 libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
239 const uint8_t *psubdesc)
241 const uint8_t *start;
243 const uint8_t *desc_next;
249 start = (const uint8_t *)pdesc->ptr;
250 end = LIBUSB20_ADD_BYTES(start, pdesc->len);
252 /* get start of next descriptor */
253 if (psubdesc == NULL)
256 psubdesc = psubdesc + psubdesc[0];
258 /* check that the next USB descriptor is within the range */
259 if ((psubdesc < start) || (psubdesc >= end))
260 return (NULL); /* out of range, or EOD */
262 /* check start of the second next USB descriptor, if any */
263 desc_next = psubdesc + psubdesc[0];
264 if ((desc_next < start) || (desc_next > end))
265 return (NULL); /* out of range */
267 /* check minimum descriptor length */
269 return (NULL); /* too short descriptor */
271 return (psubdesc); /* return start of next descriptor */
274 /*------------------------------------------------------------------------*
275 * libusb20_me_get_1 - safety wrapper to read out one byte
276 *------------------------------------------------------------------------*/
278 libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
280 if (offset < ie->len) {
281 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
286 /*------------------------------------------------------------------------*
287 * libusb20_me_get_2 - safety wrapper to read out one word
288 *------------------------------------------------------------------------*/
290 libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
292 return (libusb20_me_get_1(ie, offset) |
293 (libusb20_me_get_1(ie, offset + 1) << 8));
296 /*------------------------------------------------------------------------*
297 * libusb20_me_encode - encode a message structure
299 * Description of parameters:
300 * "len" - maximum length of output buffer
301 * "ptr" - pointer to output buffer. If NULL, no data will be written
302 * "pd" - source structure
305 * 0..65535 - Number of bytes used, limited by the "len" input parameter.
306 *------------------------------------------------------------------------*/
308 libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
310 const uint8_t *pf; /* pointer to format data */
311 uint8_t *buf; /* pointer to output buffer */
313 uint32_t pd_offset; /* decoded structure offset */
314 uint16_t len_old; /* old length */
315 uint16_t pd_count; /* decoded element count */
316 uint8_t me; /* message element */
322 pd_offset = sizeof(void *);
323 pf = (*((struct libusb20_me_format *const *)pd))->format;
329 /* get information element */
331 me = (pf[0]) & LIBUSB20_ME_MASK;
332 pd_count = pf[1] | (pf[2] << 8);
335 /* encode the message element */
338 case LIBUSB20_ME_INT8:
342 if (len < 1) /* overflow */
345 temp = *((const uint8_t *)
346 LIBUSB20_ADD_BYTES(pd, pd_offset));
355 case LIBUSB20_ME_INT16:
356 pd_offset = -((-pd_offset) & ~1); /* align */
360 if (len < 2) /* overflow */
364 temp = *((const uint16_t *)
365 LIBUSB20_ADD_BYTES(pd, pd_offset));
366 buf[1] = (temp >> 8) & 0xFF;
367 buf[0] = temp & 0xFF;
375 case LIBUSB20_ME_INT32:
376 pd_offset = -((-pd_offset) & ~3); /* align */
380 if (len < 4) /* overflow */
383 temp = *((const uint32_t *)
384 LIBUSB20_ADD_BYTES(pd, pd_offset));
385 buf[3] = (temp >> 24) & 0xFF;
386 buf[2] = (temp >> 16) & 0xFF;
387 buf[1] = (temp >> 8) & 0xFF;
388 buf[0] = temp & 0xFF;
396 case LIBUSB20_ME_INT64:
397 pd_offset = -((-pd_offset) & ~7); /* align */
401 if (len < 8) /* overflow */
405 temp = *((const uint64_t *)
406 LIBUSB20_ADD_BYTES(pd, pd_offset));
407 buf[7] = (temp >> 56) & 0xFF;
408 buf[6] = (temp >> 48) & 0xFF;
409 buf[5] = (temp >> 40) & 0xFF;
410 buf[4] = (temp >> 32) & 0xFF;
411 buf[3] = (temp >> 24) & 0xFF;
412 buf[2] = (temp >> 16) & 0xFF;
413 buf[1] = (temp >> 8) & 0xFF;
414 buf[0] = temp & 0xFF;
422 case LIBUSB20_ME_STRUCT:
423 pd_offset = -((-pd_offset) &
424 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
428 struct libusb20_me_struct *ps;
430 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
433 case LIBUSB20_ME_IS_RAW:
438 case LIBUSB20_ME_IS_ENCODED:
448 src_len = libusb20_me_get_1(pd, 0);
449 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
450 if (src_len == 0xFF) {
451 /* length is escaped */
452 src_len = libusb20_me_get_2(pd, 1);
454 LIBUSB20_ADD_BYTES(ps->ptr, 3);
458 case LIBUSB20_ME_IS_DECODED:
459 /* reserve 3 length bytes */
460 src_len = libusb20_me_encode(NULL,
465 default: /* empty structure */
471 if (src_len > 0xFE) {
472 if (src_len > (uint16_t)(0 - 1 - 3))
476 if (len < (src_len + 3))
482 buf[1] = (src_len & 0xFF);
483 buf[2] = (src_len >> 8) & 0xFF;
486 len -= (src_len + 3);
488 if (len < (src_len + 1))
493 buf[0] = (src_len & 0xFF);
496 len -= (src_len + 1);
499 /* check for buffer and non-zero length */
501 if (buf && src_len) {
502 if (ps->type == LIBUSB20_ME_IS_DECODED) {
505 * procedure - we have
507 * complete structure:
511 dummy = libusb20_me_encode(buf,
514 bcopy(src_ptr, buf, src_len);
518 pd_offset += sizeof(struct libusb20_me_struct);
527 return (len_old - len);
530 /*------------------------------------------------------------------------*
531 * libusb20_me_decode - decode a message into a decoded structure
533 * Description of parameters:
534 * "ptr" - message pointer
535 * "len" - message length
536 * "pd" - pointer to decoded structure
539 * "0..65535" - number of bytes decoded, limited by "len"
540 *------------------------------------------------------------------------*/
542 libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
544 const uint8_t *pf; /* pointer to format data */
545 const uint8_t *buf; /* pointer to input buffer */
547 uint32_t pd_offset; /* decoded structure offset */
548 uint16_t len_old; /* old length */
549 uint16_t pd_count; /* decoded element count */
550 uint8_t me; /* message element */
556 pd_offset = sizeof(void *);
557 pf = (*((struct libusb20_me_format **)pd))->format;
563 /* get information element */
565 me = (pf[0]) & LIBUSB20_ME_MASK;
566 pd_count = pf[1] | (pf[2] << 8);
569 /* decode the message element by type */
572 case LIBUSB20_ME_INT8:
584 *((uint8_t *)LIBUSB20_ADD_BYTES(pd,
590 case LIBUSB20_ME_INT16:
591 pd_offset = -((-pd_offset) & ~1); /* align */
604 *((uint16_t *)LIBUSB20_ADD_BYTES(pd,
610 case LIBUSB20_ME_INT32:
611 pd_offset = -((-pd_offset) & ~3); /* align */
621 temp |= buf[2] << 16;
627 *((uint32_t *)LIBUSB20_ADD_BYTES(pd,
633 case LIBUSB20_ME_INT64:
634 pd_offset = -((-pd_offset) & ~7); /* align */
643 temp = ((uint64_t)buf[7]) << 56;
644 temp |= ((uint64_t)buf[6]) << 48;
645 temp |= ((uint64_t)buf[5]) << 40;
646 temp |= ((uint64_t)buf[4]) << 32;
647 temp |= buf[3] << 24;
648 temp |= buf[2] << 16;
654 *((uint64_t *)LIBUSB20_ADD_BYTES(pd,
660 case LIBUSB20_ME_STRUCT:
661 pd_offset = -((-pd_offset) &
662 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
666 struct libusb20_me_struct *ps;
668 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
670 if (ps->type == LIBUSB20_ME_IS_ENCODED) {
672 * Pre-store a de-constified
676 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
679 * Get the correct number of
683 if (buf[0] == 0xFF) {
692 /* get the structure length */
695 if (buf[0] == 0xFF) {
714 /* check for invalid length */
720 /* check wanted structure type */
723 case LIBUSB20_ME_IS_ENCODED:
724 /* check for zero length */
730 ps->ptr = LIBUSB20_ADD_BYTES(
731 libusb20_me_encode_empty, 0);
738 case LIBUSB20_ME_IS_RAW:
739 /* update length and pointer */
741 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
744 case LIBUSB20_ME_IS_EMPTY:
745 case LIBUSB20_ME_IS_DECODED:
746 /* check for non-zero length */
749 ps->type = LIBUSB20_ME_IS_DECODED;
755 dummy = libusb20_me_decode(buf,
759 ps->type = LIBUSB20_ME_IS_EMPTY;
766 * nothing to do - should
775 pd_offset += sizeof(struct libusb20_me_struct);
784 return (len_old - len);