/* 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 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 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 { 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)) } }; } // https://github.com/freebsd/freebsd/blob/master/sys/dev/usb/usb_ioctl.h ioctl!(IOWR, usb_get_report_desc, b'U', 21, 32; /*struct*/ GenDescriptor); fn read_report_descriptor(fd: RawFd) -> io::Result { 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. } }