blob: 253ef1c319ef48f3a7fdbfe7820ff01e3105d376 [file] [log] [blame]
Nathan Hjelm57256dd2013-05-15 16:11:22 +02001/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
Daniel Drakea8d28812007-12-03 23:29:22 +00002/*
hjelmn@cs.unm.edu1eff2202014-01-08 23:50:34 +00003 * USB descriptor handling functions for libusb
Pete Batard791b7472012-04-03 13:40:39 +01004 * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
5 * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
Daniel Drakea8d28812007-12-03 23:29:22 +00006 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
Daniel Drakee9364d72008-01-04 00:40:49 +000022#include "libusbi.h"
Daniel Drakea8d28812007-12-03 23:29:22 +000023
Chris Dickensaaff15d2020-01-22 15:53:17 -080024#include <string.h>
25
Chris Dickense1fcd8a2020-04-17 12:21:46 -070026#define DESC_HEADER_LENGTH 2
Daniel Drakea8d28812007-12-03 23:29:22 +000027
Chris Dickens7ee92df2016-02-24 01:07:20 -080028/** @defgroup libusb_desc USB descriptors
Daniel Drakeead09cd2008-03-15 16:35:12 +000029 * This page details how to examine the various standard USB descriptors
30 * for detected devices
31 */
32
Chris Dickense8736772020-04-17 13:22:34 -070033#define READ_LE16(p) ((uint16_t) \
34 (((uint16_t)((p)[1]) << 8) | \
35 ((uint16_t)((p)[0]))))
36
37#define READ_LE32(p) ((uint32_t) \
38 (((uint32_t)((p)[3]) << 24) | \
39 ((uint32_t)((p)[2]) << 16) | \
40 ((uint32_t)((p)[1]) << 8) | \
41 ((uint32_t)((p)[0]))))
42
43static void parse_descriptor(const void *source, const char *descriptor, void *dest)
Daniel Drakea8d28812007-12-03 23:29:22 +000044{
Chris Dickense8736772020-04-17 13:22:34 -070045 const uint8_t *sp = source;
46 uint8_t *dp = dest;
47 char field_type;
Daniel Drakea8d28812007-12-03 23:29:22 +000048
Chris Dickense8736772020-04-17 13:22:34 -070049 while (*descriptor) {
50 field_type = *descriptor++;
51 switch (field_type) {
52 case 'b': /* 8-bit byte */
53 *dp++ = *sp++;
54 break;
55 case 'w': /* 16-bit word, convert from little endian to CPU */
Chris Dickensfa3f91e2020-08-13 10:31:51 -070056 dp += ((uintptr_t)dp & 1); /* Align to 16-bit word boundary */
Daniel Drake2b2e9c42008-05-16 22:37:56 +010057
Chris Dickense8736772020-04-17 13:22:34 -070058 *((uint16_t *)dp) = READ_LE16(sp);
59 sp += 2;
60 dp += 2;
61 break;
62 case 'd': /* 32-bit word, convert from little endian to CPU */
Chris Dickensfa3f91e2020-08-13 10:31:51 -070063 dp += 4 - ((uintptr_t)dp & 3); /* Align to 32-bit word boundary */
Hans de Goedeef698c62013-05-27 11:12:28 +020064
Chris Dickense8736772020-04-17 13:22:34 -070065 *((uint32_t *)dp) = READ_LE32(sp);
66 sp += 4;
67 dp += 4;
68 break;
69 case 'u': /* 16 byte UUID */
70 memcpy(dp, sp, 16);
71 sp += 16;
72 dp += 16;
73 break;
Daniel Drakea8d28812007-12-03 23:29:22 +000074 }
75 }
Daniel Drakea8d28812007-12-03 23:29:22 +000076}
77
Daniel Drake0269c752008-04-29 13:34:26 +010078static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
79{
Chris Dickensa157b552020-04-27 18:43:42 -070080 free((void *)endpoint->extra);
Daniel Drake0269c752008-04-29 13:34:26 +010081}
82
Daniel Drake1df713d2008-06-24 23:01:51 -050083static int parse_endpoint(struct libusb_context *ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -070084 struct libusb_endpoint_descriptor *endpoint, const uint8_t *buffer, int size)
Daniel Drakea8d28812007-12-03 23:29:22 +000085{
Chris Dickensfa3f91e2020-08-13 10:31:51 -070086 const struct usbi_descriptor_header *header;
87 const uint8_t *begin;
88 void *extra;
Daniel Drakea8d28812007-12-03 23:29:22 +000089 int parsed = 0;
90 int len;
91
Hans de Goedeb42954b2013-05-23 17:20:47 +020092 if (size < DESC_HEADER_LENGTH) {
93 usbi_err(ctx, "short endpoint descriptor read %d/%d",
94 size, DESC_HEADER_LENGTH);
95 return LIBUSB_ERROR_IO;
Daniel Drakea8d28812007-12-03 23:29:22 +000096 }
97
Chris Dickensfa3f91e2020-08-13 10:31:51 -070098 header = (const struct usbi_descriptor_header *)buffer;
Chris Dickens95b60dc2020-04-17 11:43:54 -070099 if (header->bDescriptorType != LIBUSB_DT_ENDPOINT) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700100 usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700101 header->bDescriptorType, LIBUSB_DT_ENDPOINT);
Daniel Drakea8d28812007-12-03 23:29:22 +0000102 return parsed;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700103 } else if (header->bLength < LIBUSB_DT_ENDPOINT_SIZE) {
104 usbi_err(ctx, "invalid endpoint bLength (%u)", header->bLength);
105 return LIBUSB_ERROR_IO;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700106 } else if (header->bLength > size) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700107 usbi_warn(ctx, "short endpoint descriptor read %d/%u",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700108 size, header->bLength);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200109 return parsed;
110 }
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700111
Chris Dickense1fcd8a2020-04-17 12:21:46 -0700112 if (header->bLength >= LIBUSB_DT_ENDPOINT_AUDIO_SIZE)
Chris Dickens9ececdb2020-04-17 12:57:49 -0700113 parse_descriptor(buffer, "bbbbwbbb", endpoint);
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700114 else
Chris Dickens9ececdb2020-04-17 12:57:49 -0700115 parse_descriptor(buffer, "bbbbwb", endpoint);
Daniel Drakea8d28812007-12-03 23:29:22 +0000116
Chris Dickens95b60dc2020-04-17 11:43:54 -0700117 buffer += header->bLength;
118 size -= header->bLength;
119 parsed += header->bLength;
Daniel Drakea8d28812007-12-03 23:29:22 +0000120
121 /* Skip over the rest of the Class Specific or Vendor Specific */
122 /* descriptors */
123 begin = buffer;
124 while (size >= DESC_HEADER_LENGTH) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700125 header = (const struct usbi_descriptor_header *)buffer;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700126 if (header->bLength < DESC_HEADER_LENGTH) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700127 usbi_err(ctx, "invalid extra ep desc len (%u)",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700128 header->bLength);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200129 return LIBUSB_ERROR_IO;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700130 } else if (header->bLength > size) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700131 usbi_warn(ctx, "short extra ep desc read %d/%u",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700132 size, header->bLength);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200133 return parsed;
Daniel Drakea8d28812007-12-03 23:29:22 +0000134 }
135
136 /* If we find another "proper" descriptor then we're done */
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700137 if (header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
138 header->bDescriptorType == LIBUSB_DT_INTERFACE ||
139 header->bDescriptorType == LIBUSB_DT_CONFIG ||
140 header->bDescriptorType == LIBUSB_DT_DEVICE)
Daniel Drakea8d28812007-12-03 23:29:22 +0000141 break;
142
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600143 usbi_dbg(ctx, "skipping descriptor 0x%x", header->bDescriptorType);
Chris Dickens95b60dc2020-04-17 11:43:54 -0700144 buffer += header->bLength;
145 size -= header->bLength;
146 parsed += header->bLength;
Daniel Drakea8d28812007-12-03 23:29:22 +0000147 }
148
149 /* Copy any unknown descriptors into a storage area for drivers */
150 /* to later parse */
151 len = (int)(buffer - begin);
Chris Dickensa157b552020-04-27 18:43:42 -0700152 if (len <= 0)
Daniel Drakea8d28812007-12-03 23:29:22 +0000153 return parsed;
Daniel Drakea8d28812007-12-03 23:29:22 +0000154
Sean McBride8a05a3f2018-12-15 17:08:34 -0500155 extra = malloc((size_t)len);
Chris Dickensa157b552020-04-27 18:43:42 -0700156 if (!extra)
Daniel Drake59c205d2008-05-05 21:17:03 +0100157 return LIBUSB_ERROR_NO_MEM;
Daniel Drakea8d28812007-12-03 23:29:22 +0000158
Daniel Draked9b2ce22008-04-01 23:28:32 +0100159 memcpy(extra, begin, len);
Chris Dickensa157b552020-04-27 18:43:42 -0700160 endpoint->extra = extra;
Daniel Drake885c2a52008-05-05 21:34:31 +0100161 endpoint->extra_length = len;
Daniel Drakea8d28812007-12-03 23:29:22 +0000162
163 return parsed;
164}
165
Pete Batard8aceb5c2010-02-14 19:47:30 -0600166static void clear_interface(struct libusb_interface *usb_interface)
Daniel Drake0269c752008-04-29 13:34:26 +0100167{
168 int i;
Daniel Drake0269c752008-04-29 13:34:26 +0100169
Nathan Hjelmdc7760a2016-03-06 15:00:31 -0700170 if (usb_interface->altsetting) {
171 for (i = 0; i < usb_interface->num_altsetting; i++) {
172 struct libusb_interface_descriptor *ifp =
173 (struct libusb_interface_descriptor *)
174 usb_interface->altsetting + i;
Chris Dickensa157b552020-04-27 18:43:42 -0700175
176 free((void *)ifp->extra);
Nathan Hjelm0dcc6462016-03-06 15:04:02 -0700177 if (ifp->endpoint) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700178 uint8_t j;
179
Nathan Hjelm0dcc6462016-03-06 15:04:02 -0700180 for (j = 0; j < ifp->bNumEndpoints; j++)
181 clear_endpoint((struct libusb_endpoint_descriptor *)
182 ifp->endpoint + j);
183 }
Chris Dickensa157b552020-04-27 18:43:42 -0700184 free((void *)ifp->endpoint);
Nathan Hjelmdc7760a2016-03-06 15:00:31 -0700185 }
Daniel Drake0269c752008-04-29 13:34:26 +0100186 }
Chris Dickensa157b552020-04-27 18:43:42 -0700187 free((void *)usb_interface->altsetting);
Gaurav98dd33c2015-06-19 08:53:59 +0530188 usb_interface->altsetting = NULL;
Daniel Drake0269c752008-04-29 13:34:26 +0100189}
190
Daniel Drake1df713d2008-06-24 23:01:51 -0500191static int parse_interface(libusb_context *ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700192 struct libusb_interface *usb_interface, const uint8_t *buffer, int size)
Daniel Drakea8d28812007-12-03 23:29:22 +0000193{
Daniel Drakea8d28812007-12-03 23:29:22 +0000194 int len;
195 int r;
196 int parsed = 0;
Hans de Goeded9f30bc2013-05-24 14:03:54 +0200197 int interface_number = -1;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700198 const struct usbi_descriptor_header *header;
199 const struct usbi_interface_descriptor *if_desc;
Daniel Drakedbb3fd82008-01-04 00:54:57 +0000200 struct libusb_interface_descriptor *ifp;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700201 const uint8_t *begin;
Daniel Drakea8d28812007-12-03 23:29:22 +0000202
Chris Dickense1fcd8a2020-04-17 12:21:46 -0700203 while (size >= LIBUSB_DT_INTERFACE_SIZE) {
Chris Dickensa157b552020-04-27 18:43:42 -0700204 struct libusb_interface_descriptor *altsetting;
205
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700206 altsetting = realloc((void *)usb_interface->altsetting,
Chris Dickensa157b552020-04-27 18:43:42 -0700207 sizeof(*altsetting) * (size_t)(usb_interface->num_altsetting + 1));
Daniel Drake0269c752008-04-29 13:34:26 +0100208 if (!altsetting) {
Daniel Drake59c205d2008-05-05 21:17:03 +0100209 r = LIBUSB_ERROR_NO_MEM;
Daniel Drake0269c752008-04-29 13:34:26 +0100210 goto err;
211 }
Pete Batard8aceb5c2010-02-14 19:47:30 -0600212 usb_interface->altsetting = altsetting;
Daniel Drakea8d28812007-12-03 23:29:22 +0000213
Pete Batard8aceb5c2010-02-14 19:47:30 -0600214 ifp = altsetting + usb_interface->num_altsetting;
Chris Dickens9ececdb2020-04-17 12:57:49 -0700215 parse_descriptor(buffer, "bbbbbbbbb", ifp);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200216 if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700217 usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)",
Hans de Goedeb42954b2013-05-23 17:20:47 +0200218 ifp->bDescriptorType, LIBUSB_DT_INTERFACE);
219 return parsed;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700220 } else if (ifp->bLength < LIBUSB_DT_INTERFACE_SIZE) {
221 usbi_err(ctx, "invalid interface bLength (%u)",
Hans de Goedeb42954b2013-05-23 17:20:47 +0200222 ifp->bLength);
223 r = LIBUSB_ERROR_IO;
224 goto err;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700225 } else if (ifp->bLength > size) {
226 usbi_warn(ctx, "short intf descriptor read %d/%u",
Hans de Goedeb42954b2013-05-23 17:20:47 +0200227 size, ifp->bLength);
228 return parsed;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700229 } else if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
230 usbi_err(ctx, "too many endpoints (%u)", ifp->bNumEndpoints);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200231 r = LIBUSB_ERROR_IO;
232 goto err;
233 }
234
235 usb_interface->num_altsetting++;
Daniel Drake0269c752008-04-29 13:34:26 +0100236 ifp->extra = NULL;
Daniel Drake885c2a52008-05-05 21:34:31 +0100237 ifp->extra_length = 0;
Daniel Drake0269c752008-04-29 13:34:26 +0100238 ifp->endpoint = NULL;
Daniel Drakea8d28812007-12-03 23:29:22 +0000239
Hans de Goeded9f30bc2013-05-24 14:03:54 +0200240 if (interface_number == -1)
241 interface_number = ifp->bInterfaceNumber;
242
Daniel Drakea8d28812007-12-03 23:29:22 +0000243 /* Skip over the interface */
244 buffer += ifp->bLength;
245 parsed += ifp->bLength;
246 size -= ifp->bLength;
247
248 begin = buffer;
249
250 /* Skip over any interface, class or vendor descriptors */
251 while (size >= DESC_HEADER_LENGTH) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700252 header = (const struct usbi_descriptor_header *)buffer;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700253 if (header->bLength < DESC_HEADER_LENGTH) {
Hans de Goedeb42954b2013-05-23 17:20:47 +0200254 usbi_err(ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700255 "invalid extra intf desc len (%u)",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700256 header->bLength);
Daniel Drake59c205d2008-05-05 21:17:03 +0100257 r = LIBUSB_ERROR_IO;
Daniel Drake0269c752008-04-29 13:34:26 +0100258 goto err;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700259 } else if (header->bLength > size) {
Hans de Goedeb42954b2013-05-23 17:20:47 +0200260 usbi_warn(ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700261 "short extra intf desc read %d/%u",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700262 size, header->bLength);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200263 return parsed;
Daniel Drakea8d28812007-12-03 23:29:22 +0000264 }
265
266 /* If we find another "proper" descriptor then we're done */
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700267 if (header->bDescriptorType == LIBUSB_DT_INTERFACE ||
268 header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
269 header->bDescriptorType == LIBUSB_DT_CONFIG ||
270 header->bDescriptorType == LIBUSB_DT_DEVICE)
Daniel Drakea8d28812007-12-03 23:29:22 +0000271 break;
272
Chris Dickens95b60dc2020-04-17 11:43:54 -0700273 buffer += header->bLength;
274 parsed += header->bLength;
275 size -= header->bLength;
Daniel Drakea8d28812007-12-03 23:29:22 +0000276 }
277
278 /* Copy any unknown descriptors into a storage area for */
279 /* drivers to later parse */
280 len = (int)(buffer - begin);
Sean McBride8a05a3f2018-12-15 17:08:34 -0500281 if (len > 0) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700282 void *extra = malloc((size_t)len);
283
Chris Dickensa157b552020-04-27 18:43:42 -0700284 if (!extra) {
Daniel Drake59c205d2008-05-05 21:17:03 +0100285 r = LIBUSB_ERROR_NO_MEM;
Daniel Drake0269c752008-04-29 13:34:26 +0100286 goto err;
Daniel Drakea8d28812007-12-03 23:29:22 +0000287 }
Chris Dickensa157b552020-04-27 18:43:42 -0700288
289 memcpy(extra, begin, len);
290 ifp->extra = extra;
Daniel Drake885c2a52008-05-05 21:34:31 +0100291 ifp->extra_length = len;
Daniel Drakea8d28812007-12-03 23:29:22 +0000292 }
293
Daniel Drakea8d28812007-12-03 23:29:22 +0000294 if (ifp->bNumEndpoints > 0) {
Daniel Draked9b2ce22008-04-01 23:28:32 +0100295 struct libusb_endpoint_descriptor *endpoint;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700296 uint8_t i;
Chris Dickensa157b552020-04-27 18:43:42 -0700297
298 endpoint = calloc(ifp->bNumEndpoints, sizeof(*endpoint));
Daniel Drake0269c752008-04-29 13:34:26 +0100299 if (!endpoint) {
Daniel Drake59c205d2008-05-05 21:17:03 +0100300 r = LIBUSB_ERROR_NO_MEM;
Daniel Drake0269c752008-04-29 13:34:26 +0100301 goto err;
302 }
Daniel Drakea8d28812007-12-03 23:29:22 +0000303
Chris Dickensa157b552020-04-27 18:43:42 -0700304 ifp->endpoint = endpoint;
Daniel Drakea8d28812007-12-03 23:29:22 +0000305 for (i = 0; i < ifp->bNumEndpoints; i++) {
Chris Dickens9ececdb2020-04-17 12:57:49 -0700306 r = parse_endpoint(ctx, endpoint + i, buffer, size);
Daniel Drakea8d28812007-12-03 23:29:22 +0000307 if (r < 0)
Daniel Drake0269c752008-04-29 13:34:26 +0100308 goto err;
Hans de Goedeb42954b2013-05-23 17:20:47 +0200309 if (r == 0) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700310 ifp->bNumEndpoints = i;
Sean McBridec1d8c8d2017-12-27 23:35:42 -0500311 break;
Hans de Goedeb42954b2013-05-23 17:20:47 +0200312 }
Daniel Drakea8d28812007-12-03 23:29:22 +0000313
314 buffer += r;
315 parsed += r;
316 size -= r;
317 }
Daniel Drake0269c752008-04-29 13:34:26 +0100318 }
Daniel Drakea8d28812007-12-03 23:29:22 +0000319
320 /* We check to see if it's an alternate to this one */
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700321 if_desc = (const struct usbi_interface_descriptor *)buffer;
Daniel Drakedbb3fd82008-01-04 00:54:57 +0000322 if (size < LIBUSB_DT_INTERFACE_SIZE ||
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700323 if_desc->bDescriptorType != LIBUSB_DT_INTERFACE ||
324 if_desc->bInterfaceNumber != interface_number)
Daniel Drakea8d28812007-12-03 23:29:22 +0000325 return parsed;
326 }
327
328 return parsed;
Daniel Drake0269c752008-04-29 13:34:26 +0100329err:
Pete Batard8aceb5c2010-02-14 19:47:30 -0600330 clear_interface(usb_interface);
Daniel Drake0269c752008-04-29 13:34:26 +0100331 return r;
332}
333
334static void clear_configuration(struct libusb_config_descriptor *config)
335{
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700336 uint8_t i;
337
Nathan Hjelmdc7760a2016-03-06 15:00:31 -0700338 if (config->interface) {
339 for (i = 0; i < config->bNumInterfaces; i++)
340 clear_interface((struct libusb_interface *)
341 config->interface + i);
342 }
Chris Dickensa157b552020-04-27 18:43:42 -0700343 free((void *)config->interface);
344 free((void *)config->extra);
Daniel Drake0269c752008-04-29 13:34:26 +0100345}
346
Daniel Drake1df713d2008-06-24 23:01:51 -0500347static int parse_configuration(struct libusb_context *ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700348 struct libusb_config_descriptor *config, const uint8_t *buffer, int size)
Daniel Drakea8d28812007-12-03 23:29:22 +0000349{
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700350 uint8_t i;
Daniel Drakea8d28812007-12-03 23:29:22 +0000351 int r;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700352 const struct usbi_descriptor_header *header;
Pete Batard8aceb5c2010-02-14 19:47:30 -0600353 struct libusb_interface *usb_interface;
Daniel Drakea8d28812007-12-03 23:29:22 +0000354
Hans de Goede25b31422013-05-23 15:20:12 +0200355 if (size < LIBUSB_DT_CONFIG_SIZE) {
356 usbi_err(ctx, "short config descriptor read %d/%d",
357 size, LIBUSB_DT_CONFIG_SIZE);
358 return LIBUSB_ERROR_IO;
359 }
360
Chris Dickens9ececdb2020-04-17 12:57:49 -0700361 parse_descriptor(buffer, "bbwbbbbb", config);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200362 if (config->bDescriptorType != LIBUSB_DT_CONFIG) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700363 usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)",
Hans de Goedeb42954b2013-05-23 17:20:47 +0200364 config->bDescriptorType, LIBUSB_DT_CONFIG);
365 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700366 } else if (config->bLength < LIBUSB_DT_CONFIG_SIZE) {
367 usbi_err(ctx, "invalid config bLength (%u)", config->bLength);
Hans de Goedeb42954b2013-05-23 17:20:47 +0200368 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700369 } else if (config->bLength > size) {
370 usbi_err(ctx, "short config descriptor read %d/%u",
Hans de Goedeb42954b2013-05-23 17:20:47 +0200371 size, config->bLength);
372 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700373 } else if (config->bNumInterfaces > USB_MAXINTERFACES) {
374 usbi_err(ctx, "too many interfaces (%u)", config->bNumInterfaces);
Daniel Drake59c205d2008-05-05 21:17:03 +0100375 return LIBUSB_ERROR_IO;
Daniel Drakea8d28812007-12-03 23:29:22 +0000376 }
377
Chris Dickensa157b552020-04-27 18:43:42 -0700378 usb_interface = calloc(config->bNumInterfaces, sizeof(*usb_interface));
Tobias Klausera7e946a2015-04-14 17:43:05 +0200379 if (!usb_interface)
Daniel Drake59c205d2008-05-05 21:17:03 +0100380 return LIBUSB_ERROR_NO_MEM;
Daniel Drakea8d28812007-12-03 23:29:22 +0000381
Chris Dickensa157b552020-04-27 18:43:42 -0700382 config->interface = usb_interface;
383
Daniel Drakea8d28812007-12-03 23:29:22 +0000384 buffer += config->bLength;
385 size -= config->bLength;
386
Daniel Drakea8d28812007-12-03 23:29:22 +0000387 for (i = 0; i < config->bNumInterfaces; i++) {
388 int len;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700389 const uint8_t *begin;
Daniel Drakea8d28812007-12-03 23:29:22 +0000390
391 /* Skip over the rest of the Class Specific or Vendor */
392 /* Specific descriptors */
393 begin = buffer;
394 while (size >= DESC_HEADER_LENGTH) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700395 header = (const struct usbi_descriptor_header *)buffer;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700396 if (header->bLength < DESC_HEADER_LENGTH) {
Hans de Goedeb42954b2013-05-23 17:20:47 +0200397 usbi_err(ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700398 "invalid extra config desc len (%u)",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700399 header->bLength);
Daniel Drake59c205d2008-05-05 21:17:03 +0100400 r = LIBUSB_ERROR_IO;
Daniel Drake0269c752008-04-29 13:34:26 +0100401 goto err;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700402 } else if (header->bLength > size) {
Hans de Goedeb42954b2013-05-23 17:20:47 +0200403 usbi_warn(ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700404 "short extra config desc read %d/%u",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700405 size, header->bLength);
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700406 config->bNumInterfaces = i;
Hans de Goedeb42954b2013-05-23 17:20:47 +0200407 return size;
Daniel Drakea8d28812007-12-03 23:29:22 +0000408 }
409
410 /* If we find another "proper" descriptor then we're done */
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700411 if (header->bDescriptorType == LIBUSB_DT_ENDPOINT ||
412 header->bDescriptorType == LIBUSB_DT_INTERFACE ||
413 header->bDescriptorType == LIBUSB_DT_CONFIG ||
414 header->bDescriptorType == LIBUSB_DT_DEVICE)
Daniel Drakea8d28812007-12-03 23:29:22 +0000415 break;
416
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600417 usbi_dbg(ctx, "skipping descriptor 0x%x", header->bDescriptorType);
Chris Dickens95b60dc2020-04-17 11:43:54 -0700418 buffer += header->bLength;
419 size -= header->bLength;
Daniel Drakea8d28812007-12-03 23:29:22 +0000420 }
421
422 /* Copy any unknown descriptors into a storage area for */
423 /* drivers to later parse */
424 len = (int)(buffer - begin);
Sean McBride8a05a3f2018-12-15 17:08:34 -0500425 if (len > 0) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700426 uint8_t *extra = realloc((void *)config->extra,
427 (size_t)(config->extra_length + len));
Daniel Drakea8d28812007-12-03 23:29:22 +0000428
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700429 if (!extra) {
430 r = LIBUSB_ERROR_NO_MEM;
431 goto err;
Daniel Drakea8d28812007-12-03 23:29:22 +0000432 }
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700433
434 memcpy(extra + config->extra_length, begin, len);
435 config->extra = extra;
436 config->extra_length += len;
Daniel Drakea8d28812007-12-03 23:29:22 +0000437 }
438
Chris Dickens9ececdb2020-04-17 12:57:49 -0700439 r = parse_interface(ctx, usb_interface + i, buffer, size);
Daniel Drakea8d28812007-12-03 23:29:22 +0000440 if (r < 0)
Daniel Drake0269c752008-04-29 13:34:26 +0100441 goto err;
Hans de Goedeb42954b2013-05-23 17:20:47 +0200442 if (r == 0) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700443 config->bNumInterfaces = i;
Hans de Goedeb42954b2013-05-23 17:20:47 +0200444 break;
445 }
Daniel Drakea8d28812007-12-03 23:29:22 +0000446
447 buffer += r;
448 size -= r;
449 }
450
451 return size;
Daniel Drake0269c752008-04-29 13:34:26 +0100452
453err:
454 clear_configuration(config);
455 return r;
Daniel Drakea8d28812007-12-03 23:29:22 +0000456}
457
Hans de Goededa5b3352013-05-23 19:24:48 +0200458static int raw_desc_to_config(struct libusb_context *ctx,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700459 const uint8_t *buf, int size, struct libusb_config_descriptor **config)
Hans de Goededa5b3352013-05-23 19:24:48 +0200460{
Chris Dickensa157b552020-04-27 18:43:42 -0700461 struct libusb_config_descriptor *_config = calloc(1, sizeof(*_config));
Hans de Goededa5b3352013-05-23 19:24:48 +0200462 int r;
Harry Mallon85d1f362019-02-12 13:18:56 +0000463
Hans de Goededa5b3352013-05-23 19:24:48 +0200464 if (!_config)
465 return LIBUSB_ERROR_NO_MEM;
466
Chris Dickens9ececdb2020-04-17 12:57:49 -0700467 r = parse_configuration(ctx, _config, buf, size);
Hans de Goededa5b3352013-05-23 19:24:48 +0200468 if (r < 0) {
469 usbi_err(ctx, "parse_configuration failed with error %d", r);
470 free(_config);
471 return r;
472 } else if (r > 0) {
473 usbi_warn(ctx, "still %d bytes of descriptor data left", r);
474 }
Harry Mallon85d1f362019-02-12 13:18:56 +0000475
Hans de Goededa5b3352013-05-23 19:24:48 +0200476 *config = _config;
477 return LIBUSB_SUCCESS;
478}
479
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700480static int get_active_config_descriptor(struct libusb_device *dev,
481 uint8_t *buffer, size_t size)
482{
483 int r = usbi_backend.get_active_config_descriptor(dev, buffer, size);
484
485 if (r < 0)
486 return r;
487
488 if (r < LIBUSB_DT_CONFIG_SIZE) {
489 usbi_err(DEVICE_CTX(dev), "short config descriptor read %d/%d",
490 r, LIBUSB_DT_CONFIG_SIZE);
491 return LIBUSB_ERROR_IO;
492 } else if (r != (int)size) {
493 usbi_warn(DEVICE_CTX(dev), "short config descriptor read %d/%d",
494 r, (int)size);
495 }
496
497 return r;
498}
499
500static int get_config_descriptor(struct libusb_device *dev, uint8_t config_idx,
501 uint8_t *buffer, size_t size)
502{
503 int r = usbi_backend.get_config_descriptor(dev, config_idx, buffer, size);
504
505 if (r < 0)
506 return r;
507 if (r < LIBUSB_DT_CONFIG_SIZE) {
508 usbi_err(DEVICE_CTX(dev), "short config descriptor read %d/%d",
509 r, LIBUSB_DT_CONFIG_SIZE);
510 return LIBUSB_ERROR_IO;
511 } else if (r != (int)size) {
512 usbi_warn(DEVICE_CTX(dev), "short config descriptor read %d/%d",
513 r, (int)size);
514 }
515
516 return r;
517}
518
Chris Dickens7ee92df2016-02-24 01:07:20 -0800519/** \ingroup libusb_desc
Daniel Drakeead09cd2008-03-15 16:35:12 +0000520 * Get the USB device descriptor for a given device.
Daniel Drake10d4e422008-05-08 23:04:52 +0100521 *
522 * This is a non-blocking function; the device descriptor is cached in memory.
523 *
hjelmn@cs.unm.edu1eff2202014-01-08 23:50:34 +0000524 * Note since libusb-1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102, this
Pete Batardb4c18fa2013-07-03 22:41:55 +0100525 * function always succeeds.
526 *
Daniel Drakeead09cd2008-03-15 16:35:12 +0000527 * \param dev the device
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100528 * \param desc output location for the descriptor data
529 * \returns 0 on success or a LIBUSB_ERROR code on failure
Daniel Drakeead09cd2008-03-15 16:35:12 +0000530 */
Pete Batard29f9f9e2010-08-13 11:59:49 +0100531int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev,
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100532 struct libusb_device_descriptor *desc)
Daniel Drakeead09cd2008-03-15 16:35:12 +0000533{
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600534 usbi_dbg(DEVICE_CTX(dev), " ");
Chris Dickensd21956d2020-04-28 12:08:08 -0700535 static_assert(sizeof(dev->device_descriptor) == LIBUSB_DT_DEVICE_SIZE,
536 "struct libusb_device_descriptor is not expected size");
537 *desc = dev->device_descriptor;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100538 return 0;
Daniel Drakeead09cd2008-03-15 16:35:12 +0000539}
540
Chris Dickens7ee92df2016-02-24 01:07:20 -0800541/** \ingroup libusb_desc
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100542 * Get the USB configuration descriptor for the currently active configuration.
543 * This is a non-blocking function which does not involve any requests being
544 * sent to the device.
545 *
546 * \param dev a device
Daniel Drakef2ede982008-05-10 21:45:42 +0100547 * \param config output location for the USB configuration descriptor. Only
548 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
549 * after use.
550 * \returns 0 on success
551 * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
552 * \returns another LIBUSB_ERROR code on error
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100553 * \see libusb_get_config_descriptor
Daniel Drakeead09cd2008-03-15 16:35:12 +0000554 */
Pete Batard29f9f9e2010-08-13 11:59:49 +0100555int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
Daniel Drakef2ede982008-05-10 21:45:42 +0100556 struct libusb_config_descriptor **config)
Daniel Drakeead09cd2008-03-15 16:35:12 +0000557{
Chris Dickensa6bfd452020-08-28 15:42:41 -0700558 union usbi_config_desc_buf _config;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700559 uint16_t config_len;
560 uint8_t *buf;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100561 int r;
562
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700563 r = get_active_config_descriptor(dev, _config.buf, sizeof(_config.buf));
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100564 if (r < 0)
Hans de Goededa5b3352013-05-23 19:24:48 +0200565 return r;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100566
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700567 config_len = libusb_le16_to_cpu(_config.desc.wTotalLength);
568 buf = malloc(config_len);
Hans de Goededa5b3352013-05-23 19:24:48 +0200569 if (!buf)
570 return LIBUSB_ERROR_NO_MEM;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100571
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700572 r = get_active_config_descriptor(dev, buf, config_len);
Hans de Goededa5b3352013-05-23 19:24:48 +0200573 if (r >= 0)
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700574 r = raw_desc_to_config(DEVICE_CTX(dev), buf, r, config);
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100575
Daniel Drake00bb2802009-05-26 15:53:26 -0400576 free(buf);
Daniel Drakef2ede982008-05-10 21:45:42 +0100577 return r;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100578}
579
Chris Dickens7ee92df2016-02-24 01:07:20 -0800580/** \ingroup libusb_desc
Daniel Drakec3844f72008-05-10 14:42:43 +0100581 * Get a USB configuration descriptor based on its index.
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100582 * This is a non-blocking function which does not involve any requests being
583 * sent to the device.
584 *
585 * \param dev a device
Daniel Drakec3844f72008-05-10 14:42:43 +0100586 * \param config_index the index of the configuration you wish to retrieve
Daniel Drakef2ede982008-05-10 21:45:42 +0100587 * \param config output location for the USB configuration descriptor. Only
588 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
589 * after use.
590 * \returns 0 on success
591 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
592 * \returns another LIBUSB_ERROR code on error
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100593 * \see libusb_get_active_config_descriptor()
Daniel Drakec3844f72008-05-10 14:42:43 +0100594 * \see libusb_get_config_descriptor_by_value()
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100595 */
Pete Batard29f9f9e2010-08-13 11:59:49 +0100596int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
Daniel Drakef2ede982008-05-10 21:45:42 +0100597 uint8_t config_index, struct libusb_config_descriptor **config)
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100598{
Chris Dickensa6bfd452020-08-28 15:42:41 -0700599 union usbi_config_desc_buf _config;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700600 uint16_t config_len;
601 uint8_t *buf;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100602 int r;
603
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600604 usbi_dbg(DEVICE_CTX(dev), "index %u", config_index);
Chris Dickens15bd82e2020-03-16 01:01:51 -0700605 if (config_index >= dev->device_descriptor.bNumConfigurations)
Daniel Drakef2ede982008-05-10 21:45:42 +0100606 return LIBUSB_ERROR_NOT_FOUND;
Daniel Drakec3844f72008-05-10 14:42:43 +0100607
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700608 r = get_config_descriptor(dev, config_index, _config.buf, sizeof(_config.buf));
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100609 if (r < 0)
Hans de Goededa5b3352013-05-23 19:24:48 +0200610 return r;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100611
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700612 config_len = libusb_le16_to_cpu(_config.desc.wTotalLength);
613 buf = malloc(config_len);
Hans de Goededa5b3352013-05-23 19:24:48 +0200614 if (!buf)
615 return LIBUSB_ERROR_NO_MEM;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100616
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700617 r = get_config_descriptor(dev, config_index, buf, config_len);
Hans de Goededa5b3352013-05-23 19:24:48 +0200618 if (r >= 0)
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700619 r = raw_desc_to_config(DEVICE_CTX(dev), buf, r, config);
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100620
Daniel Drake00bb2802009-05-26 15:53:26 -0400621 free(buf);
Daniel Drakef2ede982008-05-10 21:45:42 +0100622 return r;
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100623}
624
Chris Dickens7ee92df2016-02-24 01:07:20 -0800625/** \ingroup libusb_desc
Daniel Drakec3844f72008-05-10 14:42:43 +0100626 * Get a USB configuration descriptor with a specific bConfigurationValue.
627 * This is a non-blocking function which does not involve any requests being
628 * sent to the device.
629 *
630 * \param dev a device
631 * \param bConfigurationValue the bConfigurationValue of the configuration you
632 * wish to retrieve
Daniel Drakef2ede982008-05-10 21:45:42 +0100633 * \param config output location for the USB configuration descriptor. Only
634 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
635 * after use.
636 * \returns 0 on success
637 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
638 * \returns another LIBUSB_ERROR code on error
Daniel Drakec3844f72008-05-10 14:42:43 +0100639 * \see libusb_get_active_config_descriptor()
640 * \see libusb_get_config_descriptor()
641 */
Pete Batard29f9f9e2010-08-13 11:59:49 +0100642int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
Daniel Drakef2ede982008-05-10 21:45:42 +0100643 uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
Daniel Drakec3844f72008-05-10 14:42:43 +0100644{
Chris Dickens84768042020-04-28 12:17:50 -0700645 uint8_t idx;
646 int r;
Hans de Goede6b410742013-05-23 19:51:07 +0200647
Chris Dickenscad7d0e2017-07-05 13:44:30 -0700648 if (usbi_backend.get_config_descriptor_by_value) {
Chris Dickensfc5132c2020-04-17 14:21:44 -0700649 void *buf;
650
Chris Dickenscad7d0e2017-07-05 13:44:30 -0700651 r = usbi_backend.get_config_descriptor_by_value(dev,
Chris Dickens9ececdb2020-04-17 12:57:49 -0700652 bConfigurationValue, &buf);
Hans de Goede6b410742013-05-23 19:51:07 +0200653 if (r < 0)
654 return r;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700655
656 return raw_desc_to_config(DEVICE_CTX(dev), buf, r, config);
Hans de Goede6b410742013-05-23 19:51:07 +0200657 }
658
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600659 usbi_dbg(DEVICE_CTX(dev), "value %u", bConfigurationValue);
Chris Dickens84768042020-04-28 12:17:50 -0700660 for (idx = 0; idx < dev->device_descriptor.bNumConfigurations; idx++) {
Chris Dickensa6bfd452020-08-28 15:42:41 -0700661 union usbi_config_desc_buf _config;
Chris Dickens84768042020-04-28 12:17:50 -0700662
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700663 r = get_config_descriptor(dev, idx, _config.buf, sizeof(_config.buf));
Chris Dickens84768042020-04-28 12:17:50 -0700664 if (r < 0)
665 return r;
666
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700667 if (_config.desc.bConfigurationValue == bConfigurationValue)
Chris Dickens84768042020-04-28 12:17:50 -0700668 return libusb_get_config_descriptor(dev, idx, config);
669 }
670
671 return LIBUSB_ERROR_NOT_FOUND;
Daniel Drakec3844f72008-05-10 14:42:43 +0100672}
673
Chris Dickens7ee92df2016-02-24 01:07:20 -0800674/** \ingroup libusb_desc
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100675 * Free a configuration descriptor obtained from
676 * libusb_get_active_config_descriptor() or libusb_get_config_descriptor().
677 * It is safe to call this function with a NULL config parameter, in which
678 * case the function simply returns.
679 *
680 * \param config the configuration descriptor to free
681 */
Pete Batard29f9f9e2010-08-13 11:59:49 +0100682void API_EXPORTED libusb_free_config_descriptor(
Daniel Drakefe4adcc2008-05-09 14:34:31 +0100683 struct libusb_config_descriptor *config)
684{
685 if (!config)
686 return;
687
688 clear_configuration(config);
689 free(config);
Daniel Drakeead09cd2008-03-15 16:35:12 +0000690}
691
Chris Dickens7ee92df2016-02-24 01:07:20 -0800692/** \ingroup libusb_desc
Hans de Goedeef698c62013-05-27 11:12:28 +0200693 * Get an endpoints superspeed endpoint companion descriptor (if any)
694 *
695 * \param ctx the context to operate on, or NULL for the default context
696 * \param endpoint endpoint descriptor from which to get the superspeed
697 * endpoint companion descriptor
698 * \param ep_comp output location for the superspeed endpoint companion
699 * descriptor. Only valid if 0 was returned. Must be freed with
700 * libusb_free_ss_endpoint_companion_descriptor() after use.
701 * \returns 0 on success
702 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
703 * \returns another LIBUSB_ERROR code on error
704 */
705int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor(
Chris Dickensa157b552020-04-27 18:43:42 -0700706 libusb_context *ctx,
Hans de Goedeef698c62013-05-27 11:12:28 +0200707 const struct libusb_endpoint_descriptor *endpoint,
708 struct libusb_ss_endpoint_companion_descriptor **ep_comp)
709{
Chris Dickens95b60dc2020-04-17 11:43:54 -0700710 struct usbi_descriptor_header *header;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700711 const uint8_t *buffer = endpoint->extra;
Hans de Goedeef698c62013-05-27 11:12:28 +0200712 int size = endpoint->extra_length;
Hans de Goedeef698c62013-05-27 11:12:28 +0200713
714 *ep_comp = NULL;
715
716 while (size >= DESC_HEADER_LENGTH) {
Chris Dickens95b60dc2020-04-17 11:43:54 -0700717 header = (struct usbi_descriptor_header *)buffer;
Chris Dickens95b60dc2020-04-17 11:43:54 -0700718 if (header->bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700719 if (header->bLength < DESC_HEADER_LENGTH) {
Chris Dickens0abebc52020-08-18 15:49:22 -0700720 usbi_err(ctx, "invalid descriptor length %u",
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700721 header->bLength);
722 return LIBUSB_ERROR_IO;
723 }
Chris Dickens95b60dc2020-04-17 11:43:54 -0700724 buffer += header->bLength;
725 size -= header->bLength;
Hans de Goedeef698c62013-05-27 11:12:28 +0200726 continue;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700727 } else if (header->bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) {
728 usbi_err(ctx, "invalid ss-ep-comp-desc length %u",
Chris Dickens95b60dc2020-04-17 11:43:54 -0700729 header->bLength);
Hans de Goedeef698c62013-05-27 11:12:28 +0200730 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700731 } else if (header->bLength > size) {
732 usbi_err(ctx, "short ss-ep-comp-desc read %d/%u",
733 size, header->bLength);
734 return LIBUSB_ERROR_IO;
Hans de Goedeef698c62013-05-27 11:12:28 +0200735 }
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700736
Hans de Goedeef698c62013-05-27 11:12:28 +0200737 *ep_comp = malloc(sizeof(**ep_comp));
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700738 if (!*ep_comp)
Hans de Goedeef698c62013-05-27 11:12:28 +0200739 return LIBUSB_ERROR_NO_MEM;
Chris Dickens9ececdb2020-04-17 12:57:49 -0700740 parse_descriptor(buffer, "bbbbw", *ep_comp);
Hans de Goedeef698c62013-05-27 11:12:28 +0200741 return LIBUSB_SUCCESS;
742 }
743 return LIBUSB_ERROR_NOT_FOUND;
744}
745
Chris Dickens7ee92df2016-02-24 01:07:20 -0800746/** \ingroup libusb_desc
Hans de Goedeef698c62013-05-27 11:12:28 +0200747 * Free a superspeed endpoint companion descriptor obtained from
748 * libusb_get_ss_endpoint_companion_descriptor().
749 * It is safe to call this function with a NULL ep_comp parameter, in which
750 * case the function simply returns.
751 *
752 * \param ep_comp the superspeed endpoint companion descriptor to free
753 */
754void API_EXPORTED libusb_free_ss_endpoint_companion_descriptor(
755 struct libusb_ss_endpoint_companion_descriptor *ep_comp)
756{
757 free(ep_comp);
758}
759
Hans de Goeded7b796f2013-05-27 16:31:48 +0200760static int parse_bos(struct libusb_context *ctx,
761 struct libusb_bos_descriptor **bos,
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700762 const uint8_t *buffer, int size)
Hans de Goeded7b796f2013-05-27 16:31:48 +0200763{
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700764 struct libusb_bos_descriptor *_bos;
765 const struct usbi_bos_descriptor *bos_desc;
766 const struct usbi_descriptor_header *header;
767 uint8_t i;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200768
769 if (size < LIBUSB_DT_BOS_SIZE) {
770 usbi_err(ctx, "short bos descriptor read %d/%d",
771 size, LIBUSB_DT_BOS_SIZE);
772 return LIBUSB_ERROR_IO;
773 }
774
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700775 bos_desc = (const struct usbi_bos_descriptor *)buffer;
776 if (bos_desc->bDescriptorType != LIBUSB_DT_BOS) {
777 usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)",
778 bos_desc->bDescriptorType, LIBUSB_DT_BOS);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200779 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700780 } else if (bos_desc->bLength < LIBUSB_DT_BOS_SIZE) {
781 usbi_err(ctx, "invalid bos bLength (%u)", bos_desc->bLength);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200782 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700783 } else if (bos_desc->bLength > size) {
784 usbi_err(ctx, "short bos descriptor read %d/%u",
785 size, bos_desc->bLength);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200786 return LIBUSB_ERROR_IO;
787 }
788
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700789 _bos = calloc(1, sizeof(*_bos) + bos_desc->bNumDeviceCaps * sizeof(void *));
Hans de Goeded7b796f2013-05-27 16:31:48 +0200790 if (!_bos)
791 return LIBUSB_ERROR_NO_MEM;
792
Chris Dickens9ececdb2020-04-17 12:57:49 -0700793 parse_descriptor(buffer, "bbwb", _bos);
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700794 buffer += _bos->bLength;
795 size -= _bos->bLength;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200796
797 /* Get the device capability descriptors */
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700798 for (i = 0; i < _bos->bNumDeviceCaps; i++) {
Hans de Goeded7b796f2013-05-27 16:31:48 +0200799 if (size < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) {
800 usbi_warn(ctx, "short dev-cap descriptor read %d/%d",
801 size, LIBUSB_DT_DEVICE_CAPABILITY_SIZE);
802 break;
803 }
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700804 header = (const struct usbi_descriptor_header *)buffer;
805 if (header->bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) {
806 usbi_warn(ctx, "unexpected descriptor 0x%x (expected 0x%x)",
807 header->bDescriptorType, LIBUSB_DT_DEVICE_CAPABILITY);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200808 break;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700809 } else if (header->bLength < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) {
810 usbi_err(ctx, "invalid dev-cap bLength (%u)",
811 header->bLength);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200812 libusb_free_bos_descriptor(_bos);
813 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700814 } else if (header->bLength > size) {
815 usbi_warn(ctx, "short dev-cap descriptor read %d/%u",
816 size, header->bLength);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200817 break;
818 }
819
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700820 _bos->dev_capability[i] = malloc(header->bLength);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200821 if (!_bos->dev_capability[i]) {
822 libusb_free_bos_descriptor(_bos);
823 return LIBUSB_ERROR_NO_MEM;
824 }
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700825 memcpy(_bos->dev_capability[i], buffer, header->bLength);
826 buffer += header->bLength;
827 size -= header->bLength;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200828 }
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700829 _bos->bNumDeviceCaps = i;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200830 *bos = _bos;
831
832 return LIBUSB_SUCCESS;
833}
834
Chris Dickens7ee92df2016-02-24 01:07:20 -0800835/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +0200836 * Get a Binary Object Store (BOS) descriptor
837 * This is a BLOCKING function, which will send requests to the device.
838 *
Chris Dickens8a0c1432016-02-24 00:23:49 -0800839 * \param dev_handle the handle of an open libusb device
Hans de Goeded7b796f2013-05-27 16:31:48 +0200840 * \param bos output location for the BOS descriptor. Only valid if 0 was returned.
841 * Must be freed with \ref libusb_free_bos_descriptor() after use.
842 * \returns 0 on success
843 * \returns LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor
844 * \returns another LIBUSB_ERROR code on error
845 */
Chris Dickens8a0c1432016-02-24 00:23:49 -0800846int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle,
Hans de Goeded7b796f2013-05-27 16:31:48 +0200847 struct libusb_bos_descriptor **bos)
848{
Chris Dickensa6bfd452020-08-28 15:42:41 -0700849 union usbi_bos_desc_buf _bos;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700850 uint16_t bos_len;
851 uint8_t *bos_data;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200852 int r;
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600853 struct libusb_context *ctx = HANDLE_CTX(dev_handle);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200854
855 /* Read the BOS. This generates 2 requests on the bus,
856 * one for the header, and one for the full BOS */
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700857 r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, _bos.buf, sizeof(_bos.buf));
Hans de Goeded7b796f2013-05-27 16:31:48 +0200858 if (r < 0) {
Hans de Goedef9ef58d2013-06-14 11:10:35 +0200859 if (r != LIBUSB_ERROR_PIPE)
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600860 usbi_err(ctx, "failed to read BOS (%d)", r);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200861 return r;
862 }
863 if (r < LIBUSB_DT_BOS_SIZE) {
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600864 usbi_err(ctx, "short BOS read %d/%d",
Hans de Goeded7b796f2013-05-27 16:31:48 +0200865 r, LIBUSB_DT_BOS_SIZE);
866 return LIBUSB_ERROR_IO;
867 }
868
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700869 bos_len = libusb_le16_to_cpu(_bos.desc.wTotalLength);
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600870 usbi_dbg(ctx, "found BOS descriptor: size %u bytes, %u capabilities",
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700871 bos_len, _bos.desc.bNumDeviceCaps);
872 bos_data = calloc(1, bos_len);
873 if (!bos_data)
Hans de Goeded7b796f2013-05-27 16:31:48 +0200874 return LIBUSB_ERROR_NO_MEM;
875
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700876 r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_data, bos_len);
877 if (r >= 0) {
878 if (r != (int)bos_len)
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600879 usbi_warn(ctx, "short BOS read %d/%u", r, bos_len);
Chris Dickens9ececdb2020-04-17 12:57:49 -0700880 r = parse_bos(HANDLE_CTX(dev_handle), bos, bos_data, r);
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700881 } else {
Nathan Hjelm6cae9c62021-07-20 09:31:06 -0600882 usbi_err(ctx, "failed to read BOS (%d)", r);
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700883 }
Hans de Goeded7b796f2013-05-27 16:31:48 +0200884
885 free(bos_data);
886 return r;
887}
888
Chris Dickens7ee92df2016-02-24 01:07:20 -0800889/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +0200890 * Free a BOS descriptor obtained from libusb_get_bos_descriptor().
891 * It is safe to call this function with a NULL bos parameter, in which
892 * case the function simply returns.
893 *
894 * \param bos the BOS descriptor to free
895 */
896void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
897{
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700898 uint8_t i;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200899
900 if (!bos)
901 return;
902
903 for (i = 0; i < bos->bNumDeviceCaps; i++)
904 free(bos->dev_capability[i]);
905 free(bos);
906}
907
Chris Dickens7ee92df2016-02-24 01:07:20 -0800908/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +0200909 * Get an USB 2.0 Extension descriptor
910 *
911 * \param ctx the context to operate on, or NULL for the default context
912 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
913 * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
914 * LIBUSB_BT_USB_2_0_EXTENSION
915 * \param usb_2_0_extension output location for the USB 2.0 Extension
916 * descriptor. Only valid if 0 was returned. Must be freed with
917 * libusb_free_usb_2_0_extension_descriptor() after use.
918 * \returns 0 on success
919 * \returns a LIBUSB_ERROR code on error
920 */
921int API_EXPORTED libusb_get_usb_2_0_extension_descriptor(
Chris Dickensa157b552020-04-27 18:43:42 -0700922 libusb_context *ctx,
Hans de Goeded7b796f2013-05-27 16:31:48 +0200923 struct libusb_bos_dev_capability_descriptor *dev_cap,
924 struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension)
925{
926 struct libusb_usb_2_0_extension_descriptor *_usb_2_0_extension;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200927
928 if (dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700929 usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)",
Hans de Goeded7b796f2013-05-27 16:31:48 +0200930 dev_cap->bDevCapabilityType,
931 LIBUSB_BT_USB_2_0_EXTENSION);
932 return LIBUSB_ERROR_INVALID_PARAM;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700933 } else if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) {
934 usbi_err(ctx, "short dev-cap descriptor read %u/%d",
Hans de Goeded7b796f2013-05-27 16:31:48 +0200935 dev_cap->bLength, LIBUSB_BT_USB_2_0_EXTENSION_SIZE);
936 return LIBUSB_ERROR_IO;
937 }
938
939 _usb_2_0_extension = malloc(sizeof(*_usb_2_0_extension));
940 if (!_usb_2_0_extension)
941 return LIBUSB_ERROR_NO_MEM;
942
Chris Dickense8736772020-04-17 13:22:34 -0700943 parse_descriptor(dev_cap, "bbbd", _usb_2_0_extension);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200944
945 *usb_2_0_extension = _usb_2_0_extension;
946 return LIBUSB_SUCCESS;
947}
948
Chris Dickens7ee92df2016-02-24 01:07:20 -0800949/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +0200950 * Free a USB 2.0 Extension descriptor obtained from
951 * libusb_get_usb_2_0_extension_descriptor().
952 * It is safe to call this function with a NULL usb_2_0_extension parameter,
953 * in which case the function simply returns.
954 *
955 * \param usb_2_0_extension the USB 2.0 Extension descriptor to free
956 */
957void API_EXPORTED libusb_free_usb_2_0_extension_descriptor(
958 struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension)
959{
960 free(usb_2_0_extension);
961}
962
Chris Dickens7ee92df2016-02-24 01:07:20 -0800963/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +0200964 * Get a SuperSpeed USB Device Capability descriptor
965 *
966 * \param ctx the context to operate on, or NULL for the default context
967 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
968 * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
969 * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
970 * \param ss_usb_device_cap output location for the SuperSpeed USB Device
971 * Capability descriptor. Only valid if 0 was returned. Must be freed with
972 * libusb_free_ss_usb_device_capability_descriptor() after use.
973 * \returns 0 on success
974 * \returns a LIBUSB_ERROR code on error
975 */
976int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor(
Chris Dickensa157b552020-04-27 18:43:42 -0700977 libusb_context *ctx,
Hans de Goeded7b796f2013-05-27 16:31:48 +0200978 struct libusb_bos_dev_capability_descriptor *dev_cap,
979 struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap)
980{
981 struct libusb_ss_usb_device_capability_descriptor *_ss_usb_device_cap;
Hans de Goeded7b796f2013-05-27 16:31:48 +0200982
983 if (dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700984 usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)",
Hans de Goeded7b796f2013-05-27 16:31:48 +0200985 dev_cap->bDevCapabilityType,
986 LIBUSB_BT_SS_USB_DEVICE_CAPABILITY);
987 return LIBUSB_ERROR_INVALID_PARAM;
Chris Dickensfa3f91e2020-08-13 10:31:51 -0700988 } else if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) {
989 usbi_err(ctx, "short dev-cap descriptor read %u/%d",
Hans de Goeded7b796f2013-05-27 16:31:48 +0200990 dev_cap->bLength, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE);
991 return LIBUSB_ERROR_IO;
992 }
993
994 _ss_usb_device_cap = malloc(sizeof(*_ss_usb_device_cap));
995 if (!_ss_usb_device_cap)
996 return LIBUSB_ERROR_NO_MEM;
997
Chris Dickense8736772020-04-17 13:22:34 -0700998 parse_descriptor(dev_cap, "bbbbwbbw", _ss_usb_device_cap);
Hans de Goeded7b796f2013-05-27 16:31:48 +0200999
1000 *ss_usb_device_cap = _ss_usb_device_cap;
1001 return LIBUSB_SUCCESS;
1002}
1003
Chris Dickens7ee92df2016-02-24 01:07:20 -08001004/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +02001005 * Free a SuperSpeed USB Device Capability descriptor obtained from
1006 * libusb_get_ss_usb_device_capability_descriptor().
1007 * It is safe to call this function with a NULL ss_usb_device_cap
1008 * parameter, in which case the function simply returns.
1009 *
Harry Mallon85d1f362019-02-12 13:18:56 +00001010 * \param ss_usb_device_cap the SuperSpeed USB Device Capability descriptor
1011 * to free
Hans de Goeded7b796f2013-05-27 16:31:48 +02001012 */
1013void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor(
1014 struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap)
1015{
1016 free(ss_usb_device_cap);
1017}
1018
Chris Dickens7ee92df2016-02-24 01:07:20 -08001019/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +02001020 * Get a Container ID descriptor
1021 *
1022 * \param ctx the context to operate on, or NULL for the default context
1023 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
1024 * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
1025 * LIBUSB_BT_CONTAINER_ID
1026 * \param container_id output location for the Container ID descriptor.
1027 * Only valid if 0 was returned. Must be freed with
1028 * libusb_free_container_id_descriptor() after use.
1029 * \returns 0 on success
1030 * \returns a LIBUSB_ERROR code on error
1031 */
Chris Dickensa157b552020-04-27 18:43:42 -07001032int API_EXPORTED libusb_get_container_id_descriptor(libusb_context *ctx,
Hans de Goeded7b796f2013-05-27 16:31:48 +02001033 struct libusb_bos_dev_capability_descriptor *dev_cap,
1034 struct libusb_container_id_descriptor **container_id)
1035{
1036 struct libusb_container_id_descriptor *_container_id;
Hans de Goeded7b796f2013-05-27 16:31:48 +02001037
1038 if (dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) {
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001039 usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)",
Hans de Goeded7b796f2013-05-27 16:31:48 +02001040 dev_cap->bDevCapabilityType,
1041 LIBUSB_BT_CONTAINER_ID);
1042 return LIBUSB_ERROR_INVALID_PARAM;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001043 } else if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) {
1044 usbi_err(ctx, "short dev-cap descriptor read %u/%d",
Hans de Goeded7b796f2013-05-27 16:31:48 +02001045 dev_cap->bLength, LIBUSB_BT_CONTAINER_ID_SIZE);
1046 return LIBUSB_ERROR_IO;
1047 }
1048
1049 _container_id = malloc(sizeof(*_container_id));
1050 if (!_container_id)
1051 return LIBUSB_ERROR_NO_MEM;
1052
Chris Dickense8736772020-04-17 13:22:34 -07001053 parse_descriptor(dev_cap, "bbbbu", _container_id);
Hans de Goeded7b796f2013-05-27 16:31:48 +02001054
1055 *container_id = _container_id;
1056 return LIBUSB_SUCCESS;
1057}
1058
Chris Dickens7ee92df2016-02-24 01:07:20 -08001059/** \ingroup libusb_desc
Hans de Goeded7b796f2013-05-27 16:31:48 +02001060 * Free a Container ID descriptor obtained from
1061 * libusb_get_container_id_descriptor().
1062 * It is safe to call this function with a NULL container_id parameter,
1063 * in which case the function simply returns.
1064 *
Harry Mallon85d1f362019-02-12 13:18:56 +00001065 * \param container_id the Container ID descriptor to free
Hans de Goeded7b796f2013-05-27 16:31:48 +02001066 */
1067void API_EXPORTED libusb_free_container_id_descriptor(
1068 struct libusb_container_id_descriptor *container_id)
1069{
1070 free(container_id);
1071}
1072
Chris Dickens7ee92df2016-02-24 01:07:20 -08001073/** \ingroup libusb_desc
Daniel Drake17ecfb02008-05-04 16:20:46 +01001074 * Retrieve a string descriptor in C style ASCII.
1075 *
Pete Batard8aceb5c2010-02-14 19:47:30 -06001076 * Wrapper around libusb_get_string_descriptor(). Uses the first language
Daniel Drake17ecfb02008-05-04 16:20:46 +01001077 * supported by the device.
1078 *
Chris Dickens8a0c1432016-02-24 00:23:49 -08001079 * \param dev_handle a device handle
Daniel Drake17ecfb02008-05-04 16:20:46 +01001080 * \param desc_index the index of the descriptor to retrieve
1081 * \param data output buffer for ASCII string descriptor
1082 * \param length size of data buffer
1083 * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
1084 */
Chris Dickens8a0c1432016-02-24 00:23:49 -08001085int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_handle,
Daniel Drake17ecfb02008-05-04 16:20:46 +01001086 uint8_t desc_index, unsigned char *data, int length)
1087{
Chris Dickensa6bfd452020-08-28 15:42:41 -07001088 union usbi_string_desc_buf str;
Pete Batardd7031ee2010-05-17 19:30:27 -03001089 int r, si, di;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001090 uint16_t langid, wdata;
Daniel Drake17ecfb02008-05-04 16:20:46 +01001091
1092 /* Asking for the zero'th index is special - it returns a string
Konrad Rzepecki0f850152010-11-13 14:09:22 +01001093 * descriptor that contains all the language IDs supported by the
1094 * device. Typically there aren't many - often only one. Language
1095 * IDs are 16 bit numbers, and they start at the third byte in the
1096 * descriptor. There's also no point in trying to read descriptor 0
1097 * with this function. See USB 2.0 specification section 9.6.7 for
1098 * more information.
1099 */
1100
1101 if (desc_index == 0)
1102 return LIBUSB_ERROR_INVALID_PARAM;
1103
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001104 r = libusb_get_string_descriptor(dev_handle, 0, 0, str.buf, 4);
Daniel Drake17ecfb02008-05-04 16:20:46 +01001105 if (r < 0)
1106 return r;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001107 else if (r != 4 || str.desc.bLength < 4)
Daniel Drake17ecfb02008-05-04 16:20:46 +01001108 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001109 else if (str.desc.bDescriptorType != LIBUSB_DT_STRING)
1110 return LIBUSB_ERROR_IO;
1111 else if (str.desc.bLength & 1)
Tormod Volden78eb8652021-11-01 23:40:44 +01001112 usbi_warn(HANDLE_CTX(dev_handle), "suspicious bLength %u for language ID string descriptor", str.desc.bLength);
Daniel Drake17ecfb02008-05-04 16:20:46 +01001113
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001114 langid = libusb_le16_to_cpu(str.desc.wData[0]);
1115 r = libusb_get_string_descriptor(dev_handle, desc_index, langid, str.buf, sizeof(str.buf));
Daniel Drake17ecfb02008-05-04 16:20:46 +01001116 if (r < 0)
1117 return r;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001118 else if (r < DESC_HEADER_LENGTH || str.desc.bLength > r)
Daniel Drake17ecfb02008-05-04 16:20:46 +01001119 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001120 else if (str.desc.bDescriptorType != LIBUSB_DT_STRING)
Daniel Drake17ecfb02008-05-04 16:20:46 +01001121 return LIBUSB_ERROR_IO;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001122 else if ((str.desc.bLength & 1) || str.desc.bLength != r)
Tormod Volden78eb8652021-11-01 23:40:44 +01001123 usbi_warn(HANDLE_CTX(dev_handle), "suspicious bLength %u for string descriptor (read %d)", str.desc.bLength, r);
Daniel Drake17ecfb02008-05-04 16:20:46 +01001124
Sean McBride678a43b2017-12-29 13:30:24 -05001125 di = 0;
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001126 for (si = 2; si < str.desc.bLength; si += 2) {
Daniel Drake17ecfb02008-05-04 16:20:46 +01001127 if (di >= (length - 1))
1128 break;
1129
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001130 wdata = libusb_le16_to_cpu(str.desc.wData[di]);
1131 if (wdata < 0x80)
1132 data[di++] = (unsigned char)wdata;
Daniel Drake17ecfb02008-05-04 16:20:46 +01001133 else
Chris Dickensfa3f91e2020-08-13 10:31:51 -07001134 data[di++] = '?'; /* non-ASCII */
Daniel Drake17ecfb02008-05-04 16:20:46 +01001135 }
1136
1137 data[di] = 0;
1138 return di;
1139}