1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 extern crate libc; 6 7 use std::ffi::{CString, OsString}; 8 use std::io; 9 use std::io::{Read, Write}; 10 use std::os::unix::prelude::*; 11 12 use crate::consts::{CID_BROADCAST, MAX_HID_RPT_SIZE}; 13 use crate::platform::uhid; 14 use crate::u2ftypes::{U2FDevice, U2FDeviceInfo}; 15 use crate::util::from_unix_result; 16 17 #[derive(Debug)] 18 pub struct Device { 19 path: OsString, 20 fd: libc::c_int, 21 cid: [u8; 4], 22 dev_info: Option<U2FDeviceInfo>, 23 } 24 25 impl Device { new(path: OsString) -> io::Result<Self>26 pub fn new(path: OsString) -> io::Result<Self> { 27 let cstr = CString::new(path.as_bytes())?; 28 let fd = unsafe { libc::open(cstr.as_ptr(), libc::O_RDWR) }; 29 let fd = from_unix_result(fd)?; 30 Ok(Self { 31 path, 32 fd, 33 cid: CID_BROADCAST, 34 dev_info: None, 35 }) 36 } 37 is_u2f(&self) -> bool38 pub fn is_u2f(&self) -> bool { 39 uhid::is_u2f_device(self.fd) 40 } 41 } 42 43 impl Drop for Device { drop(&mut self)44 fn drop(&mut self) { 45 // Close the fd, ignore any errors. 46 let _ = unsafe { libc::close(self.fd) }; 47 } 48 } 49 50 impl PartialEq for Device { eq(&self, other: &Device) -> bool51 fn eq(&self, other: &Device) -> bool { 52 self.path == other.path 53 } 54 } 55 56 impl Read for Device { read(&mut self, buf: &mut [u8]) -> io::Result<usize>57 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { 58 let bufp = buf.as_mut_ptr() as *mut libc::c_void; 59 let rv = unsafe { libc::read(self.fd, bufp, buf.len()) }; 60 from_unix_result(rv as usize) 61 } 62 } 63 64 impl Write for Device { write(&mut self, buf: &[u8]) -> io::Result<usize>65 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 66 let report_id = buf[0] as i64; 67 // Skip report number when not using numbered reports. 68 let start = if report_id == 0x0 { 1 } else { 0 }; 69 let data = &buf[start..]; 70 71 let data_ptr = data.as_ptr() as *const libc::c_void; 72 let rv = unsafe { libc::write(self.fd, data_ptr, data.len()) }; 73 from_unix_result(rv as usize + 1) 74 } 75 76 // USB HID writes don't buffer, so this will be a nop. flush(&mut self) -> io::Result<()>77 fn flush(&mut self) -> io::Result<()> { 78 Ok(()) 79 } 80 } 81 82 impl U2FDevice for Device { get_cid<'a>(&'a self) -> &'a [u8; 4]83 fn get_cid<'a>(&'a self) -> &'a [u8; 4] { 84 &self.cid 85 } 86 set_cid(&mut self, cid: [u8; 4])87 fn set_cid(&mut self, cid: [u8; 4]) { 88 self.cid = cid; 89 } 90 in_rpt_size(&self) -> usize91 fn in_rpt_size(&self) -> usize { 92 MAX_HID_RPT_SIZE 93 } 94 out_rpt_size(&self) -> usize95 fn out_rpt_size(&self) -> usize { 96 MAX_HID_RPT_SIZE 97 } 98 get_property(&self, _prop_name: &str) -> io::Result<String>99 fn get_property(&self, _prop_name: &str) -> io::Result<String> { 100 Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) 101 } 102 get_device_info(&self) -> U2FDeviceInfo103 fn get_device_info(&self) -> U2FDeviceInfo { 104 // unwrap is okay, as dev_info must have already been set, else 105 // a programmer error 106 self.dev_info.clone().unwrap() 107 } 108 set_device_info(&mut self, dev_info: U2FDeviceInfo)109 fn set_device_info(&mut self, dev_info: U2FDeviceInfo) { 110 self.dev_info = Some(dev_info); 111 } 112 } 113