fixed iso14443a-4 similation, got rid of many ugly memory allocation issues

This commit is contained in:
roel@libnfc.org 2013-10-03 14:22:43 +00:00
parent 2fca3ad92d
commit ce02f6f992

View file

@ -775,48 +775,48 @@ static void CodeIso14443aAsTag(const uint8_t *cmd, int len){
CodeIso14443aAsTagPar(cmd, len, GetParity(cmd, len)); CodeIso14443aAsTagPar(cmd, len, GetParity(cmd, len));
} }
//----------------------------------------------------------------------------- ////-----------------------------------------------------------------------------
// This is to send a NACK kind of answer, its only 3 bits, I know it should be 4 //// This is to send a NACK kind of answer, its only 3 bits, I know it should be 4
//----------------------------------------------------------------------------- ////-----------------------------------------------------------------------------
static void CodeStrangeAnswerAsTag() //static void CodeStrangeAnswerAsTag()
{ //{
int i; // int i;
//
ToSendReset(); // ToSendReset();
//
// Correction bit, might be removed when not needed // // Correction bit, might be removed when not needed
ToSendStuffBit(0); // ToSendStuffBit(0);
ToSendStuffBit(0); // ToSendStuffBit(0);
ToSendStuffBit(0); // ToSendStuffBit(0);
ToSendStuffBit(0); // ToSendStuffBit(0);
ToSendStuffBit(1); // 1 // ToSendStuffBit(1); // 1
ToSendStuffBit(0); // ToSendStuffBit(0);
ToSendStuffBit(0); // ToSendStuffBit(0);
ToSendStuffBit(0); // ToSendStuffBit(0);
//
// Send startbit // // Send startbit
ToSend[++ToSendMax] = SEC_D; // ToSend[++ToSendMax] = SEC_D;
//
// 0 // // 0
ToSend[++ToSendMax] = SEC_E; // ToSend[++ToSendMax] = SEC_E;
//
// 0 // // 0
ToSend[++ToSendMax] = SEC_E; // ToSend[++ToSendMax] = SEC_E;
//
// 1 // // 1
ToSend[++ToSendMax] = SEC_D; // ToSend[++ToSendMax] = SEC_D;
//
// Send stopbit // // Send stopbit
ToSend[++ToSendMax] = SEC_F; // ToSend[++ToSendMax] = SEC_F;
//
// Flush the buffer in FPGA!! // // Flush the buffer in FPGA!!
for(i = 0; i < 5; i++) { // for(i = 0; i < 5; i++) {
ToSend[++ToSendMax] = SEC_F; // ToSend[++ToSendMax] = SEC_F;
} // }
//
// Convert from last byte pos to length // // Convert from last byte pos to length
ToSendMax++; // ToSendMax++;
} //}
static void Code4bitAnswerAsTag(uint8_t cmd) static void Code4bitAnswerAsTag(uint8_t cmd)
{ {
@ -908,6 +908,67 @@ int EmSendCmdEx(uint8_t *resp, int respLen, int correctionNeeded);
int EmSendCmd(uint8_t *resp, int respLen); int EmSendCmd(uint8_t *resp, int respLen);
int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par); int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par);
static uint8_t* free_buffer_pointer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET);
typedef struct {
uint8_t* response;
size_t response_n;
uint8_t* modulation;
size_t modulation_n;
} tag_response_info_t;
void reset_free_buffer() {
free_buffer_pointer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET);
}
bool prepare_tag_modulation(tag_response_info_t* response_info, size_t max_buffer_size) {
// Exmaple response, answer to MIFARE Classic read block will be 16 bytes + 2 CRC = 18 bytes
// This will need the following byte array for a modulation sequence
// 144 data bits (18 * 8)
// 18 parity bits
// 2 Start and stop
// 1 Correction bit (Answer in 1172 or 1236 periods, see FPGA)
// 1 just for the case
// ----------- +
// 166 bytes, since every bit that needs to be send costs us a byte
//
// Prepare the tag modulation bits from the message
CodeIso14443aAsTag(response_info->response,response_info->response_n);
// Make sure we do not exceed the free buffer space
if (ToSendMax > max_buffer_size) {
Dbprintf("Out of memory, when modulating bits for tag answer:");
Dbhexdump(response_info->response_n,response_info->response,false);
return false;
}
// Copy the byte array, used for this modulation to the buffer position
memcpy(response_info->modulation,ToSend,ToSendMax);
// Store the number of bytes that were used for encoding/modulation
response_info->modulation_n = ToSendMax;
return true;
}
bool prepare_allocated_tag_modulation(tag_response_info_t* response_info) {
// Retrieve and store the current buffer index
response_info->modulation = free_buffer_pointer;
// Determine the maximum size we can use from our buffer
size_t max_buffer_size = (((uint8_t *)BigBuf)+FREE_BUFFER_OFFSET+FREE_BUFFER_SIZE)-free_buffer_pointer;
// Forward the prepare tag modulation function to the inner function
if (prepare_tag_modulation(response_info,max_buffer_size)) {
// Update the free buffer offset
free_buffer_pointer += ToSendMax;
return true;
} else {
return false;
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Main loop of simulated tag: receive commands from reader, decide what // Main loop of simulated tag: receive commands from reader, decide what
// response to send, and send it. // response to send, and send it.
@ -990,57 +1051,41 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]);
uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce
uint8_t response6[] = { 0x03, 0x3B, 0x00, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS uint8_t response6[] = { 0x04, 0x58, 0x00, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS
ComputeCrc14443(CRC_14443_A, response6, 3, &response6[3], &response6[4]); ComputeCrc14443(CRC_14443_A, response6, 4, &response6[4], &response6[5]);
uint8_t *resp = NULL; #define TAG_RESPONSE_COUNT 7
int respLen; tag_response_info_t responses[TAG_RESPONSE_COUNT] = {
{ .response = response1, .response_n = sizeof(response1) }, // Answer to request - respond with card type
{ .response = response2, .response_n = sizeof(response2) }, // Anticollision cascade1 - respond with uid
{ .response = response2a, .response_n = sizeof(response2a) }, // Anticollision cascade2 - respond with 2nd half of uid if asked
{ .response = response3, .response_n = sizeof(response3) }, // Acknowledge select - cascade 1
{ .response = response3a, .response_n = sizeof(response3a) }, // Acknowledge select - cascade 2
{ .response = response5, .response_n = sizeof(response5) }, // Authentication answer (random nonce)
{ .response = response6, .response_n = sizeof(response6) }, // dummy ATS (pseudo-ATR), answer to RATS
};
// Longest possible response will be 16 bytes + 2 CRC = 18 bytes // Allocate 512 bytes for the dynamic modulation, created when the reader querries for it
// This will need // Such a response is less time critical, so we can prepare them on the fly
// 144 data bits (18 * 8) #define DYNAMIC_RESPONSE_BUFFER_SIZE 64
// 18 parity bits #define DYNAMIC_MODULATION_BUFFER_SIZE 512
// 2 Start and stop uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE];
// 1 Correction bit (Answer in 1172 or 1236 periods, see FPGA) uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE];
// 1 just for the case tag_response_info_t dynamic_response_info = {
// ----------- + .response = dynamic_response_buffer,
// 166 .response_n = 0,
// .modulation = dynamic_modulation_buffer,
// 166 bytes, since every bit that needs to be send costs us a byte .modulation_n = 0
// };
// Respond with card type // Reset the offset pointer of the free buffer
uint8_t *resp1 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); reset_free_buffer();
int resp1Len;
// Prepare the responses of the anticollision phase
// Anticollision cascade1 - respond with uid // there will be not enough time to do this at the moment the reader sends it REQA
uint8_t *resp2 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 166); for (size_t i=0; i<TAG_RESPONSE_COUNT; i++) {
int resp2Len; prepare_allocated_tag_modulation(&responses[i]);
}
// Anticollision cascade2 - respond with 2nd half of uid if asked
// we're only going to be asked if we set the 1st byte of the UID (during cascade1) to 0x88
uint8_t *resp2a = (((uint8_t *)BigBuf) + 1140);
int resp2aLen;
// Acknowledge select - cascade 1
uint8_t *resp3 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + (166*2));
int resp3Len;
// Acknowledge select - cascade 2
uint8_t *resp3a = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + (166*3));
int resp3aLen;
// Response to a read request - not implemented atm
uint8_t *resp4 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + (166*4));
// int resp4Len;
// Authenticate response - nonce
uint8_t *resp5 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + (166*5));
int resp5Len;
// Authenticate response - nonce
uint8_t *resp6 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + (166*6));
int resp6Len;
uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET);
int len; int len;
@ -1052,60 +1097,22 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
// Just to allow some checks // Just to allow some checks
int happened = 0; int happened = 0;
int happened2 = 0; int happened2 = 0;
int cmdsRecvd = 0; int cmdsRecvd = 0;
uint8_t* respdata = NULL;
int respsize = 0;
// uint8_t nack = 0x04;
memset(receivedCmd, 0x44, RECV_CMD_SIZE);
// Prepare the responses of the anticollision phase
// there will be not enough time to do this at the moment the reader sends it REQA
// Answer to request
CodeIso14443aAsTag(response1, sizeof(response1));
memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax;
// Send our UID (cascade 1)
CodeIso14443aAsTag(response2, sizeof(response2));
memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax;
// Answer to select (cascade1)
CodeIso14443aAsTag(response3, sizeof(response3));
memcpy(resp3, ToSend, ToSendMax); resp3Len = ToSendMax;
// Send the cascade 2 2nd part of the uid
CodeIso14443aAsTag(response2a, sizeof(response2a));
memcpy(resp2a, ToSend, ToSendMax); resp2aLen = ToSendMax;
// Answer to select (cascade 2)
CodeIso14443aAsTag(response3a, sizeof(response3a));
memcpy(resp3a, ToSend, ToSendMax); resp3aLen = ToSendMax;
// Strange answer is an example of rare message size (3 bits)
CodeStrangeAnswerAsTag();
memcpy(resp4, ToSend, ToSendMax);// resp4Len = ToSendMax;
// Authentication answer (random nonce)
CodeIso14443aAsTag(response5, sizeof(response5));
memcpy(resp5, ToSend, ToSendMax); resp5Len = ToSendMax;
// dummy ATS (pseudo-ATR), answer to RATS
CodeIso14443aAsTag(response6, sizeof(response6));
memcpy(resp6, ToSend, ToSendMax); resp6Len = ToSendMax;
// We need to listen to the high-frequency, peak-detected path. // We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc();
cmdsRecvd = 0; cmdsRecvd = 0;
tag_response_info_t* p_response;
LED_A_ON(); LED_A_ON();
for(;;) { for(;;) {
// Clean receive command buffer
memset(receivedCmd, 0x44, RECV_CMD_SIZE);
if(!GetIso14443aCommandFromReader(receivedCmd, &len, RECV_CMD_SIZE)) { if(!GetIso14443aCommandFromReader(receivedCmd, &len, RECV_CMD_SIZE)) {
DbpString("button press"); DbpString("Button press");
break; break;
} }
@ -1113,69 +1120,98 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
LogTrace(receivedCmd,len, 0, Uart.parityBits, TRUE); LogTrace(receivedCmd,len, 0, Uart.parityBits, TRUE);
} }
p_response = NULL;
// doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated // doob - added loads of debug strings so we can see what the reader is saying to us during the sim as hi14alist is not populated
// Okay, look at the command now. // Okay, look at the command now.
lastorder = order; lastorder = order;
if(receivedCmd[0] == 0x26) { // Received a REQUEST if(receivedCmd[0] == 0x26) { // Received a REQUEST
resp = resp1; respLen = resp1Len; order = 1; p_response = &responses[0]; order = 1;
respdata = response1;
respsize = sizeof(response1);
} else if(receivedCmd[0] == 0x52) { // Received a WAKEUP } else if(receivedCmd[0] == 0x52) { // Received a WAKEUP
resp = resp1; respLen = resp1Len; order = 6; p_response = &responses[0]; order = 6;
respdata = response1;
respsize = sizeof(response1);
} else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1) } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1)
resp = resp2; respLen = resp2Len; order = 2; p_response = &responses[1]; order = 2;
respdata = response2;
respsize = sizeof(response2);
} else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2)
resp = resp2a; respLen = resp2aLen; order = 20; p_response = &responses[2]; order = 20;
respdata = response2a;
respsize = sizeof(response2a);
} else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1) } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1)
resp = resp3; respLen = resp3Len; order = 3; p_response = &responses[3]; order = 3;
respdata = response3;
respsize = sizeof(response3);
} else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2) } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2)
resp = resp3a; respLen = resp3aLen; order = 30; p_response = &responses[4]; order = 30;
respdata = response3a;
respsize = sizeof(response3a);
} else if(receivedCmd[0] == 0x30) { // Received a (plain) READ } else if(receivedCmd[0] == 0x30) { // Received a (plain) READ
// resp = resp4; respLen = resp4Len; order = 4; // Do nothing
// respdata = &nack;
// respsize = sizeof(nack); // 4-bit answer
EmSendCmdEx(data+(4*receivedCmd[0]),16,false); EmSendCmdEx(data+(4*receivedCmd[0]),16,false);
Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]); Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]);
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
respLen = 0; p_response = NULL;
} else if(receivedCmd[0] == 0x50) { // Received a HALT } else if(receivedCmd[0] == 0x50) { // Received a HALT
// DbpString("Reader requested we HALT!:"); // DbpString("Reader requested we HALT!:");
// Do not respond p_response = NULL;
resp = resp1; respLen = 0; order = 0;
respdata = NULL;
respsize = 0;
} else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request
resp = resp5; respLen = resp5Len; order = 7; p_response = &responses[5]; order = 7;
respdata = response5;
respsize = sizeof(response5);
} else if(receivedCmd[0] == 0xE0) { // Received a RATS request } else if(receivedCmd[0] == 0xE0) { // Received a RATS request
resp = resp6; respLen = resp6Len; order = 70; p_response = &responses[6]; order = 70;
respdata = response6; } else if (order == 7 && len ==8) { // Received authentication request
respsize = sizeof(response6); uint32_t nr = bytes_to_num(receivedCmd,4);
} else { uint32_t ar = bytes_to_num(receivedCmd+4,4);
if (order == 7 && len ==8) { Dbprintf("Auth attempt {nr}{ar}: %08x %08x",nr,ar);
uint32_t nr = bytes_to_num(receivedCmd,4); } else {
uint32_t ar = bytes_to_num(receivedCmd+4,4); // Check for ISO 14443A-4 compliant commands, look at left nibble
Dbprintf("Auth attempt {nr}{ar}: %08x %08x",nr,ar); switch (receivedCmd[0]) {
} else {
// Never seen this command before case 0x0B:
Dbprintf("Received unknown command (len=%d):",len); case 0x0A: { // IBlock (command)
Dbhexdump(len,receivedCmd,false); dynamic_response_info.response[0] = receivedCmd[0];
dynamic_response_info.response[1] = 0x00;
dynamic_response_info.response[2] = 0x90;
dynamic_response_info.response[3] = 0x00;
dynamic_response_info.response_n = 4;
} break;
case 0x1A:
case 0x1B: { // Chaining command
dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1);
dynamic_response_info.response_n = 2;
} break;
case 0xaa:
case 0xbb: {
dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11;
dynamic_response_info.response_n = 2;
} break;
case 0xBA: { //
memcpy(dynamic_response_info.response,"\xAB\x00",2);
dynamic_response_info.response_n = 2;
} break;
case 0xCA:
case 0xC2: { // Readers sends deselect command
memcpy(dynamic_response_info.response,"\xCA\x00",2);
dynamic_response_info.response_n = 2;
} break;
default: {
// Never seen this command before
Dbprintf("Received unknown command (len=%d):",len);
Dbhexdump(len,receivedCmd,false);
// Do not respond
dynamic_response_info.response_n = 0;
} break;
}
if (dynamic_response_info.response_n > 0) {
// Copy the CID from the reader query
dynamic_response_info.response[1] = receivedCmd[1];
// Add CRC bytes, always used in ISO 14443A-4 compliant cards
AppendCrc14443a(dynamic_response_info.response,dynamic_response_info.response_n);
dynamic_response_info.response_n += 2;
if (prepare_tag_modulation(&dynamic_response_info,DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
Dbprintf("Error preparing tag response");
break;
}
p_response = &dynamic_response_info;
} }
// Do not respond
resp = resp1; respLen = 0; order = 0;
respdata = NULL;
respsize = 0;
} }
// Count number of wakeups received after a halt // Count number of wakeups received after a halt
@ -1193,25 +1229,19 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
if(cmdsRecvd > 999) { if(cmdsRecvd > 999) {
DbpString("1000 commands later..."); DbpString("1000 commands later...");
break; break;
} else {
cmdsRecvd++;
} }
cmdsRecvd++;
if(respLen > 0) { if (p_response != NULL) {
EmSendCmd14443aRaw(resp, respLen, receivedCmd[0] == 0x52); EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n, receivedCmd[0] == 0x52);
} if (tracing) {
LogTrace(p_response->response,p_response->response_n,0,SwapBits(GetParity(p_response->response,p_response->response_n),p_response->response_n),FALSE);
if (tracing) { if(traceLen > TRACE_SIZE) {
if (respdata != NULL) { DbpString("Trace full");
LogTrace(respdata,respsize, 0, SwapBits(GetParity(respdata,respsize),respsize), FALSE); // break;
} }
if(traceLen > TRACE_SIZE) { }
DbpString("Trace full"); }
break;
}
}
memset(receivedCmd, 0x44, RECV_CMD_SIZE);
} }
Dbprintf("%x %x %x", happened, happened2, cmdsRecvd); Dbprintf("%x %x %x", happened, happened2, cmdsRecvd);
@ -1242,9 +1272,6 @@ void PrepareDelayedTransfer(uint16_t delay)
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Transmit the command (to the tag) that was placed in ToSend[]. // Transmit the command (to the tag) that was placed in ToSend[].
// Parameter timing: // Parameter timing: