use crate::io_legacy::{ApduHeader, Reply, StatusWords};
use super::bolos::handle_bolos_apdu;
use super::{Comm, DecodedEventType};
static mut CURRENT_COMM: *mut core::ffi::c_void = core::ptr::null_mut();
static mut PANIC_REPLY_FN: Option<fn(Reply)> = None;
pub(super) fn set_comm<const N: usize>(comm: &mut Comm<N>) {
unsafe {
CURRENT_COMM = (comm as *mut Comm<N>) as *mut core::ffi::c_void;
}
}
pub(super) fn clear_comm() {
unsafe {
CURRENT_COMM = core::ptr::null_mut();
}
}
#[allow(dead_code)]
pub(super) fn is_comm_null() -> bool {
unsafe { CURRENT_COMM.is_null() }
}
unsafe fn get_comm<const N: usize>() -> &'static mut Comm<N> {
unsafe { &mut *(CURRENT_COMM as *mut Comm<N>) }
}
pub fn register_panic_handler<const N: usize>() {
unsafe {
PANIC_REPLY_FN = Some(panic_reply_impl::<N>);
}
}
pub(super) fn clear_panic_handler() {
unsafe {
PANIC_REPLY_FN = None;
}
}
pub fn send_panic_reply(reply: Reply) {
unsafe {
if let Some(f) = PANIC_REPLY_FN {
f(reply);
}
}
}
fn panic_reply_impl<const N: usize>(reply: Reply) {
let comm = unsafe { get_comm::<N>() };
let _ = comm.begin_response().send(reply);
}
pub(super) fn next_event_ahead_impl<const N: usize>() -> bool {
let comm = unsafe { get_comm::<N>() };
let in_flight_apdu_type = comm.apdu_type;
if comm.pending_apdu {
comm.pending_apdu = false;
comm.reject_apdu(in_flight_apdu_type, StatusWords::CmdNotAccepted);
return false;
}
match comm.next_event().into_type() {
DecodedEventType::Apdu {
header,
offset,
length,
} => {
if header.cla == 0xB0 {
let in_progress = comm.apdu_in_progress;
handle_bolos_apdu::<N>(comm, header.ins, header.p1, header.p2);
comm.apdu_in_progress = in_progress;
comm.apdu_type = in_flight_apdu_type;
return false;
}
if comm.apdu_in_progress {
let intruder_apdu_type = comm.apdu_type;
comm.reject_apdu(intruder_apdu_type, StatusWords::CmdNotAccepted);
comm.apdu_type = in_flight_apdu_type;
return false;
}
comm.pending_apdu = true;
comm.pending_header = header;
comm.pending_offset = offset;
comm.pending_length = length;
true
}
DecodedEventType::ApduError(e) => {
let intruder_apdu_type = comm.apdu_type;
comm.reject_apdu(intruder_apdu_type, StatusWords::from(e));
comm.apdu_type = in_flight_apdu_type;
false
}
_ => false,
}
}
pub(super) fn fetch_apdu_header_impl<const N: usize>() -> Option<ApduHeader> {
let comm = unsafe { get_comm::<N>() };
if comm.pending_apdu {
Some(comm.pending_header)
} else {
None
}
}
pub(super) fn reply_status_impl<const N: usize>(reply: Reply) {
let comm = unsafe { get_comm::<N>() };
if comm.pending_apdu {
comm.pending_apdu = false;
}
let _ = comm.begin_response().send(reply);
}