diff options
author | reillyg <reillyg@chromium.org> | 2016-02-12 17:54:22 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-13 01:56:10 +0000 |
commit | b61e467059e55ad71f1b7ae5e1412beb3d4803e0 (patch) | |
tree | 18f93767c81d538f8f61872a45ed4be83e2e1ab7 /device/usb/usb_descriptors.cc | |
parent | 268f1bf33d61c34c9ebcb40947f1d262a31ad0b8 (diff) | |
download | chromium_src-b61e467059e55ad71f1b7ae5e1412beb3d4803e0.zip chromium_src-b61e467059e55ad71f1b7ae5e1412beb3d4803e0.tar.gz chromium_src-b61e467059e55ad71f1b7ae5e1412beb3d4803e0.tar.bz2 |
Parse USB interface association descriptors.
USB interface association descriptors are used to combine multiple
interfaces into a single functional group. This patch adds support for
parsing them out of the |extra_data| field left by libusb's parsing of
configuration, interface and endpoint descriptors. The resulting
association is then represented by setting the |first_interface| field
of each interface in a function to the |interface_number| of the first
interface in the function.
WebUSB will use these associations to set permissions for an entire
function with a single descriptor.
BUG=492204
Review URL: https://codereview.chromium.org/1568673002
Cr-Commit-Position: refs/heads/master@{#375324}
Diffstat (limited to 'device/usb/usb_descriptors.cc')
-rw-r--r-- | device/usb/usb_descriptors.cc | 81 |
1 files changed, 80 insertions, 1 deletions
diff --git a/device/usb/usb_descriptors.cc b/device/usb/usb_descriptors.cc index 6defda8..22414d7 100644 --- a/device/usb/usb_descriptors.cc +++ b/device/usb/usb_descriptors.cc @@ -7,6 +7,7 @@ #include <stddef.h> #include <algorithm> +#include <vector> #include "base/barrier_closure.h" #include "base/bind.h" @@ -26,6 +27,42 @@ const uint8_t kStringDescriptorType = 0x03; const int kControlTransferTimeout = 60000; // 1 minute +struct UsbInterfaceAssociationDescriptor { + UsbInterfaceAssociationDescriptor(uint8_t first_interface, + uint8_t interface_count) + : first_interface(first_interface), interface_count(interface_count) {} + + bool operator<(const UsbInterfaceAssociationDescriptor& other) const { + return first_interface < other.first_interface; + } + + uint8_t first_interface; + uint8_t interface_count; +}; + +void ParseInterfaceAssociationDescriptors( + const std::vector<uint8_t>& buffer, + std::vector<UsbInterfaceAssociationDescriptor>* functions) { + const uint8_t kInterfaceAssociationDescriptorType = 11; + const uint8_t kInterfaceAssociationDescriptorLength = 8; + std::vector<uint8_t>::const_iterator it = buffer.begin(); + + while (it != buffer.end()) { + // All descriptors must be at least 2 byte which means the length and type + // are safe to read. + if (std::distance(it, buffer.end()) < 2) + return; + uint8_t length = it[0]; + if (length > std::distance(it, buffer.end())) + return; + if (it[1] == kInterfaceAssociationDescriptorType && + length == kInterfaceAssociationDescriptorLength) { + functions->push_back(UsbInterfaceAssociationDescriptor(it[2], it[3])); + } + std::advance(it, length); + } +} + void StoreStringDescriptor(IndexMap::iterator it, const base::Closure& callback, const base::string16& string) { @@ -113,7 +150,8 @@ UsbInterfaceDescriptor::UsbInterfaceDescriptor(uint8_t interface_number, alternate_setting(alternate_setting), interface_class(interface_class), interface_subclass(interface_subclass), - interface_protocol(interface_protocol) {} + interface_protocol(interface_protocol), + first_interface(interface_number) {} UsbInterfaceDescriptor::~UsbInterfaceDescriptor() = default; @@ -128,6 +166,47 @@ UsbConfigDescriptor::UsbConfigDescriptor(uint8_t configuration_value, UsbConfigDescriptor::~UsbConfigDescriptor() = default; +void UsbConfigDescriptor::AssignFirstInterfaceNumbers() { + std::vector<UsbInterfaceAssociationDescriptor> functions; + ParseInterfaceAssociationDescriptors(extra_data, &functions); + for (const auto& interface : interfaces) { + ParseInterfaceAssociationDescriptors(interface.extra_data, &functions); + for (const auto& endpoint : interface.endpoints) + ParseInterfaceAssociationDescriptors(endpoint.extra_data, &functions); + } + + // libusb has collected interface association descriptors in the |extra_data| + // fields of other descriptor types. This may have disturbed their order + // but sorting by the bFirstInterface should fix it. + std::sort(functions.begin(), functions.end()); + + uint8_t remaining_interfaces = 0; + auto function_it = functions.cbegin(); + for (auto interface_it = interfaces.begin(); interface_it != interfaces.end(); + ++interface_it) { + if (remaining_interfaces > 0) { + // Continuation of a previous function. Tag all alternate interfaces + // (which are guaranteed to be contiguous). + for (uint8_t interface_number = interface_it->interface_number; + interface_it != interfaces.end() && + interface_it->interface_number == interface_number; + ++interface_it) { + interface_it->first_interface = function_it->first_interface; + } + if (--remaining_interfaces == 0) + ++function_it; + } else if (function_it != functions.end() && + interface_it->interface_number == function_it->first_interface) { + // Start of a new function. + interface_it->first_interface = function_it->first_interface; + remaining_interfaces = function_it->interface_count - 1; + } else { + // Unassociated interfaces already have |first_interface| set to + // |interface_number|. + } + } +} + bool ParseUsbStringDescriptor(const std::vector<uint8_t>& descriptor, base::string16* output) { if (descriptor.size() < 2 || descriptor[1] != kStringDescriptorType) |