mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 13:00:42 -07:00
make style
This commit is contained in:
parent
ee40840a14
commit
ac233a346a
6 changed files with 689 additions and 670 deletions
|
@ -880,7 +880,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
uint8_t downlink_mode;
|
uint8_t downlink_mode;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *payload = (struct p *) packet->data.asBytes;
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
T55xxReadBlock(payload->page, payload->pwdmode, false, payload->blockno, payload->password,payload->downlink_mode);
|
T55xxReadBlock(payload->page, payload->pwdmode, false, payload->blockno, payload->password, payload->downlink_mode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_T55XX_WRITE_BLOCK: {
|
case CMD_T55XX_WRITE_BLOCK: {
|
||||||
|
@ -889,15 +889,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_T55XX_WAKEUP: {
|
case CMD_T55XX_WAKEUP: {
|
||||||
T55xxWakeUp(packet->oldarg[0],packet->oldarg[1]);
|
T55xxWakeUp(packet->oldarg[0], packet->oldarg[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_T55XX_RESET_READ: {
|
case CMD_T55XX_RESET_READ: {
|
||||||
T55xxResetRead(packet->data.asBytes[0]&0xff);
|
T55xxResetRead(packet->data.asBytes[0] & 0xff);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_T55XX_CHKPWDS: {
|
case CMD_T55XX_CHKPWDS: {
|
||||||
T55xx_ChkPwds(packet->data.asBytes[0]&0xff);
|
T55xx_ChkPwds(packet->data.asBytes[0] & 0xff);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_PCF7931_READ: {
|
case CMD_PCF7931_READ: {
|
||||||
|
|
|
@ -106,7 +106,7 @@ void T55xxResetRead(uint8_t flags);
|
||||||
//id T55xxWriteBlock(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
|
//id T55xxWriteBlock(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
|
||||||
void T55xxWriteBlock(uint8_t *data);
|
void T55xxWriteBlock(uint8_t *data);
|
||||||
// void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
|
// void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
|
||||||
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd,uint8_t downlink_mode);
|
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd, uint8_t downlink_mode);
|
||||||
void T55xxWakeUp(uint32_t Pwd, uint8_t flags);
|
void T55xxWakeUp(uint32_t Pwd, uint8_t flags);
|
||||||
void T55xx_ChkPwds(uint8_t flags);
|
void T55xx_ChkPwds(uint8_t flags);
|
||||||
|
|
||||||
|
|
170
armsrc/lfops.c
170
armsrc/lfops.c
|
@ -113,16 +113,22 @@
|
||||||
/*
|
/*
|
||||||
// Note: Moved * 8 to apply when used. Saving 28 bytes here (- the *8) and 28 bytes flash.
|
// Note: Moved * 8 to apply when used. Saving 28 bytes here (- the *8) and 28 bytes flash.
|
||||||
// StartGap WriteGap Bit 0/00 Bit 1/01 Bit 10 Bit 11 ReadGap
|
// StartGap WriteGap Bit 0/00 Bit 1/01 Bit 10 Bit 11 ReadGap
|
||||||
t55xx_config T55xx_Timing = {{{ 29 , 17 , 15 , 50 , 0 , 0 , 15 }, // Default Fixed
|
t55xx_config T55xx_Timing = {{
|
||||||
|
{ 29 , 17 , 15 , 50 , 0 , 0 , 15 }, // Default Fixed
|
||||||
{ 31 , 20 , 18 , 50 , 0 , 0 , 15 }, // Long Leading Ref.
|
{ 31 , 20 , 18 , 50 , 0 , 0 , 15 }, // Long Leading Ref.
|
||||||
{ 31 , 20 , 18 , 40 , 0 , 0 , 15 }, // Leading 0
|
{ 31 , 20 , 18 , 40 , 0 , 0 , 15 }, // Leading 0
|
||||||
{ 29 , 17 , 15 , 31 , 47 , 63 , 15 } }}; // 1 of 4
|
{ 29 , 17 , 15 , 31 , 47 , 63 , 15 } // 1 of 4
|
||||||
|
}
|
||||||
|
};
|
||||||
*/
|
*/
|
||||||
// StartGap WriteGap Bit 0/00 Bit 1/01 Bit 10 Bit 11 ReadGap
|
// StartGap WriteGap Bit 0/00 Bit 1/01 Bit 10 Bit 11 ReadGap
|
||||||
t55xx_config T55xx_Timing = {{{ 29 * 8 , 17 * 8 , 15 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }, // Default Fixed
|
t55xx_config T55xx_Timing = {{
|
||||||
{ 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }, // Long Leading Ref.
|
{ 29 * 8, 17 * 8, 15 * 8, 50 * 8, 0, 0, 15 * 8 }, // Default Fixed
|
||||||
{ 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 }, // Leading 0
|
{ 31 * 8, 20 * 8, 18 * 8, 50 * 8, 0, 0, 15 * 8 }, // Long Leading Ref.
|
||||||
{ 29 * 8 , 17 * 8 , 15 * 8 , 31 * 8 , 47 * 8, 63 * 8, 15 * 8 } }}; // 1 of 4
|
{ 31 * 8, 20 * 8, 18 * 8, 40 * 8, 0, 0, 15 * 8 }, // Leading 0
|
||||||
|
{ 29 * 8, 17 * 8, 15 * 8, 31 * 8, 47 * 8, 63 * 8, 15 * 8 } // 1 of 4
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Some defines for readability
|
// Some defines for readability
|
||||||
|
@ -137,16 +143,24 @@ void printT55xxConfig(void) {
|
||||||
|
|
||||||
DbpString(_BLUE_("LF T55XX config"));
|
DbpString(_BLUE_("LF T55XX config"));
|
||||||
for (DLMode = 0; DLMode < 4; DLMode++) {
|
for (DLMode = 0; DLMode < 4; DLMode++) {
|
||||||
switch (DLMode){
|
switch (DLMode) {
|
||||||
case T55xx_DLMode_Fixed : Dbprintf("r 0 fixed bit length (default)"); break;
|
case T55xx_DLMode_Fixed :
|
||||||
case T55xx_DLMode_LLR : Dbprintf("r 1 long leading reference"); break;
|
Dbprintf("r 0 fixed bit length (default)");
|
||||||
case T55xx_DLMode_Leading0 : Dbprintf("r 2 leading zero"); break;
|
break;
|
||||||
case T55xx_DLMode_1of4 : Dbprintf("r 3 1 of 4 coding reference"); break;
|
case T55xx_DLMode_LLR :
|
||||||
|
Dbprintf("r 1 long leading reference");
|
||||||
|
break;
|
||||||
|
case T55xx_DLMode_Leading0 :
|
||||||
|
Dbprintf("r 2 leading zero");
|
||||||
|
break;
|
||||||
|
case T55xx_DLMode_1of4 :
|
||||||
|
Dbprintf("r 3 1 of 4 coding reference");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Dbprintf(" [a] startgap............%d*8 (%d)", T55xx_Timing.m[DLMode].start_gap / 8, T55xx_Timing.m[DLMode].start_gap);
|
Dbprintf(" [a] startgap............%d*8 (%d)", T55xx_Timing.m[DLMode].start_gap / 8, T55xx_Timing.m[DLMode].start_gap);
|
||||||
Dbprintf(" [b] writegap............%d*8 (%d)", T55xx_Timing.m[DLMode].write_gap / 8, T55xx_Timing.m[DLMode].write_gap);
|
Dbprintf(" [b] writegap............%d*8 (%d)", T55xx_Timing.m[DLMode].write_gap / 8, T55xx_Timing.m[DLMode].write_gap);
|
||||||
Dbprintf(" [c] write_0.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_0 / 8, T55xx_Timing.m[DLMode].write_0 );
|
Dbprintf(" [c] write_0.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_0 / 8, T55xx_Timing.m[DLMode].write_0);
|
||||||
Dbprintf(" [d] write_1.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_1 / 8, T55xx_Timing.m[DLMode].write_1 );
|
Dbprintf(" [d] write_1.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_1 / 8, T55xx_Timing.m[DLMode].write_1);
|
||||||
if (DLMode == T55xx_DLMode_1of4) {
|
if (DLMode == T55xx_DLMode_1of4) {
|
||||||
Dbprintf(" [e] write_2.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_2 / 8, T55xx_Timing.m[DLMode].write_2);
|
Dbprintf(" [e] write_2.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_2 / 8, T55xx_Timing.m[DLMode].write_2);
|
||||||
Dbprintf(" [f] write_3.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_3 / 8, T55xx_Timing.m[DLMode].write_3);
|
Dbprintf(" [f] write_3.............%d*8 (%d)", T55xx_Timing.m[DLMode].write_3 / 8, T55xx_Timing.m[DLMode].write_3);
|
||||||
|
@ -168,8 +182,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) {
|
||||||
if (DLMode == T55xx_DLMode_1of4) {
|
if (DLMode == T55xx_DLMode_1of4) {
|
||||||
if (c->m[DLMode].write_2 != 0) T55xx_Timing.m[DLMode].write_2 = c->m[DLMode].write_2;// * 8;
|
if (c->m[DLMode].write_2 != 0) T55xx_Timing.m[DLMode].write_2 = c->m[DLMode].write_2;// * 8;
|
||||||
if (c->m[DLMode].write_3 != 0) T55xx_Timing.m[DLMode].write_3 = c->m[DLMode].write_3;// * 8 ;
|
if (c->m[DLMode].write_3 != 0) T55xx_Timing.m[DLMode].write_3 = c->m[DLMode].write_3;// * 8 ;
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
T55xx_Timing.m[DLMode].write_2 = 0x00;
|
T55xx_Timing.m[DLMode].write_2 = 0x00;
|
||||||
T55xx_Timing.m[DLMode].write_3 = 0x00;
|
T55xx_Timing.m[DLMode].write_3 = 0x00;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +225,7 @@ void setT55xxConfig(uint8_t arg0, t55xx_config *c) {
|
||||||
if (res == T55XX_CONFIG_LEN && DBGLEVEL > 1) {
|
if (res == T55XX_CONFIG_LEN && DBGLEVEL > 1) {
|
||||||
DbpString("T55XX Config save success");
|
DbpString("T55XX Config save success");
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1481,16 +1494,26 @@ void T55xxWriteBit(uint8_t bit, uint8_t downlink_idx) {
|
||||||
|
|
||||||
// Dbprintf ("%d",bit);
|
// Dbprintf ("%d",bit);
|
||||||
// If bit = 4 Send Long Leading Reference which is (138*8) + WRITE_0
|
// If bit = 4 Send Long Leading Reference which is (138*8) + WRITE_0
|
||||||
switch (bit){
|
switch (bit) {
|
||||||
case 0 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_0 ); break; // Send bit 0/00
|
case 0 :
|
||||||
case 1 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_1 ); break; // Send bit 1/01
|
TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_0);
|
||||||
case 2 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_2 ); break; // Send bits 10 (1 of 4)
|
break; // Send bit 0/00
|
||||||
case 3 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_3 ); break; // Send bits 11 (1 of 4)
|
case 1 :
|
||||||
case 4 : TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_0 + (136 * 8)); break; // Send Long Leading Reference
|
TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_1);
|
||||||
|
break; // Send bit 1/01
|
||||||
|
case 2 :
|
||||||
|
TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_2);
|
||||||
|
break; // Send bits 10 (1 of 4)
|
||||||
|
case 3 :
|
||||||
|
TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_3);
|
||||||
|
break; // Send bits 11 (1 of 4)
|
||||||
|
case 4 :
|
||||||
|
TurnReadLFOn(T55xx_Timing.m[downlink_idx].write_0 + (136 * 8));
|
||||||
|
break; // Send Long Leading Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
WaitUS(T55xx_Timing.m[downlink_idx].write_gap );
|
WaitUS(T55xx_Timing.m[downlink_idx].write_gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to abstract an Arbitrary length byte array to store bit pattern.
|
// Function to abstract an Arbitrary length byte array to store bit pattern.
|
||||||
|
@ -1500,33 +1523,31 @@ void T55xxWriteBit(uint8_t bit, uint8_t downlink_idx) {
|
||||||
// num_bits - how many bits (low x bits of data) Max 32 bits at a time
|
// num_bits - how many bits (low x bits of data) Max 32 bits at a time
|
||||||
// max_len - how many bytes can the bit_array hold (ensure no buffer overflow)
|
// max_len - how many bytes can the bit_array hold (ensure no buffer overflow)
|
||||||
// returns "Next" bit offset / bits stored (for next store)
|
// returns "Next" bit offset / bits stored (for next store)
|
||||||
uint8_t T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len)
|
uint8_t T55xx_SetBits(uint8_t *BitStream, uint8_t start_offset, uint32_t data, uint8_t num_bits, uint8_t max_len) {
|
||||||
{
|
|
||||||
int8_t offset;
|
int8_t offset;
|
||||||
int8_t NextOffset = start_offset;
|
int8_t NextOffset = start_offset;
|
||||||
|
|
||||||
// Check if data will fit.
|
// Check if data will fit.
|
||||||
if ((start_offset + num_bits) <= (max_len*8)) {
|
if ((start_offset + num_bits) <= (max_len * 8)) {
|
||||||
// Loop through the data and store
|
// Loop through the data and store
|
||||||
for (offset = (num_bits-1); offset >= 0; offset--) {
|
for (offset = (num_bits - 1); offset >= 0; offset--) {
|
||||||
|
|
||||||
if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1
|
if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1
|
||||||
else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0
|
else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0
|
||||||
|
|
||||||
NextOffset++;
|
NextOffset++;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Note: This should never happen unless some code changes cause it.
|
// Note: This should never happen unless some code changes cause it.
|
||||||
// So short message for coders when testing.
|
// So short message for coders when testing.
|
||||||
Dbprintf ("T55 too many bits");
|
Dbprintf("T55 too many bits");
|
||||||
}
|
}
|
||||||
return NextOffset;
|
return NextOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send one downlink command to the card
|
// Send one downlink command to the card
|
||||||
// void T55xx_SendCMD (uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) {
|
// void T55xx_SendCMD (uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) {
|
||||||
void T55xx_SendCMD (uint32_t Data, uint32_t Pwd, uint16_t arg) {
|
void T55xx_SendCMD(uint32_t Data, uint32_t Pwd, uint16_t arg) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
arg bits
|
arg bits
|
||||||
|
@ -1539,7 +1560,6 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Pwd, uint16_t arg) {
|
||||||
xxxx 1xxxxxxx 0x080 reset
|
xxxx 1xxxxxxx 0x080 reset
|
||||||
xxx1 xxxxxxxx 0x100 brute force
|
xxx1 xxxxxxxx 0x100 brute force
|
||||||
111x xxxxxxxx 0xE00 Block
|
111x xxxxxxxx 0xE00 Block
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint8_t downlink_mode = (arg >> 3) & 0x03;
|
uint8_t downlink_mode = (arg >> 3) & 0x03;
|
||||||
|
@ -1554,44 +1574,43 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Pwd, uint16_t arg) {
|
||||||
if (brute_mem) start_wait = 0;
|
if (brute_mem) start_wait = 0;
|
||||||
|
|
||||||
// Build Bit Stream to send.
|
// Build Bit Stream to send.
|
||||||
memset (BitStream,0x00,sizeof(BitStream));
|
memset(BitStream, 0x00, sizeof(BitStream));
|
||||||
|
|
||||||
BitStreamLen = 0; // Ensure 0 bit index to start.
|
BitStreamLen = 0; // Ensure 0 bit index to start.
|
||||||
|
|
||||||
// Add Leading 0 and 1 of 4 reference bit
|
// Add Leading 0 and 1 of 4 reference bit
|
||||||
if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4))
|
if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4))
|
||||||
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
|
BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, 0, 1, sizeof(BitStream));
|
||||||
|
|
||||||
// Add extra reference 0 for 1 of 4
|
// Add extra reference 0 for 1 of 4
|
||||||
if (downlink_mode == T55xx_DLMode_1of4)
|
if (downlink_mode == T55xx_DLMode_1of4)
|
||||||
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
|
BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, 0, 1, sizeof(BitStream));
|
||||||
|
|
||||||
// Add Opcode
|
// Add Opcode
|
||||||
if (t55_send_Reset) {
|
if (t55_send_Reset) {
|
||||||
// Reset : r*) 00
|
// Reset : r*) 00
|
||||||
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
|
BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, 0, 2, sizeof(BitStream));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (t55_send_TestMode) Dbprintf("TestMODE");
|
if (t55_send_TestMode) Dbprintf("TestMODE");
|
||||||
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,t55_send_TestMode ? 0 : 1 , 1,sizeof(BitStream));
|
BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, t55_send_TestMode ? 0 : 1, 1, sizeof(BitStream));
|
||||||
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,t55_send_TestMode ? 1 : t55_send_Page , 1,sizeof(BitStream));
|
BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, t55_send_TestMode ? 1 : t55_send_Page, 1, sizeof(BitStream));
|
||||||
//if (PwdMode) {
|
//if (PwdMode) {
|
||||||
if (t55_send_PwdMode) {
|
if (t55_send_PwdMode) {
|
||||||
// Leading 0 and 1 of 4 00 fixed bits if passsword used
|
// Leading 0 and 1 of 4 00 fixed bits if passsword used
|
||||||
if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) {
|
if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) {
|
||||||
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
|
BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, 0, 2, sizeof(BitStream));
|
||||||
}
|
}
|
||||||
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream));
|
BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, Pwd, 32, sizeof(BitStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add Lock bit 0
|
// Add Lock bit 0
|
||||||
if (!t55_send_RegReadMode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
|
if (!t55_send_RegReadMode) BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, 0, 1, sizeof(BitStream));
|
||||||
|
|
||||||
// Add Data if a write command
|
// Add Data if a write command
|
||||||
if (!t55_send_ReadCmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream));
|
if (!t55_send_ReadCmd) BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, Data, 32, sizeof(BitStream));
|
||||||
|
|
||||||
// Add Address
|
// Add Address
|
||||||
if (!t55_send_RegReadMode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream));
|
if (!t55_send_RegReadMode) BitStreamLen = T55xx_SetBits(BitStream, BitStreamLen, Block, 3, sizeof(BitStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send Bits to T55xx
|
// Send Bits to T55xx
|
||||||
|
@ -1607,19 +1626,18 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Pwd, uint16_t arg) {
|
||||||
|
|
||||||
// If long leading 0 send long reference pulse
|
// If long leading 0 send long reference pulse
|
||||||
if (downlink_mode == T55xx_DLMode_LLR)
|
if (downlink_mode == T55xx_DLMode_LLR)
|
||||||
T55xxWriteBit (T55xx_LongLeadingReference,downlink_mode);//Timing); // Send Long Leading Start Reference
|
T55xxWriteBit(T55xx_LongLeadingReference, downlink_mode);//Timing); // Send Long Leading Start Reference
|
||||||
|
|
||||||
if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time
|
if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time
|
||||||
for ( i = 0; i < BitStreamLen-1; i+=2 ) {
|
for (i = 0; i < BitStreamLen - 1; i += 2) {
|
||||||
SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i
|
SendBits = (BitStream[BitStream_Byte(i)] >> (BitStream_Bit(i)) & 1) << 1; // Bit i
|
||||||
SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1;
|
SendBits += (BitStream[BitStream_Byte(i + 1)] >> (BitStream_Bit(i + 1)) & 1); // Bit i+1;
|
||||||
T55xxWriteBit (SendBits & 3,downlink_mode);//Timing);
|
T55xxWriteBit(SendBits & 3, downlink_mode);//Timing);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (i = 0; i < BitStreamLen; i++) {
|
for (i = 0; i < BitStreamLen; i++) {
|
||||||
SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i));
|
SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i));
|
||||||
T55xxWriteBit (SendBits & 1,downlink_mode);//Timing);
|
T55xxWriteBit(SendBits & 1, downlink_mode);//Timing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1635,7 +1653,7 @@ void T55xxResetRead(uint8_t flags) {
|
||||||
//clear buffer now so it does not interfere with timing later
|
//clear buffer now so it does not interfere with timing later
|
||||||
BigBuf_Clear_keep_EM();
|
BigBuf_Clear_keep_EM();
|
||||||
|
|
||||||
T55xx_SendCMD (0, 0, arg);
|
T55xx_SendCMD(0, 0, arg);
|
||||||
|
|
||||||
TurnReadLFOn(T55xx_Timing.m[downlink_mode].read_gap);
|
TurnReadLFOn(T55xx_Timing.m[downlink_mode].read_gap);
|
||||||
|
|
||||||
|
@ -1671,8 +1689,8 @@ void T55xxWriteBlock(uint8_t *data) {
|
||||||
|
|
||||||
c->flags &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0
|
c->flags &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0
|
||||||
|
|
||||||
LED_A_ON ();
|
LED_A_ON();
|
||||||
T55xx_SendCMD (c->data, c->pwd, c->flags | (c->blockno << 9)) ;//, false);
|
T55xx_SendCMD(c->data, c->pwd, c->flags | (c->blockno << 9)) ; //, false);
|
||||||
|
|
||||||
// Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
|
// Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
|
||||||
// so wait a little more)
|
// so wait a little more)
|
||||||
|
@ -1706,7 +1724,7 @@ void T55xxWriteBlock(uint8_t *data) {
|
||||||
|
|
||||||
// cmd_send(CMD_ACK,0,0,0,0,0);
|
// cmd_send(CMD_ACK,0,0,0,0,0);
|
||||||
reply_ng(CMD_T55XX_WRITE_BLOCK, PM3_SUCCESS, NULL, 0);
|
reply_ng(CMD_T55XX_WRITE_BLOCK, PM3_SUCCESS, NULL, 0);
|
||||||
LED_A_OFF ();
|
LED_A_OFF();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1719,7 +1737,7 @@ void T55xxWriteBlock(uint8_t *data) {
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
// Read one card block in page [page]
|
// Read one card block in page [page]
|
||||||
void T55xxReadBlockExt (uint16_t flags, uint8_t block, uint32_t pwd) {
|
void T55xxReadBlockExt(uint16_t flags, uint8_t block, uint32_t pwd) {
|
||||||
/ *
|
/ *
|
||||||
flag bits
|
flag bits
|
||||||
xxxx xxxxxxx1 0x0001 PwdMode
|
xxxx xxxxxxx1 0x0001 PwdMode
|
||||||
|
@ -1729,10 +1747,10 @@ void T55xxReadBlockExt (uint16_t flags, uint8_t block, uint32_t pwd) {
|
||||||
xxxx xx1xxxxx 0x0020 !reg_readmode
|
xxxx xx1xxxxx 0x0020 !reg_readmode
|
||||||
xxxx x1xxxxxx 0x0040 called for a read, so no data packet
|
xxxx x1xxxxxx 0x0040 called for a read, so no data packet
|
||||||
xxxx 1xxxxxxx 0x0080 reset
|
xxxx 1xxxxxxx 0x0080 reset
|
||||||
xxx1 xxxxxxxx 0x0100 brute/leave field on
|
xxx1 xxxxxxxx 0x0100 brute / leave field on
|
||||||
* /
|
* /
|
||||||
size_t samples = 12000;
|
size_t samples = 12000;
|
||||||
bool brute_mem = (flags & 0x0100) >> 8;
|
bool brute_mem = (flags & 0x0100) >> 8;
|
||||||
|
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
||||||
|
@ -1750,14 +1768,14 @@ void T55xxReadBlockExt (uint16_t flags, uint8_t block, uint32_t pwd) {
|
||||||
//clear buffer now so it does not interfere with timing later
|
//clear buffer now so it does not interfere with timing later
|
||||||
BigBuf_Clear_keep_EM();
|
BigBuf_Clear_keep_EM();
|
||||||
|
|
||||||
T55xx_SendCMD (0, pwd, flags | (block << 9)); //, true);
|
T55xx_SendCMD(0, pwd, flags | (block << 9)); //, true);
|
||||||
|
|
||||||
// Turn field on to read the response
|
// Turn field on to read the response
|
||||||
// 137*8 seems to get to the start of data pretty well...
|
// 137*8 seems to get to the start of data pretty well...
|
||||||
// but we want to go past the start and let the repeating data settle in...
|
// but we want to go past the start and let the repeating data settle in...
|
||||||
|
|
||||||
// TurnReadLFOn(210*8); // issues with block 1 reads so dropping down seemed to help
|
// TurnReadLFOn(210*8); // issues with block 1 reads so dropping down seemed to help
|
||||||
TurnReadLFOn(137*8);
|
TurnReadLFOn(137 * 8);
|
||||||
|
|
||||||
// Acquisition
|
// Acquisition
|
||||||
// Now do the acquisition
|
// Now do the acquisition
|
||||||
|
@ -1775,14 +1793,14 @@ void T55xxReadBlockExt (uint16_t flags, uint8_t block, uint32_t pwd) {
|
||||||
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd, uint8_t downlink_mode) {
|
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd, uint8_t downlink_mode) {
|
||||||
/*
|
/*
|
||||||
flag bits
|
flag bits
|
||||||
xxxxxxx1 0x0001 PwdMode
|
xxxx xxxxxxx1 0x0001 PwdMode
|
||||||
xxxxxx1x 0x0002 Page
|
xxxx xxxxxx1x 0x0002 Page
|
||||||
xxxxx1xx 0x0004 testMode
|
xxxx xxxxx1xx 0x0004 testMode
|
||||||
xxx11xxx 0x0018 downlink mode
|
xxxx xxx11xxx 0x0018 downlink mode
|
||||||
xx1xxxxx 0x0020 !reg_readmode
|
xxxx xx1xxxxx 0x0020 !reg_readmode
|
||||||
x1xxxxxx 0x0040 called for a read, so no data packet
|
xxxx x1xxxxxx 0x0040 called for a read, so no data packet
|
||||||
1xxxxxxx 0x0080 reset
|
xxxx 1xxxxxxx 0x0080 reset
|
||||||
1xxxxxxxx 0x0100 brute/leave field on
|
xxx1 xxxxxxxx 0x0100 brute / leave field on
|
||||||
*/
|
*/
|
||||||
uint16_t flags = 0x0040; // read packet
|
uint16_t flags = 0x0040; // read packet
|
||||||
if (pwd_mode) flags |= 0x0001;
|
if (pwd_mode) flags |= 0x0001;
|
||||||
|
@ -1810,14 +1828,14 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block,
|
||||||
//clear buffer now so it does not interfere with timing later
|
//clear buffer now so it does not interfere with timing later
|
||||||
BigBuf_Clear_keep_EM();
|
BigBuf_Clear_keep_EM();
|
||||||
|
|
||||||
T55xx_SendCMD (0, pwd, flags | (block << 9)); //, true);
|
T55xx_SendCMD(0, pwd, flags | (block << 9)); //, true);
|
||||||
|
|
||||||
// Turn field on to read the response
|
// Turn field on to read the response
|
||||||
// 137*8 seems to get to the start of data pretty well...
|
// 137*8 seems to get to the start of data pretty well...
|
||||||
// but we want to go past the start and let the repeating data settle in...
|
// but we want to go past the start and let the repeating data settle in...
|
||||||
|
|
||||||
// TurnReadLFOn(210*8); // issues with block 1 reads so dropping down seemed to help
|
// TurnReadLFOn(210*8); // issues with block 1 reads so dropping down seemed to help
|
||||||
TurnReadLFOn(137*8);
|
TurnReadLFOn(137 * 8);
|
||||||
|
|
||||||
// Acquisition
|
// Acquisition
|
||||||
// Now do the acquisition
|
// Now do the acquisition
|
||||||
|
@ -1847,7 +1865,7 @@ void T55xx_ChkPwds(uint8_t flags) {
|
||||||
uint8_t x = 32;
|
uint8_t x = 32;
|
||||||
while (x--) {
|
while (x--) {
|
||||||
b1 = 0;
|
b1 = 0;
|
||||||
T55xxReadBlock(0, 0, true, 1, 0,downlink_mode);
|
T55xxReadBlock(0, 0, true, 1, 0, downlink_mode);
|
||||||
for (uint16_t j = 0; j < 1024; ++j)
|
for (uint16_t j = 0; j < 1024; ++j)
|
||||||
b1 += buf[j];
|
b1 += buf[j];
|
||||||
|
|
||||||
|
@ -1892,7 +1910,7 @@ void T55xx_ChkPwds(uint8_t flags) {
|
||||||
|
|
||||||
pwd = bytes_to_num(pwds + i * 4, 4);
|
pwd = bytes_to_num(pwds + i * 4, 4);
|
||||||
|
|
||||||
T55xxReadBlock(0, true, true, 0, pwd,downlink_mode);
|
T55xxReadBlock(0, true, true, 0, pwd, downlink_mode);
|
||||||
|
|
||||||
// calc mean of BigBuf 1024 samples.
|
// calc mean of BigBuf 1024 samples.
|
||||||
uint32_t sum = 0;
|
uint32_t sum = 0;
|
||||||
|
@ -1929,7 +1947,7 @@ void T55xxWakeUp(uint32_t Pwd, uint8_t flags) {
|
||||||
flags |= 0x01 | 0x40 | 0x20; //Password | Read Call (no data) | reg_read no block
|
flags |= 0x01 | 0x40 | 0x20; //Password | Read Call (no data) | reg_read no block
|
||||||
LED_B_ON();
|
LED_B_ON();
|
||||||
|
|
||||||
T55xx_SendCMD (0, Pwd, flags);
|
T55xx_SendCMD(0, Pwd, flags);
|
||||||
|
|
||||||
//-- Turn and leave field on to let the begin repeating transmission
|
//-- Turn and leave field on to let the begin repeating transmission
|
||||||
TurnReadLFOn(20 * 1000);
|
TurnReadLFOn(20 * 1000);
|
||||||
|
@ -1946,7 +1964,7 @@ void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) {
|
||||||
for (uint8_t i = numblocks + startblock; i > startblock; i--) {
|
for (uint8_t i = numblocks + startblock; i > startblock; i--) {
|
||||||
cmd.data = blockdata[i - 1];
|
cmd.data = blockdata[i - 1];
|
||||||
cmd.blockno = i - 1;
|
cmd.blockno = i - 1;
|
||||||
T55xxWriteBlock ((uint8_t *)&cmd);
|
T55xxWriteBlock((uint8_t *)&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,7 +397,7 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, uint8_t override, uin
|
||||||
if (usepwd) {
|
if (usepwd) {
|
||||||
// try reading the config block and verify that PWD bit is set before doing this!
|
// try reading the config block and verify that PWD bit is set before doing this!
|
||||||
if (!override) {
|
if (!override) {
|
||||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,downlink_mode)) return PM3_ESOFT;
|
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, downlink_mode)) return PM3_ESOFT;
|
||||||
|
|
||||||
if (!tryDetectModulation()) {
|
if (!tryDetectModulation()) {
|
||||||
PrintAndLogEx(NORMAL, "Safety Check: Could not detect if PWD bit is set in config block. Exits.");
|
PrintAndLogEx(NORMAL, "Safety Check: Could not detect if PWD bit is set in config block. Exits.");
|
||||||
|
@ -455,9 +455,9 @@ static int CmdT55xxReadBlock(const char *Cmd) {
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'R':
|
case 'R':
|
||||||
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
|
downlink_mode = param_getchar(Cmd, cmdp + 1) - '0';
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
cmdp +=2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -556,21 +556,29 @@ static int SanityOfflineCheck(bool useGraphBuffer) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void T55xx_Print_DownlinkMode (uint8_t downlink_mode)
|
void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
|
||||||
{
|
|
||||||
char Msg[80];
|
char Msg[80];
|
||||||
sprintf (Msg,"Downlink Mode used : ");
|
sprintf(Msg, "Downlink Mode used : ");
|
||||||
|
|
||||||
switch (downlink_mode) {
|
switch (downlink_mode) {
|
||||||
case 0 : strcat (Msg,"default/fixed bit length"); break;
|
case 0 :
|
||||||
case 1 : strcat (Msg,"long leading reference (r 1)"); break;
|
strcat(Msg, "default/fixed bit length");
|
||||||
case 2 : strcat (Msg,"leading zero reference (r 2)"); break;
|
break;
|
||||||
case 3 : strcat (Msg,"1 of 4 coding reference (r 3)"); break;
|
case 1 :
|
||||||
|
strcat(Msg, "long leading reference (r 1)");
|
||||||
|
break;
|
||||||
|
case 2 :
|
||||||
|
strcat(Msg, "leading zero reference (r 2)");
|
||||||
|
break;
|
||||||
|
case 3 :
|
||||||
|
strcat(Msg, "1 of 4 coding reference (r 3)");
|
||||||
|
break;
|
||||||
default :
|
default :
|
||||||
strcat (Msg,"default/fixed bit length"); break;
|
strcat(Msg, "default/fixed bit length");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx (NORMAL,Msg);
|
PrintAndLogEx(NORMAL, Msg);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
static int CmdT55xxDetect(const char *Cmd) {
|
static int CmdT55xxDetect(const char *Cmd) {
|
||||||
|
@ -600,10 +608,10 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
cmdp++;
|
cmdp++;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
|
downlink_mode = param_getchar(Cmd, cmdp + 1) - '0';
|
||||||
if (downlink_mode == 4) try_all_dl_modes = true;
|
if (downlink_mode == 4) try_all_dl_modes = true;
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
cmdp +=2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||||
|
@ -618,22 +626,21 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
|
|
||||||
if (!useGB) {
|
if (!useGB) {
|
||||||
for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
|
for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
|
||||||
found = AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,dl_mode);
|
found = AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, dl_mode);
|
||||||
|
|
||||||
// found = false if password is supplied but wrong d/l mode
|
// found = false if password is supplied but wrong d/l mode
|
||||||
// so keep trying other modes (if requested)
|
// so keep trying other modes (if requested)
|
||||||
/* if (!found) {
|
/*
|
||||||
|
if (!found) {
|
||||||
printf ("Aquire not found");
|
printf ("Aquire not found");
|
||||||
return PM3_ENODATA;
|
return PM3_ENODATA;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (tryDetectModulation())
|
if (tryDetectModulation()) {
|
||||||
{
|
T55xx_Print_DownlinkMode(dl_mode);
|
||||||
T55xx_Print_DownlinkMode (dl_mode);
|
|
||||||
dl_mode = 4;
|
dl_mode = 4;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
} else found = false;
|
||||||
else found = false;
|
|
||||||
|
|
||||||
if (!try_all_dl_modes) dl_mode = 4;
|
if (!try_all_dl_modes) dl_mode = 4;
|
||||||
}
|
}
|
||||||
|
@ -646,7 +653,8 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
|
PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
|
||||||
|
|
||||||
|
|
||||||
/* if (!useGB) {
|
/*
|
||||||
|
if (!useGB) {
|
||||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode))
|
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode))
|
||||||
return PM3_ENODATA;
|
return PM3_ENODATA;
|
||||||
}
|
}
|
||||||
|
@ -654,7 +662,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
|
PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
|
||||||
else
|
else
|
||||||
T55xx_Print_DownlinkMode (downlink_mode);
|
T55xx_Print_DownlinkMode (downlink_mode);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1118,9 +1126,9 @@ static int CmdT55xxWakeUp(const char *Cmd) {
|
||||||
errors = false;
|
errors = false;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
|
downlink_mode = param_getchar(Cmd, cmdp + 1) - '0';
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
cmdp +=2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||||
|
@ -1183,9 +1191,9 @@ static int CmdT55xxWriteBlock(const char *Cmd) {
|
||||||
cmdp++;
|
cmdp++;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
|
downlink_mode = param_getchar(Cmd, cmdp + 1) - '0';
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
cmdp +=2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||||
|
@ -1253,7 +1261,7 @@ static int CmdT55xxReadTrace(const char *Cmd) {
|
||||||
uint32_t password = 0;
|
uint32_t password = 0;
|
||||||
// REGULAR_READ_MODE_BLOCK - yeilds correct Page 1 Block 2 data i.e. + 32 bit offset.
|
// REGULAR_READ_MODE_BLOCK - yeilds correct Page 1 Block 2 data i.e. + 32 bit offset.
|
||||||
// if (!AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, pwdmode, password,downlink_mode))
|
// if (!AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, pwdmode, password,downlink_mode))
|
||||||
if (!AquireData(T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password,downlink_mode))
|
if (!AquireData(T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password, downlink_mode))
|
||||||
return PM3_ENODATA;
|
return PM3_ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1518,7 +1526,7 @@ static int CmdT55xxInfo(const char *Cmd) {
|
||||||
cmdp += 2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
downlink_mode = param_getchar(Cmd, cmdp+1)- '0';
|
downlink_mode = param_getchar(Cmd, cmdp + 1) - '0';
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
cmdp += 2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
|
@ -1540,7 +1548,7 @@ static int CmdT55xxInfo(const char *Cmd) {
|
||||||
|
|
||||||
bool pwdmode = false;
|
bool pwdmode = false;
|
||||||
uint32_t password = 0;
|
uint32_t password = 0;
|
||||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password,downlink_mode))
|
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password, downlink_mode))
|
||||||
return PM3_ENODATA;
|
return PM3_ENODATA;
|
||||||
}
|
}
|
||||||
if (!gotdata) {
|
if (!gotdata) {
|
||||||
|
@ -1659,14 +1667,14 @@ static int CmdT55xxDump(const char *Cmd) {
|
||||||
|
|
||||||
printT5xxHeader(0);
|
printT5xxHeader(0);
|
||||||
for (uint8_t i = 0; i < 8; ++i) {
|
for (uint8_t i = 0; i < 8; ++i) {
|
||||||
T55xxReadBlock(i, 0, usepwd, override, password,downlink_mode);
|
T55xxReadBlock(i, 0, usepwd, override, password, downlink_mode);
|
||||||
// idea for better user experience and display.
|
// idea for better user experience and display.
|
||||||
// only show override warning on the first block read
|
// only show override warning on the first block read
|
||||||
if (override) override |= 2; // flag not to show safty for 2nd and on.
|
if (override) override |= 2; // flag not to show safty for 2nd and on.
|
||||||
}
|
}
|
||||||
printT5xxHeader(1);
|
printT5xxHeader(1);
|
||||||
for (uint8_t i = 0; i < 4; i++)
|
for (uint8_t i = 0; i < 4; i++)
|
||||||
T55xxReadBlock(i, 1, usepwd, override, password,downlink_mode);
|
T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode);
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -1955,12 +1963,12 @@ static int CmdResetRead(const char *Cmd) {
|
||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
|
|
||||||
|
|
||||||
if (strlen (Cmd) == 3)
|
if (strlen(Cmd) == 3)
|
||||||
downlink_mode = param_getchar(Cmd, 1) - '0';
|
downlink_mode = param_getchar(Cmd, 1) - '0';
|
||||||
|
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
|
|
||||||
printf ("DL : %d\n",downlink_mode);
|
printf("DL : %d\n", downlink_mode);
|
||||||
flags = downlink_mode << 3;
|
flags = downlink_mode << 3;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_T55XX_RESET_READ, &flags, sizeof(flags));
|
SendCommandNG(CMD_T55XX_RESET_READ, &flags, sizeof(flags));
|
||||||
|
@ -2032,24 +2040,24 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||||
int dl_mode; // to try each downlink mode for each password
|
int dl_mode; // to try each downlink mode for each password
|
||||||
|
|
||||||
|
|
||||||
cmdp = tolower(param_getchar(Cmd,0));
|
cmdp = tolower(param_getchar(Cmd, 0));
|
||||||
|
|
||||||
if (cmdp == 'h') return usage_t55xx_chk();
|
if (cmdp == 'h') return usage_t55xx_chk();
|
||||||
if (cmdp == 'm') {
|
if (cmdp == 'm') {
|
||||||
from_flash = true;
|
from_flash = true;
|
||||||
Cmd +=2;
|
Cmd += 2;
|
||||||
cmdp = tolower(param_getchar(Cmd,0));
|
cmdp = tolower(param_getchar(Cmd, 0));
|
||||||
}
|
}
|
||||||
if (cmdp == 'r') {
|
if (cmdp == 'r') {
|
||||||
Cmd += 2;
|
Cmd += 2;
|
||||||
downlink_mode = param_getchar(Cmd,0 ) - '0'; // get 2nd option, as this is fixed order.
|
downlink_mode = param_getchar(Cmd, 0) - '0'; // get 2nd option, as this is fixed order.
|
||||||
if (downlink_mode == 4) try_all_dl_modes = true;
|
if (downlink_mode == 4) try_all_dl_modes = true;
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
Cmd += 2;
|
Cmd += 2;
|
||||||
cmdp = param_getchar(Cmd,0);
|
cmdp = param_getchar(Cmd, 0);
|
||||||
}
|
}
|
||||||
if (cmdp == 'i') {
|
if (cmdp == 'i') {
|
||||||
Cmd+=2;
|
Cmd += 2;
|
||||||
len = strlen(Cmd);
|
len = strlen(Cmd);
|
||||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||||
memcpy(filename, Cmd, len);
|
memcpy(filename, Cmd, len);
|
||||||
|
@ -2089,11 +2097,11 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||||
if (resp.oldarg[0]) {
|
if (resp.oldarg[0]) {
|
||||||
PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08X") " ]. Trying to validate", resp.oldarg[1]);
|
PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08X") " ]. Trying to validate", resp.oldarg[1]);
|
||||||
|
|
||||||
if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, resp.oldarg[1],downlink_mode)) {
|
if (AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, resp.oldarg[1], downlink_mode)) {
|
||||||
found = tryDetectModulation();
|
found = tryDetectModulation();
|
||||||
if (found) {
|
if (found) {
|
||||||
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") " ]", resp.oldarg[1]);
|
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") " ]", resp.oldarg[1]);
|
||||||
T55xx_Print_DownlinkMode (downlink_mode);
|
T55xx_Print_DownlinkMode(downlink_mode);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Check pwd failed");
|
PrintAndLogEx(WARNING, "Check pwd failed");
|
||||||
|
@ -2143,16 +2151,16 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||||
curr_password = bytes_to_num(keyBlock + 4 * c, 4);
|
curr_password = bytes_to_num(keyBlock + 4 * c, 4);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Testing %08X", curr_password);
|
PrintAndLogEx(INFO, "Testing %08X", curr_password);
|
||||||
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){
|
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) {
|
||||||
|
|
||||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr_password,dl_mode)) {
|
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, curr_password, dl_mode)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
found = tryDetectModulation();
|
found = tryDetectModulation();
|
||||||
if (found) {
|
if (found) {
|
||||||
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") " ]", curr_password);
|
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") " ]", curr_password);
|
||||||
T55xx_Print_DownlinkMode (dl_mode);
|
T55xx_Print_DownlinkMode(dl_mode);
|
||||||
dl_mode = 4; // Exit other downlink mode checks
|
dl_mode = 4; // Exit other downlink mode checks
|
||||||
c = keycount; // Exit loop
|
c = keycount; // Exit loop
|
||||||
}
|
}
|
||||||
|
@ -2187,7 +2195,7 @@ static int CmdT55xxBruteForce(const char *Cmd) {
|
||||||
if (cmdp == 'h') return usage_t55xx_bruteforce();
|
if (cmdp == 'h') return usage_t55xx_bruteforce();
|
||||||
if (cmdp == 'r') { // downlink mode supplied
|
if (cmdp == 'r') { // downlink mode supplied
|
||||||
cmd_opt_idx++; // skip over 'r'
|
cmd_opt_idx++; // skip over 'r'
|
||||||
downlink_mode = param_getchar (Cmd,cmd_opt_idx++) - '0';
|
downlink_mode = param_getchar(Cmd, cmd_opt_idx++) - '0';
|
||||||
if (downlink_mode > 4) downlink_mode = 0;
|
if (downlink_mode > 4) downlink_mode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2214,7 +2222,7 @@ static int CmdT55xxBruteForce(const char *Cmd) {
|
||||||
return PM3_EOPABORTED;
|
return PM3_EOPABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
found = tryOnePassword(curr,downlink_mode);
|
found = tryOnePassword(curr, downlink_mode);
|
||||||
|
|
||||||
if (curr == end_password)
|
if (curr == end_password)
|
||||||
break;
|
break;
|
||||||
|
@ -2225,10 +2233,9 @@ static int CmdT55xxBruteForce(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") "]", curr-1);
|
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") "]", curr - 1);
|
||||||
T55xx_Print_DownlinkMode ((found >> 1) & 3);
|
T55xx_Print_DownlinkMode((found >> 1) & 3);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
PrintAndLogEx(WARNING, "Bruteforce failed, last tried: [ " _YELLOW_("%08X") " ]", curr);
|
PrintAndLogEx(WARNING, "Bruteforce failed, last tried: [ " _YELLOW_("%08X") " ]", curr);
|
||||||
|
|
||||||
t1 = msclock() - t1;
|
t1 = msclock() - t1;
|
||||||
|
@ -2248,14 +2255,13 @@ uint8_t tryOnePassword(uint32_t password, uint8_t downlink_mode) {
|
||||||
downlink_mode = (downlink_mode & 3); // ensure 0-3
|
downlink_mode = (downlink_mode & 3); // ensure 0-3
|
||||||
|
|
||||||
// check if dl mode 4 and loop if needed
|
// check if dl mode 4 and loop if needed
|
||||||
for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++){
|
for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
|
||||||
|
|
||||||
AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password,dl_mode);
|
AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode);
|
||||||
|
|
||||||
// if (getSignalProperties()->isnoise == false) {
|
// if (getSignalProperties()->isnoise == false) {
|
||||||
// } else {
|
// } else {
|
||||||
if (tryDetectModulation())
|
if (tryDetectModulation()) {
|
||||||
{
|
|
||||||
return 1 + (dl_mode << 1);
|
return 1 + (dl_mode << 1);
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
@ -2279,7 +2285,7 @@ static int CmdT55xxRecoverPW(const char *Cmd) {
|
||||||
if (cmdp == 'h') return usage_t55xx_recoverpw();
|
if (cmdp == 'h') return usage_t55xx_recoverpw();
|
||||||
if (cmdp == 'r') { // downlink mode supplied
|
if (cmdp == 'r') { // downlink mode supplied
|
||||||
cmd_opt_idx++; // skip over 'r'
|
cmd_opt_idx++; // skip over 'r'
|
||||||
downlink_mode = param_getchar (Cmd,cmd_opt_idx++) - '0';
|
downlink_mode = param_getchar(Cmd, cmd_opt_idx++) - '0';
|
||||||
if (downlink_mode > 4) downlink_mode = 0;
|
if (downlink_mode > 4) downlink_mode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2288,7 +2294,7 @@ static int CmdT55xxRecoverPW(const char *Cmd) {
|
||||||
// first try fliping each bit in the expected password
|
// first try fliping each bit in the expected password
|
||||||
while (bit < 32) {
|
while (bit < 32) {
|
||||||
curr_password = orig_password ^ (1u << bit);
|
curr_password = orig_password ^ (1u << bit);
|
||||||
found = tryOnePassword(curr_password,downlink_mode);
|
found = tryOnePassword(curr_password, downlink_mode);
|
||||||
if (found > 0) // xx1 for found xx = dl mode used
|
if (found > 0) // xx1 for found xx = dl mode used
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -2313,7 +2319,7 @@ static int CmdT55xxRecoverPW(const char *Cmd) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
found = tryOnePassword(curr_password,downlink_mode);
|
found = tryOnePassword(curr_password, downlink_mode);
|
||||||
if (found > 0)
|
if (found > 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -2335,7 +2341,7 @@ static int CmdT55xxRecoverPW(const char *Cmd) {
|
||||||
bit++;
|
bit++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
found = tryOnePassword(curr_password,downlink_mode);
|
found = tryOnePassword(curr_password, downlink_mode);
|
||||||
if (found > 0)
|
if (found > 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -2352,9 +2358,8 @@ out:
|
||||||
|
|
||||||
if (found > 0) {
|
if (found > 0) {
|
||||||
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") "]", curr_password);
|
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08X") "]", curr_password);
|
||||||
T55xx_Print_DownlinkMode ((found >> 1) & 3);
|
T55xx_Print_DownlinkMode((found >> 1) & 3);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
PrintAndLogEx(WARNING, "Recover pwd failed");
|
PrintAndLogEx(WARNING, "Recover pwd failed");
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -2371,7 +2376,7 @@ bool tryDetectP1(bool getData) {
|
||||||
bool st = true;
|
bool st = true;
|
||||||
|
|
||||||
if (getData) {
|
if (getData) {
|
||||||
if (!AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, false, 0,0))
|
if (!AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, false, 0, 0))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2499,10 +2504,10 @@ static int CmdT55xxDetectPage1(const char *Cmd) {
|
||||||
cmdp++;
|
cmdp++;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
|
downlink_mode = param_getchar(Cmd, cmdp + 1) - '0';
|
||||||
if (downlink_mode == 4) try_all_dl_modes = true;
|
if (downlink_mode == 4) try_all_dl_modes = true;
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
if (downlink_mode > 3) downlink_mode = 0;
|
||||||
cmdp +=2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||||
|
@ -2514,14 +2519,12 @@ static int CmdT55xxDetectPage1(const char *Cmd) {
|
||||||
|
|
||||||
if (!useGB) {
|
if (!useGB) {
|
||||||
for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
|
for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) {
|
||||||
found = AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, usepwd, password,dl_mode);
|
found = AquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, usepwd, password, dl_mode);
|
||||||
//return PM3_ENODATA;
|
//return PM3_ENODATA;
|
||||||
if (tryDetectP1(false)) //tryDetectModulation())
|
if (tryDetectP1(false)) { //tryDetectModulation())
|
||||||
{
|
|
||||||
found = dl_mode;
|
found = dl_mode;
|
||||||
dl_mode = 4;
|
dl_mode = 4;
|
||||||
}
|
} else found = false;
|
||||||
else found = false;
|
|
||||||
|
|
||||||
if (!try_all_dl_modes) dl_mode = 4;
|
if (!try_all_dl_modes) dl_mode = 4;
|
||||||
}
|
}
|
||||||
|
@ -2532,9 +2535,8 @@ static int CmdT55xxDetectPage1(const char *Cmd) {
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
PrintAndLogEx(SUCCESS, "T55xx chip found!");
|
PrintAndLogEx(SUCCESS, "T55xx chip found!");
|
||||||
T55xx_Print_DownlinkMode (found);
|
T55xx_Print_DownlinkMode(found);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
|
PrintAndLogEx(WARNING, "Could not detect modulation automatically. Try setting it manually with " _YELLOW_("\'lf t55xx config\'"));
|
||||||
|
|
||||||
|
|
||||||
|
@ -2606,12 +2608,11 @@ static int CmdT55xxSetDeviceConfig(const char *Cmd) {
|
||||||
|
|
||||||
// printf ("DLmode %d\n",downlink_mode);
|
// printf ("DLmode %d\n",downlink_mode);
|
||||||
t55xx_config conf = {0};
|
t55xx_config conf = {0};
|
||||||
printf ("Size conf %zu\n",sizeof(conf));
|
printf("Size conf %zu\n", sizeof(conf));
|
||||||
if (erase) {
|
if (erase) {
|
||||||
memset (&conf,0xff, sizeof(conf));
|
memset(&conf, 0xff, sizeof(conf));
|
||||||
printf ("Conf.m[0] %x\n",conf.m[0].start_gap);
|
printf("Conf.m[0] %x\n", conf.m[0].start_gap);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
|
|
||||||
conf.m[downlink_mode].start_gap = startgap * 8;
|
conf.m[downlink_mode].start_gap = startgap * 8;
|
||||||
conf.m[downlink_mode].write_gap = writegap * 8;
|
conf.m[downlink_mode].write_gap = writegap * 8;
|
||||||
|
|
|
@ -903,7 +903,7 @@ static int l_T55xx_readblock(lua_State *L) {
|
||||||
// try reading the config block and verify that PWD bit is set before doing this!
|
// try reading the config block and verify that PWD bit is set before doing this!
|
||||||
if (!override) {
|
if (!override) {
|
||||||
|
|
||||||
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,0)) {
|
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, 0)) {
|
||||||
return returnToLuaWithError(L, "Failed to read config block");
|
return returnToLuaWithError(L, "Failed to read config block");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,7 +920,7 @@ static int l_T55xx_readblock(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AquireData(usepage1, block, usepwd, password,0)) {
|
if (!AquireData(usepage1, block, usepwd, password, 0)) {
|
||||||
return returnToLuaWithError(L, "Failed to aquire data from card");
|
return returnToLuaWithError(L, "Failed to aquire data from card");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,7 +977,7 @@ static int l_T55xx_detect(lua_State *L) {
|
||||||
|
|
||||||
if (!useGB) {
|
if (!useGB) {
|
||||||
|
|
||||||
isok = AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,0);
|
isok = AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, 0);
|
||||||
if (isok == false) {
|
if (isok == false) {
|
||||||
return returnToLuaWithError(L, "Failed to aquire LF signal data");
|
return returnToLuaWithError(L, "Failed to aquire LF signal data");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue