openpcd/openpicc/application/iso14443a_pretender.c

275 lines
6.8 KiB
C

/***************************************************************
*
* OpenPICC - ISO 14443 Layer 3 response pretender,
* proof of concept
*
* Copyright 2008 Henryk Plötz <henryk@ploetzli.ch>
*
***************************************************************
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <FreeRTOS.h>
#include <board.h>
#include <task.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "openpicc.h"
#include "ssc_buffer.h"
#include "iso14443.h"
#include "iso14443_layer2a.h"
#include "iso14443a_pretender.h"
#include "iso14443a_manchester.h"
#include "usb_print.h"
#include "cmd.h"
extern volatile int fdt_offset;
#include "led.h"
static const iso14443_frame ATQA_FRAME = {
TYPE_A,
{{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
2,
0, 0,
{4, 0},
{}
};
static const iso14443_frame UID_FRAME = {
TYPE_A,
{{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
5,
0, 0,
{0xF4, 0xAC, 0xF9, 0xD7, 0x76},
{}
};
static const iso14443_frame ATS_FRAME = {
TYPE_A,
{{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
3,
0, 0,
{0x08, 0xB6, 0xDD},
{}
};
static const iso14443_frame NONCE_FRAME = {
TYPE_A,
{{STANDARD_FRAME, PARITY, ISO14443A_LAST_BIT_NONE, CRC_UNCALCULATED}},
4,
0, 0,
{0xFF, 0xCF, 0x80, 0xE3},
{}
};
#define FRAME_SIZE(bytes) (2* (1+(9*bytes)+1) )
#define SIZED_BUFFER(bytes) struct { int len; u_int8_t data[FRAME_SIZE(bytes)]; }
static ssc_dma_tx_buffer_t ATQA_BUFFER, UID_BUFFER, ATS_BUFFER, NONCE_BUFFER;
static void fast_receive_callback(ssc_dma_rx_buffer_t *buffer, u_int8_t in_irq)
{
(void)buffer; (void)in_irq;
unsigned int buffy=0;
u_int32_t cv = *AT91C_TC2_CV;
ssc_dma_tx_buffer_t *tx_buffer=NULL;
int fdt = 0;
switch(buffer->len_transfers) {
case 3: case 4: /* REQA (7 bits) */
//case 7: case 8: case 9:
case 11:
tx_buffer = &ATQA_BUFFER;
fdt = 1172;
break;
case 6: case 7: /* ANTICOL (2 bytes) */
case 8: case 9:
tx_buffer = &UID_BUFFER;
fdt = 1172;
case 21: case 22: /* SELECT (9 bytes) */
tx_buffer = &ATS_BUFFER;
fdt = 1172;
break;
case 577:
usb_print_string_f("f", 0);
buffy=(unsigned int)buffer;
break;
}
/* Add some extra room to the fdt for testing */
//fdt += 3*128;
fdt += fdt_offset;
if(tx_buffer != NULL) {
tx_buffer->state = SSC_FULL;
if( iso14443_transmit(tx_buffer, fdt, 1, 0) < 0) {
usb_print_string_f("Tx failed ", 0);
}
}
u_int32_t cv2 = *AT91C_TC2_CV;
int old=usb_print_set_default_flush(0);
DumpUIntToUSB(cv);
DumpStringToUSB(":");
DumpUIntToUSB(cv2);
if(buffy!=0) {
DumpStringToUSB("§");
DumpUIntToUSB(buffy);
}
usb_print_set_default_flush(old);
usb_print_string_f("%", 0);
}
void iso14443a_pretender (void *pvParameters)
{
(void)pvParameters;
int res;
/* Delay until USB print etc. are ready */
int i;
for(i=0; i<=1000; i++) {
vLedSetBrightness(LED_RED, i);
vLedSetBrightness(LED_GREEN, i);
vTaskDelay(1*portTICK_RATE_MS);
}
for(i=0; i<=1000; i+=4) {
vLedSetBrightness(LED_GREEN, 1000-i);
vTaskDelay(1*portTICK_RATE_MS);
}
int ret;
#define PREFILL_BUFFER(dst, src) ret = manchester_encode(dst.data, sizeof(dst.data), &src); \
if(ret < 0) goto prefill_failed; else dst.len = ret;
PREFILL_BUFFER(ATQA_BUFFER, ATQA_FRAME);
PREFILL_BUFFER(UID_BUFFER, UID_FRAME);
PREFILL_BUFFER(ATS_BUFFER, ATS_FRAME);
PREFILL_BUFFER(NONCE_BUFFER, NONCE_FRAME);
if(0) {
prefill_failed:
usb_print_string("Buffer prefilling failed\n\r");
while(1) {
for(i=1000; i<=3000; i++) {
vLedSetBrightness(LED_GREEN, abs(1000-(i%2000)));
vTaskDelay(1*portTICK_RATE_MS);
}
}
}
do {
res = iso14443_layer2a_init(1);
if(res < 0) {
usb_print_string("Pretender: Initialization failed\n\r");
for(i=0; i<=10000; i++) {
vLedSetBrightness(LED_RED, abs(1000-(i%2000)));
vTaskDelay(1*portTICK_RATE_MS);
}
}
} while(res < 0);
usb_print_string("Waiting for carrier. ");
while(iso14443_wait_for_carrier(1000 * portTICK_RATE_MS) != 0) {
}
usb_print_string("Carrier detected.\n\r");
for(i=0; i<=1000; i+=4) {
vLedSetBrightness(LED_RED, 1000-i);
vTaskDelay(1*portTICK_RATE_MS);
}
vTaskDelay(250*portTICK_RATE_MS);
vLedSetGreen(0);
vLedSetRed(0);
int current_detected = 0, last_detected = 0;
portTickType last_switched = 0;
#define DETECTED_14443A_3 1
#define DETECTED_14443A_4 2
#define DETECTED_MIFARE 4
while(true) {
ssc_dma_rx_buffer_t *buffer = 0;
res = iso14443_receive(fast_receive_callback, &buffer, 1000 * portTICK_RATE_MS);
if(res >= 0) {
DumpUIntToUSB(buffer->len_transfers);
DumpStringToUSB("\n\r");
switch(buffer->len_transfers) {
case 3: case 4: /* REQA (7 bits) */
current_detected |= DETECTED_14443A_3;
break;
case 6: case 7: /* ANTICOL (2 bytes) */
case 22: /* SELECT (9 bytes) */
current_detected |= DETECTED_14443A_3;
break;
case 10: case 11: /* AUTH1A (or any other four byte frame) */
case 19: case 20: /* AUTH2 (8 bytes) */
current_detected |= DETECTED_MIFARE;
break;
}
portENTER_CRITICAL();
buffer->state = SSC_FREE;
portEXIT_CRITICAL();
} else {
if(res != -ETIMEDOUT) {
usb_print_string("Receive error: ");
switch(res) {
case -ENETDOWN: usb_print_string("PLL is not locked or PLL lock lost\n\r"); break;
case -EBUSY: usb_print_string("A Tx is currently running or pending, can't receive\n\r"); break;
case -EALREADY: usb_print_string("There's already an iso14443_receive() invocation running\n\r"); break;
}
vTaskDelay(1000 * portTICK_RATE_MS); // FIXME Proper error handling, e.g. wait for Tx end in case of EBUSY
} else if(0) {
DumpStringToUSB("\n\r");
DumpTimeToUSB(xTaskGetTickCount());
usb_print_string(": -- Mark --");
}
}
if( last_switched < xTaskGetTickCount()-(1000*portTICK_RATE_MS) ) {
last_detected = current_detected;
current_detected = 0;
last_switched = xTaskGetTickCount();
}
#if 0
if(last_detected & (DETECTED_14443A_3 | DETECTED_14443A_4 | DETECTED_MIFARE)) {
if(last_detected & DETECTED_MIFARE) {
vLedSetGreen(0);
vLedSetRed(1);
} else if(last_detected & DETECTED_14443A_4) {
vLedSetGreen(1);
vLedSetRed(0);
} else {
vLedSetGreen(1);
vLedSetRed(1);
}
} else {
vLedSetGreen(0);
vLedSetRed(0);
}
#endif
}
}