mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-11-21 04:50:29 -08:00
924 lines
31 KiB
C
924 lines
31 KiB
C
//-----------------------------------------------------------------------------
|
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
|
//
|
|
// 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, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// 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.
|
|
//
|
|
// See LICENSE.txt for the text of the license.
|
|
//-----------------------------------------------------------------------------
|
|
#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
|
|
# define FELICA_REQUEST_GUARD_TIME ((512 + 0 * 256) * 64 / 16 + 1)
|
|
#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(const uint8_t *frame, uint16_t len, const uint32_t *NYI_timing_NYI, 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};
|
|
|
|
|
|
// We try 10 times, or if answer was received.
|
|
int len = 25;
|
|
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);
|
|
|
|
// 1. timed-out
|
|
if (len == 0) {
|
|
return 1;
|
|
}
|
|
|
|
// 2. wrong answer
|
|
if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK) {
|
|
return 2;
|
|
}
|
|
|
|
// 3. wrong crc. residue is 0, hence if crc is a value it failed.
|
|
if (check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2) == false) {
|
|
|
|
if (g_dbglevel >= DBG_DEBUG) {
|
|
Dbprintf("Error: CRC check failed!");
|
|
Dbhexdump(FelicaFrame.len - 2, FelicaFrame.framebytes + 2, 0);
|
|
}
|
|
return 3;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
// 0. OK
|
|
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(const uint8_t *idm, uint8_t blocknum, const 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(const uint8_t *frame, uint16_t len, const uint32_t *NYI_timing_NYI, uint8_t power, uint8_t highspeed) {
|
|
|
|
if (NYI_timing_NYI != NULL) {
|
|
DbpString("Error: TransmitFor18092_AsReader does not check or set parameter NYI_timing_NYI");
|
|
return;
|
|
}
|
|
|
|
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;
|
|
|
|
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
|
|
);
|
|
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) {
|
|
|
|
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_calloc(FELICA_MAX_FRAME_SIZE));
|
|
|
|
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; // 418
|
|
// iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card
|
|
iso18092_set_timeout(1060); // 106 * 10ms 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(const PacketCommandNG *c) {
|
|
|
|
felica_command_t param = c->oldarg[0];
|
|
size_t len = c->oldarg[1] & 0xffff;
|
|
uint32_t arg0;
|
|
|
|
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
|
clear_trace();
|
|
}
|
|
set_tracing(true);
|
|
|
|
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
|
|
|
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
|
|
|
// notify client selecting status.
|
|
// if failed selecting, turn off antenna and quite.
|
|
if ((param & FELICA_NO_SELECT) != FELICA_NO_SELECT) {
|
|
|
|
felica_card_select_t card;
|
|
arg0 = felica_select_card(&card);
|
|
reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t));
|
|
if (arg0) {
|
|
felica_reset_frame_mode();
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ((param & FELICA_RAW) == FELICA_RAW) {
|
|
|
|
// 2 sync, 1 len, 2crc == 5
|
|
uint8_t *buf = BigBuf_calloc(len + 5);
|
|
// add sync bits
|
|
buf[0] = 0xb2;
|
|
buf[1] = 0x4d;
|
|
buf[2] = len;
|
|
|
|
// copy command
|
|
memcpy(buf + 2, c->data.asBytes, len);
|
|
|
|
if ((param & FELICA_APPEND_CRC) == FELICA_APPEND_CRC) {
|
|
// Don't append crc on empty bytearray...
|
|
if (len > 0) {
|
|
AddCrc(buf + 2, 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) == FELICA_NO_DISCONNECT) {
|
|
return;
|
|
}
|
|
|
|
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;
|
|
|
|
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(const 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;
|
|
const 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() == false) && (data_available() == false)) {
|
|
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];
|
|
|
|
const 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
|
|
// iceman: is this still needed?!?
|
|
set_tracelen(cnt);
|
|
reply_mix(CMD_ACK, isOK, cnt, 0, 0, 0);
|
|
}
|