mirror of
https://github.com/bettse/seader.git
synced 2026-10-23 00:03:29 +00:00
refactor(ccid,t1): introduce typed protocol state and named constants
This commit is contained in:
1 parent
9a00e1e515
commit
27a61555b1
7 files changed
+272
-197
No files matched your search
@@ -1,40 +1,52 @@
|
||||
#include "seader_i.h"
|
||||
|
||||
#define TAG "SeaderCCID"
|
||||
|
||||
bool hasSAM = false;
|
||||
const uint8_t SAM_ATR[] =
|
||||
{0x3b, 0x95, 0x96, 0x80, 0xb1, 0xfe, 0x55, 0x1f, 0xc7, 0x47, 0x72, 0x61, 0x63, 0x65, 0x13};
|
||||
const uint8_t SAM_ATR2[] = {0x3b, 0x90, 0x96, 0x91, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0xc7, 0xd4};
|
||||
//3b95968011fc47726163653c
|
||||
const uint8_t SAM_ATR3[] = {0x3b, 0x95, 0x96, 0x80, 0x11, 0xfc, 0x47, 0x72, 0x61, 0x63, 0x65, 0x3c};
|
||||
|
||||
bool powered[2] = {false, false};
|
||||
uint8_t sam_slot = 0;
|
||||
uint8_t sequence[2] = {0, 0};
|
||||
uint8_t retries = 3;
|
||||
static SeaderCcidState* seader_ccid_state(SeaderUartBridge* seader_uart) {
|
||||
return &seader_uart->ccid;
|
||||
}
|
||||
|
||||
uint8_t getSequence(uint8_t slot) {
|
||||
if(sequence[slot] > 254) {
|
||||
sequence[slot] = 0;
|
||||
static SeaderCcidSlotState* seader_ccid_slot_state(SeaderUartBridge* seader_uart, uint8_t slot) {
|
||||
furi_check(slot < SEADER_CCID_SLOT_COUNT);
|
||||
return &seader_ccid_state(seader_uart)->slots[slot];
|
||||
}
|
||||
|
||||
static uint8_t seader_ccid_current_slot(SeaderUartBridge* seader_uart) {
|
||||
return seader_ccid_state(seader_uart)->sam_slot;
|
||||
}
|
||||
|
||||
static void seader_ccid_reset_slot_sequence(SeaderUartBridge* seader_uart, uint8_t slot) {
|
||||
seader_ccid_slot_state(seader_uart, slot)->sequence = 0;
|
||||
}
|
||||
|
||||
static uint8_t seader_ccid_next_sequence(SeaderUartBridge* seader_uart, uint8_t slot) {
|
||||
SeaderCcidSlotState* slot_state = seader_ccid_slot_state(seader_uart, slot);
|
||||
if(slot_state->sequence > 254) {
|
||||
slot_state->sequence = 0;
|
||||
}
|
||||
return sequence[slot]++;
|
||||
return slot_state->sequence++;
|
||||
}
|
||||
|
||||
void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
|
||||
if(powered[slot]) {
|
||||
SeaderCcidSlotState* slot_state = seader_ccid_slot_state(seader_uart, slot);
|
||||
if(slot_state->powered) {
|
||||
return;
|
||||
}
|
||||
powered[slot] = true;
|
||||
slot_state->powered = true;
|
||||
|
||||
FURI_LOG_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_IccPowerOn;
|
||||
seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_ON;
|
||||
|
||||
seader_uart->tx_buf[2 + 5] = slot;
|
||||
seader_uart->tx_buf[2 + 6] = getSequence(slot);
|
||||
seader_uart->tx_buf[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
|
||||
seader_uart->tx_buf[2 + 7] = 1; //power
|
||||
|
||||
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
|
||||
@@ -42,26 +54,29 @@ void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
|
||||
}
|
||||
|
||||
void seader_ccid_IccPowerOff(SeaderUartBridge* seader_uart, uint8_t slot) {
|
||||
powered[slot] = false;
|
||||
seader_ccid_slot_state(seader_uart, slot)->powered = false;
|
||||
|
||||
FURI_LOG_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_IccPowerOff;
|
||||
seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_OFF;
|
||||
|
||||
seader_uart->tx_buf[2 + 5] = slot;
|
||||
seader_uart->tx_buf[2 + 6] = getSequence(slot);
|
||||
seader_uart->tx_buf[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
|
||||
|
||||
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
|
||||
furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
|
||||
}
|
||||
|
||||
void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart) {
|
||||
hasSAM = false; // If someone is calling this, reset sam state
|
||||
powered[0] = false;
|
||||
powered[1] = false;
|
||||
retries = 3;
|
||||
SeaderCcidState* ccid_state = seader_ccid_state(seader_uart);
|
||||
ccid_state->has_sam = false; // If someone is calling this, reset sam state
|
||||
ccid_state->sam_slot = 0;
|
||||
ccid_state->retries = 3;
|
||||
for(size_t slot = 0; slot < SEADER_CCID_SLOT_COUNT; slot++) {
|
||||
ccid_state->slots[slot].powered = false;
|
||||
}
|
||||
seader_ccid_GetSlotStatus(seader_uart, 0);
|
||||
}
|
||||
|
||||
@@ -70,9 +85,9 @@ void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t 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_GetSlotStatus;
|
||||
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] = getSequence(slot);
|
||||
seader_uart->tx_buf[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
|
||||
|
||||
seader_uart->tx_len = seader_add_lrc(seader_uart->tx_buf, 2 + 10);
|
||||
furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
|
||||
@@ -92,16 +107,16 @@ void seader_ccid_SetParameters(Seader* seader, uint8_t 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_SetParameters;
|
||||
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] = getSequence(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* atr = seader->ATR;
|
||||
seader_uart->IFSC = atr[5];
|
||||
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.
|
||||
@@ -116,7 +131,7 @@ void seader_ccid_SetParameters(Seader* seader, uint8_t slot) {
|
||||
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->IFSC; //bIFSC
|
||||
seader_uart->tx_buf[2 + 15] = seader_uart->t1.ifsc; //bIFSC
|
||||
seader_uart->tx_buf[2 + 16] = 0x00; //bNadValue
|
||||
} else if(seader_uart->T == 1) {
|
||||
seader_uart->tx_buf[2 + 10] = 0x11; //atr[2]; //bmFindexDindex
|
||||
@@ -124,7 +139,7 @@ void seader_ccid_SetParameters(Seader* seader, uint8_t slot) {
|
||||
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->IFSC; //bIFSC
|
||||
seader_uart->tx_buf[2 + 15] = seader_uart->t1.ifsc; //bIFSC
|
||||
seader_uart->tx_buf[2 + 16] = 0x00; //bNadValue
|
||||
}
|
||||
|
||||
@@ -136,10 +151,11 @@ 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_GetParameters;
|
||||
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] = sam_slot;
|
||||
seader_uart->tx_buf[2 + 6] = getSequence(sam_slot);
|
||||
seader_uart->tx_buf[2 + 5] = seader_ccid_current_slot(seader_uart);
|
||||
seader_uart->tx_buf[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;
|
||||
@@ -150,7 +166,7 @@ void seader_ccid_GetParameters(SeaderUartBridge* seader_uart) {
|
||||
}
|
||||
|
||||
void seader_ccid_XfrBlock(SeaderUartBridge* seader_uart, uint8_t* data, size_t len) {
|
||||
seader_ccid_XfrBlockToSlot(seader_uart, sam_slot, data, len);
|
||||
seader_ccid_XfrBlockToSlot(seader_uart, seader_ccid_current_slot(seader_uart), data, len);
|
||||
}
|
||||
|
||||
void seader_ccid_XfrBlockToSlot(
|
||||
@@ -191,13 +207,13 @@ void seader_ccid_XfrBlockToSlot(
|
||||
|
||||
frame[0] = SYNC;
|
||||
frame[1] = CTRL;
|
||||
frame[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock;
|
||||
frame[2 + 0] = CCID_MESSAGE_TYPE_PC_TO_RDR_XFR_BLOCK;
|
||||
frame[2 + 1] = (len >> 0) & 0xff;
|
||||
frame[2 + 2] = (len >> 8) & 0xff;
|
||||
frame[2 + 3] = (len >> 16) & 0xff;
|
||||
frame[2 + 4] = (len >> 24) & 0xff;
|
||||
frame[2 + 5] = slot;
|
||||
frame[2 + 6] = getSequence(slot);
|
||||
frame[2 + 6] = seader_ccid_next_sequence(seader_uart, slot);
|
||||
frame[2 + 7] = 5;
|
||||
frame[2 + 8] = 0;
|
||||
frame[2 + 9] = 0;
|
||||
@@ -221,6 +237,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
SeaderUartBridge* seader_uart = seader_worker->uart;
|
||||
CCID_Message message;
|
||||
message.consumed = 0;
|
||||
SeaderCcidState* ccid_state = seader_ccid_state(seader_uart);
|
||||
|
||||
char* display = malloc(cmd_len * 2 + 1);
|
||||
for(uint8_t i = 0; i < cmd_len; i++) {
|
||||
@@ -230,26 +247,26 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
free(display);
|
||||
|
||||
if(cmd_len == 2) {
|
||||
if(cmd[0] == CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange) {
|
||||
switch(cmd[1] & SLOT_0_MASK) {
|
||||
if(cmd[0] == CCID_MESSAGE_TYPE_RDR_TO_PC_NOTIFY_SLOT_CHANGE) {
|
||||
switch(cmd[1] & CCID_SLOT_0_MASK) {
|
||||
case 0:
|
||||
case 1:
|
||||
// No change, no-op
|
||||
break;
|
||||
case CARD_IN_1:
|
||||
case CCID_SLOT_0_CARD_IN:
|
||||
FURI_LOG_D(TAG, "Card Inserted (0)");
|
||||
if(hasSAM && sam_slot == 0) {
|
||||
if(ccid_state->has_sam && ccid_state->sam_slot == 0) {
|
||||
break;
|
||||
}
|
||||
sequence[0] = 0;
|
||||
seader_ccid_reset_slot_sequence(seader_uart, 0);
|
||||
seader_ccid_IccPowerOn(seader_uart, 0);
|
||||
break;
|
||||
case CARD_OUT_1:
|
||||
case CCID_SLOT_0_CARD_OUT:
|
||||
FURI_LOG_D(TAG, "Card Removed (0)");
|
||||
if(hasSAM && sam_slot == 0) {
|
||||
powered[0] = false;
|
||||
hasSAM = false;
|
||||
retries = 3;
|
||||
if(ccid_state->has_sam && ccid_state->sam_slot == 0) {
|
||||
ccid_state->slots[0].powered = false;
|
||||
ccid_state->has_sam = false;
|
||||
ccid_state->retries = 3;
|
||||
if(seader_worker->callback) {
|
||||
seader_worker->callback(
|
||||
SeaderWorkerEventSamMissing, seader_worker->context);
|
||||
@@ -258,25 +275,25 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
break;
|
||||
};
|
||||
|
||||
switch(cmd[1] & SLOT_1_MASK) {
|
||||
switch(cmd[1] & CCID_SLOT_1_MASK) {
|
||||
case 0:
|
||||
case 1:
|
||||
// No change, no-op
|
||||
break;
|
||||
case CARD_IN_2:
|
||||
case CCID_SLOT_1_CARD_IN:
|
||||
FURI_LOG_D(TAG, "Card Inserted (1)");
|
||||
if(hasSAM && sam_slot == 1) {
|
||||
if(ccid_state->has_sam && ccid_state->sam_slot == 1) {
|
||||
break;
|
||||
}
|
||||
sequence[1] = 0;
|
||||
seader_ccid_reset_slot_sequence(seader_uart, 1);
|
||||
seader_ccid_IccPowerOn(seader_uart, 1);
|
||||
break;
|
||||
case CARD_OUT_2:
|
||||
case CCID_SLOT_1_CARD_OUT:
|
||||
FURI_LOG_D(TAG, "Card Removed (1)");
|
||||
if(hasSAM && sam_slot == 1) {
|
||||
powered[1] = false;
|
||||
hasSAM = false;
|
||||
retries = 3;
|
||||
if(ccid_state->has_sam && ccid_state->sam_slot == 1) {
|
||||
ccid_state->slots[1].powered = false;
|
||||
ccid_state->has_sam = false;
|
||||
ccid_state->retries = 3;
|
||||
if(seader_worker->callback) {
|
||||
seader_worker->callback(
|
||||
SeaderWorkerEventSamMissing, seader_worker->context);
|
||||
@@ -332,16 +349,16 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
|
||||
//0306 81 00000000 0000 0200 01 87
|
||||
//0306 81 00000000 0000 0100 01 84
|
||||
if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus) {
|
||||
if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_TO_PC_SLOT_STATUS) {
|
||||
uint8_t status = (message.bStatus & BMICCSTATUS_MASK);
|
||||
if(status == 0 || status == 1) {
|
||||
seader_ccid_IccPowerOn(seader_uart, message.bSlot);
|
||||
return message.consumed;
|
||||
} else if(status == 2) {
|
||||
FURI_LOG_W(TAG, "No ICC is present [retries %d]", retries);
|
||||
if(retries-- > 1 && hasSAM == false) {
|
||||
} else if(status == CCID_ICC_STATUS_NOT_PRESENT) {
|
||||
FURI_LOG_W(TAG, "No ICC is present [retries %d]", ccid_state->retries);
|
||||
if(ccid_state->retries-- > 1 && ccid_state->has_sam == false) {
|
||||
furi_delay_ms(100);
|
||||
seader_ccid_GetSlotStatus(seader_uart, retries % 2);
|
||||
seader_ccid_GetSlotStatus(seader_uart, ccid_state->retries % 2);
|
||||
} else {
|
||||
if(seader_worker->callback) {
|
||||
seader_worker->callback(
|
||||
@@ -355,7 +372,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
//0306 80 00000000 0001 42fe 00 38
|
||||
if(message.bStatus == 0x41 && message.bError == 0xfe) {
|
||||
FURI_LOG_W(TAG, "card probably upside down");
|
||||
hasSAM = false;
|
||||
ccid_state->has_sam = false;
|
||||
if(seader_worker->callback) {
|
||||
seader_worker->callback(SeaderWorkerEventSamMissing, seader_worker->context);
|
||||
}
|
||||
@@ -370,10 +387,10 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
}
|
||||
if(message.bError != 0) {
|
||||
switch(message.bError) {
|
||||
case 0xfe: // CCID_ERROR_ICC_MUTE:
|
||||
case CCID_ERROR_ICC_MUTE:
|
||||
FURI_LOG_W(TAG, "CCID error ICC_MUTE");
|
||||
break;
|
||||
case 0xfb: // HW_ERROR
|
||||
case CCID_ERROR_HW_ERROR:
|
||||
FURI_LOG_W(TAG, "CCID error HW_ERROR");
|
||||
break;
|
||||
default:
|
||||
@@ -387,7 +404,7 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
return message.consumed;
|
||||
}
|
||||
|
||||
if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_Parameters) {
|
||||
if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_TO_PC_PARAMETERS) {
|
||||
FURI_LOG_D(TAG, "Got Parameters");
|
||||
if(seader_uart->T == 1) {
|
||||
seader_t_1_set_IFSD(seader);
|
||||
@@ -397,9 +414,9 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
seader_worker->callback(SeaderWorkerEventSamPresent, seader_worker->context);
|
||||
}
|
||||
}
|
||||
} else if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock) {
|
||||
if(hasSAM) {
|
||||
if(message.bSlot == sam_slot) {
|
||||
} else if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_TO_PC_DATA_BLOCK) {
|
||||
if(ccid_state->has_sam) {
|
||||
if(message.bSlot == ccid_state->sam_slot) {
|
||||
if(seader_uart->T == 0) {
|
||||
seader_worker_process_sam_message(
|
||||
seader, message.payload, message.dwLength);
|
||||
@@ -412,33 +429,33 @@ size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
|
||||
} else {
|
||||
if(memcmp(SAM_ATR, message.payload, sizeof(SAM_ATR)) == 0) {
|
||||
FURI_LOG_I(TAG, "SAM ATR!");
|
||||
hasSAM = true;
|
||||
sam_slot = message.bSlot;
|
||||
ccid_state->has_sam = true;
|
||||
ccid_state->sam_slot = message.bSlot;
|
||||
seader->ATR_len = sizeof(SAM_ATR);
|
||||
memcpy(seader->ATR, message.payload, seader->ATR_len);
|
||||
if(seader_uart->T == 0) {
|
||||
seader_ccid_GetParameters(seader_uart);
|
||||
} else if(seader_uart->T == 1) {
|
||||
seader_ccid_SetParameters(seader, sam_slot);
|
||||
seader_ccid_SetParameters(seader, ccid_state->sam_slot);
|
||||
}
|
||||
} else if(memcmp(SAM_ATR2, message.payload, sizeof(SAM_ATR2)) == 0) {
|
||||
FURI_LOG_I(TAG, "SAM ATR2!");
|
||||
hasSAM = true;
|
||||
sam_slot = message.bSlot;
|
||||
ccid_state->has_sam = true;
|
||||
ccid_state->sam_slot = message.bSlot;
|
||||
seader->ATR_len = sizeof(SAM_ATR);
|
||||
memcpy(seader->ATR, message.payload, seader->ATR_len);
|
||||
// I don't have an ATR2 to test with
|
||||
seader_ccid_GetParameters(seader_uart);
|
||||
} else if(memcmp(SAM_ATR3, message.payload, sizeof(SAM_ATR3)) == 0) {
|
||||
FURI_LOG_I(TAG, "SAM ATR3!");
|
||||
hasSAM = true;
|
||||
sam_slot = message.bSlot;
|
||||
ccid_state->has_sam = true;
|
||||
ccid_state->sam_slot = message.bSlot;
|
||||
seader->ATR_len = sizeof(SAM_ATR);
|
||||
memcpy(seader->ATR, message.payload, seader->ATR_len);
|
||||
if(seader_uart->T == 0) {
|
||||
seader_ccid_GetParameters(seader_uart);
|
||||
} else if(seader_uart->T == 1) {
|
||||
seader_ccid_SetParameters(seader, sam_slot);
|
||||
seader_ccid_SetParameters(seader, ccid_state->sam_slot);
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_W(TAG, "Unknown ATR");
|
||||
|
||||
@@ -22,67 +22,74 @@
|
||||
*/
|
||||
|
||||
// TODO: rename/renumber
|
||||
#define SLOT_0_MASK 0x03
|
||||
#define CARD_OUT_1 0x02
|
||||
#define CARD_IN_1 0x03
|
||||
#define SLOT_1_MASK 0x0C
|
||||
#define CARD_IN_2 0x04
|
||||
#define CARD_OUT_2 0x0C
|
||||
#define CCID_SLOT_0_MASK 0x03
|
||||
#define CCID_SLOT_0_CARD_OUT 0x02
|
||||
#define CCID_SLOT_0_CARD_IN 0x03
|
||||
#define CCID_SLOT_1_MASK 0x0C
|
||||
#define CCID_SLOT_1_CARD_IN 0x04
|
||||
#define CCID_SLOT_1_CARD_OUT 0x0C
|
||||
|
||||
/*
|
||||
* * BULK_OUT messages from PC to Reader
|
||||
* * Defined in CCID Rev 1.1 6.1 (page 26)
|
||||
* */
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72
|
||||
#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
|
||||
typedef enum {
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_ON = 0x62,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_POWER_OFF = 0x63,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_GET_SLOT_STATUS = 0x65,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_XFR_BLOCK = 0x6f,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_GET_PARAMETERS = 0x6c,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_RESET_PARAMETERS = 0x6d,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_SET_PARAMETERS = 0x61,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_ESCAPE = 0x6b,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_ICC_CLOCK = 0x6e,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_T0_APDU = 0x6a,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_SECURE = 0x69,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_MECHANICAL = 0x71,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_ABORT = 0x72,
|
||||
CCID_MESSAGE_TYPE_PC_TO_RDR_SET_DATA_RATE_AND_CLOCK_FREQUENCY = 0x73,
|
||||
} SeaderCcidPcToRdrMessageType;
|
||||
/*
|
||||
* * BULK_IN messages from Reader to PC
|
||||
* * Defined in CCID Rev 1.1 6.2 (page 48)
|
||||
* */
|
||||
#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80
|
||||
#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81
|
||||
#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82
|
||||
#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83
|
||||
#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
|
||||
typedef enum {
|
||||
CCID_MESSAGE_TYPE_RDR_TO_PC_DATA_BLOCK = 0x80,
|
||||
CCID_MESSAGE_TYPE_RDR_TO_PC_SLOT_STATUS = 0x81,
|
||||
CCID_MESSAGE_TYPE_RDR_TO_PC_PARAMETERS = 0x82,
|
||||
CCID_MESSAGE_TYPE_RDR_TO_PC_ESCAPE = 0x83,
|
||||
CCID_MESSAGE_TYPE_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQUENCY = 0x84,
|
||||
} SeaderCcidRdrToPcMessageType;
|
||||
/*
|
||||
* * INTERRUPT_IN messages from Reader to PC
|
||||
* * Defined in CCID Rev 1.1 6.3 (page 56)
|
||||
* */
|
||||
#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50
|
||||
#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51
|
||||
typedef enum {
|
||||
CCID_MESSAGE_TYPE_RDR_TO_PC_NOTIFY_SLOT_CHANGE = 0x50,
|
||||
CCID_MESSAGE_TYPE_RDR_TO_PC_HARDWARE_ERROR = 0x51,
|
||||
} SeaderCcidInterruptMessageType;
|
||||
|
||||
/* Status codes that go in bStatus (see 6.2.6) */
|
||||
enum {
|
||||
ICC_STATUS_PRESENT_ACTIVE = 0,
|
||||
ICC_STATUS_PRESENT_INACTIVE,
|
||||
ICC_STATUS_NOT_PRESENT
|
||||
};
|
||||
enum {
|
||||
COMMAND_STATUS_NO_ERROR = 0,
|
||||
COMMAND_STATUS_FAILED,
|
||||
COMMAND_STATUS_TIME_EXTENSION_REQUIRED
|
||||
};
|
||||
typedef enum {
|
||||
CCID_ICC_STATUS_PRESENT_ACTIVE = 0,
|
||||
CCID_ICC_STATUS_PRESENT_INACTIVE = 1,
|
||||
CCID_ICC_STATUS_NOT_PRESENT = 2,
|
||||
} SeaderCcidIccStatus;
|
||||
|
||||
typedef enum {
|
||||
CCID_COMMAND_STATUS_NO_ERROR = 0,
|
||||
CCID_COMMAND_STATUS_FAILED = 1,
|
||||
CCID_COMMAND_STATUS_TIME_EXTENSION_REQUIRED = 2,
|
||||
} SeaderCcidCommandStatus;
|
||||
/* Error codes that go in bError (see 6.2.6) */
|
||||
enum {
|
||||
ERROR_CMD_NOT_SUPPORTED = 0,
|
||||
ERROR_CMD_ABORTED = -1,
|
||||
ERROR_ICC_MUTE = -2,
|
||||
ERROR_XFR_PARITY_ERROR = -3,
|
||||
ERROR_XFR_OVERRUN = -4,
|
||||
ERROR_HW_ERROR = -5,
|
||||
};
|
||||
typedef enum {
|
||||
CCID_ERROR_CMD_NOT_SUPPORTED = 0x00,
|
||||
CCID_ERROR_CMD_ABORTED = 0xff,
|
||||
CCID_ERROR_ICC_MUTE = 0xfe,
|
||||
CCID_ERROR_XFR_PARITY_ERROR = 0xfd,
|
||||
CCID_ERROR_XFR_OVERRUN = 0xfc,
|
||||
CCID_ERROR_HW_ERROR = 0xfb,
|
||||
} SeaderCcidError;
|
||||
|
||||
struct CCID_Message {
|
||||
uint8_t bMessageType;
|
||||
|
||||
@@ -57,7 +57,7 @@ void seader_scene_read_card_success_on_enter(void* context) {
|
||||
|
||||
SeaderWorker* seader_worker = seader->worker;
|
||||
SeaderUartBridge* seader_uart = seader_worker->uart;
|
||||
seader_t_1_reset();
|
||||
seader_t_1_reset(seader->uart);
|
||||
seader_ccid_check_for_sam(seader_uart);
|
||||
}
|
||||
|
||||
|
||||
+32
-1
@@ -11,6 +11,9 @@
|
||||
|
||||
// https://ww1.microchip.com/downloads/en/DeviceDoc/00001561C.pdf
|
||||
#define SEADER_UART_RX_BUF_SIZE (300)
|
||||
#define SEADER_CCID_SLOT_COUNT (2U)
|
||||
|
||||
typedef struct BitBuffer BitBuffer;
|
||||
|
||||
typedef struct {
|
||||
uint8_t uart_ch;
|
||||
@@ -23,6 +26,33 @@ typedef struct {
|
||||
uint8_t protocol;
|
||||
} SeaderUartState;
|
||||
|
||||
typedef struct {
|
||||
bool powered;
|
||||
/* CCID sequence counter for this slot. */
|
||||
uint8_t sequence;
|
||||
} SeaderCcidSlotState;
|
||||
|
||||
typedef struct {
|
||||
bool has_sam;
|
||||
uint8_t sam_slot;
|
||||
uint8_t retries;
|
||||
SeaderCcidSlotState slots[SEADER_CCID_SLOT_COUNT];
|
||||
} SeaderCcidState;
|
||||
|
||||
typedef struct {
|
||||
/* ICC information field size for T=1. */
|
||||
uint8_t ifsc;
|
||||
/* Host NAD used for T=1 block exchange. */
|
||||
uint8_t nad;
|
||||
/* Last transmit I-block sequence bit. */
|
||||
uint8_t send_pcb;
|
||||
/* Last receive I-block sequence bit. */
|
||||
uint8_t recv_pcb;
|
||||
BitBuffer* tx_buffer;
|
||||
size_t tx_buffer_offset;
|
||||
BitBuffer* rx_buffer;
|
||||
} SeaderT1State;
|
||||
|
||||
struct SeaderUartBridge {
|
||||
SeaderUartConfig cfg;
|
||||
SeaderUartConfig cfg_new;
|
||||
@@ -43,7 +73,8 @@ struct SeaderUartBridge {
|
||||
|
||||
// T=0 or T=1
|
||||
uint8_t T;
|
||||
uint8_t IFSC;
|
||||
SeaderCcidState ccid;
|
||||
SeaderT1State t1;
|
||||
};
|
||||
|
||||
typedef struct SeaderUartBridge SeaderUartBridge;
|
||||
@@ -6,47 +6,53 @@
|
||||
|
||||
/* I know my T=1 is terrible, but I'm also only targetting one specific 'card' */
|
||||
|
||||
#define MORE_BIT 0x20
|
||||
#define R_BLOCK 0x80
|
||||
#define S_BLOCK 0xC0
|
||||
#define R_SEQUENCE_NUMBER_MASK 0x10
|
||||
#define T1_S_IFS 0x01
|
||||
static SeaderT1State* seader_t1_state(SeaderUartBridge* seader_uart) {
|
||||
return &seader_uart->t1;
|
||||
}
|
||||
|
||||
// TODO: T1 struct
|
||||
uint8_t NAD = 0x00;
|
||||
uint8_t dPCB = 0x40; // Init to 0x40 so first call to next_pcb will return 0x00
|
||||
uint8_t cPCB = 0x00; // Init to 0x40 so first call to next_pcb will return 0x00
|
||||
|
||||
uint8_t seader_next_dpcb() {
|
||||
uint8_t next_pcb = dPCB ^ 0x40;
|
||||
static uint8_t seader_next_dpcb(SeaderUartBridge* seader_uart) {
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t next_pcb = t1->send_pcb ^ SEADER_T1_PCB_SEQUENCE_BIT;
|
||||
//FURI_LOG_D(TAG, "dPCB was: %02X, current dPCB: %02X", dPCB, next_pcb);
|
||||
dPCB = next_pcb;
|
||||
return dPCB;
|
||||
t1->send_pcb = next_pcb;
|
||||
return t1->send_pcb;
|
||||
}
|
||||
|
||||
uint8_t seader_next_cpcb() {
|
||||
uint8_t next_pcb = cPCB ^ 0x40;
|
||||
static uint8_t seader_next_cpcb(SeaderUartBridge* seader_uart) {
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t next_pcb = t1->recv_pcb ^ SEADER_T1_PCB_SEQUENCE_BIT;
|
||||
//FURI_LOG_D(TAG, "cPCB was: %02X, current cPCB: %02X", cPCB, next_pcb);
|
||||
cPCB = next_pcb;
|
||||
return cPCB;
|
||||
t1->recv_pcb = next_pcb;
|
||||
return t1->recv_pcb;
|
||||
}
|
||||
|
||||
void seader_t_1_reset() {
|
||||
NAD = 0x00;
|
||||
dPCB = 0x40;
|
||||
cPCB = 0x00;
|
||||
void seader_t_1_reset(SeaderUartBridge* seader_uart) {
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
t1->nad = 0x00;
|
||||
t1->send_pcb = SEADER_T1_PCB_SEQUENCE_BIT;
|
||||
t1->recv_pcb = 0x00;
|
||||
if(t1->tx_buffer != NULL) {
|
||||
bit_buffer_free(t1->tx_buffer);
|
||||
}
|
||||
t1->tx_buffer = NULL;
|
||||
t1->tx_buffer_offset = 0;
|
||||
if(t1->rx_buffer != NULL) {
|
||||
bit_buffer_free(t1->rx_buffer);
|
||||
}
|
||||
t1->rx_buffer = NULL;
|
||||
}
|
||||
|
||||
void seader_t_1_set_IFSD(Seader* seader) {
|
||||
SeaderWorker* seader_worker = seader->worker;
|
||||
SeaderUartBridge* seader_uart = seader_worker->uart;
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t frame[5];
|
||||
uint8_t frame_len = 0;
|
||||
|
||||
frame[0] = NAD;
|
||||
frame[1] = S_BLOCK | T1_S_IFS; // S(IFS request)
|
||||
frame[0] = t1->nad;
|
||||
frame[1] = SEADER_T1_PCB_S_BLOCK | SEADER_T1_S_BLOCK_IFS; // S(IFS request)
|
||||
frame[2] = 0x01;
|
||||
frame[3] = seader_uart->IFSC;
|
||||
frame[3] = t1->ifsc;
|
||||
frame_len = 4;
|
||||
|
||||
frame_len = seader_add_lrc(frame, frame_len);
|
||||
@@ -57,13 +63,14 @@ void seader_t_1_set_IFSD(Seader* seader) {
|
||||
void seader_t_1_IFSD_response(Seader* seader) {
|
||||
SeaderWorker* seader_worker = seader->worker;
|
||||
SeaderUartBridge* seader_uart = seader_worker->uart;
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t frame[5];
|
||||
uint8_t frame_len = 0;
|
||||
|
||||
frame[0] = NAD;
|
||||
frame[0] = t1->nad;
|
||||
frame[1] = 0xE0 | 0x01; // S(IFS response)
|
||||
frame[2] = 0x01;
|
||||
frame[3] = seader_uart->IFSC;
|
||||
frame[3] = t1->ifsc;
|
||||
frame_len = 4;
|
||||
|
||||
frame_len = seader_add_lrc(frame, frame_len);
|
||||
@@ -74,11 +81,12 @@ void seader_t_1_IFSD_response(Seader* seader) {
|
||||
void seader_t_1_send_ack(Seader* seader) {
|
||||
SeaderWorker* seader_worker = seader->worker;
|
||||
SeaderUartBridge* seader_uart = seader_worker->uart;
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t frame[4];
|
||||
uint8_t frame_len = 0;
|
||||
|
||||
frame[0] = NAD;
|
||||
frame[1] = R_BLOCK | (seader_next_cpcb() >> 2);
|
||||
frame[0] = t1->nad;
|
||||
frame[1] = SEADER_T1_PCB_R_BLOCK | (seader_next_cpcb(seader_uart) >> 2);
|
||||
frame[2] = 0x00;
|
||||
frame_len = 3;
|
||||
|
||||
@@ -89,14 +97,12 @@ void seader_t_1_send_ack(Seader* seader) {
|
||||
seader_ccid_XfrBlock(seader_uart, frame, frame_len);
|
||||
}
|
||||
|
||||
BitBuffer* seader_t_1_tx_buffer;
|
||||
size_t seader_t_1_tx_buffer_offset = 0;
|
||||
|
||||
void seader_send_t1_chunk(SeaderUartBridge* seader_uart, uint8_t PCB, uint8_t* chunk, size_t len) {
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t* frame = malloc(3 + len + 1);
|
||||
uint8_t frame_len = 0;
|
||||
|
||||
frame[0] = NAD;
|
||||
frame[0] = t1->nad;
|
||||
frame[1] = PCB;
|
||||
frame[2] = len;
|
||||
frame_len = 3;
|
||||
@@ -117,8 +123,9 @@ void seader_send_t1_scratchpad(
|
||||
uint8_t PCB,
|
||||
uint8_t* apdu,
|
||||
size_t len) {
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t* frame = apdu - 3;
|
||||
frame[0] = NAD;
|
||||
frame[0] = t1->nad;
|
||||
frame[1] = PCB;
|
||||
frame[2] = (uint8_t)len;
|
||||
|
||||
@@ -127,50 +134,51 @@ void seader_send_t1_scratchpad(
|
||||
}
|
||||
|
||||
void seader_send_t1(SeaderUartBridge* seader_uart, uint8_t* apdu, size_t len) {
|
||||
uint8_t ifsc = seader_uart->IFSC;
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
uint8_t ifsc = t1->ifsc;
|
||||
|
||||
bool in_scratchpad =
|
||||
(apdu >= seader_uart->tx_buf + 3 && apdu < seader_uart->tx_buf + SEADER_UART_RX_BUF_SIZE);
|
||||
|
||||
if(len > ifsc) {
|
||||
if(seader_t_1_tx_buffer == NULL) {
|
||||
seader_t_1_tx_buffer = bit_buffer_alloc(768);
|
||||
bit_buffer_copy_bytes(seader_t_1_tx_buffer, apdu, len);
|
||||
if(t1->tx_buffer == NULL) {
|
||||
t1->tx_buffer = bit_buffer_alloc(768);
|
||||
bit_buffer_copy_bytes(t1->tx_buffer, apdu, len);
|
||||
}
|
||||
size_t remaining =
|
||||
(bit_buffer_get_size_bytes(seader_t_1_tx_buffer) - seader_t_1_tx_buffer_offset);
|
||||
(bit_buffer_get_size_bytes(t1->tx_buffer) - t1->tx_buffer_offset);
|
||||
size_t copy_length = remaining > ifsc ? ifsc : remaining;
|
||||
|
||||
uint8_t* chunk =
|
||||
(uint8_t*)bit_buffer_get_data(seader_t_1_tx_buffer) + seader_t_1_tx_buffer_offset;
|
||||
uint8_t* chunk = (uint8_t*)bit_buffer_get_data(t1->tx_buffer) + t1->tx_buffer_offset;
|
||||
|
||||
if(remaining > ifsc) {
|
||||
uint8_t PCB = seader_next_dpcb() | MORE_BIT;
|
||||
uint8_t PCB = seader_next_dpcb(seader_uart) | SEADER_T1_PCB_I_BLOCK_MORE;
|
||||
seader_send_t1_chunk(seader_uart, PCB, chunk, copy_length);
|
||||
} else {
|
||||
uint8_t PCB = seader_next_dpcb();
|
||||
uint8_t PCB = seader_next_dpcb(seader_uart);
|
||||
seader_send_t1_chunk(seader_uart, PCB, chunk, copy_length);
|
||||
}
|
||||
|
||||
seader_t_1_tx_buffer_offset += copy_length;
|
||||
if(seader_t_1_tx_buffer_offset >= bit_buffer_get_size_bytes(seader_t_1_tx_buffer)) {
|
||||
bit_buffer_free(seader_t_1_tx_buffer);
|
||||
seader_t_1_tx_buffer = NULL;
|
||||
seader_t_1_tx_buffer_offset = 0;
|
||||
t1->tx_buffer_offset += copy_length;
|
||||
if(t1->tx_buffer_offset >= bit_buffer_get_size_bytes(t1->tx_buffer)) {
|
||||
bit_buffer_free(t1->tx_buffer);
|
||||
t1->tx_buffer = NULL;
|
||||
t1->tx_buffer_offset = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(in_scratchpad) {
|
||||
seader_send_t1_scratchpad(seader_uart, seader_next_dpcb(), apdu, len);
|
||||
seader_send_t1_scratchpad(seader_uart, seader_next_dpcb(seader_uart), apdu, len);
|
||||
} else {
|
||||
seader_send_t1_chunk(seader_uart, seader_next_dpcb(), apdu, len);
|
||||
seader_send_t1_chunk(seader_uart, seader_next_dpcb(seader_uart), apdu, len);
|
||||
}
|
||||
}
|
||||
|
||||
BitBuffer* seader_t_1_rx_buffer;
|
||||
|
||||
bool seader_recv_t1(Seader* seader, CCID_Message* message) {
|
||||
SeaderWorker* seader_worker = seader->worker;
|
||||
SeaderUartBridge* seader_uart = seader_worker->uart;
|
||||
SeaderT1State* t1 = seader_t1_state(seader_uart);
|
||||
// remove/validate NAD, PCB, LEN, LRC
|
||||
if(message->dwLength < 4) {
|
||||
FURI_LOG_W(TAG, "Invalid T=1 frame: too short");
|
||||
@@ -193,20 +201,20 @@ bool seader_recv_t1(Seader* seader, CCID_Message* message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(rPCB == cPCB) {
|
||||
seader_next_cpcb();
|
||||
if(seader_t_1_rx_buffer != NULL) {
|
||||
bit_buffer_append_bytes(seader_t_1_rx_buffer, message->payload + 3, LEN);
|
||||
if(rPCB == t1->recv_pcb) {
|
||||
seader_next_cpcb(seader_uart);
|
||||
if(t1->rx_buffer != NULL) {
|
||||
bit_buffer_append_bytes(t1->rx_buffer, message->payload + 3, LEN);
|
||||
|
||||
// TODO: validate LRC
|
||||
|
||||
seader_worker_process_sam_message(
|
||||
seader,
|
||||
(uint8_t*)bit_buffer_get_data(seader_t_1_rx_buffer),
|
||||
bit_buffer_get_size_bytes(seader_t_1_rx_buffer));
|
||||
(uint8_t*)bit_buffer_get_data(t1->rx_buffer),
|
||||
bit_buffer_get_size_bytes(t1->rx_buffer));
|
||||
|
||||
bit_buffer_free(seader_t_1_rx_buffer);
|
||||
seader_t_1_rx_buffer = NULL;
|
||||
bit_buffer_free(t1->rx_buffer);
|
||||
t1->rx_buffer = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -223,24 +231,24 @@ bool seader_recv_t1(Seader* seader, CCID_Message* message) {
|
||||
return true;
|
||||
}
|
||||
return seader_worker_process_sam_message(seader, message->payload, message->dwLength);
|
||||
} else if(rPCB == (cPCB | MORE_BIT)) {
|
||||
} else if(rPCB == (t1->recv_pcb | SEADER_T1_PCB_I_BLOCK_MORE)) {
|
||||
//FURI_LOG_D(TAG, "Received T=1 frame with more bit set");
|
||||
if(seader_t_1_rx_buffer == NULL) {
|
||||
seader_t_1_rx_buffer = bit_buffer_alloc(512);
|
||||
if(t1->rx_buffer == NULL) {
|
||||
t1->rx_buffer = bit_buffer_alloc(512);
|
||||
}
|
||||
bit_buffer_append_bytes(seader_t_1_rx_buffer, message->payload + 3, LEN);
|
||||
bit_buffer_append_bytes(t1->rx_buffer, message->payload + 3, LEN);
|
||||
seader_t_1_send_ack(seader);
|
||||
return false;
|
||||
} else if((rPCB & S_BLOCK) == S_BLOCK) {
|
||||
} else if((rPCB & SEADER_T1_PCB_S_BLOCK) == SEADER_T1_PCB_S_BLOCK) {
|
||||
//FURI_LOG_D(TAG, "Received S-Block");
|
||||
if((rPCB & 0x0F) == T1_S_IFS) {
|
||||
if((rPCB & 0x0F) == SEADER_T1_S_BLOCK_IFS) {
|
||||
seader_t_1_IFSD_response(seader);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if((rPCB & R_BLOCK) == R_BLOCK) {
|
||||
uint8_t R_SEQ = (rPCB & R_SEQUENCE_NUMBER_MASK) >> 4;
|
||||
uint8_t I_SEQ = (dPCB ^ 0x40) >> 6;
|
||||
} else if((rPCB & SEADER_T1_PCB_R_BLOCK) == SEADER_T1_PCB_R_BLOCK) {
|
||||
uint8_t R_SEQ = (rPCB & SEADER_T1_R_BLOCK_SEQUENCE_MASK) >> 4;
|
||||
uint8_t I_SEQ = (t1->send_pcb ^ SEADER_T1_PCB_SEQUENCE_BIT) >> 6;
|
||||
if(R_SEQ != I_SEQ) {
|
||||
/*
|
||||
FURI_LOG_D(
|
||||
@@ -254,19 +262,20 @@ bool seader_recv_t1(Seader* seader, CCID_Message* message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(seader_t_1_tx_buffer != NULL) {
|
||||
if(t1->tx_buffer != NULL) {
|
||||
// Send more data, re-using the buffer to trigger the code path that sends the next block
|
||||
SeaderWorker* seader_worker = seader->worker;
|
||||
SeaderUartBridge* seader_uart = seader_worker->uart;
|
||||
seader_send_t1(
|
||||
seader_uart,
|
||||
(uint8_t*)bit_buffer_get_data(seader_t_1_tx_buffer),
|
||||
bit_buffer_get_size_bytes(seader_t_1_tx_buffer));
|
||||
(uint8_t*)bit_buffer_get_data(t1->tx_buffer),
|
||||
bit_buffer_get_size_bytes(t1->tx_buffer));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_W(
|
||||
TAG, "Invalid T=1 frame: PCB mismatch. Expected: %02X, Received: %02X", cPCB, rPCB);
|
||||
TAG,
|
||||
"Invalid T=1 frame: PCB mismatch. Expected: %02X, Received: %02X",
|
||||
t1->recv_pcb,
|
||||
rPCB);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -4,7 +4,16 @@
|
||||
|
||||
typedef struct CCID_Message CCID_Message;
|
||||
|
||||
typedef enum {
|
||||
SEADER_T1_PCB_I_BLOCK_MORE = 0x20,
|
||||
SEADER_T1_PCB_SEQUENCE_BIT = 0x40,
|
||||
SEADER_T1_PCB_R_BLOCK = 0x80,
|
||||
SEADER_T1_PCB_S_BLOCK = 0xC0,
|
||||
SEADER_T1_R_BLOCK_SEQUENCE_MASK = 0x10,
|
||||
SEADER_T1_S_BLOCK_IFS = 0x01,
|
||||
} SeaderT1Constant;
|
||||
|
||||
void seader_send_t1(SeaderUartBridge* seader_uart, uint8_t* apdu, size_t len);
|
||||
bool seader_recv_t1(Seader* seader, CCID_Message* message);
|
||||
void seader_t_1_set_IFSD(Seader* seader);
|
||||
void seader_t_1_reset();
|
||||
void seader_t_1_reset(SeaderUartBridge* seader_uart);
|
||||
@@ -148,9 +148,11 @@ int32_t seader_uart_worker(void* context) {
|
||||
}
|
||||
|
||||
SeaderUartBridge* seader_uart_enable(SeaderUartConfig* cfg, Seader* seader) {
|
||||
SeaderUartBridge* seader_uart = malloc(sizeof(SeaderUartBridge));
|
||||
SeaderUartBridge* seader_uart = calloc(1, sizeof(SeaderUartBridge));
|
||||
|
||||
seader_uart->T = 1;
|
||||
seader_t_1_reset(seader_uart);
|
||||
seader_uart->ccid.retries = 3;
|
||||
|
||||
memcpy(&(seader_uart->cfg_new), cfg, sizeof(SeaderUartConfig));
|
||||
|
||||
|
||||
Reference in new issue
Block a user