ccid: build control frames off scratch buffer

This commit is contained in:
CinderSocket
2026-06-17 16:36:09 -07:00
parent 8839e1c43a
commit d27641e87a
4 changed files with 100 additions and 68 deletions
+77 -68
View File
@@ -37,6 +37,10 @@ static void seader_ccid_publish_tx_frame(SeaderUartBridge* seader_uart, const ui
}
}
static size_t seader_ccid_build_control_frame_lrc(uint8_t* frame, size_t frame_len) {
return seader_add_lrc(frame, frame_len);
}
static SeaderUartBridge* seader_ccid_active_uart(Seader* seader) {
furi_check(seader);
furi_check(seader->worker);
@@ -52,33 +56,35 @@ void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
slot_state->powered = true;
SEADER_VERBOSE_D(TAG, "Sending Power On (%d)", slot);
memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
seader_uart->tx_buf[0] = SYNC;
seader_uart->tx_buf[1] = CTRL;
seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_ON;
uint8_t frame[2 + 10 + 1] = {0};
frame[0] = SYNC;
frame[1] = CTRL;
frame[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_ON;
seader_uart->tx_buf[2 + 5] = slot;
seader_uart->tx_buf[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
seader_uart->tx_buf[2 + 7] = 1; //power
frame[2 + 5] = slot;
frame[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
frame[2 + 7] = 1; //power
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
seader_ccid_publish_tx_frame(seader_uart, seader_uart->tx_buf, seader_uart->tx_len);
seader_uart->tx_len =
seader_ccid_build_control_frame_lrc(frame, seader_ccid_control_frame_size(0U));
seader_ccid_publish_tx_frame(seader_uart, frame, seader_uart->tx_len);
}
void seader_ccid_IccPowerOff(SeaderUartBridge* seader_uart, uint8_t slot) {
seader_ccid_slot_state(seader_uart, slot)->powered = false;
SEADER_VERBOSE_D(TAG, "Sending Power Off (%d)", slot);
memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
seader_uart->tx_buf[0] = SYNC;
seader_uart->tx_buf[1] = CTRL;
seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_OFF;
uint8_t frame[2 + 10 + 1] = {0};
frame[0] = SYNC;
frame[1] = CTRL;
frame[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_OFF;
seader_uart->tx_buf[2 + 5] = slot;
seader_uart->tx_buf[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
frame[2 + 5] = slot;
frame[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
seader_ccid_publish_tx_frame(seader_uart, seader_uart->tx_buf, seader_uart->tx_len);
seader_uart->tx_len =
seader_ccid_build_control_frame_lrc(frame, seader_ccid_control_frame_size(0U));
seader_ccid_publish_tx_frame(seader_uart, frame, seader_uart->tx_len);
}
void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart) {
@@ -94,15 +100,16 @@ void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart) {
void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot) {
SEADER_VERBOSE_D(TAG, "seader_ccid_GetSlotStatus(%d)", slot);
memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
seader_uart->tx_buf[0] = SYNC;
seader_uart->tx_buf[1] = CTRL;
seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_GET_SLOT_STATUS;
seader_uart->tx_buf[2 + 5] = slot;
seader_uart->tx_buf[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
uint8_t frame[2 + 10 + 1] = {0};
frame[0] = SYNC;
frame[1] = CTRL;
frame[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_GET_SLOT_STATUS;
frame[2 + 5] = slot;
frame[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
seader_ccid_publish_tx_frame(seader_uart, seader_uart->tx_buf, seader_uart->tx_len);
seader_uart->tx_len =
seader_ccid_build_control_frame_lrc(frame, seader_ccid_control_frame_size(0U));
seader_ccid_publish_tx_frame(seader_uart, frame, seader_uart->tx_len);
}
void seader_ccid_SetParameters(Seader* seader, uint8_t slot) {
@@ -115,65 +122,67 @@ void seader_ccid_SetParameters(Seader* seader, uint8_t slot) {
} else if(seader_uart->T == 1) {
payloadLen = 7;
}
memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
seader_uart->tx_buf[0] = SYNC;
seader_uart->tx_buf[1] = CTRL;
seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_SET_PARAMETERS;
seader_uart->tx_buf[2 + 1] = payloadLen;
seader_uart->tx_buf[2 + 5] = slot;
seader_uart->tx_buf[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
seader_uart->tx_buf[2 + 7] = seader_uart->T;
seader_uart->tx_buf[2 + 8] = 0;
seader_uart->tx_buf[2 + 9] = 0;
uint8_t frame[2 + 10 + 7 + 1] = {0};
frame[0] = SYNC;
frame[1] = CTRL;
frame[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_SET_PARAMETERS;
frame[2 + 1] = payloadLen;
frame[2 + 5] = slot;
frame[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
frame[2 + 7] = seader_uart->T;
frame[2 + 8] = 0;
frame[2 + 9] = 0;
uint8_t* atr = seader->ATR;
seader_uart->t1.ifsc = atr[5];
if(seader_uart->T == 0) {
// I'm leaving this here for completeness, but it was actually causing ICC_MUTE on the first apdu.
seader_uart->tx_buf[2 + 10] = 0x11; //atr[2]; //bmFindexDindex
seader_uart->tx_buf[2 + 11] = 0x00; //bmTCCKST1
seader_uart->tx_buf[2 + 12] = 0x00; //bGuardTimeT0
seader_uart->tx_buf[2 + 13] = 0x0a; //bWaitingIntegerT0
seader_uart->tx_buf[2 + 14] = 0x00; //bClockStop
frame[2 + 10] = 0x11; //atr[2]; //bmFindexDindex
frame[2 + 11] = 0x00; //bmTCCKST1
frame[2 + 12] = 0x00; //bGuardTimeT0
frame[2 + 13] = 0x0a; //bWaitingIntegerT0
frame[2 + 14] = 0x00; //bClockStop
} else if(atr[4] == 0xB1 && seader_uart->T == 1) {
seader_uart->tx_buf[2 + 10] = atr[2]; //bmFindexDindex
seader_uart->tx_buf[2 + 11] = 0x10; //bmTCCKST1
seader_uart->tx_buf[2 + 12] = 0xfe; //bGuardTimeT1
seader_uart->tx_buf[2 + 13] = atr[6]; //bWaitingIntegerT1
seader_uart->tx_buf[2 + 14] = atr[8]; //bClockStop
seader_uart->tx_buf[2 + 15] = seader_uart->t1.ifsc; //bIFSC
seader_uart->tx_buf[2 + 16] = 0x00; //bNadValue
frame[2 + 10] = atr[2]; //bmFindexDindex
frame[2 + 11] = 0x10; //bmTCCKST1
frame[2 + 12] = 0xfe; //bGuardTimeT1
frame[2 + 13] = atr[6]; //bWaitingIntegerT1
frame[2 + 14] = atr[8]; //bClockStop
frame[2 + 15] = seader_uart->t1.ifsc; //bIFSC
frame[2 + 16] = 0x00; //bNadValue
} else if(seader_uart->T == 1) {
seader_uart->tx_buf[2 + 10] = 0x11; //atr[2]; //bmFindexDindex
seader_uart->tx_buf[2 + 11] = 0x10; //bmTCCKST1
seader_uart->tx_buf[2 + 12] = 0x00; //bGuardTimeT1
seader_uart->tx_buf[2 + 13] = 0x4d; //atr[6]; //bWaitingIntegerT1
seader_uart->tx_buf[2 + 14] = 0x00; //atr[8]; //bClockStop
seader_uart->tx_buf[2 + 15] = seader_uart->t1.ifsc; //bIFSC
seader_uart->tx_buf[2 + 16] = 0x00; //bNadValue
frame[2 + 10] = 0x11; //atr[2]; //bmFindexDindex
frame[2 + 11] = 0x10; //bmTCCKST1
frame[2 + 12] = 0x00; //bGuardTimeT1
frame[2 + 13] = 0x4d; //atr[6]; //bWaitingIntegerT1
frame[2 + 14] = 0x00; //atr[8]; //bClockStop
frame[2 + 15] = seader_uart->t1.ifsc; //bIFSC
frame[2 + 16] = 0x00; //bNadValue
}
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10 + payloadLen);
seader_ccid_publish_tx_frame(seader_uart, seader_uart->tx_buf, seader_uart->tx_len);
seader_uart->tx_len =
seader_ccid_build_control_frame_lrc(frame, seader_ccid_control_frame_size(payloadLen));
seader_ccid_publish_tx_frame(seader_uart, frame, seader_uart->tx_len);
}
void seader_ccid_GetParameters(SeaderUartBridge* seader_uart) {
memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
seader_uart->tx_buf[0] = SYNC;
seader_uart->tx_buf[1] = CTRL;
seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_GET_PARAMETERS;
seader_uart->tx_buf[2 + 1] = 0;
seader_uart->tx_buf[2 + 5] = seader_ccid_current_slot(seader_uart);
seader_uart->tx_buf[2 + 6] =
uint8_t frame[2 + 10 + 1] = {0};
frame[0] = SYNC;
frame[1] = CTRL;
frame[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_GET_PARAMETERS;
frame[2 + 1] = 0;
frame[2 + 5] = seader_ccid_current_slot(seader_uart);
frame[2 + 6] =
seader_ccid_next_sequence(seader_uart, seader_ccid_current_slot(seader_uart));
seader_uart->tx_buf[2 + 7] = 0;
seader_uart->tx_buf[2 + 8] = 0;
seader_uart->tx_buf[2 + 9] = 0;
frame[2 + 7] = 0;
frame[2 + 8] = 0;
frame[2 + 9] = 0;
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
seader_uart->tx_len =
seader_ccid_build_control_frame_lrc(frame, seader_ccid_control_frame_size(0U));
seader_ccid_publish_tx_frame(seader_uart, seader_uart->tx_buf, seader_uart->tx_len);
seader_ccid_publish_tx_frame(seader_uart, frame, seader_uart->tx_len);
}
void seader_ccid_XfrBlock(SeaderUartBridge* seader_uart, uint8_t* data, size_t len) {
+4
View File
@@ -111,3 +111,7 @@ bool seader_ccid_payload_matches_exact(
return memcmp(payload, expected, expected_len) == 0;
}
size_t seader_ccid_control_frame_size(size_t payload_len) {
return 2U + 10U + payload_len;
}
+1
View File
@@ -54,3 +54,4 @@ bool seader_ccid_payload_matches_exact(
size_t payload_len,
const uint8_t* expected,
size_t expected_len);
size_t seader_ccid_control_frame_size(size_t payload_len);
+18
View File
@@ -198,6 +198,18 @@ static MunitResult test_payload_match_requires_exact_length(
return MUNIT_OK;
}
static MunitResult test_control_frame_size_includes_transport_header(
const MunitParameter params[],
void* fixture) {
(void)params;
(void)fixture;
munit_assert_size(seader_ccid_control_frame_size(0U), ==, 12U);
munit_assert_size(seader_ccid_control_frame_size(5U), ==, 17U);
munit_assert_size(seader_ccid_control_frame_size(7U), ==, 19U);
return MUNIT_OK;
}
static MunitTest test_ccid_cases[] = {
{(char*)"/sequence/advance-wraps-through-ff",
test_sequence_advance_wraps,
@@ -272,6 +284,12 @@ static MunitTest test_ccid_cases[] = {
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/frame/control-size-includes-header",
test_control_frame_size_includes_transport_header,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{NULL, NULL, NULL, NULL, 0, NULL},
};