summary refs log tree commit diff
path: root/usb_util/src/descriptor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'usb_util/src/descriptor.rs')
-rw-r--r--usb_util/src/descriptor.rs499
1 files changed, 499 insertions, 0 deletions
diff --git a/usb_util/src/descriptor.rs b/usb_util/src/descriptor.rs
new file mode 100644
index 0000000..cf711d1
--- /dev/null
+++ b/usb_util/src/descriptor.rs
@@ -0,0 +1,499 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::types::{self, Descriptor, DescriptorHeader, EndpointDescriptor};
+use crate::{Error, Result};
+use data_model::DataInit;
+use std::collections::BTreeMap;
+use std::io::{self, Read};
+use std::mem::size_of;
+use std::ops::Deref;
+use sys_util::warn;
+
+#[derive(Clone)]
+pub struct DeviceDescriptorTree {
+    inner: types::DeviceDescriptor,
+    // Map of bConfigurationValue to ConfigDescriptor
+    config_descriptors: BTreeMap<u8, ConfigDescriptorTree>,
+}
+
+#[derive(Clone)]
+pub struct ConfigDescriptorTree {
+    inner: types::ConfigDescriptor,
+    // Map of (bInterfaceNumber, bAlternateSetting) to InterfaceDescriptor
+    interface_descriptors: BTreeMap<(u8, u8), InterfaceDescriptorTree>,
+}
+
+#[derive(Clone)]
+pub struct InterfaceDescriptorTree {
+    inner: types::InterfaceDescriptor,
+    // Map of bEndpointAddress to EndpointDescriptor
+    endpoint_descriptors: BTreeMap<u8, EndpointDescriptor>,
+}
+
+impl DeviceDescriptorTree {
+    pub fn get_config_descriptor(&self, config_value: u8) -> Option<&ConfigDescriptorTree> {
+        self.config_descriptors.get(&config_value)
+    }
+}
+
+impl Deref for DeviceDescriptorTree {
+    type Target = types::DeviceDescriptor;
+
+    fn deref(&self) -> &types::DeviceDescriptor {
+        &self.inner
+    }
+}
+
+impl ConfigDescriptorTree {
+    /// Get interface by number and alt setting.
+    pub fn get_interface_descriptor(
+        &self,
+        interface_num: u8,
+        alt_setting: u8,
+    ) -> Option<&InterfaceDescriptorTree> {
+        self.interface_descriptors
+            .get(&(interface_num, alt_setting))
+    }
+}
+
+impl Deref for ConfigDescriptorTree {
+    type Target = types::ConfigDescriptor;
+
+    fn deref(&self) -> &types::ConfigDescriptor {
+        &self.inner
+    }
+}
+
+impl InterfaceDescriptorTree {
+    pub fn get_endpoint_descriptor(&self, ep_idx: u8) -> Option<&EndpointDescriptor> {
+        self.endpoint_descriptors.get(&ep_idx)
+    }
+}
+
+impl Deref for InterfaceDescriptorTree {
+    type Target = types::InterfaceDescriptor;
+
+    fn deref(&self) -> &types::InterfaceDescriptor {
+        &self.inner
+    }
+}
+
+/// Given a `reader` for a full set of descriptors as provided by the Linux kernel
+/// usbdevfs `descriptors` file, parse the descriptors into a tree data structure.
+pub fn parse_usbfs_descriptors<R: Read>(mut reader: R) -> Result<DeviceDescriptorTree> {
+    // Given a structure of length `struct_length`, of which `bytes_consumed` have
+    // already been read, skip the remainder of the struct. If `bytes_consumed` is
+    // more than `struct_length`, no additional bytes are skipped.
+    fn skip<R: Read>(reader: R, bytes_consumed: usize, struct_length: u8) -> io::Result<u64> {
+        let bytes_to_skip = u64::from(struct_length).saturating_sub(bytes_consumed as u64);
+        io::copy(&mut reader.take(bytes_to_skip), &mut io::sink())
+    }
+
+    // Find the next descriptor of type T and return it.
+    // Any other descriptors encountered while searching for the expected type are skipped.
+    fn next_descriptor<R: Read, T: Descriptor + DataInit>(mut reader: R) -> Result<T> {
+        let desc_type = T::descriptor_type() as u8;
+        loop {
+            let hdr = DescriptorHeader::from_reader(&mut reader).map_err(Error::DescriptorRead)?;
+            if hdr.bDescriptorType == desc_type {
+                if usize::from(hdr.bLength) < size_of::<DescriptorHeader>() + size_of::<T>() {
+                    return Err(Error::DescriptorParse);
+                }
+
+                let desc = T::from_reader(&mut reader).map_err(Error::DescriptorRead)?;
+
+                // Skip any extra data beyond the standard descriptor length.
+                skip(
+                    &mut reader,
+                    size_of::<DescriptorHeader>() + size_of::<T>(),
+                    hdr.bLength,
+                )
+                .map_err(Error::DescriptorRead)?;
+                return Ok(desc);
+            }
+
+            // Skip this entire descriptor, since it's not the right type.
+            skip(&mut reader, size_of::<DescriptorHeader>(), hdr.bLength)
+                .map_err(Error::DescriptorRead)?;
+        }
+    }
+
+    let raw_device_descriptor: types::DeviceDescriptor = next_descriptor(&mut reader)?;
+    let mut device_descriptor = DeviceDescriptorTree {
+        inner: raw_device_descriptor,
+        config_descriptors: BTreeMap::new(),
+    };
+
+    for cfg_idx in 0..device_descriptor.bNumConfigurations {
+        if let Ok(raw_config_descriptor) =
+            next_descriptor::<_, types::ConfigDescriptor>(&mut reader)
+        {
+            let mut config_descriptor = ConfigDescriptorTree {
+                inner: raw_config_descriptor,
+                interface_descriptors: BTreeMap::new(),
+            };
+
+            for intf_idx in 0..config_descriptor.bNumInterfaces {
+                if let Ok(raw_interface_descriptor) =
+                    next_descriptor::<_, types::InterfaceDescriptor>(&mut reader)
+                {
+                    let mut interface_descriptor = InterfaceDescriptorTree {
+                        inner: raw_interface_descriptor,
+                        endpoint_descriptors: BTreeMap::new(),
+                    };
+
+                    for ep_idx in 0..interface_descriptor.bNumEndpoints {
+                        if let Ok(endpoint_descriptor) =
+                            next_descriptor::<_, EndpointDescriptor>(&mut reader)
+                        {
+                            interface_descriptor
+                                .endpoint_descriptors
+                                .insert(ep_idx, endpoint_descriptor);
+                        } else {
+                            warn!("Could not read endpoint descriptor {}", ep_idx);
+                            break;
+                        }
+                    }
+
+                    config_descriptor.interface_descriptors.insert(
+                        (
+                            interface_descriptor.bInterfaceNumber,
+                            interface_descriptor.bAlternateSetting,
+                        ),
+                        interface_descriptor,
+                    );
+                } else {
+                    warn!("Could not read interface descriptor {}", intf_idx);
+                    break;
+                }
+            }
+
+            device_descriptor
+                .config_descriptors
+                .insert(config_descriptor.bConfigurationValue, config_descriptor);
+        } else {
+            warn!("Could not read config descriptor {}", cfg_idx);
+            break;
+        }
+    }
+
+    Ok(device_descriptor)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn parse_descriptors_mass_storage() {
+        let data: &[u8] = &[
+            0x12, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x81, 0x07, 0x80, 0x55, 0x10, 0x00,
+            0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x2C, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09,
+            0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x04,
+            0x00, 0x06, 0x30, 0x0F, 0x00, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x00, 0x04, 0x00,
+            0x06, 0x30, 0x0F, 0x00, 0x00, 0x00,
+        ];
+
+        let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed");
+
+        // The seemingly-redundant u16::from() calls avoid borrows of packed fields.
+
+        assert_eq!(u16::from(d.bcdUSB), 0x03_00);
+        assert_eq!(d.bDeviceClass, 0x00);
+        assert_eq!(d.bDeviceSubClass, 0x00);
+        assert_eq!(d.bDeviceProtocol, 0x00);
+        assert_eq!(d.bMaxPacketSize0, 9);
+        assert_eq!(u16::from(d.idVendor), 0x0781);
+        assert_eq!(u16::from(d.idProduct), 0x5580);
+        assert_eq!(u16::from(d.bcdDevice), 0x00_10);
+        assert_eq!(d.iManufacturer, 1);
+        assert_eq!(d.iProduct, 2);
+        assert_eq!(d.iSerialNumber, 3);
+        assert_eq!(d.bNumConfigurations, 1);
+
+        let c = d
+            .get_config_descriptor(1)
+            .expect("could not get config descriptor 1");
+        assert_eq!(u16::from(c.wTotalLength), 44);
+        assert_eq!(c.bNumInterfaces, 1);
+        assert_eq!(c.bConfigurationValue, 1);
+        assert_eq!(c.iConfiguration, 0);
+        assert_eq!(c.bmAttributes, 0x80);
+        assert_eq!(c.bMaxPower, 50);
+
+        let i = c
+            .get_interface_descriptor(0, 0)
+            .expect("could not get interface descriptor 0 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 0);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0x08);
+        assert_eq!(i.bInterfaceSubClass, 0x06);
+        assert_eq!(i.bInterfaceProtocol, 0x50);
+        assert_eq!(i.iInterface, 0);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x81);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0400);
+        assert_eq!(e.bInterval, 0);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x02);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0400);
+        assert_eq!(e.bInterval, 0);
+    }
+
+    #[test]
+    fn parse_descriptors_servo() {
+        let data: &[u8] = &[
+            0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xd1, 0x18, 0x1b, 0x50, 0x00, 0x01,
+            0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x7c, 0x00, 0x06, 0x01, 0x04, 0xc0, 0xfa, 0x09,
+            0x04, 0x00, 0x00, 0x02, 0xff, 0x50, 0x01, 0x06, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00,
+            0x0a, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, 0x02, 0xff,
+            0x52, 0x01, 0x05, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x0a, 0x07, 0x05, 0x03, 0x02,
+            0x40, 0x00, 0x00, 0x09, 0x04, 0x03, 0x00, 0x02, 0xff, 0x50, 0x01, 0x07, 0x07, 0x05,
+            0x84, 0x02, 0x10, 0x00, 0x0a, 0x07, 0x05, 0x04, 0x02, 0x10, 0x00, 0x00, 0x09, 0x04,
+            0x04, 0x00, 0x02, 0xff, 0x50, 0x01, 0x08, 0x07, 0x05, 0x85, 0x02, 0x10, 0x00, 0x0a,
+            0x07, 0x05, 0x05, 0x02, 0x10, 0x00, 0x00, 0x09, 0x04, 0x05, 0x00, 0x02, 0xff, 0x53,
+            0xff, 0x09, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x0a, 0x07, 0x05, 0x06, 0x02, 0x40,
+            0x00, 0x00,
+        ];
+
+        // Note: configuration 1 has bNumInterfaces == 6, but it actually only contains 5
+        // interface descriptors. This causes us to try to read beyond EOF, which should be
+        // silently ignored by parse_usbfs_descriptors so that we can use the rest of the
+        // descriptors.
+        let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed");
+
+        // The seemingly-redundant u16::from() calls avoid borrows of packed fields.
+
+        assert_eq!(u16::from(d.bcdUSB), 0x02_00);
+        assert_eq!(d.bDeviceClass, 0x00);
+        assert_eq!(d.bDeviceSubClass, 0x00);
+        assert_eq!(d.bDeviceProtocol, 0x00);
+        assert_eq!(d.bMaxPacketSize0, 64);
+        assert_eq!(u16::from(d.idVendor), 0x18d1);
+        assert_eq!(u16::from(d.idProduct), 0x501b);
+        assert_eq!(u16::from(d.bcdDevice), 0x01_00);
+        assert_eq!(d.iManufacturer, 1);
+        assert_eq!(d.iProduct, 2);
+        assert_eq!(d.iSerialNumber, 3);
+        assert_eq!(d.bNumConfigurations, 1);
+
+        let c = d
+            .get_config_descriptor(1)
+            .expect("could not get config descriptor 1");
+        assert_eq!(u16::from(c.wTotalLength), 124);
+        assert_eq!(c.bNumInterfaces, 6);
+        assert_eq!(c.bConfigurationValue, 1);
+        assert_eq!(c.iConfiguration, 4);
+        assert_eq!(c.bmAttributes, 0xc0);
+        assert_eq!(c.bMaxPower, 250);
+
+        let i = c
+            .get_interface_descriptor(0, 0)
+            .expect("could not get interface descriptor 0 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 0);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x50);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 6);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x81);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x01);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(2, 0)
+            .expect("could not get interface descriptor 2 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 2);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x52);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 5);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x83);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x03);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(3, 0)
+            .expect("could not get interface descriptor 3 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 3);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x50);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 7);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x84);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x04);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(4, 0)
+            .expect("could not get interface descriptor 4 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 4);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x50);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 8);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x85);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x05);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0010);
+        assert_eq!(e.bInterval, 0);
+
+        let i = c
+            .get_interface_descriptor(5, 0)
+            .expect("could not get interface descriptor 5 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 5);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x53);
+        assert_eq!(i.bInterfaceProtocol, 0xff);
+        assert_eq!(i.iInterface, 9);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x86);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 10);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x06);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0040);
+        assert_eq!(e.bInterval, 0);
+    }
+
+    #[test]
+    fn parse_descriptors_adb() {
+        let data: &[u8] = &[
+            0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0xd1, 0x18, 0xe7, 0x4e, 0x10, 0x03,
+            0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0xfa, 0x09,
+            0x04, 0x00, 0x00, 0x02, 0xff, 0x42, 0x01, 0x05, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02,
+            0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00,
+        ];
+
+        let d = parse_usbfs_descriptors(data).expect("parse_usbfs_descriptors failed");
+
+        // The seemingly-redundant u16::from() calls avoid borrows of packed fields.
+
+        assert_eq!(u16::from(d.bcdUSB), 0x02_00);
+        assert_eq!(d.bDeviceClass, 0x00);
+        assert_eq!(d.bDeviceSubClass, 0x00);
+        assert_eq!(d.bDeviceProtocol, 0x00);
+        assert_eq!(d.bMaxPacketSize0, 64);
+        assert_eq!(u16::from(d.idVendor), 0x18d1);
+        assert_eq!(u16::from(d.idProduct), 0x4ee7);
+        assert_eq!(u16::from(d.bcdDevice), 0x03_10);
+        assert_eq!(d.iManufacturer, 1);
+        assert_eq!(d.iProduct, 2);
+        assert_eq!(d.iSerialNumber, 3);
+        assert_eq!(d.bNumConfigurations, 1);
+
+        let c = d
+            .get_config_descriptor(1)
+            .expect("could not get config descriptor 1");
+        assert_eq!(u16::from(c.wTotalLength), 32);
+        assert_eq!(c.bNumInterfaces, 1);
+        assert_eq!(c.bConfigurationValue, 1);
+        assert_eq!(c.iConfiguration, 0);
+        assert_eq!(c.bmAttributes, 0x80);
+        assert_eq!(c.bMaxPower, 250);
+
+        let i = c
+            .get_interface_descriptor(0, 0)
+            .expect("could not get interface descriptor 0 alt setting 0");
+        assert_eq!(i.bInterfaceNumber, 0);
+        assert_eq!(i.bAlternateSetting, 0);
+        assert_eq!(i.bNumEndpoints, 2);
+        assert_eq!(i.bInterfaceClass, 0xff);
+        assert_eq!(i.bInterfaceSubClass, 0x42);
+        assert_eq!(i.bInterfaceProtocol, 0x01);
+        assert_eq!(i.iInterface, 5);
+
+        let e = i
+            .get_endpoint_descriptor(0)
+            .expect("could not get endpoint 0 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x01);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x200);
+        assert_eq!(e.bInterval, 0);
+
+        let e = i
+            .get_endpoint_descriptor(1)
+            .expect("could not get endpoint 1 descriptor");
+        assert_eq!(e.bEndpointAddress, 0x81);
+        assert_eq!(e.bmAttributes, 0x02);
+        assert_eq!(u16::from(e.wMaxPacketSize), 0x0200);
+        assert_eq!(e.bInterval, 0);
+    }
+}