forked from google/OpenSK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nfct_test.rs
250 lines (231 loc) · 9.64 KB
/
nfct_test.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#![no_main]
#![no_std]
extern crate alloc;
extern crate lang_items;
extern crate libtock_drivers;
use core::fmt::Write;
use libtock_console::{Console, ConsoleWriter};
use libtock_runtime::{set_main, stack_size, TockSyscalls};
stack_size! {0x4000}
set_main! {main}
type Syscalls = TockSyscalls;
#[cfg(not(feature = "with_nfc"))]
mod example {
use super::{ConsoleWriter, Syscalls, Write};
pub fn nfc(console: &mut ConsoleWriter<Syscalls>) {
writeln!(console, "NFC feature flag is missing!").unwrap();
}
}
#[cfg(feature = "with_nfc")]
mod example {
use super::{Console, ConsoleWriter, Write};
use crate::Syscalls;
use libtock_drivers::nfc::{NfcTag, RecvOp};
use libtock_drivers::result::{FlexUnwrap, TockError};
use libtock_drivers::timer;
use libtock_drivers::timer::{Timer, Timestamp};
use libtock_platform::{DefaultConfig, ErrorCode};
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(clippy::upper_case_acronyms)]
enum ReturnCode {
/// Operation completed successfully
SUCCESS,
/// Generic failure condition
FAIL,
/// Underlying system is busy; retry
EBUSY,
/// The component is powered down
EOFF,
/// An invalid parameter was passed
EINVAL,
/// Operation canceled by a call
ECANCEL,
/// Memory required not available
ENOMEM,
/// Operation or command is unsupported
ENOSUPPORT,
}
impl From<ErrorCode> for ReturnCode {
fn from(original: ErrorCode) -> ReturnCode {
match original {
ErrorCode::Fail => ReturnCode::FAIL,
ErrorCode::Busy => ReturnCode::EBUSY,
ErrorCode::Off => ReturnCode::EOFF,
ErrorCode::Invalid => ReturnCode::EINVAL,
ErrorCode::Cancel => ReturnCode::ECANCEL,
ErrorCode::NoMem => ReturnCode::ENOMEM,
_ => ReturnCode::ENOSUPPORT,
}
}
}
/// Helper function to write on console the received packet.
fn print_rx_buffer(buf: &mut [u8]) {
if let Some((last, bytes)) = buf.split_last() {
let mut console = Console::<Syscalls>::writer();
write!(console, "RX:").unwrap();
for byte in bytes {
write!(console, " {:02x?}", byte).unwrap();
}
writeln!(console, " {:02x?}", last).unwrap();
}
}
/// Function to identify the time elapsed for a transmission request.
fn bench_transmit(
console: &mut ConsoleWriter<Syscalls>,
timer: &Timer<Syscalls>,
title: &str,
buf: &mut [u8],
) -> ReturnCode {
let amount = buf.len();
let start =
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
match NfcTag::<Syscalls, DefaultConfig>::transmit(buf, amount as u32) {
Ok(_) => (),
Err(TockError::Command(ErrorCode::Cancel)) => return ReturnCode::ECANCEL,
Err(_) => writeln!(console, " -- tx error!").unwrap(),
}
let end =
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let elapsed = (end - start).ms();
writeln!(
console,
"{}\n{:.2} ms elapsed for {} bytes ({:.2} kbit/s)",
title,
elapsed,
amount,
(amount as f64) / elapsed * 8.
)
.unwrap();
ReturnCode::SUCCESS
}
fn receive_packet(console: &mut ConsoleWriter<Syscalls>, buf: &mut [u8; 256]) -> ReturnCode {
match NfcTag::<Syscalls, DefaultConfig>::receive(buf) {
Ok(RecvOp {
recv_amount: amount,
..
}) => {
if amount <= buf.len() as u32 {
print_rx_buffer(&mut buf[..amount as usize]);
}
}
Err(TockError::Command(code)) => return code.into(),
Err(_) => {
writeln!(console, " -- RX Err").unwrap();
return ReturnCode::ECANCEL;
}
}
ReturnCode::SUCCESS
}
fn transmit_reply(
console: &mut ConsoleWriter<Syscalls>,
timer: &Timer<Syscalls>,
buf: &[u8],
) -> ReturnCode {
let mut return_code = ReturnCode::SUCCESS;
match buf[0] {
0xe0 /* RATS */=> {
let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
return_code = bench_transmit(console, timer, "TX: ATS", &mut answer_to_select);
}
0xc2 /* DESELECT */ => {
// Ignore the request
let mut command_error = [0x6A, 0x81];
return_code = bench_transmit(console, timer, "TX: DESELECT", &mut command_error);
}
0x02 | 0x03 /* APDU Prefix */ => match buf[2] {
// If the received packet is applet selection command (FIDO 2)
0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
// Vesion: "FIDO_2_0"
let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
return_code = bench_transmit(console, timer, "TX: Version Str", &mut reply);
} else if (buf[6] == 0xd2 && buf[7] == 0x76) || (buf[6] == 0xe1 && (buf[7] == 0x03 || buf[7] == 0x04)){
let mut reply = [buf[0], 0x90, 0x00];
return_code = bench_transmit(console, timer, "TX: 0x9000", &mut reply);
} else /* Unknown file */ {
let mut reply = [buf[0], 0x6a, 0x82];
return_code = bench_transmit(console, timer, "TX: 0x6A82", &mut reply);
}
0xb0 /* READ */ => match buf[5] {
0x02 => {
let mut reply = [buf[0], 0x12, 0x90, 0x00,];
return_code = bench_transmit(console, timer, "TX: File Size", &mut reply);
}
0x12 => {
let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65,
0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,];
return_code = bench_transmit(console, timer, "TX: NDEF", &mut reply);
}
0x0f => {
let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,];
return_code = bench_transmit(console, timer, "TX: CC", &mut reply);
}
_ => {
let mut reply = [buf[0], 0x90, 0x00];
return_code = bench_transmit(console, timer, "TX: 0x9000", &mut reply);
}
}
_ => {
let mut reply = [buf[0], 0x90, 0x00];
return_code = bench_transmit(console, timer, "TX: 0x9000", &mut reply);
}
}
0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {
return ReturnCode::EOFF;
}
_ => (),
}
return_code
}
pub fn nfc(console: &mut ConsoleWriter<Syscalls>) {
// Setup the timer with a dummy callback (we only care about reading the current time, but the
// API forces us to set an alarm callback too).
let mut with_callback = timer::with_callback(|_| {});
let timer = with_callback.init().flex_unwrap();
writeln!(console, "Clock frequency: {:?} Hz", timer.clock_frequency()).unwrap();
let mut state_change_counter = 0;
loop {
let mut rx_buf = [0; 256];
match receive_packet(console, &mut rx_buf) {
ReturnCode::EOFF => {
// Not configured
while !NfcTag::<Syscalls, DefaultConfig>::enable_emulation() {}
// Configure Type 4 tag
while !NfcTag::<Syscalls, DefaultConfig>::configure(4) {}
}
ReturnCode::ECANCEL /* field lost */ => {
NfcTag::<Syscalls, DefaultConfig>::disable_emulation();
}
ReturnCode::EBUSY /* awaiting select*/ => (),
ReturnCode::ENOMEM => {
writeln!(console, " -- Amount more than buffer limit").unwrap()
}
ReturnCode::FAIL => writeln!(console, " -- Invalid CRC").unwrap(),
ReturnCode::EINVAL /* covered in driver interface */ => (),
ReturnCode::ENOSUPPORT => (),
ReturnCode::SUCCESS => {
// If the reader restarts the communication then disable the tag.
match transmit_reply(console, &timer, &rx_buf) {
ReturnCode::ECANCEL | ReturnCode::EOFF => {
if NfcTag::<Syscalls, DefaultConfig>::disable_emulation() {
writeln!(console, " -- TAG DISABLED").unwrap();
}
state_change_counter += 1;
}
_ => (),
}
}
}
if state_change_counter > 100 {
break;
}
}
}
}
fn main() {
let mut console = Console::<Syscalls>::writer();
writeln!(console, "****************************************").unwrap();
writeln!(console, "nfct_test application is installed").unwrap();
example::nfc(&mut console);
writeln!(console, "****************************************").unwrap();
}