X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/b7d3e89923d418c8a7b6acf1ca74f45b436be26d..refs/pull/504/head:/armsrc/iso14443a.c?ds=sidebyside

diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c
index 45425e07..a0fe2326 100644
--- a/armsrc/iso14443a.c
+++ b/armsrc/iso14443a.c
@@ -81,6 +81,8 @@ typedef struct {
 } tUart;
 
 static uint32_t iso14a_timeout;
+#define MAX_ISO14A_TIMEOUT 524288
+
 int rsamples = 0;
 uint8_t trigger = 0;
 // the block number for the ISO14443-4 PCB
@@ -187,33 +189,15 @@ void iso14a_set_trigger(bool enable) {
 
 
 void iso14a_set_timeout(uint32_t timeout) {
-	iso14a_timeout = timeout;
-	if(MF_DBGLEVEL >= 3) Dbprintf("ISO14443A Timeout set to %ld (%dms)", iso14a_timeout, iso14a_timeout / 106);
+	iso14a_timeout = timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8);
+	if(MF_DBGLEVEL >= 3) Dbprintf("ISO14443A Timeout set to %ld (%dms)", timeout, timeout / 106);
 }
 
 
-static void iso14a_set_ATS_timeout(uint8_t *ats) {
-
-	uint8_t tb1;
-	uint8_t fwi; 
-	uint32_t fwt;
-	
-	if (ats[0] > 1) {							// there is a format byte T0
-		if ((ats[1] & 0x20) == 0x20) {			// there is an interface byte TB(1)
-			if ((ats[1] & 0x10) == 0x10) {		// there is an interface byte TA(1) preceding TB(1)
-				tb1 = ats[3];
-			} else {
-				tb1 = ats[2];
-			}
-			fwi = (tb1 & 0xf0) >> 4;			// frame waiting indicator (FWI)
-			fwt = 256 * 16 * (1 << fwi);		// frame waiting time (FWT) in 1/fc
-			
-			iso14a_set_timeout(fwt/(8*16));
-		}
-	}
+uint32_t iso14a_get_timeout(void) {
+	return iso14a_timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8);
 }
 
-
 //-----------------------------------------------------------------------------
 // Generate the parity value for a byte sequence
 //
@@ -901,11 +885,11 @@ static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int
 }
 
 
-static int EmSend4bitEx(uint8_t resp, bool correctionNeeded);
+static int EmSend4bitEx(uint8_t resp);
 int EmSend4bit(uint8_t resp);
-static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, bool correctionNeeded, uint8_t *par);
-int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool correctionNeeded);
-int EmSendPrecompiledCmd(tag_response_info_t *response_info, bool correctionNeeded);
+static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
+int EmSendCmdEx(uint8_t *resp, uint16_t respLen);
+int EmSendPrecompiledCmd(tag_response_info_t *response_info);
 
 
 static bool prepare_tag_modulation(tag_response_info_t* response_info, size_t max_buffer_size) {
@@ -1139,7 +1123,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
 		} else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) {	// Received a SELECT (cascade 2)
 			p_response = &responses[4]; order = 30;
 		} else if(receivedCmd[0] == 0x30) {	// Received a (plain) READ
-			EmSendCmdEx(data+(4*receivedCmd[1]),16,false);
+			EmSendCmdEx(data+(4*receivedCmd[1]),16);
 			// 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
 			p_response = NULL;
@@ -1232,7 +1216,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
 		cmdsRecvd++;
 
 		if (p_response != NULL) {
-			EmSendPrecompiledCmd(p_response, receivedCmd[0] == 0x52);
+			EmSendPrecompiledCmd(p_response);
 		}
 		
 		if (!tracing) {
@@ -1275,7 +1259,7 @@ static void PrepareDelayedTransfer(uint16_t delay)
 // Transmit the command (to the tag) that was placed in ToSend[].
 // Parameter timing:
 // if NULL: transfer at next possible time, taking into account
-// 			request guard time and frame delay time
+// 			request guard time, startup frame guard time and frame delay time
 // if == 0:	transfer immediately and return time of transfer
 // if != 0: delay transfer until time specified
 //-------------------------------------------------------------------------------------
@@ -1414,12 +1398,6 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity)
 	int analogCnt = 0;
 	int analogAVG = 0;
 
-	// Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
-	// only, since we are receiving, not transmitting).
-	// Signal field is off with the appropriate LED
-	LED_D_OFF();
-	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
-
 	// Set ADC to read field strength
 	AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
 	AT91C_BASE_ADC->ADC_MR =
@@ -1430,12 +1408,23 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity)
 	// start ADC
 	AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
 	
-	// Now run a 'software UART' on the stream of incoming samples.
+	// Run a 'software UART' on the stream of incoming samples.
 	UartInit(received, parity);
 
-	// Clear RXRDY:
-    uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
-	
+	// Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN
+	do {
+		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+			AT91C_BASE_SSC->SSC_THR = SEC_F;
+			uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; (void) b;
+		}
+	} while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3));
+
+	// Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
+	// only, since we are receiving, not transmitting).
+	// Signal field is off with the appropriate LED
+	LED_D_OFF();
+	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
+
 	for(;;) {
 		WDT_HIT();
 
@@ -1461,7 +1450,7 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity)
 
 		// receive and test the miller decoding
         if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
-            b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
+            uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
 			if(MillerDecoding(b, 0)) {
 				*len = Uart.len;
 				EmLogTraceReader();
@@ -1473,18 +1462,27 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity)
 }
 
 
-static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen, bool correctionNeeded)
+static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen)
 {
 	uint8_t b;
 	uint16_t i = 0;
-	
+	bool correctionNeeded;
+
 	// Modulate Manchester
 	FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
 
 	// include correction bit if necessary
-	if (Uart.parityBits & 0x01) {
-		correctionNeeded = true;
+	if (Uart.bitCount == 7)
+	{
+		// Short tags (7 bits) don't have parity, determine the correct value from MSB
+		correctionNeeded = Uart.output[0] & 0x40;
 	}
+	else
+	{
+		// Look at the last parity bit
+		correctionNeeded = Uart.parity[(Uart.len-1)/8] & (0x80 >> ((Uart.len-1) & 7));
+	}
+
 	if(correctionNeeded) {
 		// 1236, so correction bit needed
 		i = 0;
@@ -1518,23 +1516,13 @@ static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen, bool correctionNe
 		}
 	}
 
-	// Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again:
-	uint8_t fpga_queued_bits = FpgaSendQueueDelay >> 3;
-	for (i = 0; i < fpga_queued_bits/8; ) {
-		if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
-			AT91C_BASE_SSC->SSC_THR = SEC_F;
-			FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
-			i++;
-		}
-	}
-
 	return 0;
 }
 
 
-static int EmSend4bitEx(uint8_t resp, bool correctionNeeded){
+static int EmSend4bitEx(uint8_t resp){
 	Code4bitAnswerAsTag(resp);
-	int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded);
+	int res = EmSendCmd14443aRaw(ToSend, ToSendMax);
 	// do the tracing for the previous reader request and this tag answer:
 	EmLogTraceTag(&resp, 1, NULL, LastProxToAirDuration);
 	return res;
@@ -1542,40 +1530,40 @@ static int EmSend4bitEx(uint8_t resp, bool correctionNeeded){
 
 
 int EmSend4bit(uint8_t resp){
-	return EmSend4bitEx(resp, false);
+	return EmSend4bitEx(resp);
 }
 
 
-static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, bool correctionNeeded, uint8_t *par){
+static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par){
 	CodeIso14443aAsTagPar(resp, respLen, par);
-	int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded);
+	int res = EmSendCmd14443aRaw(ToSend, ToSendMax);
 	// do the tracing for the previous reader request and this tag answer:
 	EmLogTraceTag(resp, respLen, par, LastProxToAirDuration);
 	return res;
 }
 
 
-int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool correctionNeeded){
+int EmSendCmdEx(uint8_t *resp, uint16_t respLen){
 	uint8_t par[MAX_PARITY_SIZE];
 	GetParity(resp, respLen, par);
-	return EmSendCmdExPar(resp, respLen, correctionNeeded, par);
+	return EmSendCmdExPar(resp, respLen, par);
 }
 
 
 int EmSendCmd(uint8_t *resp, uint16_t respLen){
 	uint8_t par[MAX_PARITY_SIZE];
 	GetParity(resp, respLen, par);
-	return EmSendCmdExPar(resp, respLen, false, par);
+	return EmSendCmdExPar(resp, respLen, par);
 }
 
 
 int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){
-	return EmSendCmdExPar(resp, respLen, false, par);
+	return EmSendCmdExPar(resp, respLen, par);
 }
 
 
-int EmSendPrecompiledCmd(tag_response_info_t *response_info, bool correctionNeeded) {
-	int ret = EmSendCmd14443aRaw(response_info->modulation, response_info->modulation_n, correctionNeeded);
+int EmSendPrecompiledCmd(tag_response_info_t *response_info) {
+	int ret = EmSendCmd14443aRaw(response_info->modulation, response_info->modulation_n);
 	// do the tracing for the previous reader request and this tag answer:
 	EmLogTraceTag(response_info->response, response_info->response_n, &(response_info->par), response_info->ProxToAirDuration);
 	return ret;
@@ -1679,6 +1667,59 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity)
 	return Demod.len;
 }
 
+
+static void iso14a_set_ATS_times(uint8_t *ats) {
+
+	uint8_t tb1;
+	uint8_t fwi, sfgi; 
+	uint32_t fwt, sfgt;
+	
+	if (ats[0] > 1) {							// there is a format byte T0
+		if ((ats[1] & 0x20) == 0x20) {			// there is an interface byte TB(1)
+			if ((ats[1] & 0x10) == 0x10) {		// there is an interface byte TA(1) preceding TB(1)
+				tb1 = ats[3];
+			} else {
+				tb1 = ats[2];
+			}
+			fwi = (tb1 & 0xf0) >> 4;			// frame waiting time integer (FWI)
+			if (fwi != 15) {
+				fwt = 256 * 16 * (1 << fwi);	// frame waiting time (FWT) in 1/fc
+				iso14a_set_timeout(fwt/(8*16));
+			}
+			sfgi = tb1 & 0x0f;					// startup frame guard time integer (SFGI)
+			if (sfgi != 0 && sfgi != 15) {
+				sfgt = 256 * 16 * (1 << sfgi);	// startup frame guard time (SFGT) in 1/fc
+				NextTransferTime = MAX(NextTransferTime, Demod.endTime + (sfgt - DELAY_AIR2ARM_AS_READER - DELAY_ARM2AIR_AS_READER)/16);
+			}
+		}
+	}
+}
+
+
+static int GetATQA(uint8_t *resp, uint8_t *resp_par) {
+
+#define WUPA_RETRY_TIMEOUT	10	// 10ms
+	uint8_t wupa[]       = { 0x52 };  // 0x26 - REQA  0x52 - WAKE-UP
+
+	uint32_t save_iso14a_timeout = iso14a_get_timeout();
+	iso14a_set_timeout(1236/(16*8)+1);		// response to WUPA is expected at exactly 1236/fc. No need to wait longer.
+	
+	uint32_t start_time = GetTickCount();
+	int len;
+	
+	// we may need several tries if we did send an unknown command or a wrong authentication before...
+	do {
+		// Broadcast for a card, WUPA (0x52) will force response from all cards in the field
+		ReaderTransmitBitsPar(wupa, 7, NULL, NULL);
+		// Receive the ATQA
+		len = ReaderReceive(resp, resp_par);
+	} while (len == 0 && GetTickCount() <= start_time + WUPA_RETRY_TIMEOUT);
+			
+	iso14a_set_timeout(save_iso14a_timeout);
+	return len;
+}
+
+
 // performs iso14443a anticollision (optional) and card select procedure
 // fills the uid and cuid pointer unless NULL
 // fills the card info record unless NULL
@@ -1686,7 +1727,6 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity)
 // and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID)
 // requests ATS unless no_rats is true
 int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) {
-	uint8_t wupa[]       = { 0x52 };  // 0x26 - REQA  0x52 - WAKE-UP
 	uint8_t sel_all[]    = { 0x93,0x20 };
 	uint8_t sel_uid[]    = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 	uint8_t rats[]       = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0
@@ -1706,11 +1746,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
 		p_hi14a_card->ats_len = 0;
 	}
 
-	// Broadcast for a card, WUPA (0x52) will force response from all cards in the field
-    ReaderTransmitBitsPar(wupa, 7, NULL, NULL);
-	
-	// Receive the ATQA
-	if(!ReaderReceive(resp, resp_par)) return 0;
+	if (!GetATQA(resp, resp_par)) {
+		return 0;
+	}
 
 	if(p_hi14a_card) {
 		memcpy(p_hi14a_card->atqa, resp, 2);
@@ -1839,8 +1877,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
 		// reset the PCB block number
 		iso14_pcb_blocknum = 0;
 
-		// set default timeout based on ATS
-		iso14a_set_ATS_timeout(resp);
+		// set default timeout and delay next transfer based on ATS
+		iso14a_set_ATS_times(resp);
+		
 	}
 	return 1;	
 }
@@ -1871,7 +1910,30 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
 	iso14a_set_timeout(1060); // 10ms default
 }
 
-
+/* Peter Fillmore 2015
+Added card id field to the function
+ info from ISO14443A standard
+b1 = Block Number
+b2 = RFU (always 1)
+b3 = depends on block
+b4 = Card ID following if set to 1
+b5 = depends on block type
+b6 = depends on block type
+b7,b8 = block type.
+Coding of I-BLOCK:
+b8 b7 b6 b5 b4 b3 b2 b1
+0  0  0  x  x  x  1  x
+b5 = chaining bit
+Coding of R-block:
+b8 b7 b6 b5 b4 b3 b2 b1
+1  0  1  x  x  0  1  x
+b5 = ACK/NACK
+Coding of S-block:
+b8 b7 b6 b5 b4 b3 b2 b1
+1  1  x  x  x  0  1  0 
+b5,b6 = 00 - DESELECT
+        11 - WTX 
+*/    
 int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
 	uint8_t parity[MAX_PARITY_SIZE];
 	uint8_t real_cmd[cmd_len + 4];
@@ -1890,10 +1952,28 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
 
 	if (!len) {
 		return 0; //DATA LINK ERROR
-		
-	// if we received an I- or R(ACK)-Block with a block number equal to the
-	// current block number, toggle the current block number
 	} else{
+		// S-Block WTX 
+		while((data_bytes[0] & 0xF2) == 0xF2) {
+			uint32_t save_iso14a_timeout = iso14a_timeout;
+			// temporarily increase timeout
+			iso14a_timeout = MAX((data_bytes[1] & 0x3f) * iso14a_timeout, MAX_ISO14A_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.
+			AppendCrc14443a(data_bytes, len - 2);
+			// transmit S-Block
+			ReaderTransmit(data_bytes, len, NULL);
+			// retrieve the result again (with increased timeout) 
+			len = ReaderReceive(data, parity);
+			data_bytes = data;
+			// restore timeout
+			iso14a_timeout = save_iso14a_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