mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-18 19:13:41 +08:00
Make sure we respond in a valid time slot. We were responding too early, the first time slot (which is always allowed) starts after 512 * 64 / fc. Also, respond in incremental time slots. We could have used a fixed time slot (#0 is always allowed), but by using incremental time slots we have a better chance the reader will get our response in the expected time frame. (when our timing is wrong, we have a risk of responding too early when using the first slot, and too late when using the last slot. Slots in the middle of the allowed range have the best chance)
880 lines
30 KiB
C
880 lines
30 KiB
C
#include "felica.h"
|
|
#include "proxmark3_arm.h"
|
|
#include "BigBuf.h"
|
|
#include "util.h"
|
|
#include "protocols.h"
|
|
#include "crc16.h"
|
|
#include "fpgaloader.h"
|
|
#include "string.h"
|
|
#include "commonutil.h"
|
|
#include "dbprint.h"
|
|
#include "ticks.h"
|
|
#include "iso18.h"
|
|
|
|
// FeliCa timings
|
|
// minimum time between the start bits of consecutive transfers from reader to tag: 6800 carrier (13.56MHz) cycles
|
|
#ifndef FELICA_REQUEST_GUARD_TIME
|
|
# define FELICA_REQUEST_GUARD_TIME (6800/16 + 1) // 426
|
|
#endif
|
|
// FRAME DELAY TIME 2672 carrier cycles
|
|
#ifndef FELICA_FRAME_DELAY_TIME
|
|
# define FELICA_FRAME_DELAY_TIME (2672/16 + 1) // 168
|
|
#endif
|
|
#ifndef DELAY_AIR2ARM_AS_READER
|
|
#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) // 91
|
|
#endif
|
|
#ifndef DELAY_ARM2AIR_AS_READER
|
|
#define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) // 209
|
|
#endif
|
|
#define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len))
|
|
|
|
static uint32_t felica_timeout;
|
|
static uint32_t felica_nexttransfertime;
|
|
static uint32_t felica_lasttime_prox2air_start;
|
|
|
|
static void iso18092_setup(uint8_t fpga_minor_mode);
|
|
static uint8_t felica_select_card(felica_card_select_t *card);
|
|
static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed);
|
|
static bool WaitForFelicaReply(uint16_t maxbytes);
|
|
|
|
static void iso18092_set_timeout(uint32_t timeout) {
|
|
felica_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / (16 * 8) + 2;
|
|
}
|
|
|
|
static uint32_t iso18092_get_timeout(void) {
|
|
return felica_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / (16 * 8) - 2;
|
|
}
|
|
|
|
#ifndef FELICA_MAX_FRAME_SIZE
|
|
#define FELICA_MAX_FRAME_SIZE 260
|
|
#endif
|
|
|
|
//structure to hold outgoing NFC frame
|
|
static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE + 4];
|
|
|
|
//structure to hold incoming NFC frame, used for ISO/IEC 18092-compatible frames
|
|
static struct {
|
|
enum {
|
|
STATE_UNSYNCD,
|
|
STATE_TRYING_SYNC,
|
|
STATE_GET_LENGTH,
|
|
STATE_GET_DATA,
|
|
STATE_GET_CRC,
|
|
STATE_FULL
|
|
} state;
|
|
|
|
uint16_t shiftReg; //for synchronization and offset calculation
|
|
int posCnt;
|
|
bool crc_ok;
|
|
int rem_len;
|
|
uint16_t len;
|
|
uint8_t byte_offset;
|
|
uint8_t *framebytes;
|
|
//should be enough. maxlen is 255, 254 for data, 2 for sync, 2 for crc
|
|
// 0,1 -> SYNC, 2 - len, 3-(len+1)->data, then crc
|
|
} FelicaFrame;
|
|
|
|
//b2 4d is SYNC, 45645 in 16-bit notation, 10110010 01001101 binary. Frame will not start filling until this is shifted in
|
|
//bit order in byte -reverse, I guess? [((bt>>0)&1),((bt>>1)&1),((bt>>2)&1),((bt>>3)&1),((bt>>4)&1),((bt>>5)&1),((bt>>6)&1),((bt>>7)&1)] -at least in the mode that I read those in
|
|
#ifndef SYNC_16BIT
|
|
# define SYNC_16BIT 0xB24D
|
|
#endif
|
|
|
|
static void FelicaFrameReset(void) {
|
|
FelicaFrame.state = STATE_UNSYNCD;
|
|
FelicaFrame.posCnt = 0;
|
|
FelicaFrame.crc_ok = false;
|
|
FelicaFrame.byte_offset = 0;
|
|
}
|
|
static void FelicaFrameinit(uint8_t *data) {
|
|
FelicaFrame.framebytes = data;
|
|
FelicaFrameReset();
|
|
}
|
|
|
|
//shift byte into frame, reversing it at the same time
|
|
static void shiftInByte(uint8_t bt) {
|
|
uint8_t j;
|
|
for (j = 0; j < FelicaFrame.byte_offset; j++) {
|
|
FelicaFrame.framebytes[FelicaFrame.posCnt] = (FelicaFrame.framebytes[FelicaFrame.posCnt] << 1) + (bt & 1);
|
|
bt >>= 1;
|
|
}
|
|
FelicaFrame.posCnt++;
|
|
FelicaFrame.rem_len--;
|
|
for (j = FelicaFrame.byte_offset; j < 8; j++) {
|
|
FelicaFrame.framebytes[FelicaFrame.posCnt] = (FelicaFrame.framebytes[FelicaFrame.posCnt] << 1) + (bt & 1);
|
|
bt >>= 1;
|
|
}
|
|
}
|
|
|
|
static void Process18092Byte(uint8_t bt) {
|
|
switch (FelicaFrame.state) {
|
|
case STATE_UNSYNCD: {
|
|
//almost any nonzero byte can be start of SYNC. SYNC should be preceded by zeros, but that is not always the case
|
|
if (bt > 0) {
|
|
FelicaFrame.shiftReg = reflect8(bt);
|
|
FelicaFrame.state = STATE_TRYING_SYNC;
|
|
}
|
|
break;
|
|
}
|
|
case STATE_TRYING_SYNC: {
|
|
if (bt == 0) {
|
|
//desync
|
|
FelicaFrame.shiftReg = bt;
|
|
FelicaFrame.state = STATE_UNSYNCD;
|
|
} else {
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
|
|
if (FelicaFrame.shiftReg == SYNC_16BIT) {
|
|
//SYNC done!
|
|
FelicaFrame.state = STATE_GET_LENGTH;
|
|
FelicaFrame.framebytes[0] = 0xb2;
|
|
FelicaFrame.framebytes[1] = 0x4d;
|
|
FelicaFrame.byte_offset = i;
|
|
//shift in remaining byte, slowly...
|
|
for (uint8_t j = i; j < 8; j++) {
|
|
FelicaFrame.framebytes[2] = (FelicaFrame.framebytes[2] << 1) + (bt & 1);
|
|
bt >>= 1;
|
|
}
|
|
|
|
FelicaFrame.posCnt = 2;
|
|
if (i == 0)
|
|
break;
|
|
}
|
|
FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 1) + (bt & 1);
|
|
bt >>= 1;
|
|
}
|
|
|
|
//that byte was last byte of sync
|
|
if (FelicaFrame.shiftReg == SYNC_16BIT) {
|
|
//Force SYNC on next byte
|
|
FelicaFrame.state = STATE_GET_LENGTH;
|
|
FelicaFrame.framebytes[0] = 0xb2;
|
|
FelicaFrame.framebytes[1] = 0x4d;
|
|
FelicaFrame.byte_offset = 0;
|
|
FelicaFrame.posCnt = 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case STATE_GET_LENGTH: {
|
|
shiftInByte(bt);
|
|
FelicaFrame.rem_len = FelicaFrame.framebytes[2] - 1;
|
|
FelicaFrame.len = FelicaFrame.framebytes[2] + 4; //with crc and sync
|
|
FelicaFrame.state = STATE_GET_DATA;
|
|
break;
|
|
}
|
|
case STATE_GET_DATA: {
|
|
shiftInByte(bt);
|
|
if (FelicaFrame.rem_len <= 0) {
|
|
FelicaFrame.state = STATE_GET_CRC;
|
|
FelicaFrame.rem_len = 2;
|
|
}
|
|
break;
|
|
}
|
|
case STATE_GET_CRC: {
|
|
shiftInByte(bt);
|
|
if (FelicaFrame.rem_len <= 0) {
|
|
FelicaFrame.rem_len = 0;
|
|
// skip sync 2bytes. IF ok, residue should be 0x0000
|
|
FelicaFrame.crc_ok = check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2);
|
|
FelicaFrame.state = STATE_FULL;
|
|
}
|
|
break;
|
|
}
|
|
case STATE_FULL: //ignore byte. Don't forget to clear frame to receive next one...
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Perform FeliCa polling card
|
|
* Currently does NOT do any collision handling.
|
|
* It expects 0-1 cards in the device's range.
|
|
* return 0 if selection was successful
|
|
*/
|
|
static uint8_t felica_select_card(felica_card_select_t *card) {
|
|
|
|
// POLL command
|
|
// 0xB2 0x4B = sync code
|
|
// 0x06 = len
|
|
// 0x00 = rfu
|
|
// 0xff = system code service
|
|
// 0xff = system code service
|
|
// 0x00 = request code
|
|
// b7 = automatic switching of data rate
|
|
// b6-b2 = reserved
|
|
// b1 = fc/32 (414kbps)
|
|
// b0 = fc/64 (212kbps)
|
|
// 0x00 = timeslot
|
|
// 0x09 0x21 = crc
|
|
static uint8_t poll[10] = {0xb2, 0x4d, 0x06, FELICA_POLL_REQ, 0xFF, 0xFF, 0x00, 0x00, 0x09, 0x21};
|
|
int len = 10;
|
|
|
|
// We try 10 times, or if answer was received.
|
|
do {
|
|
// end-of-reception response packet data, wait approx. 501μs
|
|
// end-of-transmission command packet data, wait approx. 197μs
|
|
// polling card
|
|
TransmitFor18092_AsReader(poll, sizeof(poll), NULL, 1, 0);
|
|
|
|
// polling card, break if success
|
|
if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK)
|
|
break;
|
|
|
|
WDT_HIT();
|
|
|
|
} while (--len);
|
|
|
|
// timed-out
|
|
if (len == 0) {
|
|
if (g_dbglevel >= DBG_DEBUG)
|
|
Dbprintf("Error: Time out card selection!");
|
|
return 1;
|
|
}
|
|
|
|
// wrong answer
|
|
if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK) {
|
|
if (g_dbglevel >= DBG_DEBUG)
|
|
Dbprintf("Error: Wrong answer selecting card!");
|
|
return 2;
|
|
}
|
|
|
|
// VALIDATE CRC residue is 0, hence if crc is a value it failed.
|
|
if (!check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2)) {
|
|
if (g_dbglevel >= DBG_DEBUG) {
|
|
Dbprintf("Error: CRC check failed!");
|
|
Dbprintf("CRC check was done on Frame: ");
|
|
Dbhexdump(FelicaFrame.len - 2, FelicaFrame.framebytes + 2, 0);
|
|
}
|
|
return 3;
|
|
}
|
|
|
|
if (g_dbglevel >= DBG_DEBUG)
|
|
Dbprintf("Card selection successful!");
|
|
// copy UID
|
|
// idm 8
|
|
if (card) {
|
|
memcpy(card->IDm, FelicaFrame.framebytes + 4, 8);
|
|
memcpy(card->PMm, FelicaFrame.framebytes + 4 + 8, 8);
|
|
//memcpy(card->servicecode, FelicaFrame.framebytes + 4 + 8 + 8, 2);
|
|
memcpy(card->code, card->IDm, 2);
|
|
memcpy(card->uid, card->IDm + 2, 6);
|
|
memcpy(card->iccode, card->PMm, 2);
|
|
memcpy(card->mrt, card->PMm + 2, 6);
|
|
if (g_dbglevel >= DBG_DEBUG) {
|
|
Dbprintf("Received Frame: ");
|
|
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes, 0);
|
|
}
|
|
}
|
|
// more status bytes?
|
|
return 0;
|
|
}
|
|
|
|
// poll-0: 0xb2,0x4d,0x06,0x00,0xff,0xff,0x00,0x00,0x09,0x21,
|
|
// resp: 0xb2,0x4d,0x12,0x01,0x01,0x2e,0x3d,0x17,0x26,0x47,0x80,0x95,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f,
|
|
// poll-1 (reply with available system codes - NFC Tag3 specs, IIRC): 0xb2,0x4d,0x06,0x00,0xff,0xff,0x01,0x00,0x3a,0x10
|
|
// resp: 0xb2,0x4d,0x14,0x01, 0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX, 0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,0x0c,0xe2,
|
|
// page-req: 0xb2,0x4d,0x10,0x06, 0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX, 0x01, 0x0b,0x00, 0x01, 0x80,0x00, 0x2e,0xb3,
|
|
// page-req: 0x06, IDm(8), ServiceNum(1),Slist(2*num) BLocknum (1) BLockids(2-3*num)
|
|
// page-resp: 0xb2,0x4d,0x1d,0x07, 0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX, 0x00, 0x00, 0x01, 0x10,0x04,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x23, 0xcb,0x6e,
|
|
|
|
// builds a readblock frame for felica lite(s). Using SERVICE: SERVICE_FELICA_LITE_READONLY
|
|
// Felica standard has a different file system, AFAIK,
|
|
// 8-byte IDm, number of blocks, blocks numbers
|
|
// number of blocks limited to 4 for FelicaLite(S)
|
|
static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) {
|
|
if (blocknum > 4 || blocknum <= 0)
|
|
Dbprintf("Invalid number of blocks, %d != 4", blocknum);
|
|
|
|
uint8_t c = 0, i = 0;
|
|
|
|
// Sync bytes
|
|
frameSpace[c++] = 0xb2;
|
|
frameSpace[c++] = 0x4d;
|
|
|
|
c++; //set length later
|
|
|
|
frameSpace[c++] = FELICA_RDBLK_REQ; //command number
|
|
|
|
//card IDm, from poll
|
|
frameSpace[c++] = idm[0];
|
|
frameSpace[c++] = idm[1];
|
|
frameSpace[c++] = idm[2];
|
|
frameSpace[c++] = idm[3];
|
|
frameSpace[c++] = idm[4];
|
|
frameSpace[c++] = idm[5];
|
|
frameSpace[c++] = idm[6];
|
|
frameSpace[c++] = idm[7];
|
|
|
|
//number of services
|
|
frameSpace[c++] = 0x01;
|
|
|
|
//service code
|
|
frameSpace[c++] = (SERVICE_FELICA_LITE_READONLY >> 8);
|
|
frameSpace[c++] = SERVICE_FELICA_LITE_READONLY & 0xFF;
|
|
|
|
//number of blocks
|
|
frameSpace[c++] = blocknum;
|
|
|
|
for (i = 0; i < blocknum; i++) {
|
|
|
|
//3-byte block
|
|
if (blocks[i] >= 256) {
|
|
frameSpace[c++] = 0x00;
|
|
frameSpace[c++] = (blocks[i] >> 8); //block number, little endian....
|
|
frameSpace[c++] = (blocks[i] & 0xff);
|
|
} else {
|
|
frameSpace[c++] = 0x80;
|
|
frameSpace[c++] = blocks[i];
|
|
}
|
|
}
|
|
|
|
//set length
|
|
frameSpace[2] = c - 2;
|
|
//Add CRC
|
|
AddCrc(frameSpace + 2, c - 2);
|
|
}
|
|
|
|
static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) {
|
|
uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092;
|
|
if (power)
|
|
flags |= FPGA_HF_ISO18092_FLAG_READER;
|
|
if (highspeed)
|
|
flags |= FPGA_HF_ISO18092_FLAG_424K;
|
|
|
|
FpgaWriteConfWord(flags);
|
|
|
|
uint32_t curr_transfer_time = ((MAX(felica_nexttransfertime, GetCountSspClk()) & 0xfffffff8) + 8);
|
|
|
|
while (GetCountSspClk() < curr_transfer_time) {};
|
|
|
|
felica_lasttime_prox2air_start = curr_transfer_time;
|
|
|
|
// preamble
|
|
// sending 0x00 0x00 0x00 0x00 0x00 0x00
|
|
uint16_t c = 0;
|
|
while (c < 6) {
|
|
// keep tx buffer in a defined state anyway.
|
|
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
|
|
AT91C_BASE_SSC->SSC_THR = 0x00;
|
|
c++;
|
|
}
|
|
}
|
|
// sending data with sync bytes
|
|
c = 0;
|
|
if (g_dbglevel >= DBG_DEBUG) {
|
|
Dbprintf("Sending frame:");
|
|
Dbhexdump(len, frame, 0);
|
|
}
|
|
|
|
while (c < len) {
|
|
// Put byte into tx holding register as soon as it is ready
|
|
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
|
|
AT91C_BASE_SSC->SSC_THR = frame[c++];
|
|
}
|
|
}
|
|
|
|
/**/
|
|
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) {};
|
|
AT91C_BASE_SSC->SSC_THR = 0x00; //minimum delay
|
|
|
|
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) {};
|
|
AT91C_BASE_SSC->SSC_THR = 0x00; //spin
|
|
/**/
|
|
|
|
// log
|
|
LogTrace(
|
|
frame,
|
|
len,
|
|
(felica_lasttime_prox2air_start << 4) + DELAY_ARM2AIR_AS_READER,
|
|
((felica_lasttime_prox2air_start + felica_lasttime_prox2air_start) << 4) + DELAY_ARM2AIR_AS_READER,
|
|
NULL,
|
|
true
|
|
);
|
|
|
|
felica_nexttransfertime = MAX(felica_nexttransfertime, felica_lasttime_prox2air_start + FELICA_REQUEST_GUARD_TIME);
|
|
}
|
|
|
|
// Wait for tag reply
|
|
// stop when button is pressed
|
|
// or return TRUE when command is captured
|
|
bool WaitForFelicaReply(uint16_t maxbytes) {
|
|
if (g_dbglevel >= DBG_DEBUG)
|
|
Dbprintf("WaitForFelicaReply Start");
|
|
uint32_t c = 0;
|
|
// power, no modulation
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
|
FelicaFrameReset();
|
|
|
|
// clear RXRDY:
|
|
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
|
(void)b;
|
|
|
|
uint32_t timeout = iso18092_get_timeout();
|
|
|
|
for (;;) {
|
|
WDT_HIT();
|
|
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
|
b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
|
Process18092Byte(b);
|
|
if (FelicaFrame.state == STATE_FULL) {
|
|
felica_nexttransfertime = MAX(felica_nexttransfertime,
|
|
(GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME);
|
|
|
|
LogTrace(
|
|
FelicaFrame.framebytes,
|
|
FelicaFrame.len,
|
|
((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER - timeout,
|
|
((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER,
|
|
NULL,
|
|
false
|
|
);
|
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("All bytes received! STATE_FULL");
|
|
return true;
|
|
} else if (c++ > timeout && (FelicaFrame.state == STATE_UNSYNCD || FelicaFrame.state == STATE_TRYING_SYNC)) {
|
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Timeout! STATE_UNSYNCD");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set up FeliCa communication (similar to iso14443a_setup)
|
|
// field is setup for "Sending as Reader"
|
|
static void iso18092_setup(uint8_t fpga_minor_mode) {
|
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Start iso18092_setup");
|
|
|
|
LEDsoff();
|
|
#if defined XC3
|
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
|
#else
|
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF_FELICA);
|
|
#endif
|
|
// allocate command receive buffer
|
|
BigBuf_free();
|
|
BigBuf_Clear_ext(false);
|
|
|
|
// Initialize Demod and Uart structs
|
|
// DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
|
|
FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE));
|
|
|
|
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER;
|
|
iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card
|
|
|
|
init_table(CRC_FELICA);
|
|
|
|
// connect Demodulated Signal to ADC:
|
|
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
|
|
|
// Set up the synchronous serial port
|
|
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO18092);
|
|
|
|
// LSB transfer. Remember to set it back to MSB with
|
|
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
|
|
|
// Signal field is on with the appropriate LED
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | fpga_minor_mode);
|
|
|
|
//20.4 ms generate field, start sending polling command afterwars.
|
|
SpinDelay(100);
|
|
|
|
// Start the timer
|
|
StartCountSspClk();
|
|
|
|
LED_D_ON();
|
|
}
|
|
|
|
static void felica_reset_frame_mode(void) {
|
|
switch_off();
|
|
//Resetting Frame mode (First set in fpgaloader.c)
|
|
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// RAW FeliCa commands. Send out commands and store answers.
|
|
//-----------------------------------------------------------------------------
|
|
// arg0 FeliCa flags
|
|
// arg1 len of commandbytes
|
|
// d.asBytes command bytes to send
|
|
void felica_sendraw(PacketCommandNG *c) {
|
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("FeliCa_sendraw Enter");
|
|
|
|
felica_command_t param = c->oldarg[0];
|
|
size_t len = c->oldarg[1] & 0xffff;
|
|
uint8_t *cmd = c->data.asBytes;
|
|
uint32_t arg0;
|
|
|
|
felica_card_select_t card;
|
|
|
|
if ((param & FELICA_CONNECT))
|
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Clear trace");
|
|
clear_trace();
|
|
|
|
set_tracing(true);
|
|
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
|
|
|
if ((param & FELICA_CONNECT)) {
|
|
// notify client selecting status.
|
|
// if failed selecting, turn off antenna and quite.
|
|
if (!(param & FELICA_NO_SELECT)) {
|
|
arg0 = felica_select_card(&card);
|
|
reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t));
|
|
if (arg0 > 0) {
|
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Error: Failed selecting card! ");
|
|
felica_reset_frame_mode();
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
if (g_dbglevel >= DBG_DEBUG) Dbprintf("No card selection");
|
|
}
|
|
|
|
if ((param & FELICA_RAW)) {
|
|
|
|
// 2 sync, 1 len, 2crc == 5
|
|
uint8_t *buf = BigBuf_malloc(len + 5);
|
|
// add sync bits
|
|
buf[0] = 0xb2;
|
|
buf[1] = 0x4d;
|
|
buf[2] = len;
|
|
|
|
// copy command
|
|
memcpy(buf + 2, cmd, len);
|
|
|
|
if ((param & FELICA_APPEND_CRC)) {
|
|
// Don't append crc on empty bytearray...
|
|
if (len > 0) {
|
|
AddCrc(buf, len);
|
|
}
|
|
}
|
|
if (g_dbglevel >= DBG_DEBUG) {
|
|
Dbprintf("Transmit Frame (no CRC shown):");
|
|
Dbhexdump(len, buf, 0);
|
|
Dbprintf("Buffer Length: %i", buf[2] + 4);
|
|
};
|
|
TransmitFor18092_AsReader(buf, buf[2] + 4, NULL, 1, 0);
|
|
arg0 = WaitForFelicaReply(1024);
|
|
if (g_dbglevel >= DBG_DEBUG) {
|
|
Dbprintf("Received Frame Code: %d", arg0);
|
|
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes, 0);
|
|
};
|
|
|
|
uint32_t result = reply_mix(CMD_ACK, FelicaFrame.len, arg0, 0, FelicaFrame.framebytes, FelicaFrame.len);
|
|
if (result) {
|
|
Dbprintf("Reply to Client Error Code: %i", result);
|
|
}
|
|
}
|
|
if ((param & FELICA_NO_DISCONNECT)) {
|
|
Dbprintf("Disconnect");
|
|
}
|
|
if (g_dbglevel >= DBG_DEBUG)
|
|
Dbprintf("FeliCa_sendraw Exit");
|
|
felica_reset_frame_mode();
|
|
return;
|
|
}
|
|
|
|
void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
|
|
|
clear_trace();
|
|
set_tracing(true);
|
|
iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD);
|
|
|
|
LED_D_ON();
|
|
|
|
int retval = PM3_SUCCESS;
|
|
int remFrames = (samplesToSkip) ? samplesToSkip : 0;
|
|
int trigger_cnt = 0;
|
|
uint32_t timeout = iso18092_get_timeout();
|
|
bool isReaderFrame = true;
|
|
|
|
uint8_t flip = 0;
|
|
uint16_t checker = 0;
|
|
for (;;) {
|
|
|
|
WDT_HIT();
|
|
|
|
// since simulation is a tight time critical loop,
|
|
// we only check for user request to end at iteration 3000, 9000.
|
|
if (flip == 3) {
|
|
if (data_available()) {
|
|
retval = PM3_EOPABORTED;
|
|
break;
|
|
}
|
|
flip = 0;
|
|
}
|
|
|
|
if (checker >= 3000) {
|
|
|
|
if (BUTTON_PRESS()) {
|
|
retval = PM3_EOPABORTED;
|
|
break;
|
|
}
|
|
flip++;
|
|
checker = 0;
|
|
}
|
|
++checker;
|
|
|
|
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
|
|
|
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
|
Process18092Byte(dist);
|
|
|
|
if ((dist >= 178) && (++trigger_cnt > triggersToSkip)) {
|
|
Dbprintf("triggers To skip kicked %d", dist);
|
|
break;
|
|
}
|
|
if (FelicaFrame.state == STATE_FULL) {
|
|
if ((FelicaFrame.framebytes[3] % 2) == 0) {
|
|
isReaderFrame = true; // All Reader Frames are even and all Tag frames are odd
|
|
} else {
|
|
isReaderFrame = false;
|
|
}
|
|
remFrames--;
|
|
if (remFrames <= 0) {
|
|
Dbprintf("Stop Sniffing - samples To skip reached!");
|
|
break;
|
|
}
|
|
LogTrace(FelicaFrame.framebytes,
|
|
FelicaFrame.len,
|
|
((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER - timeout,
|
|
((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER,
|
|
NULL,
|
|
isReaderFrame
|
|
);
|
|
FelicaFrameReset();
|
|
}
|
|
}
|
|
}
|
|
switch_off();
|
|
//reset framing
|
|
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
|
|
|
Dbprintf("Felica sniffing done, tracelen: %i", BigBuf_get_traceLen());
|
|
reply_ng(CMD_HF_FELICA_SNIFF, retval, NULL, 0);
|
|
LED_D_OFF();
|
|
}
|
|
|
|
#define R_POLL0_LEN 0x16
|
|
#define R_POLL1_LEN 0x18
|
|
#define R_READBLK_LEN 0x21
|
|
//simulate NFC Tag3 card - for now only poll response works
|
|
// second half (4 bytes) of NDEF2 goes into nfcid2_0, first into nfcid2_1
|
|
void felica_sim_lite(uint8_t *uid) {
|
|
|
|
// prepare our 3 responses...
|
|
uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2, 0x4d, 0x12, FELICA_POLL_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7f};
|
|
uint8_t resp_poll1[R_POLL1_LEN] = { 0xb2, 0x4d, 0x14, FELICA_POLL_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0x88, 0xb4, 0xb3, 0x7f};
|
|
uint8_t resp_readblk[R_READBLK_LEN] = { 0xb2, 0x4d, 0x1d, FELICA_RDBLK_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x04, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x23, 0xcb, 0x6e};
|
|
|
|
// NFC tag 3/ ISo technically. Many overlapping standards
|
|
DbpString("Felica Lite-S simulation start");
|
|
Dbprintf("NDEF2 UID: %02x %02x %02x %02x %02x %02x %02x %02x",
|
|
uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]
|
|
);
|
|
|
|
// fill in blanks
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
resp_poll0[i + 4] = uid[i];
|
|
resp_poll1[i + 4] = uid[i];
|
|
resp_readblk[i + 4] = uid[i];
|
|
}
|
|
|
|
// calculate and set CRC
|
|
AddCrc(&resp_poll0[2], resp_poll0[2]);
|
|
AddCrc(&resp_poll1[2], resp_poll1[2]);
|
|
AddCrc(&resp_readblk[2], resp_readblk[2]);
|
|
|
|
iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD);
|
|
|
|
int retval = PM3_SUCCESS;
|
|
int curlen = 0;
|
|
uint8_t *curresp = NULL;
|
|
bool listenmode = true;
|
|
// uint32_t frtm = GetCountSspClk();
|
|
|
|
uint8_t flip = 0;
|
|
uint16_t checker = 0;
|
|
for (;;) {
|
|
|
|
WDT_HIT();
|
|
|
|
// since simulation is a tight time critical loop,
|
|
// we only check for user request to end at iteration 3000, 9000.
|
|
if (flip == 3) {
|
|
if (data_available()) {
|
|
retval = PM3_EOPABORTED;
|
|
break;
|
|
}
|
|
flip = 0;
|
|
}
|
|
|
|
if (checker >= 3000) {
|
|
|
|
if (BUTTON_PRESS()) {
|
|
retval = PM3_EOPABORTED;
|
|
break;
|
|
}
|
|
flip++;
|
|
checker = 0;
|
|
}
|
|
++checker;
|
|
|
|
WDT_HIT();
|
|
|
|
if (listenmode) {
|
|
// waiting for request...
|
|
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
|
|
|
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
|
// frtm = GetCountSspClk();
|
|
Process18092Byte(dist);
|
|
|
|
if (FelicaFrame.state == STATE_FULL) {
|
|
|
|
if (FelicaFrame.crc_ok) {
|
|
|
|
if (FelicaFrame.framebytes[2] == 6 && FelicaFrame.framebytes[3] == 0) {
|
|
static uint8_t timeslot = 0;
|
|
|
|
// polling... there are two types of polling we answer to
|
|
if (FelicaFrame.framebytes[6] == 0) {
|
|
curresp = resp_poll0;
|
|
curlen = R_POLL0_LEN;
|
|
listenmode = false;
|
|
}
|
|
if (FelicaFrame.framebytes[6] == 1) {
|
|
curresp = resp_poll1;
|
|
curlen = R_POLL1_LEN;
|
|
listenmode = false;
|
|
}
|
|
if (timeslot > FelicaFrame.framebytes[7]) {
|
|
// framebytes[7] contains the maximum time slot in which we are allowed to respond (#0..#15)
|
|
timeslot = 0;
|
|
}
|
|
// first time slot (#0) starts after 512 * 64 / fc, slot length equals 256 * 64 / fc
|
|
felica_nexttransfertime = GetCountSspClk() - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + (512 + timeslot * 256) * 64 / 16 + 1;
|
|
timeslot++; // we should use a random time slot, but responding in incremental slots should do just fine for now
|
|
}
|
|
|
|
if (FelicaFrame.framebytes[2] > 5 && FelicaFrame.framebytes[3] == 0x06) {
|
|
// we should rebuild it depending on page size, but...
|
|
// Let's see first
|
|
curresp = resp_readblk;
|
|
curlen = R_READBLK_LEN;
|
|
listenmode = false;
|
|
}
|
|
// clear frame
|
|
FelicaFrameReset();
|
|
} else {
|
|
// frame invalid, clear it out to allow for the next one
|
|
FelicaFrameReset();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (listenmode == false) {
|
|
// trying to answer... here to start answering immediately.
|
|
// this one is a bit finicky. Seems that being a bit late is better than earlier
|
|
// TransmitFor18092_AsReader(curresp, curlen, frtm+512, 0, 0);
|
|
TransmitFor18092_AsReader(curresp, curlen, NULL, 0, 0);
|
|
|
|
// switch back
|
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD);
|
|
|
|
FelicaFrameReset();
|
|
listenmode = true;
|
|
curlen = 0;
|
|
curresp = NULL;
|
|
}
|
|
}
|
|
|
|
switch_off();
|
|
|
|
// reset framing
|
|
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
|
|
|
Dbprintf("FeliCa Lite-S emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
|
|
reply_ng(CMD_HF_FELICALITE_SIMULATE, retval, NULL, 0);
|
|
}
|
|
|
|
#define RES_SVC_LEN 11 + 3
|
|
|
|
void felica_dump_lite_s(void) {
|
|
uint8_t ndef[8];
|
|
uint8_t poll[10] = { 0xb2, 0x4d, 0x06, FELICA_POLL_REQ, 0xff, 0xff, 0x00, 0x00, 0x09, 0x21};
|
|
uint16_t liteblks[28] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x90, 0x91, 0x92, 0xa0};
|
|
|
|
// setup device.
|
|
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
|
|
|
uint8_t blknum;
|
|
bool isOK = false;
|
|
uint16_t cnt = 0, cntfails = 0;
|
|
uint8_t *dest = BigBuf_get_addr();
|
|
|
|
while (!BUTTON_PRESS() && !data_available()) {
|
|
WDT_HIT();
|
|
// polling?
|
|
//TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0);
|
|
TransmitFor18092_AsReader(poll, 10, NULL, 1, 0);
|
|
|
|
if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) {
|
|
// copy 8bytes to ndef.
|
|
memcpy(ndef, FelicaFrame.framebytes + 4, 8);
|
|
// for (c=0; c < 8; c++)
|
|
// ndef[c] = FelicaFrame.framebytes[c+4];
|
|
|
|
for (blknum = 0; blknum < ARRAYLEN(liteblks);) {
|
|
// block to read.
|
|
BuildFliteRdblk(ndef, 1, &liteblks[blknum]);
|
|
|
|
//TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, GetCountSspClk()+512, 1, 0);
|
|
|
|
|
|
|
|
TransmitFor18092_AsReader(frameSpace, frameSpace[2] + 4, NULL, 1, 0);
|
|
// read block
|
|
if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) {
|
|
|
|
dest[cnt++] = liteblks[blknum];
|
|
|
|
uint8_t *fb = FelicaFrame.framebytes;
|
|
dest[cnt++] = fb[12];
|
|
dest[cnt++] = fb[13];
|
|
|
|
//memcpy(dest+cnt, FelicaFrame.framebytes + 15, 16);
|
|
//cnt += 16;
|
|
for (uint8_t j = 0; j < 16; j++)
|
|
dest[cnt++] = fb[15 + j];
|
|
|
|
blknum++;
|
|
cntfails = 0;
|
|
|
|
// // print raw log.
|
|
// Dbprintf("LEN %u | Dump bytes count %u ", FelicaFrame.len, cnt);
|
|
Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes + 15, 0);
|
|
} else {
|
|
cntfails++;
|
|
if (cntfails > 12) {
|
|
blknum++;
|
|
cntfails = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
isOK = true;
|
|
break;
|
|
}
|
|
}
|
|
switch_off();
|
|
|
|
//Resetting Frame mode (First set in fpgaloader.c)
|
|
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
|
|
|
//setting tracelen - important! it was set by buffer overflow before
|
|
set_tracelen(cnt);
|
|
reply_mix(CMD_ACK, isOK, cnt, 0, 0, 0);
|
|
}
|