Replaced Libtock driver clock with embedded_time::Clock (#422)

* Replaced Libtock driver clock with embedded_time::Clock

* Add unittest and address some comments

* Add unittest and address some comments
This commit is contained in:
Shiling Wang
2022-03-10 16:18:47 +01:00
committed by GitHub
parent d81af2857e
commit 2050f9f272
15 changed files with 587 additions and 413 deletions

View File

@@ -17,6 +17,7 @@ pub mod send;
use self::receive::MessageAssembler;
use self::send::HidPacketIterator;
use super::super::clock::{ClockInt, CtapInstant};
#[cfg(feature = "with_ctap1")]
use super::ctap1;
use super::status_code::Ctap2StatusCode;
@@ -26,7 +27,7 @@ use crate::env::Env;
use alloc::vec;
use alloc::vec::Vec;
use arrayref::{array_ref, array_refs};
use libtock_drivers::timer::{ClockValue, Duration, Timestamp};
use embedded_time::duration::Milliseconds;
pub type HidPacket = [u8; 64];
pub type ChannelID = [u8; 4];
@@ -166,18 +167,16 @@ impl CtapHid {
const CAPABILITY_CBOR: u8 = 0x04;
#[cfg(not(feature = "with_ctap1"))]
const CAPABILITY_NMSG: u8 = 0x08;
// Capabilitites currently supported by this device.
#[cfg(feature = "with_ctap1")]
const CAPABILITIES: u8 = CtapHid::CAPABILITY_WINK | CtapHid::CAPABILITY_CBOR;
const CAPABILITIES: u8 = Self::CAPABILITY_WINK | Self::CAPABILITY_CBOR;
#[cfg(not(feature = "with_ctap1"))]
const CAPABILITIES: u8 =
CtapHid::CAPABILITY_WINK | CtapHid::CAPABILITY_CBOR | CtapHid::CAPABILITY_NMSG;
const CAPABILITIES: u8 = Self::CAPABILITY_WINK | Self::CAPABILITY_CBOR | Self::CAPABILITY_NMSG;
// TODO: Is this timeout duration specified?
const TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(100);
const WINK_TIMEOUT_DURATION: Duration<isize> = Duration::from_ms(5000);
const TIMEOUT_DURATION: Milliseconds<ClockInt> = Milliseconds(100 as ClockInt);
const WINK_TIMEOUT_DURATION: Milliseconds<ClockInt> = Milliseconds(5000 as ClockInt);
/// Creates a new idle HID state.
pub fn new() -> CtapHid {
CtapHid {
assembler: MessageAssembler::new(),
@@ -209,12 +208,9 @@ impl CtapHid {
&mut self,
env: &mut impl Env,
packet: &HidPacket,
clock_value: ClockValue,
clock_value: CtapInstant,
) -> Option<Message> {
match self
.assembler
.parse_packet(packet, Timestamp::<isize>::from_clock_value(clock_value))
{
match self.assembler.parse_packet(packet, clock_value) {
Ok(Some(message)) => {
debug_ctap!(env, "Received message: {:02x?}", message);
self.preprocess_message(message)
@@ -331,7 +327,7 @@ impl CtapHid {
&mut self,
env: &mut impl Env,
message: Message,
clock_value: ClockValue,
clock_value: CtapInstant,
ctap_state: &mut CtapState,
) -> Message {
// If another command arrives, stop winking to prevent accidential button touches.
@@ -389,7 +385,7 @@ impl CtapHid {
&mut self,
env: &mut impl Env,
packet: &HidPacket,
clock_value: ClockValue,
clock_value: CtapInstant,
ctap_state: &mut CtapState,
) -> HidPacketIterator {
if let Some(message) = self.parse_packet(env, packet, clock_value) {
@@ -482,7 +478,7 @@ impl CtapHid {
}
/// Returns whether a wink permission is currently granted.
pub fn should_wink(&self, now: ClockValue) -> bool {
pub fn should_wink(&self, now: CtapInstant) -> bool {
self.wink_permission.is_granted(now)
}
@@ -514,11 +510,6 @@ mod test {
use super::*;
use crate::env::test::TestEnv;
const CLOCK_FREQUENCY_HZ: usize = 32768;
// Except for tests for timeouts (done in ctap1.rs), transactions are time independant.
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ);
const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
fn process_messages(
env: &mut TestEnv,
ctap_hid: &mut CtapHid,
@@ -527,12 +518,14 @@ mod test {
) -> Option<Vec<Message>> {
let mut result = Vec::new();
let mut assembler_reply = MessageAssembler::new();
// Except for tests for timeouts (done in ctap1.rs), transactions are time independant.
for msg_request in request {
for pkt_request in HidPacketIterator::new(msg_request).unwrap() {
for pkt_reply in
ctap_hid.process_hid_packet(env, &pkt_request, DUMMY_CLOCK_VALUE, ctap_state)
ctap_hid.process_hid_packet(env, &pkt_request, CtapInstant::new(0), ctap_state)
{
match assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP) {
match assembler_reply.parse_packet(&pkt_reply, CtapInstant::new(0)) {
Ok(Some(message)) => result.push(message),
Ok(None) => (),
Err(_) => return None,
@@ -584,7 +577,7 @@ mod test {
let mut messages = Vec::new();
let mut assembler = MessageAssembler::new();
for packet in HidPacketIterator::new(message.clone()).unwrap() {
match assembler.parse_packet(&packet, DUMMY_TIMESTAMP) {
match assembler.parse_packet(&packet, CtapInstant::new(0)) {
Ok(Some(msg)) => messages.push(msg),
Ok(None) => (),
Err(_) => panic!("Couldn't assemble packet: {:02x?}", &packet as &[u8]),
@@ -598,19 +591,19 @@ mod test {
#[test]
fn test_spurious_continuation_packet() {
let mut env = TestEnv::new();
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let mut ctap_hid = CtapHid::new();
let mut packet = [0x00; 64];
packet[0..7].copy_from_slice(&[0xC1, 0xC1, 0xC1, 0xC1, 0x00, 0x51, 0x51]);
let mut assembler_reply = MessageAssembler::new();
for pkt_reply in
ctap_hid.process_hid_packet(&mut env, &packet, DUMMY_CLOCK_VALUE, &mut ctap_state)
ctap_hid.process_hid_packet(&mut env, &packet, CtapInstant::new(0), &mut ctap_state)
{
// Continuation packets are silently ignored.
assert_eq!(
assembler_reply
.parse_packet(&pkt_reply, DUMMY_TIMESTAMP)
.parse_packet(&pkt_reply, CtapInstant::new(0))
.unwrap(),
None
);
@@ -620,7 +613,7 @@ mod test {
#[test]
fn test_command_init() {
let mut env = TestEnv::new();
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let mut ctap_hid = CtapHid::new();
let reply = process_messages(
@@ -665,7 +658,7 @@ mod test {
#[test]
fn test_command_init_for_sync() {
let mut env = TestEnv::new();
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let mut ctap_hid = CtapHid::new();
let cid = cid_from_init(&mut env, &mut ctap_hid, &mut ctap_state);
@@ -685,11 +678,11 @@ mod test {
for pkt_reply in ctap_hid.process_hid_packet(
&mut env,
pkt_request,
DUMMY_CLOCK_VALUE,
CtapInstant::new(0),
&mut ctap_state,
) {
if let Some(message) = assembler_reply
.parse_packet(&pkt_reply, DUMMY_TIMESTAMP)
.parse_packet(&pkt_reply, CtapInstant::new(0))
.unwrap()
{
result.push(message);
@@ -727,7 +720,7 @@ mod test {
#[test]
fn test_command_ping() {
let mut env = TestEnv::new();
let mut ctap_state = CtapState::new(&mut env, DUMMY_CLOCK_VALUE);
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let mut ctap_hid = CtapHid::new();
let cid = cid_from_init(&mut env, &mut ctap_hid, &mut ctap_state);

View File

@@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::clock::CtapInstant;
use super::super::customization::MAX_MSG_SIZE;
use super::{ChannelID, CtapHid, CtapHidCommand, HidPacket, Message, ProcessedPacket};
use alloc::vec::Vec;
use core::mem::swap;
use libtock_drivers::timer::Timestamp;
// A structure to assemble CTAPHID commands from a series of incoming USB HID packets.
pub struct MessageAssembler {
@@ -25,7 +26,7 @@ pub struct MessageAssembler {
// Current channel ID.
cid: ChannelID,
// Timestamp of the last packet received on the current channel.
last_timestamp: Timestamp<isize>,
last_timestamp: CtapInstant,
// Current command.
cmd: u8,
// Sequence number expected for the next packet.
@@ -57,7 +58,7 @@ impl MessageAssembler {
MessageAssembler {
idle: true,
cid: [0, 0, 0, 0],
last_timestamp: Timestamp::from_ms(0),
last_timestamp: CtapInstant::new(0),
cmd: 0,
seq: 0,
remaining_payload_len: 0,
@@ -70,7 +71,7 @@ impl MessageAssembler {
pub fn reset(&mut self) {
self.idle = true;
self.cid = [0, 0, 0, 0];
self.last_timestamp = Timestamp::from_ms(0);
self.last_timestamp = CtapInstant::new(0);
self.cmd = 0;
self.seq = 0;
self.remaining_payload_len = 0;
@@ -87,13 +88,13 @@ impl MessageAssembler {
pub fn parse_packet(
&mut self,
packet: &HidPacket,
timestamp: Timestamp<isize>,
timestamp: CtapInstant,
) -> Result<Option<Message>, (ChannelID, Error)> {
// TODO: Support non-full-speed devices (i.e. packet len != 64)? This isn't recommended by
// section 8.8.1
let (cid, processed_packet) = CtapHid::process_single_packet(packet);
if !self.idle && timestamp - self.last_timestamp >= CtapHid::TIMEOUT_DURATION {
if !self.idle && timestamp >= self.last_timestamp + CtapHid::TIMEOUT_DURATION {
// The current channel timed out.
// Save the channel ID and reset the state.
let current_cid = self.cid;
@@ -160,7 +161,7 @@ impl MessageAssembler {
cmd: u8,
len: usize,
data: &[u8],
timestamp: Timestamp<isize>,
timestamp: CtapInstant,
) -> Result<Option<Message>, (ChannelID, Error)> {
// Reject invalid lengths early to reduce the risk of running out of memory.
// TODO: also reject invalid commands early?
@@ -198,12 +199,10 @@ impl MessageAssembler {
#[cfg(test)]
mod test {
use super::*;
use libtock_drivers::timer::Duration;
use crate::ctap::hid::CtapHid;
use embedded_time::duration::Milliseconds;
// Except for tests that exercise timeouts, all packets are synchronized at the same dummy
// timestamp.
const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
use super::*;
fn byte_extend(bytes: &[u8], padding: u8) -> HidPacket {
let len = bytes.len();
@@ -223,10 +222,12 @@ mod test {
#[test]
fn test_empty_payload() {
let mut assembler = MessageAssembler::new();
// Except for tests that exercise timeouts, all packets are synchronized at the same dummy
// timestamp.
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -242,7 +243,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -261,7 +262,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x90, 0x00, 0x10], 0xFF),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -277,14 +278,14 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -300,21 +301,21 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x80]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -330,7 +331,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x1D, 0xB9]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
@@ -338,7 +339,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
@@ -346,7 +347,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -371,21 +372,21 @@ mod test {
&[0x12, 0x34, 0x56, 0x78, 0x80 | cmd as u8, 0x00, 0x80],
byte
),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x00], byte),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x01], byte),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -409,21 +410,21 @@ mod test {
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, cid, 0x80 | cmd as u8, 0x00, 0x80], byte),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, cid, 0x00], byte),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, cid, 0x01], byte),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, cid],
@@ -440,7 +441,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
@@ -452,7 +453,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, 0x9A, cmd as u8, 0x00], byte),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Err(([0x12, 0x34, 0x56, 0x9A], Error::UnexpectedChannel))
);
@@ -462,7 +463,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -484,7 +485,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x10], byte),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],
@@ -498,7 +499,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Err(([0x12, 0x34, 0x56, 0x78], Error::UnexpectedContinuation))
);
@@ -511,14 +512,14 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x80]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Err(([0x12, 0x34, 0x56, 0x78], Error::UnexpectedInit))
);
@@ -530,14 +531,14 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x01]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Err(([0x12, 0x34, 0x56, 0x78], Error::UnexpectedSeq))
);
@@ -549,14 +550,14 @@ mod test {
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x00, 0x40]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
assert_eq!(
assembler.parse_packet(
&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x00]),
DUMMY_TIMESTAMP + CtapHid::TIMEOUT_DURATION
CtapInstant::new(0) + CtapHid::TIMEOUT_DURATION
),
Err(([0x12, 0x34, 0x56, 0x78], Error::Timeout))
);
@@ -564,9 +565,9 @@ mod test {
#[test]
fn test_just_in_time_packets() {
let mut timestamp = DUMMY_TIMESTAMP;
let mut timestamp: CtapInstant = CtapInstant::new(0);
// Delay between each packet is just below the threshold.
let delay = CtapHid::TIMEOUT_DURATION - Duration::from_ms(1);
let delay = CtapHid::TIMEOUT_DURATION - Milliseconds(1_u32);
let mut assembler = MessageAssembler::new();
assert_eq!(
@@ -577,13 +578,13 @@ mod test {
Ok(None)
);
for seq in 0..0x7F {
timestamp += delay;
timestamp = timestamp + delay;
assert_eq!(
assembler.parse_packet(&zero_extend(&[0x12, 0x34, 0x56, 0x78, seq]), timestamp),
Ok(None)
);
}
timestamp += delay;
timestamp = timestamp + delay;
assert_eq!(
assembler.parse_packet(&zero_extend(&[0x12, 0x34, 0x56, 0x78, 0x7F]), timestamp),
Ok(Some(Message {
@@ -601,7 +602,7 @@ mod test {
assert_eq!(
assembler.parse_packet(
&byte_extend(&[0x12, 0x34, 0x56, 0x78, 0x81, 0x02, 0x00], 0x51),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(None)
);
@@ -612,7 +613,7 @@ mod test {
0x12, 0x34, 0x56, 0x78, 0x86, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
0xDE, 0xF0
]),
DUMMY_TIMESTAMP
CtapInstant::new(0)
),
Ok(Some(Message {
cid: [0x12, 0x34, 0x56, 0x78],