Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
extern crate libc;
use std::io;
use std::os::unix::io::RawFd;
use std::ptr;
use crate::transport::hidproto::*;
use crate::util::from_unix_result;
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug)]
pub struct GenDescriptor {
ugd_data: *mut u8,
ugd_lang_id: u16,
ugd_maxlen: u16,
ugd_actlen: u16,
ugd_offset: u16,
ugd_config_index: u8,
ugd_string_index: u8,
ugd_iface_index: u8,
ugd_altif_index: u8,
ugd_endpt_index: u8,
ugd_report_index: u8,
reserved: [u8; 16],
}
impl Default for GenDescriptor {
fn default() -> GenDescriptor {
GenDescriptor {
ugd_data: ptr::null_mut(),
ugd_lang_id: 0,
ugd_maxlen: 65535,
ugd_actlen: 0,
ugd_offset: 0,
ugd_config_index: 0,
ugd_string_index: 0,
ugd_iface_index: 0,
ugd_altif_index: 0,
ugd_endpt_index: 0,
ugd_report_index: 0,
reserved: [0; 16],
}
}
}
const IOWR: u32 = 0x40000000 | 0x80000000;
const IOCPARM_SHIFT: u32 = 13;
const IOCPARM_MASK: u32 = (1 << IOCPARM_SHIFT) - 1;
const TYPESHIFT: u32 = 8;
const SIZESHIFT: u32 = 16;
macro_rules! ioctl {
($dir:expr, $name:ident, $ioty:expr, $nr:expr, $size:expr; $ty:ty) => {
pub unsafe fn $name(fd: libc::c_int, val: *mut $ty) -> io::Result<libc::c_int> {
let ioc = ($dir as u32)
| (($size as u32 & IOCPARM_MASK) << SIZESHIFT)
| (($ioty as u32) << TYPESHIFT)
| ($nr as u32);
from_unix_result(libc::ioctl(fd, ioc as libc::c_ulong, val))
}
};
}
ioctl!(IOWR, usb_get_report_desc, b'U', 21, 32; /*struct*/ GenDescriptor);
fn read_report_descriptor(fd: RawFd) -> io::Result<ReportDescriptor> {
let mut desc = GenDescriptor::default();
let _ = unsafe { usb_get_report_desc(fd, &mut desc)? };
desc.ugd_maxlen = desc.ugd_actlen;
let mut value = vec![0; desc.ugd_actlen as usize];
desc.ugd_data = value.as_mut_ptr();
let _ = unsafe { usb_get_report_desc(fd, &mut desc)? };
Ok(ReportDescriptor { value })
}
pub fn is_u2f_device(fd: RawFd) -> bool {
match read_report_descriptor(fd) {
Ok(desc) => has_fido_usage(desc),
Err(_) => false, // Upon failure, just say it's not a U2F device.
}
}