use std::time::Duration;
use libusb::{request_type, Direction, RequestType, Recipient};
use super::*;
use std;
use util::*;
bitflags! {
pub flags Flags: u8 {
const SLOT_WRITE_FLAG = 0x80,
const RESP_PENDING_FLAG = 0x40
}
}
const SLOT_DATA_SIZE: usize = 64;
const HID_GET_REPORT: u8 = 0x01;
const HID_SET_REPORT: u8 = 0x09;
const REPORT_TYPE_FEATURE: u16 = 0x03;
impl<'a> YubiKeyHandle<'a> {
pub fn wait<F: Fn(Flags) -> bool>(&mut self, f: F, buf: &mut [u8]) -> Result<(), Error> {
loop {
try!(self.read(buf));
println!("wait {:?}", buf);
let flags = Flags::from_bits_truncate(buf[7]);
if flags.contains(SLOT_WRITE_FLAG) || flags.is_empty() {
self.version = Some((Version {
major: buf[1],
minor: buf[2],
build: buf[3],
},
buf[4]))
}
if f(flags) {
return Ok(());
}
std::thread::sleep(Duration::new(0, 1000000));
}
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
assert_eq!(buf.len(), 8);
let reqtype = request_type(Direction::In, RequestType::Class, Recipient::Interface);
let value = REPORT_TYPE_FEATURE << 8;
Ok(try!(self.h.read_control(reqtype, HID_GET_REPORT, value, 0, buf, Duration::new(2, 0))))
}
pub fn write_frame(&mut self, frame: &Frame) -> Result<(), Error> {
let mut data =
unsafe { std::slice::from_raw_parts(frame as *const Frame as *const u8, 70) };
let mut seq = 0;
let mut buf = [0; 8];
while !data.is_empty() {
let (a, b) = data.split_at(7);
if seq == 0 || b.is_empty() || a.iter().any(|&x| x != 0) {
let mut packet = [0; 8];
(&mut packet[ .. 7 ]).copy_from_slice(a);
packet[7] = SLOT_WRITE_FLAG.bits() + seq;
try!(self.wait(|x| !x.contains(SLOT_WRITE_FLAG), &mut buf));
println!("{:?}", packet);
try!(self.raw_write(&packet))
}
data = b;
seq += 1
}
Ok(())
}
pub fn raw_write(&mut self, packet: &[u8]) -> Result<(), Error> {
let reqtype = request_type(Direction::Out, RequestType::Class, Recipient::Interface);
let value = REPORT_TYPE_FEATURE << 8;
if try!(self.h.write_control(reqtype,
HID_SET_REPORT,
value,
0,
&packet,
Duration::new(2, 0))) != 8 {
Err(Error::CouldNotWrite)
} else {
Ok(())
}
}
pub fn write_reset(&mut self) -> Result<(), Error> {
try!(self.raw_write(&[0, 0, 0, 0, 0, 0, 0, 0x8f]));
let mut buf = [0; 8];
try!(self.wait(|x| !x.contains(SLOT_WRITE_FLAG), &mut buf));
Ok(())
}
pub fn read_response(&mut self, response:&mut [u8]) -> Result<usize, Error> {
let mut r0 = 0;
println!("Waiting for response");
try!(self.wait(|f| {
if !f.is_empty() { println!("flag: {:?}", f); }
f.contains(RESP_PENDING_FLAG)
}, &mut response[.. 8]));
println!("done");
r0 += 7;
loop {
if try!(self.read(&mut response[r0..r0 + 8])) < 8 {
break;
}
let flags = Flags::from_bits_truncate(response[r0 + 7]);
if flags.contains(RESP_PENDING_FLAG) {
let seq = response[r0 + 7] & 0b00011111;
if r0 > 0 && seq == 0 {
break;
}
} else {
break;
}
r0 += 7;
}
try!(self.write_reset());
Ok(r0)
}
}
#[repr(C)]
#[repr(packed)]
pub struct Frame {
pub payload: [u8; SLOT_DATA_SIZE],
command: Command,
crc: u16,
filler: [u8; 3],
}
pub trait CommandT {
fn cmd(&self) -> u8;
}
impl Frame {
pub fn new(command: Command, payload: [u8; 64]) -> Self {
let mut f = Frame {
payload: payload,
command: command,
crc: 0,
filler: [0; 3],
};
f.crc = crc16(&f.payload).to_le();
f
}
}