mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 18:48:13 -07:00
added: hf 14b apdu
This commit is contained in:
parent
c3c59e35cb
commit
181bb3bc74
4 changed files with 483 additions and 93 deletions
|
@ -41,15 +41,18 @@
|
|||
|
||||
// defaults to 2000ms
|
||||
#ifndef FWT_TIMEOUT_14B
|
||||
# define FWT_TIMEOUT_14B 35312
|
||||
# define FWT_TIMEOUT_14B 35312
|
||||
#endif
|
||||
|
||||
// 1 tick == 1/13.56 mhz
|
||||
// 1 us = 1.5 tick
|
||||
|
||||
// 330/848kHz = 1558us / 4 == 400us,
|
||||
#define ISO14443B_READER_TIMEOUT 1700 //330
|
||||
#define ISO14443B_READER_TIMEOUT 10000 //330
|
||||
|
||||
// 1024/3.39MHz = 302.1us between end of tag response and next reader cmd
|
||||
#define DELAY_ISO14443B_VICC_TO_VCD_READER 600 // 1024
|
||||
#define DELAY_ISO14443B_VCD_TO_VICC_READER 600// 1056
|
||||
#define DELAY_ISO14443B_VICC_TO_VCD_READER (28*9) // 1024 ( counting from start of PICC EOF 14 ETU's)
|
||||
#define DELAY_ISO14443B_VCD_TO_VICC_READER (28*9) // 1056
|
||||
|
||||
#ifndef RECEIVE_MASK
|
||||
# define RECEIVE_MASK (DMA_BUFFER_SIZE - 1)
|
||||
|
@ -57,7 +60,7 @@
|
|||
|
||||
// Guard Time (per 14443-2)
|
||||
#ifndef TR0
|
||||
# define TR0 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA
|
||||
# define TR0 32 // TR0 max is 151/fs = 151/(848kHz) = 302us or 64 samples from FPGA
|
||||
#endif
|
||||
|
||||
// Synchronization time (per 14443-2)
|
||||
|
@ -76,10 +79,9 @@ static void iso14b_set_timeout(uint32_t timeout);
|
|||
static void iso14b_set_maxframesize(uint16_t size);
|
||||
|
||||
// the block number for the ISO14443-4 PCB (used with APDUs)
|
||||
static uint8_t pcb_blocknum = 0;
|
||||
static uint8_t iso14b_pcb_blocknum = 0;
|
||||
static uint32_t iso14b_timeout = FWT_TIMEOUT_14B;
|
||||
|
||||
|
||||
/* ISO 14443 B
|
||||
*
|
||||
* Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig)
|
||||
|
@ -306,7 +308,6 @@ static void Demod14bInit(uint8_t *data, uint16_t max_len) {
|
|||
Demod14bReset();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 9.4395 us = 1 ETU and clock is about 1.5 us
|
||||
* 13560000Hz
|
||||
|
@ -740,7 +741,7 @@ void SimulateIso14443bTag(uint32_t pupi) {
|
|||
*/
|
||||
static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
||||
|
||||
int v;
|
||||
int v = 0;
|
||||
|
||||
// The soft decision on the bit uses an estimate of just the
|
||||
// quadrant of the reference angle, not the exact angle.
|
||||
|
@ -757,7 +758,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
} \
|
||||
}
|
||||
|
||||
#define SUBCARRIER_DETECT_THRESHOLD 8
|
||||
#define SUBCARRIER_DETECT_THRESHOLD 8
|
||||
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
|
||||
#define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2))
|
||||
|
||||
|
@ -797,7 +798,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
|
||||
Demod.posCount = 0; // start of SOF sequence
|
||||
} else {
|
||||
if (Demod.posCount > 200 / 4) { // maximum length of TR1 = 200 1/fs
|
||||
if (Demod.posCount > 200/4) { // maximum length of TR1 = 200 1/fs
|
||||
Demod.state = DEMOD_UNSYNCD;
|
||||
}
|
||||
}
|
||||
|
@ -820,7 +821,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
Demod.state = DEMOD_AWAITING_START_BIT;
|
||||
}
|
||||
} else {
|
||||
if (Demod.posCount > 14 * 2) { // low phase of SOF too long (> 12 etu)
|
||||
if (Demod.posCount > 12 * 2) { // low phase of SOF too long (> 12 etu)
|
||||
Demod.state = DEMOD_UNSYNCD;
|
||||
LED_C_OFF();
|
||||
}
|
||||
|
@ -831,7 +832,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
Demod.posCount++;
|
||||
MAKE_SOFT_DECISION();
|
||||
if (v > 0) {
|
||||
if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
|
||||
if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
|
||||
LED_C_OFF();
|
||||
if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass
|
||||
return true;
|
||||
|
@ -873,7 +874,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
Demod.bitCount = 0;
|
||||
Demod.state = DEMOD_AWAITING_START_BIT;
|
||||
} else {
|
||||
Demod.state = DEMOD_UNSYNCD;
|
||||
Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
|
||||
LED_C_OFF();
|
||||
if (s == 0x000) {
|
||||
// This is EOF (start, stop and all data bits == '0'
|
||||
|
@ -894,23 +895,16 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Demodulate the samples we received from the tag, also log to tracebuffer
|
||||
*/
|
||||
static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeout, uint32_t *eof_time) {
|
||||
|
||||
|
||||
int samples = 0, ret = 0;
|
||||
|
||||
// Set up the demodulator for tag -> reader responses.
|
||||
Demod14bInit(response, max_len);
|
||||
|
||||
// wait for last transfer to complete
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {};
|
||||
|
||||
// And put the FPGA in the appropriate mode
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
|
||||
|
||||
|
||||
// Setup and start DMA.
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
|
||||
|
||||
|
@ -924,6 +918,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
|||
uint32_t dma_start_time = 0;
|
||||
uint16_t *upTo = dma->buf;
|
||||
|
||||
// Put FPGA in the appropriate mode
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
|
||||
|
||||
for (;;) {
|
||||
|
||||
volatile uint16_t behindBy = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1);
|
||||
|
@ -971,7 +968,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
|||
|
||||
if (Handle14443bSamplesFromTag(ci, cq)) {
|
||||
|
||||
*eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
*eof_time = dma_start_time + (samples ) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
|
||||
if (Demod.len > Demod.max_len) {
|
||||
ret = -2; // overflow
|
||||
|
@ -986,19 +983,17 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
|||
}
|
||||
|
||||
FpgaDisableSscDma();
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (Demod.len > 0) {
|
||||
uint32_t sof_time = *eof_time
|
||||
- (Demod.len * 8 * 8 * 16) // time for byte transfers
|
||||
- (32 * 16) // time for SOF transfer
|
||||
- 0; // time for EOF transfer
|
||||
- (Demod.len * (8 + 2)) // time for byte transfers
|
||||
- (12) // time for SOF transfer
|
||||
- (12); // time for EOF transfer
|
||||
LogTrace(Demod.output, Demod.len, (sof_time * 4), (*eof_time * 4), NULL, false);
|
||||
}
|
||||
|
||||
return Demod.len;
|
||||
}
|
||||
|
||||
|
@ -1011,6 +1006,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
|
|||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
|
||||
|
||||
// TR2 minimum 14 ETUs
|
||||
if (*start_time < DELAY_ARM_TO_TAG) {
|
||||
*start_time = DELAY_ARM_TO_TAG;
|
||||
}
|
||||
|
@ -1018,21 +1014,20 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
|
|||
*start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0;
|
||||
|
||||
if (GetCountSspClk() > *start_time) { // we may miss the intended time
|
||||
*start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time
|
||||
*start_time = (GetCountSspClk() + 32) & 0xfffffff0; // next possible time
|
||||
}
|
||||
|
||||
|
||||
// wait
|
||||
while (GetCountSspClk() < *start_time) ;
|
||||
while (GetCountSspClk() < *start_time);
|
||||
|
||||
LED_B_ON();
|
||||
for (int c = 0; c < ts->max; c++) {
|
||||
volatile uint8_t data = ts->buf[c];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
volatile uint16_t send_word = (data & 0x80) ? 0x0000 : 0xFFFF;
|
||||
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
|
||||
|
||||
AT91C_BASE_SSC->SSC_THR = send_word;
|
||||
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
|
||||
|
@ -1045,6 +1040,9 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
|
|||
LED_B_OFF();
|
||||
|
||||
*start_time += DELAY_ARM_TO_TAG;
|
||||
|
||||
// wait for last transfer to complete
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {};
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1061,32 +1059,38 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
|
|||
* - no modulation ONES
|
||||
*
|
||||
* 1 ETU == 1 BIT!
|
||||
* TR0 - 8 ETUS minimum.
|
||||
* TR0 - 8 ETU's minimum.
|
||||
* TR0 - 32 ETU's maximum for ATQB only
|
||||
* TR0 - FWT for all other commands
|
||||
*
|
||||
* QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode?
|
||||
* 1 "stuffbit" = 1ETU (9us)
|
||||
*
|
||||
* TR2 - After the PICC response, the PCD is required to wait the Frame Delay Time (TR2)
|
||||
before transmission of the next command. The minimum frame delay time required for
|
||||
all commands is 14 ETUs
|
||||
*
|
||||
*/
|
||||
|
||||
int i;
|
||||
tosend_reset();
|
||||
|
||||
|
||||
// Send SOF
|
||||
// 10-11 ETUs of ZERO
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (i = 0; i < 10; i++) {
|
||||
tosend_stuffbit(0);
|
||||
|
||||
|
||||
}
|
||||
// 2-3 ETUs of ONE
|
||||
tosend_stuffbit(1);
|
||||
tosend_stuffbit(1);
|
||||
|
||||
// Sending cmd, LSB
|
||||
// from here we add BITS
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
// Start bit
|
||||
tosend_stuffbit(0);
|
||||
// Data bits
|
||||
uint8_t b = cmd[i];
|
||||
|
||||
// Data bits
|
||||
volatile uint8_t b = cmd[i];
|
||||
tosend_stuffbit(b & 1);
|
||||
tosend_stuffbit((b >> 1) & 1);
|
||||
tosend_stuffbit((b >> 2) & 1);
|
||||
|
@ -1098,28 +1102,28 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
|
|||
|
||||
// Stop bit
|
||||
tosend_stuffbit(1);
|
||||
// EGT extra guard time
|
||||
// For PCD it ranges 0-57us (1etu = 9us)
|
||||
// tosend_stuffbit(1);
|
||||
// tosend_stuffbit(1);
|
||||
// tosend_stuffbit(1);
|
||||
// EGT extra guard time 1 ETU = 9us
|
||||
// For PCD it ranges 0-57us === 0 - 6 ETU
|
||||
// FOR PICC it ranges 0-19us == 0 - 2 ETU
|
||||
}
|
||||
|
||||
// Send EOF
|
||||
// 10-11 ETUs of ZERO
|
||||
for (int i = 0; i < 10; i++)
|
||||
for (i = 0; i < 10; i++) {
|
||||
tosend_stuffbit(0);
|
||||
}
|
||||
|
||||
// Transition time. TR0 - guard time
|
||||
// 8ETUS minum?
|
||||
// Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF.
|
||||
// I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode
|
||||
tosend_stuffbit(1);
|
||||
/* Transition time. TR0 - guard time
|
||||
* TR0 - 8 ETU's minimum.
|
||||
* TR0 - 32 ETU's maximum for ATQB only
|
||||
* TR0 - FWT for all other commands
|
||||
* 32,64,128,256,512, ... , 262144, 524288 ETU
|
||||
*/
|
||||
|
||||
// ensure that last byte is filled up
|
||||
for (int i = 0; i < 8 ; ++i)
|
||||
for (i = 0; i < 8 ; ++i)
|
||||
tosend_stuffbit(1);
|
||||
|
||||
// TR1 - Synchronization time
|
||||
// Convert from last character reference to length
|
||||
tosend_t *ts = get_tosend();
|
||||
ts->max++;
|
||||
|
@ -1132,54 +1136,100 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
|||
tosend_t *ts = get_tosend();
|
||||
CodeIso14443bAsReader(cmd, len);
|
||||
TransmitFor14443b_AsReader(start_time);
|
||||
*eof_time = *start_time + (32 * (8 * ts->max));
|
||||
*eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
|
||||
LogTrace(cmd, len, *start_time, *eof_time, NULL, true);
|
||||
}
|
||||
|
||||
/* Sends an APDU to the tag
|
||||
* TODO: check CRC and preamble
|
||||
*/
|
||||
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen) {
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen) {
|
||||
|
||||
LED_A_ON();
|
||||
uint8_t message_frame[message_length + 4];
|
||||
// PCB
|
||||
message_frame[0] = 0x0A | pcb_blocknum;
|
||||
pcb_blocknum ^= 1;
|
||||
// CID
|
||||
message_frame[1] = 0;
|
||||
// INF
|
||||
memcpy(message_frame + 2, message, message_length);
|
||||
// EDC (CRC)
|
||||
AddCrc14B(message_frame, message_length + 2);
|
||||
uint8_t real_cmd[msg_len + 4];
|
||||
|
||||
if (msg_len) {
|
||||
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
|
||||
real_cmd[0] = 0x02; // bnr, nad, cid, chn=0; i-block(0x00)
|
||||
if (send_chaining) {
|
||||
real_cmd[0] |= 0x10;
|
||||
}
|
||||
// put block number into the PCB
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
memcpy(real_cmd + 1, msg, msg_len);
|
||||
} else {
|
||||
// R-block. ACK
|
||||
real_cmd[0] = 0xA2; // r-block + ACK
|
||||
real_cmd[0] |= iso14b_pcb_blocknum;
|
||||
}
|
||||
|
||||
AddCrc14B(real_cmd, msg_len + 1);
|
||||
|
||||
// send
|
||||
uint32_t start_time = 0;
|
||||
uint32_t eof_time = 0;
|
||||
CodeAndTransmit14443bAsReader(message_frame, sizeof(message_frame), &start_time, &eof_time);
|
||||
|
||||
// Get response?
|
||||
if (response == NULL) {
|
||||
LED_A_OFF();
|
||||
return 0;
|
||||
}
|
||||
CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time);
|
||||
|
||||
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
|
||||
int retlen = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
|
||||
int len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (retlen < 3) {
|
||||
LED_A_OFF();
|
||||
return -1;
|
||||
uint8_t *data_bytes = (uint8_t *) response;
|
||||
|
||||
if (len <= 0) {
|
||||
return 0; //DATA LINK ERROR
|
||||
} else {
|
||||
// S-Block WTX
|
||||
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
|
||||
uint32_t save_iso14b_timeout = iso14b_timeout;
|
||||
// temporarily increase timeout
|
||||
iso14b_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14b_timeout, ISO14443B_READER_TIMEOUT));
|
||||
// Transmit WTX back
|
||||
// byte1 - WTXM [1..59]. command FWT=FWT*WTXM
|
||||
data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b
|
||||
// now need to fix CRC.
|
||||
AddCrc14B(data_bytes, len - 2);
|
||||
|
||||
// transmit S-Block
|
||||
CodeAndTransmit14443bAsReader(data_bytes, len, &start_time, &eof_time);
|
||||
|
||||
// retrieve the result again (with increased timeout)
|
||||
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
|
||||
len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
|
||||
FpgaDisableTracing();
|
||||
|
||||
data_bytes = response;
|
||||
// restore timeout
|
||||
iso14b_set_timeout(save_iso14b_timeout);
|
||||
}
|
||||
|
||||
// if we received an I- or R(ACK)-Block with a block number equal to the
|
||||
// current block number, toggle the current block number
|
||||
if (len >= 3 // PCB+CRC = 3 bytes
|
||||
&& ((data_bytes[0] & 0xC0) == 0 // I-Block
|
||||
|| (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
|
||||
&& (data_bytes[0] & 0x01) == iso14b_pcb_blocknum) { // equal block numbers
|
||||
iso14b_pcb_blocknum ^= 1;
|
||||
}
|
||||
|
||||
// if we received I-block with chaining we need to send ACK and receive another block of data
|
||||
if (response)
|
||||
*response = data_bytes[0];
|
||||
|
||||
// crc check
|
||||
if (len >= 3 && !check_crc(CRC_14443_B, data_bytes, len)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// VALIDATE CRC
|
||||
if (!check_crc(CRC_14443_B, response, retlen)) {
|
||||
if (DBGLEVEL > DBG_DEBUG) DbpString("CRC fail");
|
||||
return -2;
|
||||
if (len) {
|
||||
// cut frame byte
|
||||
len -= 1;
|
||||
// memmove(data_bytes, data_bytes + 1, len);
|
||||
for (int i = 0; i < len; i++)
|
||||
data_bytes[i] = data_bytes[i + 1];
|
||||
}
|
||||
|
||||
return retlen;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1272,7 +1322,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
|
|||
int iso14443b_select_card(iso14b_card_select_t *card) {
|
||||
// WUPB command (including CRC)
|
||||
// Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state
|
||||
static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 };
|
||||
// WUTB or REQB is denoted in the third byte, lower nibble. 0 vs 8
|
||||
//static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 };
|
||||
static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xff };
|
||||
|
||||
// ATTRIB command (with space for CRC)
|
||||
uint8_t attrib[] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
|
@ -1350,7 +1403,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
|
|||
}
|
||||
}
|
||||
// reset PCB block number
|
||||
pcb_blocknum = 0;
|
||||
iso14b_pcb_blocknum = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1773,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
|
|||
|
||||
if ((param & ISO14B_APDU) == ISO14B_APDU) {
|
||||
uint8_t buf[100] = {0};
|
||||
status = iso14443b_apdu(cmd, len, buf, sizeof(buf));
|
||||
status = iso14443b_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, sizeof(buf));
|
||||
reply_mix(CMD_HF_ISO14443B_COMMAND, status, status, 0, buf, status);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue