mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-10 06:54:19 +00:00
CCID: Support PC To Reader Transfer Block data (#3126)
* CCID: Support PC To Reader Transfer Block data * Format sources Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
65a56cdb4a
commit
4308a5e377
5 changed files with 209 additions and 153 deletions
|
@ -39,15 +39,25 @@ void icc_power_on_callback(uint8_t* atrBuffer, uint32_t* atrlen, void* context)
|
|||
iso7816_answer_to_reset(atrBuffer, atrlen);
|
||||
}
|
||||
|
||||
void xfr_datablock_callback(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context) {
|
||||
//dataBlock points to the buffer
|
||||
//dataBlockLen tells reader how nany bytes should be read
|
||||
void xfr_datablock_callback(
|
||||
const uint8_t* dataBlock,
|
||||
uint32_t dataBlockLen,
|
||||
uint8_t* responseDataBlock,
|
||||
uint32_t* responseDataBlockLen,
|
||||
void* context) {
|
||||
UNUSED(context);
|
||||
|
||||
struct ISO7816_Command_APDU commandAPDU;
|
||||
iso7816_read_command_apdu(&commandAPDU, dataBlock, dataBlockLen);
|
||||
|
||||
struct ISO7816_Response_APDU responseAPDU;
|
||||
//class not supported
|
||||
responseAPDU.SW1 = 0x6E;
|
||||
responseAPDU.SW2 = 0x00;
|
||||
|
||||
iso7816_write_response_apdu(&responseAPDU, dataBlock, dataBlockLen);
|
||||
iso7816_write_response_apdu(&responseAPDU, responseDataBlock, responseDataBlockLen);
|
||||
}
|
||||
|
||||
static const CcidCallbacks ccid_cb = {
|
||||
|
@ -66,7 +76,7 @@ static void ccid_test_app_render_callback(Canvas* canvas, void* ctx) {
|
|||
canvas_draw_str(canvas, 0, 63, "Hold [back] to exit");
|
||||
}
|
||||
|
||||
static void ccid_test_app__input_callback(InputEvent* input_event, void* ctx) {
|
||||
static void ccid_test_app_input_callback(InputEvent* input_event, void* ctx) {
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
|
||||
CcidTestAppEvent event;
|
||||
|
@ -94,7 +104,7 @@ CcidTestApp* ccid_test_app_alloc() {
|
|||
//message queue
|
||||
app->event_queue = furi_message_queue_alloc(8, sizeof(CcidTestAppEvent));
|
||||
furi_check(app->event_queue);
|
||||
view_port_input_callback_set(app->view_port, ccid_test_app__input_callback, app->event_queue);
|
||||
view_port_input_callback_set(app->view_port, ccid_test_app_input_callback, app->event_queue);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <furi.h>
|
||||
#include "iso7816_t0_apdu.h"
|
||||
|
||||
void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen) {
|
||||
void iso7816_answer_to_reset(uint8_t* dataBuffer, uint32_t* atrlen) {
|
||||
//minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00
|
||||
uint8_t AtrBuffer[2] = {
|
||||
0x3B, //TS (direct convention)
|
||||
|
@ -12,18 +12,19 @@ void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen) {
|
|||
};
|
||||
*atrlen = 2;
|
||||
|
||||
memcpy(atrBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen));
|
||||
memcpy(dataBuffer, AtrBuffer, sizeof(uint8_t) * (*atrlen));
|
||||
}
|
||||
|
||||
void iso7816_read_command_apdu(
|
||||
struct ISO7816_Command_APDU* command,
|
||||
const uint8_t* dataBuffer,
|
||||
uint32_t dataLen) {
|
||||
furi_assert(dataLen <= 4);
|
||||
UNUSED(dataLen);
|
||||
command->CLA = dataBuffer[0];
|
||||
command->INS = dataBuffer[1];
|
||||
command->P1 = dataBuffer[2];
|
||||
command->P2 = dataBuffer[3];
|
||||
command->Lc = dataBuffer[4];
|
||||
}
|
||||
|
||||
void iso7816_write_response_apdu(
|
||||
|
|
|
@ -6,18 +6,18 @@
|
|||
struct ISO7816_Command_APDU {
|
||||
//header
|
||||
uint8_t CLA;
|
||||
uint32_t INS;
|
||||
uint8_t INS;
|
||||
uint8_t P1;
|
||||
uint8_t P2;
|
||||
|
||||
//body
|
||||
uint8_t Nc;
|
||||
uint8_t Ne;
|
||||
uint8_t Lc;
|
||||
uint8_t Le;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ISO7816_Response_APDU {
|
||||
uint8_t SW1;
|
||||
uint32_t SW2;
|
||||
uint8_t SW2;
|
||||
} __attribute__((packed));
|
||||
|
||||
void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen);
|
||||
|
|
|
@ -250,76 +250,136 @@ static void ccid_on_suspend(usbd_device* dev) {
|
|||
connected = false;
|
||||
}
|
||||
|
||||
struct ccid_bulk_message_header {
|
||||
typedef struct ccid_bulk_message_header {
|
||||
uint8_t bMessageType;
|
||||
uint32_t dwLength;
|
||||
uint8_t bSlot;
|
||||
uint8_t bSeq;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed)) ccid_bulk_message_header_t;
|
||||
|
||||
static struct rdr_to_pc_slot_status responseSlotStatus;
|
||||
static struct rdr_to_pc_data_block responseDataBlock;
|
||||
static struct rdr_to_pc_parameters_t0 responseParameters;
|
||||
uint8_t SendDataBlock[CCID_DATABLOCK_SIZE];
|
||||
uint8_t SendBuffer[sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE];
|
||||
|
||||
uint8_t CALLBACK_CCID_GetSlotStatus(uint8_t slot, uint8_t* error) {
|
||||
if(slot == CCID_SLOT_INDEX) {
|
||||
*error = CCID_ERROR_NOERROR;
|
||||
if(smartcard_inserted) {
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
|
||||
} else {
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
} else {
|
||||
*error = CCID_ERROR_SLOTNOTFOUND;
|
||||
return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
}
|
||||
//stores the data p
|
||||
uint8_t ReceiveBuffer[sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE];
|
||||
|
||||
uint8_t
|
||||
CALLBACK_CCID_IccPowerOn(uint8_t slot, uint8_t* atrBuffer, uint32_t* atrlen, uint8_t* error) {
|
||||
if(slot == CCID_SLOT_INDEX) {
|
||||
*error = CCID_ERROR_NOERROR;
|
||||
if(smartcard_inserted) {
|
||||
if(callbacks[CCID_SLOT_INDEX] != NULL) {
|
||||
callbacks[CCID_SLOT_INDEX]->icc_power_on_callback(atrBuffer, atrlen, NULL);
|
||||
} else {
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDINACTIVE;
|
||||
}
|
||||
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
|
||||
} else {
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
} else {
|
||||
*error = CCID_ERROR_SLOTNOTFOUND;
|
||||
return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CALLBACK_CCID_XfrBlock(
|
||||
void CALLBACK_CCID_GetSlotStatus(
|
||||
uint8_t slot,
|
||||
uint8_t* dataBlock,
|
||||
uint32_t* dataBlockLen,
|
||||
uint8_t* error) {
|
||||
if(slot == CCID_SLOT_INDEX) {
|
||||
*error = CCID_ERROR_NOERROR;
|
||||
if(smartcard_inserted) {
|
||||
if(callbacks[CCID_SLOT_INDEX] != NULL) {
|
||||
callbacks[CCID_SLOT_INDEX]->xfr_datablock_callback(dataBlock, dataBlockLen, NULL);
|
||||
} else {
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDINACTIVE;
|
||||
}
|
||||
uint8_t seq,
|
||||
struct rdr_to_pc_slot_status* responseSlotStatus) {
|
||||
responseSlotStatus->bMessageType = RDR_TO_PC_SLOTSTATUS;
|
||||
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_PRESENTANDACTIVE;
|
||||
responseSlotStatus->bSlot = slot;
|
||||
responseSlotStatus->bSeq = seq;
|
||||
responseSlotStatus->bClockStatus = 0;
|
||||
|
||||
responseSlotStatus->dwLength = 0;
|
||||
|
||||
if(responseSlotStatus->bSlot == CCID_SLOT_INDEX) {
|
||||
responseSlotStatus->bError = CCID_ERROR_NOERROR;
|
||||
if(smartcard_inserted) {
|
||||
responseSlotStatus->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDACTIVE;
|
||||
} else {
|
||||
return CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
responseSlotStatus->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
} else {
|
||||
*error = CCID_ERROR_SLOTNOTFOUND;
|
||||
return CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
responseSlotStatus->bError = CCID_ERROR_SLOTNOTFOUND;
|
||||
responseSlotStatus->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
void CALLBACK_CCID_SetParametersT0(
|
||||
struct pc_to_rdr_set_parameters_t0* requestSetParametersT0,
|
||||
struct rdr_to_pc_parameters_t0* responseSetParametersT0) {
|
||||
furi_assert(requestSetParametersT0->bProtocolNum == 0x00); //T0
|
||||
responseSetParametersT0->bMessageType = RDR_TO_PC_PARAMETERS;
|
||||
responseSetParametersT0->bSlot = requestSetParametersT0->bSlot;
|
||||
responseSetParametersT0->bSeq = requestSetParametersT0->bSeq;
|
||||
|
||||
responseSetParametersT0->dwLength =
|
||||
sizeof(struct pc_to_rdr_set_parameters_t0) - sizeof(ccid_bulk_message_header_t);
|
||||
|
||||
if(responseSetParametersT0->bSlot == CCID_SLOT_INDEX) {
|
||||
responseSetParametersT0->bError = CCID_ERROR_NOERROR;
|
||||
if(smartcard_inserted) {
|
||||
responseSetParametersT0->bProtocolNum = requestSetParametersT0->bProtocolNum;
|
||||
responseSetParametersT0->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDACTIVE;
|
||||
} else {
|
||||
responseSetParametersT0->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
} else {
|
||||
responseSetParametersT0->bError = CCID_ERROR_SLOTNOTFOUND;
|
||||
responseSetParametersT0->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
void CALLBACK_CCID_IccPowerOn(
|
||||
uint8_t slot,
|
||||
uint8_t seq,
|
||||
struct rdr_to_pc_data_block* responseDataBlock) {
|
||||
responseDataBlock->bMessageType = RDR_TO_PC_DATABLOCK;
|
||||
responseDataBlock->dwLength = 0;
|
||||
responseDataBlock->bSlot = slot;
|
||||
responseDataBlock->bSeq = seq;
|
||||
|
||||
if(responseDataBlock->bSlot == CCID_SLOT_INDEX) {
|
||||
responseDataBlock->bError = CCID_ERROR_NOERROR;
|
||||
if(smartcard_inserted) {
|
||||
if(callbacks[CCID_SLOT_INDEX] != NULL) {
|
||||
callbacks[CCID_SLOT_INDEX]->icc_power_on_callback(
|
||||
responseDataBlock->abData, &responseDataBlock->dwLength, NULL);
|
||||
} else {
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDINACTIVE;
|
||||
}
|
||||
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDACTIVE;
|
||||
} else {
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
} else {
|
||||
responseDataBlock->bError = CCID_ERROR_SLOTNOTFOUND;
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
void CALLBACK_CCID_XfrBlock(
|
||||
struct pc_to_rdr_xfr_block* receivedXfrBlock,
|
||||
struct rdr_to_pc_data_block* responseDataBlock) {
|
||||
responseDataBlock->bMessageType = RDR_TO_PC_DATABLOCK;
|
||||
responseDataBlock->bSlot = receivedXfrBlock->bSlot;
|
||||
responseDataBlock->bSeq = receivedXfrBlock->bSeq;
|
||||
responseDataBlock->bChainParameter = 0;
|
||||
|
||||
if(responseDataBlock->bSlot == CCID_SLOT_INDEX) {
|
||||
responseDataBlock->bError = CCID_ERROR_NOERROR;
|
||||
if(smartcard_inserted) {
|
||||
if(callbacks[CCID_SLOT_INDEX] != NULL) {
|
||||
callbacks[CCID_SLOT_INDEX]->xfr_datablock_callback(
|
||||
(const uint8_t*)receivedXfrBlock->abData,
|
||||
receivedXfrBlock->dwLength,
|
||||
responseDataBlock->abData,
|
||||
&responseDataBlock->dwLength,
|
||||
NULL);
|
||||
} else {
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDINACTIVE;
|
||||
}
|
||||
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_PRESENTANDACTIVE;
|
||||
} else {
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR |
|
||||
CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
} else {
|
||||
responseDataBlock->bError = CCID_ERROR_SLOTNOTFOUND;
|
||||
responseDataBlock->bStatus = CCID_COMMANDSTATUS_FAILED | CCID_ICCSTATUS_NOICCPRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,109 +407,89 @@ static void ccid_tx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
|||
if(event == usbd_evt_eprx) {
|
||||
if(connected == false) return;
|
||||
|
||||
struct ccid_bulk_message_header message;
|
||||
usbd_ep_read(usb_dev, ep, &message, sizeof(message));
|
||||
//read initial CCID message header
|
||||
|
||||
uint8_t Status;
|
||||
uint8_t Error = CCID_ERROR_NOERROR;
|
||||
int32_t bytes_read = usbd_ep_read(
|
||||
usb_dev, ep, &ReceiveBuffer, sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE);
|
||||
//minimum request size is header size
|
||||
furi_assert((uint16_t)bytes_read >= sizeof(ccid_bulk_message_header_t));
|
||||
ccid_bulk_message_header_t* message = (ccid_bulk_message_header_t*)&ReceiveBuffer;
|
||||
|
||||
uint32_t dataBlockLen = 0;
|
||||
uint8_t* dataBlockBuffer = NULL;
|
||||
if(message->bMessageType == PC_TO_RDR_ICCPOWERON) {
|
||||
struct pc_to_rdr_icc_power_on* requestDataBlock =
|
||||
(struct pc_to_rdr_icc_power_on*)message;
|
||||
struct rdr_to_pc_data_block* responseDataBlock =
|
||||
(struct rdr_to_pc_data_block*)&SendBuffer;
|
||||
|
||||
if(message.bMessageType == PC_TO_RDR_GETSLOTSTATUS) {
|
||||
responseSlotStatus.bMessageType = RDR_TO_PC_SLOTSTATUS;
|
||||
responseSlotStatus.dwLength = 0;
|
||||
responseSlotStatus.bSlot = message.bSlot;
|
||||
responseSlotStatus.bSeq = message.bSeq;
|
||||
CALLBACK_CCID_IccPowerOn(
|
||||
requestDataBlock->bSlot, requestDataBlock->bSeq, responseDataBlock);
|
||||
|
||||
responseSlotStatus.bClockStatus = 0;
|
||||
|
||||
Status = CALLBACK_CCID_GetSlotStatus(message.bSlot, &Error);
|
||||
|
||||
responseSlotStatus.bStatus = Status;
|
||||
responseSlotStatus.bError = Error;
|
||||
|
||||
usbd_ep_write(
|
||||
usb_dev, CCID_IN_EPADDR, &responseSlotStatus, sizeof(responseSlotStatus));
|
||||
} else if(message.bMessageType == PC_TO_RDR_ICCPOWERON) {
|
||||
responseDataBlock.bMessageType = RDR_TO_PC_DATABLOCK;
|
||||
responseDataBlock.bSlot = message.bSlot;
|
||||
responseDataBlock.bSeq = message.bSeq;
|
||||
responseDataBlock.bChainParameter = 0;
|
||||
|
||||
dataBlockLen = 0;
|
||||
dataBlockBuffer = (uint8_t*)SendDataBlock;
|
||||
Status = CALLBACK_CCID_IccPowerOn(
|
||||
message.bSlot, (uint8_t*)dataBlockBuffer, &dataBlockLen, &Error);
|
||||
|
||||
furi_assert(dataBlockLen < CCID_DATABLOCK_SIZE);
|
||||
responseDataBlock.dwLength = dataBlockLen;
|
||||
|
||||
responseSlotStatus.bStatus = Status;
|
||||
responseSlotStatus.bError = Error;
|
||||
|
||||
memcpy(responseDataBlock.abData, SendDataBlock, dataBlockLen);
|
||||
usbd_ep_write(
|
||||
usb_dev,
|
||||
CCID_IN_EPADDR,
|
||||
&responseDataBlock,
|
||||
sizeof(struct rdr_to_pc_data_block) + (sizeof(uint8_t) * dataBlockLen));
|
||||
} else if(message.bMessageType == PC_TO_RDR_ICCPOWEROFF) {
|
||||
responseSlotStatus.bMessageType = RDR_TO_PC_SLOTSTATUS;
|
||||
responseSlotStatus.dwLength = 0;
|
||||
responseSlotStatus.bSlot = message.bSlot;
|
||||
responseSlotStatus.bSeq = message.bSeq;
|
||||
responseDataBlock,
|
||||
sizeof(struct rdr_to_pc_data_block) +
|
||||
(sizeof(uint8_t) * responseDataBlock->dwLength));
|
||||
} else if(message->bMessageType == PC_TO_RDR_ICCPOWEROFF) {
|
||||
struct pc_to_rdr_icc_power_off* requestIccPowerOff =
|
||||
(struct pc_to_rdr_icc_power_off*)message;
|
||||
struct rdr_to_pc_slot_status* responseSlotStatus =
|
||||
(struct rdr_to_pc_slot_status*)&SendBuffer;
|
||||
|
||||
responseSlotStatus.bClockStatus = 0;
|
||||
|
||||
uint8_t Status;
|
||||
uint8_t Error = CCID_ERROR_NOERROR;
|
||||
Status = CALLBACK_CCID_GetSlotStatus(message.bSlot, &Error);
|
||||
|
||||
responseSlotStatus.bStatus = Status;
|
||||
responseSlotStatus.bError = Error;
|
||||
CALLBACK_CCID_GetSlotStatus(
|
||||
requestIccPowerOff->bSlot, requestIccPowerOff->bSeq, responseSlotStatus);
|
||||
|
||||
usbd_ep_write(
|
||||
usb_dev, CCID_IN_EPADDR, &responseSlotStatus, sizeof(responseSlotStatus));
|
||||
} else if(message.bMessageType == PC_TO_RDR_SETPARAMETERS) {
|
||||
responseParameters.bMessageType = RDR_TO_PC_PARAMETERS;
|
||||
responseParameters.bSlot = message.bSlot;
|
||||
responseParameters.bSeq = message.bSeq;
|
||||
responseParameters.bProtocolNum = 0; //T0
|
||||
usb_dev, CCID_IN_EPADDR, responseSlotStatus, sizeof(struct rdr_to_pc_slot_status));
|
||||
} else if(message->bMessageType == PC_TO_RDR_GETSLOTSTATUS) {
|
||||
struct pc_to_rdr_get_slot_status* requestSlotStatus =
|
||||
(struct pc_to_rdr_get_slot_status*)message;
|
||||
struct rdr_to_pc_slot_status* responseSlotStatus =
|
||||
(struct rdr_to_pc_slot_status*)&SendBuffer;
|
||||
|
||||
uint8_t Status = CCID_COMMANDSTATUS_PROCESSEDWITHOUTERROR;
|
||||
uint8_t Error = CCID_ERROR_NOERROR;
|
||||
|
||||
responseParameters.bStatus = Status;
|
||||
responseParameters.bError = Error;
|
||||
|
||||
responseParameters.dwLength = sizeof(struct rdr_to_pc_parameters_t0);
|
||||
CALLBACK_CCID_GetSlotStatus(
|
||||
requestSlotStatus->bSlot, requestSlotStatus->bSeq, responseSlotStatus);
|
||||
|
||||
usbd_ep_write(
|
||||
usb_dev, CCID_IN_EPADDR, &responseParameters, sizeof(responseParameters));
|
||||
} else if(message.bMessageType == PC_TO_RDR_XFRBLOCK) {
|
||||
responseDataBlock.bMessageType = RDR_TO_PC_DATABLOCK;
|
||||
responseDataBlock.bSlot = message.bSlot;
|
||||
responseDataBlock.bSeq = message.bSeq;
|
||||
responseDataBlock.bChainParameter = 0;
|
||||
usb_dev, CCID_IN_EPADDR, responseSlotStatus, sizeof(struct rdr_to_pc_slot_status));
|
||||
} else if(message->bMessageType == PC_TO_RDR_XFRBLOCK) {
|
||||
struct pc_to_rdr_xfr_block* receivedXfrBlock = (struct pc_to_rdr_xfr_block*)message;
|
||||
struct rdr_to_pc_data_block* responseDataBlock =
|
||||
(struct rdr_to_pc_data_block*)&SendBuffer;
|
||||
|
||||
dataBlockLen = 0;
|
||||
dataBlockBuffer = (uint8_t*)SendDataBlock;
|
||||
Status = CALLBACK_CCID_XfrBlock(
|
||||
message.bSlot, (uint8_t*)dataBlockBuffer, &dataBlockLen, &Error);
|
||||
furi_assert(receivedXfrBlock->dwLength <= CCID_DATABLOCK_SIZE);
|
||||
furi_assert(
|
||||
(uint16_t)bytes_read >=
|
||||
sizeof(ccid_bulk_message_header_t) + receivedXfrBlock->dwLength);
|
||||
|
||||
furi_assert(dataBlockLen < CCID_DATABLOCK_SIZE);
|
||||
responseDataBlock.dwLength = dataBlockLen;
|
||||
CALLBACK_CCID_XfrBlock(receivedXfrBlock, responseDataBlock);
|
||||
|
||||
responseSlotStatus.bStatus = Status;
|
||||
responseSlotStatus.bError = Error;
|
||||
furi_assert(responseDataBlock->dwLength <= CCID_DATABLOCK_SIZE);
|
||||
|
||||
memcpy(responseDataBlock.abData, SendDataBlock, dataBlockLen);
|
||||
usbd_ep_write(
|
||||
usb_dev,
|
||||
CCID_IN_EPADDR,
|
||||
&responseDataBlock,
|
||||
sizeof(struct rdr_to_pc_data_block) + (sizeof(uint8_t) * dataBlockLen));
|
||||
responseDataBlock,
|
||||
sizeof(struct rdr_to_pc_data_block) +
|
||||
(sizeof(uint8_t) * responseDataBlock->dwLength));
|
||||
} else if(message->bMessageType == PC_TO_RDR_SETPARAMETERS) {
|
||||
struct pc_to_rdr_set_parameters_t0* requestSetParametersT0 =
|
||||
(struct pc_to_rdr_set_parameters_t0*)message;
|
||||
struct rdr_to_pc_parameters_t0* responseSetParametersT0 =
|
||||
(struct rdr_to_pc_parameters_t0*)&SendBuffer;
|
||||
|
||||
furi_assert(requestSetParametersT0->dwLength <= CCID_DATABLOCK_SIZE);
|
||||
furi_assert(
|
||||
(uint16_t)bytes_read >=
|
||||
sizeof(ccid_bulk_message_header_t) + requestSetParametersT0->dwLength);
|
||||
|
||||
CALLBACK_CCID_SetParametersT0(requestSetParametersT0, responseSetParametersT0);
|
||||
|
||||
usbd_ep_write(
|
||||
usb_dev,
|
||||
CCID_IN_EPADDR,
|
||||
responseSetParametersT0,
|
||||
sizeof(struct rdr_to_pc_parameters_t0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,12 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
void (*icc_power_on_callback)(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context);
|
||||
void (*xfr_datablock_callback)(uint8_t* dataBlock, uint32_t* dataBlockLen, void* context);
|
||||
void (*xfr_datablock_callback)(
|
||||
const uint8_t* dataBlock,
|
||||
uint32_t dataBlockLen,
|
||||
uint8_t* responseDataBlock,
|
||||
uint32_t* responseDataBlockLen,
|
||||
void* context);
|
||||
} CcidCallbacks;
|
||||
|
||||
void furi_hal_ccid_set_callbacks(CcidCallbacks* cb);
|
||||
|
|
Loading…
Reference in a new issue