micetools/src/micetools/dll/devices/ser_tn32msec.c

401 lines
13 KiB
C

#include "_devices.h"
static BYTE read_one(com_device_t* dev) {
while (!comdev_available(dev)) Sleep(50);
BYTE data;
comdev_read(dev, &data, 1);
return data;
}
BYTE extra[0xff];
/**
* 51 and 55 are guesses based on the code. Makes sense given their opcodes
* too.
* TODO: Validate against a real board
*/
enum TN32_Opcode {
TN32Op_Unknown20 = 0x20, // where did this come from??
TN32Op_GetFWVersion = 0x30,
TN32Op_GetHWVersion = 0x32,
TN32Op_RadioOn = 0x40,
TN32Op_RadioOff = 0x41,
TN32Op_Poll = 0x42,
TN32Op_MifareSelectTag = 0x43,
TN32Op_Unknown44 = 0x44, // Present in code, not seen used
TN32Op_SetKeyBana = 0x50,
TN32Op_GetKeyBana = 0x51,
TN32Op_ReadBlock = 0x52,
TN32Op_Unknown53 = 0x53, // Present in code, not seen used
TN32Op_SetKeyAime = 0x54,
TN32Op_GetKeyAime = 0x55,
// Firmware update (I think)
TN32Op_Unknown60 = 0x60, // Present in code, not seen used
TN32Op_Unknown61 = 0x61, // Present in code, not seen used
TN32Op_Reset = 0x62,
TN32Op_Unknown63 = 0x63,
TN32Op_Unknown64 = 0x64,
TN32Op_Unknown70 = 0x70, // Present in code, not seen used
TN32Op_FelicaEncap = 0x71,
// No responses to either
LedUnknown80 = 0x80,
LedSetColour = 0x81,
LedGetInfo = 0xf0,
LedF2 = 0xf2,
LedF3 = 0xf3,
LedF4 = 0xf4,
LedReset = 0xf5,
};
char* OpcodeNames[256];
const char FWVer[] = "TN32MSEC003S F/W Ver1.2";
const char HWVer[] = "TN32MSEC003S H/W Ver3.0";
#define CardType_Mifare 0x10
#define CardType_FeliCa 0x20
#pragma pack(push, 1)
typedef struct NFCMifare {
BYTE type;
BYTE id_len;
DWORD uid;
} NFCMifare_t;
typedef struct NFCFelica {
BYTE type;
BYTE id_len;
uint64_t IDm;
uint64_t PMm;
} NFCFelica_t;
typedef struct MifareBlock {
BYTE bytes[16];
} MifareBlock_t;
typedef struct MifareSector {
MifareBlock_t blocks[4];
} MifareSector_t;
typedef struct MifareMemory_t {
MifareSector_t sectors[16];
} MifareMemory_t;
typedef struct FelicaBlock {
BYTE bytes[16];
} FelicaBlock_t;
typedef struct FelicaMemory {
FelicaBlock_t dataBlocks[15];
FelicaBlock_t systemBlocks[9];
} FelicaMemory_t;
#pragma pack(pop)
MifareMemory_t mifareMemory;
FelicaMemory_t felicaMemory;
BYTE luid[10] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89 };
#define PMm_VALUE 0x00F1000000014300ULL
#define FelicaSystemBlock_RC 0x00
#define FelicaSystemBlock_MAC 0x01
#define FelicaSystemBlock_ID 0x02
#define FelicaSystemBlock_D_ID 0x03
#define FelicaSystemBlock_SER_C 0x04
#define FelicaSystemBlock_SYS_C 0x05
#define FelicaSystemBlock_CKV 0x06
#define FelicaSystemBlock_CK 0x07
#define FelicaSystemBlock_MC 0x08
void populate_felica(NFCFelica_t* card) {
card->type = CardType_FeliCa;
card->id_len = sizeof(card->IDm) + sizeof(card->PMm);
card->IDm = _byteswap_uint64(0x012E4CD8A30A39B3ULL);
card->PMm = _byteswap_uint64(PMm_VALUE);
// Key name
felicaMemory.dataBlocks[0x0D].bytes[0] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[1] = 0x02;
felicaMemory.dataBlocks[0x0D].bytes[2] = 'N';
felicaMemory.dataBlocks[0x0D].bytes[3] = 'B';
felicaMemory.dataBlocks[0x0D].bytes[4] = 'G';
felicaMemory.dataBlocks[0x0D].bytes[5] = 'I';
felicaMemory.dataBlocks[0x0D].bytes[6] = 'C';
felicaMemory.dataBlocks[0x0D].bytes[7] = '0';
// Setup the fake blowfish data
felicaMemory.dataBlocks[0x0D].bytes[8] = 0x89;
felicaMemory.dataBlocks[0x0D].bytes[9] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[10] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[11] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[12] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[13] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[14] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[15] = 0x00;
BYTE block0[16] = {
0xC2, 0x1C, 0xCB, 0xC7, 0x58, 0xCA, 0x81, 0xB7,
0xC0, 0x0B, 0x8E, 0x3A, 0x45, 0x43, 0xFE, 0xFC,
};
memcpy(felicaMemory.dataBlocks[0].bytes, block0, 16);
memset(felicaMemory.dataBlocks[0x0e].bytes, 0xFF, 16);
BYTE blockID[16] = {
// IDd (=IDm)
0x01, 0x2E, 0x4C, 0xD8, 0xA3, 0x0A, 0x39, 0xB3,
// ID
0x00, 0x2a, 0x05, 0x73, 0x02, 0x01, 0x03, 0x00,
// ^DFC^ ^~~~~~ arbitary value
};
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_ID].bytes, blockID, 16);
BYTE blockDID[16] = {
// IDd (=IDm)
0x01,
0x2E,
0x4C,
0xD8,
0xA3,
0x0A,
0x39,
0xB3,
// PMm
0x00,
0xF1,
0x00,
0x00,
0x00,
0x01,
0x43,
0x00,
};
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_D_ID].bytes, blockDID, 16);
}
void populate_mifare(NFCMifare_t* card) {
card->type = CardType_Mifare;
card->id_len = sizeof(card->uid);
card->uid = _byteswap_ulong(0x01020304);
// TODO: Better state haha
// Flash the card memory
for (BYTE i = 0; i < 10; i++) {
BYTE b = luid[i];
mifareMemory.sectors[0].blocks[2].bytes[i + 6] = b;
mifareMemory.sectors[0].blocks[1].bytes[i + 6] = b;
}
}
void nfc_poll(com_device_t* dev, comio_recv_head_t* req) {
BYTE data[256];
BYTE nbytes = 1;
// felica present
if (GetAsyncKeyState('L') < 0) {
NFCFelica_t card;
populate_felica(&card);
memcpy(data + nbytes, &card, sizeof card);
nbytes += sizeof card;
data[0]++;
}
// mifare (aime, bana) present
if (GetAsyncKeyState('P') < 0) {
NFCMifare_t card;
populate_mifare(&card);
memcpy(data + nbytes, &card, sizeof card);
nbytes += sizeof card;
data[0]++;
}
comio_reply(dev, req, COMIO_STATUS_OK, nbytes, data);
}
BYTE AIME_KEY[6];
BYTE BANA_KEY[6];
DWORD WINAPI aime_bd_thread(com_device_t* dev) {
static int fwNumBytes = 0;
log_info("aime_bd", "%ls woke up", dev->com->wName);
bool radio = false;
while (1) {
comio_recv_head_t req;
unsigned char sum = comio_next_req(dev, &req, extra);
log_info("aime_bd", "(%d) %02x(%d) = %s", req.dst, req.op, req.length, OpcodeNames[req.op]);
if (req.dst == 0x00 || req.dst == 0x01) {
// Aime readers
switch (req.op) {
case TN32Op_Reset:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_GetFWVersion:
// BYTE fver = 0x10;
// comio_reply(dev, &req, COMIO_STATUS_OK, 1, &fver);
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1, (LPBYTE)FWVer);
break;
case TN32Op_GetHWVersion:
// BYTE hver = 0x10;
// comio_reply(dev, &req, COMIO_STATUS_OK, 1, &hver);
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1, (LPBYTE)HWVer);
break;
case TN32Op_SetKeyAime:
if (req.length != sizeof AIME_KEY) {
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
} else {
memcpy(AIME_KEY, extra, sizeof AIME_KEY);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info("aime_bd", "Aime key: %02x %02x %02x %02x %02x %02x", AIME_KEY[0],
AIME_KEY[1], AIME_KEY[2], AIME_KEY[3], AIME_KEY[4], AIME_KEY[5]);
}
break;
case TN32Op_SetKeyBana:
if (req.length != sizeof BANA_KEY) {
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
} else {
memcpy(BANA_KEY, extra, sizeof BANA_KEY);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info("aime_bd", "Bana key: %02x %02x %02x %02x %02x %02x", BANA_KEY[0],
BANA_KEY[1], BANA_KEY[2], BANA_KEY[3], BANA_KEY[4], BANA_KEY[5]);
}
break;
case TN32Op_RadioOn:
radio = true;
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_RadioOff:
radio = false;
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_Poll:
nfc_poll(dev, &req);
break;
case TN32Op_GetKeyBana:
case TN32Op_GetKeyAime:
if (req.length != 5) {
//
}
case TN32Op_Unknown44:
case TN32Op_MifareSelectTag:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_Unknown60:
// req.length == 0; start firmware update?
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_Unknown61:
// null-terminated line of the firmware hex!
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info("aime_bd", "Recv firmware: %s", extra);
break;
case TN32Op_Unknown63:
// req.length == 0; start binary firmware update?
fwNumBytes = 0;
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_Unknown64:
// Raw binary firmware data
// [req.length == 256 -> wraps to 00] [256 bytes]
if (req.length == 0) {
unsigned char update_buffer[256];
update_buffer[0] = sum;
comio_read(dev, update_buffer + 1, 255);
// We need to account for the actual checksum at the end of this lot
comio_read(dev, &sum, 1);
fwNumBytes += 256;
} else {
fwNumBytes += req.length;
}
// nxAuth is segfaulting past this. Rather than figure it out, let's just
// protect it from itself for now.
if (fwNumBytes >= 0x3000)
;
else
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
// TODO: These
case TN32Op_ReadBlock:
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
break;
case TN32Op_FelicaEncap:
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
break;
}
} else if (req.dst == 0x08 || req.dst == 0x09) {
// LED sub-boards
switch (req.op) {
case LedReset:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case LedGetInfo:
// TODO: I'm not sure what this actually means.
// 838-15084 is probably a part number
comio_reply(dev, &req, COMIO_STATUS_OK, 9, (BYTE*)"15084\xff\x10\x00\x12");
break;
case LedSetColour:
log_misc("nfc", "Set LED: #%02x%02x%02x", extra[0], extra[1], extra[2]);
printf(
"\033[48;2;%d;%d;%dm "
" \033[0m",
extra[0], extra[1], extra[2]);
// No response expected here!
break;
}
}
Sleep(50);
}
}
void install_aime_bd() {
ZeroMemory(OpcodeNames, sizeof OpcodeNames);
OpcodeNames[TN32Op_Unknown20] = "Unknown20";
OpcodeNames[TN32Op_GetFWVersion] = "GetFWVersion";
OpcodeNames[TN32Op_GetHWVersion] = "GetHWVersion";
OpcodeNames[TN32Op_RadioOn] = "RadioOn";
OpcodeNames[TN32Op_RadioOff] = "RadioOff";
OpcodeNames[TN32Op_Poll] = "Poll";
OpcodeNames[TN32Op_MifareSelectTag] = "MifareSelectTag";
OpcodeNames[TN32Op_Unknown44] = "Unknown44";
OpcodeNames[TN32Op_SetKeyBana] = "SetKeyBana";
OpcodeNames[TN32Op_GetKeyBana] = "GetKeyBana";
OpcodeNames[TN32Op_ReadBlock] = "ReadBlock";
OpcodeNames[TN32Op_Unknown53] = "Unknown53";
OpcodeNames[TN32Op_SetKeyAime] = "SetKeyAime";
OpcodeNames[TN32Op_GetKeyAime] = "GetKeyAime";
OpcodeNames[TN32Op_Unknown60] = "Unknown60";
OpcodeNames[TN32Op_Unknown61] = "Unknown61";
OpcodeNames[TN32Op_Reset] = "Reset";
OpcodeNames[TN32Op_Unknown70] = "Unknown70";
OpcodeNames[TN32Op_FelicaEncap] = "FelicaEncap";
OpcodeNames[LedReset] = "LedReset";
OpcodeNames[LedGetInfo] = "LedGetInfo";
OpcodeNames[LedSetColour] = "LedSetColour";
char* text = MiceConfig.devices.aime_bd;
char* copy = (char*)malloc(strlen(text) + 1);
memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1);
char* next_token;
char* token = strtok_s(copy, ",", &next_token);
while (token != NULL) {
BYTE com_port = atoi(token) & 0xFF;
if (com_port) com_device_thread(new_com_device(com_port), aime_bd_thread);
token = strtok_s(NULL, ",", &next_token);
}
free(copy);
}