diff --git a/src/descriptors.rs b/src/descriptors.rs index 4e9be3a..eb238e3 100644 --- a/src/descriptors.rs +++ b/src/descriptors.rs @@ -181,6 +181,36 @@ macro_rules! descriptor_fields { } } +/// Check whether the buffer contains a valid device descriptor. +/// On success, it will return length of the descriptor, or returns `None`. +pub(crate) fn validate_device_descriptor(buf: &[u8]) -> Option { + if buf.len() < DESCRIPTOR_LEN_DEVICE as usize { + if buf.len() != 0 { + warn!( + "device descriptor buffer is {} bytes, need {}", + buf.len(), + DESCRIPTOR_LEN_DEVICE + ); + } + return None; + } + + if buf[0] < DESCRIPTOR_LEN_DEVICE { + warn!("invalid device descriptor bLength"); + return None; + } + + if buf[1] != DESCRIPTOR_TYPE_DEVICE { + warn!( + "device bDescriptorType is {}, not a device descriptor", + buf[1] + ); + return None; + } + + return Some(buf[0] as usize); +} + /// Information about a USB device. #[derive(Clone)] pub struct DeviceDescriptor<'a>(&'a [u8]); diff --git a/src/device.rs b/src/device.rs index b3d6227..5c706f8 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,7 +1,8 @@ use crate::{ descriptors::{ - decode_string_descriptor, validate_string_descriptor, ActiveConfigurationError, - Configuration, InterfaceAltSetting, DESCRIPTOR_TYPE_STRING, + decode_string_descriptor, validate_device_descriptor, validate_string_descriptor, + ActiveConfigurationError, Configuration, DeviceDescriptor, InterfaceAltSetting, + DESCRIPTOR_TYPE_STRING, }, platform, transfer::{ @@ -341,6 +342,22 @@ impl Device { t.submit::(data); TransferFuture::new(t) } + + /// Get the device descriptor. + /// + /// The only situation when it returns `None` is + /// that the cached descriptors contain no valid device descriptor. + /// + /// ### Platform-specific notes + /// + /// * This is only supported on Linux at present. + /// * On Linux, this method uses descriptors cached in memory, instead + /// of sending a request to the device for a descriptor. + #[cfg(any(target_os = "linux", target_os = "android"))] + pub fn device_descriptor(&self) -> Option { + let buf = self.backend.descriptors(); + validate_device_descriptor(&buf).map(|len| DeviceDescriptor::new(&buf[0..len])) + } } /// An opened interface of a USB device. diff --git a/src/platform/linux_usbfs/device.rs b/src/platform/linux_usbfs/device.rs index 0db566f..a0c9cfd 100644 --- a/src/platform/linux_usbfs/device.rs +++ b/src/platform/linux_usbfs/device.rs @@ -405,6 +405,10 @@ impl LinuxDevice { ); return Err(ErrorKind::Other.into()); } + + pub(crate) fn descriptors(&self) -> &[u8] { + &self.descriptors + } } impl Drop for LinuxDevice {