2018-09-07 03:43:20 +08:00
//-----------------------------------------------------------------------------
// Copyright (C) 2009 Michael Gernoth <michael at gernoth.net>
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Code for communicating with the proxmark3 hardware.
//-----------------------------------------------------------------------------
# include "comms.h"
2019-08-08 22:57:33 +08:00
# include <inttypes.h>
# include <string.h>
# include <stdio.h>
# include "uart.h"
# include "ui.h"
2019-04-17 02:00:17 +08:00
# include "crc16.h"
2019-08-08 22:57:33 +08:00
# include "util_posix.h" // msclock
2019-08-12 18:39:16 +08:00
# include "util_darwin.h" // en/dis-ableNapp();
2018-09-07 03:43:20 +08:00
2019-04-29 07:20:03 +08:00
//#define COMMS_DEBUG
//#define COMMS_DEBUG_RAW
2020-01-29 22:16:50 +08:00
uint8_t gui_serial_port_name [ FILE_PATH_SIZE ] ;
2018-09-07 03:43:20 +08:00
// Serial port that we are communicating with the PM3 on.
static serial_port sp = NULL ;
2019-04-26 19:53:11 +08:00
communication_arg_t conn ;
2019-04-27 08:46:20 +08:00
capabilities_t pm3_capabilities ;
2018-09-07 03:43:20 +08:00
2019-05-06 20:11:23 +08:00
static pthread_t communication_thread ;
static bool comm_thread_dead = false ;
2018-09-07 03:43:20 +08:00
// Transmit buffer.
2019-04-18 18:43:35 +08:00
static PacketCommandOLD txBuffer ;
static PacketCommandNGRaw txBufferNG ;
2019-04-16 16:01:08 +08:00
size_t txBufferNGLen ;
2018-09-07 03:43:20 +08:00
static bool txBuffer_pending = false ;
static pthread_mutex_t txBufferMutex = PTHREAD_MUTEX_INITIALIZER ;
static pthread_cond_t txBufferSig = PTHREAD_COND_INITIALIZER ;
2019-04-17 02:49:32 +08:00
2019-04-18 18:43:35 +08:00
// Used by PacketResponseReceived as a ring buffer for messages that are yet to be
2018-09-07 03:43:20 +08:00
// processed by a command handler (WaitForResponse{,Timeout})
2019-04-18 18:43:35 +08:00
static PacketResponseNG rxBuffer [ CMD_BUFFER_SIZE ] ;
2018-09-07 03:43:20 +08:00
// Points to the next empty position to write to
static int cmd_head = 0 ;
// Points to the position of the last unread command
static int cmd_tail = 0 ;
// to lock rxBuffer operations from different threads
static pthread_mutex_t rxBufferMutex = PTHREAD_MUTEX_INITIALIZER ;
2019-04-22 08:11:46 +08:00
// Global start time for WaitForResponseTimeout & dl_it, so we can reset timeout when we get packets
// as sending lot of these packets can slow down things wuite a lot on slow links (e.g. hw status or lf read at 9600)
static uint64_t timeout_start_time ;
2019-04-22 05:56:04 +08:00
2019-08-07 18:30:44 +08:00
static uint64_t last_packet_time ;
2019-10-27 01:49:46 +08:00
static bool dl_it ( uint8_t * dest , uint32_t bytes , PacketResponseNG * response , size_t ms_timeout , bool show_warning , uint32_t rec_cmd ) ;
2019-04-18 03:30:01 +08:00
2019-05-08 19:31:58 +08:00
// Simple alias to track usages linked to the Bootloader, these commands must not be migrated.
// - commands sent to enter bootloader mode as we might have to talk to old firmwares
// - commands sent to the bootloader as it only supports OLD frames (which will always be the case for old BL)
void SendCommandBL ( uint64_t cmd , uint64_t arg0 , uint64_t arg1 , uint64_t arg2 , void * data , size_t len ) {
SendCommandOLD ( cmd , arg0 , arg1 , arg2 , data , len ) ;
}
2019-05-08 07:32:32 +08:00
void SendCommandOLD ( uint64_t cmd , uint64_t arg0 , uint64_t arg1 , uint64_t arg2 , void * data , size_t len ) {
PacketCommandOLD c = { CMD_UNKNOWN , { 0 , 0 , 0 } , { { 0 } } } ;
c . cmd = cmd ;
c . arg [ 0 ] = arg0 ;
c . arg [ 1 ] = arg1 ;
c . arg [ 2 ] = arg2 ;
if ( len & & data )
memcpy ( & c . d , data , len ) ;
2018-09-07 03:43:20 +08:00
2019-03-10 07:00:59 +08:00
# ifdef COMMS_DEBUG
2019-04-30 04:38:54 +08:00
PrintAndLogEx ( NORMAL , " Sending %s " , " OLD " ) ;
2019-04-29 07:20:03 +08:00
# endif
# ifdef COMMS_DEBUG_RAW
2019-05-08 07:32:32 +08:00
print_hex_break ( ( uint8_t * ) & c . cmd , sizeof ( c . cmd ) , 32 ) ;
print_hex_break ( ( uint8_t * ) & c . arg , sizeof ( c . arg ) , 32 ) ;
print_hex_break ( ( uint8_t * ) & c . d , sizeof ( c . d ) , 32 ) ;
2019-03-10 07:00:59 +08:00
# endif
2019-03-09 15:59:13 +08:00
2019-05-01 05:52:40 +08:00
if ( ! session . pm3_present ) {
2019-04-17 20:54:42 +08:00
PrintAndLogEx ( WARNING , " Sending bytes to Proxmark3 failed. " _YELLOW_ ( " offline " ) ) ;
2019-03-10 06:35:06 +08:00
return ;
}
2018-09-07 03:43:20 +08:00
2019-03-10 06:35:06 +08:00
pthread_mutex_lock ( & txBufferMutex ) ;
/**
This causes hangups at times , when the pm3 unit is unresponsive or disconnected . The main console thread is alive ,
but comm thread just spins here . Not good . . . / holiman
* */
while ( txBuffer_pending ) {
// wait for communication thread to complete sending a previous commmand
pthread_cond_wait ( & txBufferSig , & txBufferMutex ) ;
}
2018-09-07 03:43:20 +08:00
2019-05-08 07:32:32 +08:00
txBuffer = c ;
2019-03-10 06:35:06 +08:00
txBuffer_pending = true ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
// tell communication thread that a new command can be send
pthread_cond_signal ( & txBufferSig ) ;
2018-09-07 03:43:20 +08:00
2019-03-10 06:35:06 +08:00
pthread_mutex_unlock ( & txBufferMutex ) ;
2019-03-09 15:59:13 +08:00
2018-09-07 03:43:20 +08:00
//__atomic_test_and_set(&txcmd_pending, __ATOMIC_SEQ_CST);
}
2019-04-20 08:41:40 +08:00
static void SendCommandNG_internal ( uint16_t cmd , uint8_t * data , size_t len , bool ng ) {
2019-04-16 16:01:08 +08:00
# ifdef COMMS_DEBUG
2019-04-30 04:38:54 +08:00
PrintAndLogEx ( NORMAL , " Sending %s " , ng ? " NG " : " MIX " ) ;
2019-04-16 16:01:08 +08:00
# endif
2019-05-01 05:52:40 +08:00
if ( ! session . pm3_present ) {
2019-04-16 16:01:08 +08:00
PrintAndLogEx ( NORMAL , " Sending bytes to proxmark failed - offline " ) ;
return ;
}
2019-05-01 03:10:11 +08:00
if ( len > PM3_CMD_DATA_SIZE ) {
2019-10-06 05:56:19 +08:00
PrintAndLogEx ( WARNING , " Sending %zu bytes of payload is too much, abort " , len ) ;
2019-04-16 16:01:08 +08:00
return ;
}
2019-04-18 18:43:35 +08:00
PacketCommandNGPostamble * tx_post = ( PacketCommandNGPostamble * ) ( ( uint8_t * ) & txBufferNG + sizeof ( PacketCommandNGPreamble ) + len ) ;
2019-04-16 16:01:08 +08:00
pthread_mutex_lock ( & txBufferMutex ) ;
/**
This causes hangups at times , when the pm3 unit is unresponsive or disconnected . The main console thread is alive ,
but comm thread just spins here . Not good . . . / holiman
* */
while ( txBuffer_pending ) {
// wait for communication thread to complete sending a previous commmand
pthread_cond_wait ( & txBufferSig , & txBufferMutex ) ;
}
2019-04-19 03:49:32 +08:00
txBufferNG . pre . magic = COMMANDNG_PREAMBLE_MAGIC ;
2019-04-20 08:41:40 +08:00
txBufferNG . pre . ng = ng ;
2019-04-18 06:12:52 +08:00
txBufferNG . pre . length = len ;
txBufferNG . pre . cmd = cmd ;
2019-07-13 06:38:30 +08:00
if ( len > 0 & & data )
2019-06-14 03:13:41 +08:00
memcpy ( & txBufferNG . data , data , len ) ;
2019-04-19 03:41:48 +08:00
2019-05-04 04:30:17 +08:00
if ( ( conn . send_via_fpc_usart & & conn . send_with_crc_on_fpc ) | | ( ( ! conn . send_via_fpc_usart ) & & conn . send_with_crc_on_usb ) ) {
2019-04-19 03:39:35 +08:00
uint8_t first , second ;
compute_crc ( CRC_14443_A , ( uint8_t * ) & txBufferNG , sizeof ( PacketCommandNGPreamble ) + len , & first , & second ) ;
tx_post - > crc = ( first < < 8 ) + second ;
} else {
2019-04-19 03:49:32 +08:00
tx_post - > crc = COMMANDNG_POSTAMBLE_MAGIC ;
2019-04-19 03:39:35 +08:00
}
2019-04-18 18:43:35 +08:00
txBufferNGLen = sizeof ( PacketCommandNGPreamble ) + len + sizeof ( PacketCommandNGPostamble ) ;
2019-04-29 07:20:03 +08:00
# ifdef COMMS_DEBUG_RAW
2019-04-30 04:38:54 +08:00
print_hex_break ( ( uint8_t * ) & txBufferNG . pre , sizeof ( PacketCommandNGPreamble ) , 32 ) ;
if ( ng ) {
print_hex_break ( ( uint8_t * ) & txBufferNG . data , len , 32 ) ;
} else {
print_hex_break ( ( uint8_t * ) & txBufferNG . data , 3 * sizeof ( uint64_t ) , 32 ) ;
print_hex_break ( ( uint8_t * ) & txBufferNG . data + 3 * sizeof ( uint64_t ) , len - 3 * sizeof ( uint64_t ) , 32 ) ;
}
2019-04-30 05:02:49 +08:00
print_hex_break ( ( uint8_t * ) tx_post , sizeof ( PacketCommandNGPostamble ) , 32 ) ;
2019-04-29 07:20:03 +08:00
# endif
2019-04-16 16:01:08 +08:00
txBuffer_pending = true ;
// tell communication thread that a new command can be send
pthread_cond_signal ( & txBufferSig ) ;
pthread_mutex_unlock ( & txBufferMutex ) ;
//__atomic_test_and_set(&txcmd_pending, __ATOMIC_SEQ_CST);
}
2019-04-20 08:41:40 +08:00
void SendCommandNG ( uint16_t cmd , uint8_t * data , size_t len ) {
SendCommandNG_internal ( cmd , data , len , true ) ;
}
void SendCommandMIX ( uint64_t cmd , uint64_t arg0 , uint64_t arg1 , uint64_t arg2 , void * data , size_t len ) {
uint64_t arg [ 3 ] = { arg0 , arg1 , arg2 } ;
2019-05-01 03:10:11 +08:00
if ( len > PM3_CMD_DATA_SIZE_MIX ) {
2019-10-06 05:56:19 +08:00
PrintAndLogEx ( WARNING , " Sending %zu bytes of payload is too much for MIX frames, abort " , len ) ;
2019-04-20 08:41:40 +08:00
return ;
}
2019-05-01 03:10:11 +08:00
uint8_t cmddata [ PM3_CMD_DATA_SIZE ] ;
2019-04-20 08:41:40 +08:00
memcpy ( cmddata , arg , sizeof ( arg ) ) ;
if ( len & & data )
memcpy ( cmddata + sizeof ( arg ) , data , len ) ;
SendCommandNG_internal ( cmd , cmddata , len + sizeof ( arg ) , false ) ;
}
2018-09-07 03:43:20 +08:00
/**
* @ brief This method should be called when sending a new command to the pm3 . In case any old
* responses from previous commands are stored in the buffer , a call to this method should clear them .
* A better method could have been to have explicit command - ACKS , so we can know which ACK goes to which
* operation . Right now we ' ll just have to live with this .
*/
2019-03-10 18:20:22 +08:00
void clearCommandBuffer ( ) {
2019-03-10 06:35:06 +08:00
//This is a very simple operation
pthread_mutex_lock ( & rxBufferMutex ) ;
cmd_tail = cmd_head ;
pthread_mutex_unlock ( & rxBufferMutex ) ;
2018-09-07 03:43:20 +08:00
}
/**
* @ brief storeCommand stores a USB command in a circular buffer
* @ param UC
*/
2019-04-18 18:43:35 +08:00
static void storeReply ( PacketResponseNG * packet ) {
2019-03-10 06:35:06 +08:00
pthread_mutex_lock ( & rxBufferMutex ) ;
2019-03-10 07:00:59 +08:00
if ( ( cmd_head + 1 ) % CMD_BUFFER_SIZE = = cmd_tail ) {
2018-09-07 03:43:20 +08:00
//If these two are equal, we're about to overwrite in the
// circular buffer.
PrintAndLogEx ( FAILED , " WARNING: Command buffer about to overwrite command! This needs to be fixed! " ) ;
2019-03-10 06:35:06 +08:00
fflush ( stdout ) ;
2018-09-07 03:43:20 +08:00
}
//Store the command at the 'head' location
2019-04-18 18:43:35 +08:00
PacketResponseNG * destination = & rxBuffer [ cmd_head ] ;
memcpy ( destination , packet , sizeof ( PacketResponseNG ) ) ;
2018-09-07 03:43:20 +08:00
2019-03-10 07:00:59 +08:00
//increment head and wrap
cmd_head = ( cmd_head + 1 ) % CMD_BUFFER_SIZE ;
2019-03-10 06:35:06 +08:00
pthread_mutex_unlock ( & rxBufferMutex ) ;
2018-09-07 03:43:20 +08:00
}
/**
* @ brief getCommand gets a command from an internal circular buffer .
* @ param response location to write command
* @ return 1 if response was returned , 0 if nothing has been received
*/
2019-04-18 18:43:35 +08:00
static int getReply ( PacketResponseNG * packet ) {
2019-03-10 06:35:06 +08:00
pthread_mutex_lock ( & rxBufferMutex ) ;
2018-09-07 03:43:20 +08:00
//If head == tail, there's nothing to read, or if we just got initialized
if ( cmd_head = = cmd_tail ) {
2019-03-10 06:35:06 +08:00
pthread_mutex_unlock ( & rxBufferMutex ) ;
return 0 ;
}
2019-03-09 15:59:13 +08:00
2018-09-07 03:43:20 +08:00
//Pick out the next unread command
2019-04-18 18:43:35 +08:00
memcpy ( packet , & rxBuffer [ cmd_tail ] , sizeof ( PacketResponseNG ) ) ;
2018-09-07 03:43:20 +08:00
//Increment tail - this is a circular buffer, so modulo buffer size
2019-03-10 07:00:59 +08:00
cmd_tail = ( cmd_tail + 1 ) % CMD_BUFFER_SIZE ;
2018-09-07 03:43:20 +08:00
2019-03-10 06:35:06 +08:00
pthread_mutex_unlock ( & rxBufferMutex ) ;
2018-09-07 03:43:20 +08:00
return 1 ;
}
//-----------------------------------------------------------------------------
// Entry point into our code: called whenever we received a packet over USB
// that we weren't necessarily expecting, for example a debug print.
//-----------------------------------------------------------------------------
2019-04-18 18:43:35 +08:00
static void PacketResponseReceived ( PacketResponseNG * packet ) {
2019-04-17 07:06:26 +08:00
2019-04-22 05:56:04 +08:00
// we got a packet, reset WaitForResponseTimeout timeout
2019-08-07 18:30:44 +08:00
uint64_t prev_clk = __atomic_load_n ( & last_packet_time , __ATOMIC_SEQ_CST ) ;
uint64_t clk = msclock ( ) ;
__atomic_store_n ( & timeout_start_time , clk , __ATOMIC_SEQ_CST ) ;
__atomic_store_n ( & last_packet_time , clk , __ATOMIC_SEQ_CST ) ;
( void ) prev_clk ;
// PrintAndLogEx(NORMAL, "[%07"PRIu64"] RECV %s magic %08x length %04x status %04x crc %04x cmd %04x",
// clk - prev_clk, packet->ng ? "NG" : "OLD", packet->magic, packet->length, packet->status, packet->crc, packet->cmd);
2019-04-22 05:56:04 +08:00
2019-04-18 05:44:48 +08:00
switch ( packet - > cmd ) {
2019-03-10 06:35:06 +08:00
// First check if we are handling a debug message
case CMD_DEBUG_PRINT_STRING : {
2019-05-01 03:10:11 +08:00
char s [ PM3_CMD_DATA_SIZE + 1 ] ;
2019-03-10 06:35:06 +08:00
memset ( s , 0x00 , sizeof ( s ) ) ;
2019-04-22 07:33:32 +08:00
size_t len ;
uint16_t flag ;
if ( packet - > ng ) {
struct d {
uint16_t flag ;
2019-05-01 03:10:11 +08:00
uint8_t buf [ PM3_CMD_DATA_SIZE - sizeof ( uint16_t ) ] ;
2019-04-22 07:33:32 +08:00
} PACKED ;
2019-04-25 23:06:40 +08:00
struct d * data = ( struct d * ) & packet - > data . asBytes ;
2019-04-22 07:33:32 +08:00
len = packet - > length - sizeof ( data - > flag ) ;
flag = data - > flag ;
2019-04-30 19:02:27 +08:00
memcpy ( s , data - > buf , len ) ;
2019-04-22 07:33:32 +08:00
} else {
2019-05-01 03:10:11 +08:00
len = MIN ( packet - > oldarg [ 0 ] , PM3_CMD_DATA_SIZE ) ;
2019-04-22 07:33:32 +08:00
flag = packet - > oldarg [ 1 ] ;
2019-04-30 19:02:27 +08:00
memcpy ( s , packet - > data . asBytes , len ) ;
2019-04-22 07:33:32 +08:00
}
2019-03-10 06:35:06 +08:00
2019-04-26 16:36:06 +08:00
if ( flag & FLAG_LOG ) {
PrintAndLogEx ( NORMAL , " #db# %s " , s ) ;
} else {
if ( flag & FLAG_INPLACE )
printf ( " \r " ) ;
printf ( " %s " , s ) ;
if ( flag & FLAG_NEWLINE )
printf ( " \r \n " ) ;
2019-03-10 06:35:06 +08:00
}
2019-04-26 16:36:06 +08:00
2019-03-10 06:35:06 +08:00
fflush ( stdout ) ;
break ;
}
case CMD_DEBUG_PRINT_INTEGERS : {
2019-10-06 07:18:04 +08:00
if ( ! packet - > ng )
PrintAndLogEx ( NORMAL , " #db# % " PRIx64 " , % " PRIx64 " , % " PRIx64 " " , packet - > oldarg [ 0 ] , packet - > oldarg [ 1 ] , packet - > oldarg [ 2 ] ) ;
2019-03-10 06:35:06 +08:00
break ;
}
// iceman: hw status - down the path on device, runs printusbspeed which starts sending a lot of
2019-05-05 05:56:59 +08:00
// CMD_DOWNLOAD_BIGBUF packages which is not dealt with. I wonder if simply ignoring them will
2019-03-10 06:35:06 +08:00
// work. lets try it.
default : {
2019-04-17 07:06:26 +08:00
storeReply ( packet ) ;
2019-03-10 06:35:06 +08:00
break ;
}
}
2018-09-07 03:43:20 +08:00
}
2019-05-06 20:11:23 +08:00
// The communications thread.
// signals to main thread when a response is ready to process.
2019-05-08 07:35:51 +08:00
//
2019-04-13 06:25:43 +08:00
static void
2018-09-07 03:43:20 +08:00
# ifdef __has_attribute
# if __has_attribute(force_align_arg_pointer)
2019-03-09 15:59:13 +08:00
__attribute__ ( ( force_align_arg_pointer ) )
2018-09-07 03:43:20 +08:00
# endif
# endif
2019-03-10 18:20:22 +08:00
* uart_communication ( void * targ ) {
2019-04-08 16:13:15 +08:00
communication_arg_t * connection = ( communication_arg_t * ) targ ;
2019-04-21 07:05:02 +08:00
uint32_t rxlen ;
2019-05-07 05:23:45 +08:00
bool commfailed = false ;
2019-04-18 18:43:35 +08:00
PacketResponseNG rx ;
PacketResponseNGRaw rx_raw ;
2018-10-06 19:29:20 +08:00
# if defined(__MACH__) && defined(__APPLE__)
2019-03-10 06:35:06 +08:00
disableAppNap ( " Proxmark3 polling UART " ) ;
2018-10-06 19:29:20 +08:00
# endif
2019-03-09 15:59:13 +08:00
2019-05-07 04:41:00 +08:00
// is this connection->run a cross thread call?
2019-04-08 16:13:15 +08:00
while ( connection - > run ) {
2019-03-10 06:35:06 +08:00
rxlen = 0 ;
bool ACK_received = false ;
2019-04-17 07:06:26 +08:00
bool error = false ;
2019-05-07 04:41:00 +08:00
int res ;
2019-05-06 04:04:35 +08:00
2019-05-07 04:41:00 +08:00
// Signal to main thread that communications seems off.
// main thread will kill and restart this thread.
2019-05-08 07:35:51 +08:00
if ( commfailed ) {
2019-05-08 17:14:29 +08:00
if ( conn . last_command ! = CMD_HARDWARE_RESET ) {
PrintAndLogEx ( WARNING , " Communicating with Proxmark3 device " _RED_ ( " failed " ) ) ;
}
2019-05-06 20:11:23 +08:00
__atomic_test_and_set ( & comm_thread_dead , __ATOMIC_SEQ_CST ) ;
break ;
}
2019-05-07 04:41:00 +08:00
res = uart_receive ( sp , ( uint8_t * ) & rx_raw . pre , sizeof ( PacketResponseNGPreamble ) , & rxlen ) ;
if ( ( res = = PM3_SUCCESS ) & & ( rxlen = = sizeof ( PacketResponseNGPreamble ) ) ) {
2019-04-18 05:44:48 +08:00
rx . magic = rx_raw . pre . magic ;
2019-04-20 09:17:19 +08:00
uint16_t length = rx_raw . pre . length ;
rx . ng = rx_raw . pre . ng ;
2019-04-18 05:44:48 +08:00
rx . status = rx_raw . pre . status ;
rx . cmd = rx_raw . pre . cmd ;
2019-04-19 03:49:32 +08:00
if ( rx . magic = = RESPONSENG_PREAMBLE_MAGIC ) { // New style NG reply
2019-05-01 03:10:11 +08:00
if ( length > PM3_CMD_DATA_SIZE ) {
2019-04-20 09:17:19 +08:00
PrintAndLogEx ( WARNING , " Received packet frame with incompatible length: 0x%04x " , length ) ;
2019-04-17 07:06:26 +08:00
error = true ;
}
2019-04-20 09:17:19 +08:00
if ( ( ! error ) & & ( length > 0 ) ) { // Get the variable length payload
2019-05-08 07:35:51 +08:00
2019-05-07 04:41:00 +08:00
res = uart_receive ( sp , ( uint8_t * ) & rx_raw . data , length , & rxlen ) ;
2019-05-08 07:35:51 +08:00
if ( ( res ! = PM3_SUCCESS ) | | ( rxlen ! = length ) ) {
2019-07-14 18:17:34 +08:00
PrintAndLogEx ( WARNING , " Received packet frame with variable part too short? %d/%d " , rxlen , length ) ;
2019-04-17 07:06:26 +08:00
error = true ;
2019-04-18 05:44:48 +08:00
} else {
2019-04-20 09:17:19 +08:00
2019-05-06 04:34:22 +08:00
if ( rx . ng ) { // Received a valid NG frame
2019-04-20 09:17:19 +08:00
memcpy ( & rx . data , & rx_raw . data , length ) ;
rx . length = length ;
2019-05-06 04:34:22 +08:00
if ( ( rx . cmd = = conn . last_command ) & & ( rx . status = = PM3_SUCCESS ) ) {
ACK_received = true ;
}
2019-04-20 09:17:19 +08:00
} else {
uint64_t arg [ 3 ] ;
if ( length < sizeof ( arg ) ) {
PrintAndLogEx ( WARNING , " Received MIX packet frame with incompatible length: 0x%04x " , length ) ;
error = true ;
}
2019-05-06 04:34:22 +08:00
if ( ! error ) { // Received a valid MIX frame
2019-04-20 09:17:19 +08:00
memcpy ( arg , & rx_raw . data , sizeof ( arg ) ) ;
rx . oldarg [ 0 ] = arg [ 0 ] ;
rx . oldarg [ 1 ] = arg [ 1 ] ;
rx . oldarg [ 2 ] = arg [ 2 ] ;
memcpy ( & rx . data , ( ( uint8_t * ) & rx_raw . data ) + sizeof ( arg ) , length - sizeof ( arg ) ) ;
rx . length = length - sizeof ( arg ) ;
2019-04-30 04:39:18 +08:00
if ( rx . cmd = = CMD_ACK ) {
ACK_received = true ;
}
2019-04-20 09:17:19 +08:00
}
}
2019-04-17 07:06:26 +08:00
}
}
if ( ! error ) { // Get the postamble
2019-05-07 04:41:00 +08:00
res = uart_receive ( sp , ( uint8_t * ) & rx_raw . foopost , sizeof ( PacketResponseNGPostamble ) , & rxlen ) ;
if ( ( res ! = PM3_SUCCESS ) | | ( rxlen ! = sizeof ( PacketResponseNGPostamble ) ) ) {
2019-07-14 18:17:34 +08:00
PrintAndLogEx ( WARNING , " Received packet frame without postamble " ) ;
2019-04-17 07:06:26 +08:00
error = true ;
}
2019-04-18 05:44:48 +08:00
}
2019-04-19 03:39:35 +08:00
if ( ! error ) { // Check CRC, accept MAGIC as placeholder
2019-04-18 06:12:52 +08:00
rx . crc = rx_raw . foopost . crc ;
2019-04-19 03:49:32 +08:00
if ( rx . crc ! = RESPONSENG_POSTAMBLE_MAGIC ) {
2019-04-19 03:39:35 +08:00
uint8_t first , second ;
2019-04-20 09:17:19 +08:00
compute_crc ( CRC_14443_A , ( uint8_t * ) & rx_raw , sizeof ( PacketResponseNGPreamble ) + length , & first , & second ) ;
2019-04-19 03:39:35 +08:00
if ( ( first < < 8 ) + second ! = rx . crc ) {
2019-07-14 18:17:34 +08:00
PrintAndLogEx ( WARNING , " Received packet frame with invalid CRC %02X%02X <> %04X " , first , second , rx . crc ) ;
2019-04-19 03:39:35 +08:00
error = true ;
}
2019-04-17 07:06:26 +08:00
}
}
2019-05-06 04:34:22 +08:00
if ( ! error ) { // Received a valid OLD frame
2019-04-30 04:38:54 +08:00
# ifdef COMMS_DEBUG
PrintAndLogEx ( NORMAL , " Receiving %s: " , rx . ng ? " NG " : " MIX " ) ;
# endif
# ifdef COMMS_DEBUG_RAW
print_hex_break ( ( uint8_t * ) & rx_raw . pre , sizeof ( PacketResponseNGPreamble ) , 32 ) ;
print_hex_break ( ( uint8_t * ) & rx_raw . data , rx_raw . pre . length , 32 ) ;
print_hex_break ( ( uint8_t * ) & rx_raw . foopost , sizeof ( PacketResponseNGPostamble ) , 32 ) ;
# endif
2019-04-18 18:43:35 +08:00
PacketResponseReceived ( & rx ) ;
2019-04-17 07:06:26 +08:00
}
} else { // Old style reply
2019-04-18 18:43:35 +08:00
PacketResponseOLD rx_old ;
memcpy ( & rx_old , & rx_raw . pre , sizeof ( PacketResponseNGPreamble ) ) ;
2019-05-08 07:35:51 +08:00
2019-05-07 04:41:00 +08:00
res = uart_receive ( sp , ( ( uint8_t * ) & rx_old ) + sizeof ( PacketResponseNGPreamble ) , sizeof ( PacketResponseOLD ) - sizeof ( PacketResponseNGPreamble ) , & rxlen ) ;
if ( ( res ! = PM3_SUCCESS ) | | ( rxlen ! = sizeof ( PacketResponseOLD ) - sizeof ( PacketResponseNGPreamble ) ) ) {
2019-10-06 05:56:19 +08:00
PrintAndLogEx ( WARNING , " Received packet OLD frame with payload too short? %d/%zu " , rxlen , sizeof ( PacketResponseOLD ) - sizeof ( PacketResponseNGPreamble ) ) ;
2019-04-17 07:06:26 +08:00
error = true ;
}
if ( ! error ) {
2019-04-30 04:38:54 +08:00
# ifdef COMMS_DEBUG
PrintAndLogEx ( NORMAL , " Receiving OLD: " ) ;
# endif
# ifdef COMMS_DEBUG_RAW
print_hex_break ( ( uint8_t * ) & rx_old . cmd , sizeof ( rx_old . cmd ) , 32 ) ;
print_hex_break ( ( uint8_t * ) & rx_old . arg , sizeof ( rx_old . arg ) , 32 ) ;
print_hex_break ( ( uint8_t * ) & rx_old . d , sizeof ( rx_old . d ) , 32 ) ;
# endif
2019-04-18 03:30:01 +08:00
rx . ng = false ;
rx . magic = 0 ;
rx . status = 0 ;
rx . crc = 0 ;
2019-04-18 05:44:48 +08:00
rx . cmd = rx_old . cmd ;
rx . oldarg [ 0 ] = rx_old . arg [ 0 ] ;
rx . oldarg [ 1 ] = rx_old . arg [ 1 ] ;
rx . oldarg [ 2 ] = rx_old . arg [ 2 ] ;
2019-05-01 03:10:11 +08:00
rx . length = PM3_CMD_DATA_SIZE ;
2019-04-18 05:44:48 +08:00
memcpy ( & rx . data , & rx_old . d , rx . length ) ;
2019-04-18 18:43:35 +08:00
PacketResponseReceived ( & rx ) ;
2019-04-18 05:44:48 +08:00
if ( rx . cmd = = CMD_ACK ) {
2019-04-17 07:06:26 +08:00
ACK_received = true ;
}
}
2019-03-10 06:35:06 +08:00
}
2019-04-17 07:06:26 +08:00
} else {
if ( rxlen > 0 ) {
2019-10-06 05:56:19 +08:00
PrintAndLogEx ( WARNING , " Received packet frame preamble too short: %d/%zu " , rxlen , sizeof ( PacketResponseNGPreamble ) ) ;
2019-04-17 07:06:26 +08:00
error = true ;
2019-03-10 06:35:06 +08:00
}
2019-05-07 05:23:45 +08:00
if ( res = = PM3_ENOTTY ) {
commfailed = true ;
}
2019-03-10 06:35:06 +08:00
}
2019-05-06 04:04:35 +08:00
2019-04-24 21:57:24 +08:00
// TODO if error, shall we resync ?
2019-03-10 06:35:06 +08:00
pthread_mutex_lock ( & txBufferMutex ) ;
2019-04-08 16:13:15 +08:00
if ( connection - > block_after_ACK ) {
2019-03-10 06:35:06 +08:00
// if we just received an ACK, wait here until a new command is to be transmitted
2019-04-26 19:53:11 +08:00
// This is only working on OLD frames, and only used by flasher and flashmem
2019-03-10 06:35:06 +08:00
if ( ACK_received ) {
2019-04-30 04:38:54 +08:00
# ifdef COMMS_DEBUG
PrintAndLogEx ( NORMAL , " Received ACK, fast TX mode: ignoring other RX till TX " ) ;
# endif
2019-03-10 06:35:06 +08:00
while ( ! txBuffer_pending ) {
pthread_cond_wait ( & txBufferSig , & txBufferMutex ) ;
}
}
}
if ( txBuffer_pending ) {
2019-05-06 04:04:35 +08:00
2019-04-16 16:01:08 +08:00
if ( txBufferNGLen ) { // NG packet
2019-05-07 04:41:00 +08:00
res = uart_send ( sp , ( uint8_t * ) & txBufferNG , txBufferNGLen ) ;
if ( res = = PM3_EIO ) {
2019-05-07 05:23:45 +08:00
commfailed = true ;
2019-04-16 16:01:08 +08:00
}
2019-05-06 04:34:22 +08:00
conn . last_command = txBufferNG . pre . cmd ;
2019-04-16 16:01:08 +08:00
txBufferNGLen = 0 ;
} else {
2019-05-07 04:41:00 +08:00
res = uart_send ( sp , ( uint8_t * ) & txBuffer , sizeof ( PacketCommandOLD ) ) ;
if ( res = = PM3_EIO ) {
2019-05-07 05:23:45 +08:00
commfailed = true ;
2019-04-16 16:01:08 +08:00
}
2019-05-06 04:34:22 +08:00
conn . last_command = txBuffer . cmd ;
2019-03-10 06:35:06 +08:00
}
2019-05-06 04:04:35 +08:00
2019-03-10 06:35:06 +08:00
txBuffer_pending = false ;
2019-05-08 07:35:51 +08:00
2019-05-07 04:41:00 +08:00
// main thread doesn't know send failed...
2019-05-08 07:35:51 +08:00
2019-03-10 06:35:06 +08:00
// tell main thread that txBuffer is empty
pthread_cond_signal ( & txBufferSig ) ;
}
pthread_mutex_unlock ( & txBufferMutex ) ;
}
2018-09-07 03:43:20 +08:00
2019-05-06 20:11:23 +08:00
// when thread dies, we close the serial port.
2019-03-10 06:35:06 +08:00
uart_close ( sp ) ;
sp = NULL ;
2018-10-06 19:29:20 +08:00
# if defined(__MACH__) && defined(__APPLE__)
2019-03-10 06:35:06 +08:00
enableAppNap ( ) ;
2018-10-06 19:29:20 +08:00
# endif
2019-05-08 07:35:51 +08:00
2019-03-10 06:35:06 +08:00
pthread_exit ( NULL ) ;
return NULL ;
2018-09-07 03:43:20 +08:00
}
2019-05-06 20:11:23 +08:00
bool IsCommunicationThreadDead ( void ) {
2019-05-07 04:41:00 +08:00
bool ret = __atomic_load_n ( & comm_thread_dead , __ATOMIC_SEQ_CST ) ;
return ret ;
2019-05-06 20:11:23 +08:00
}
2019-04-03 04:06:10 +08:00
bool OpenProxmark ( void * port , bool wait_for_port , int timeout , bool flash_mode , uint32_t speed ) {
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
char * portname = ( char * ) port ;
if ( ! wait_for_port ) {
2019-04-15 00:51:07 +08:00
PrintAndLogEx ( INFO , " Using UART port " _YELLOW_ ( " %s " ) , portname ) ;
2019-04-03 04:06:10 +08:00
sp = uart_open ( portname , speed ) ;
2019-03-10 06:35:06 +08:00
} else {
2019-04-17 02:00:25 +08:00
PrintAndLogEx ( SUCCESS , " Waiting for Proxmark3 to appear on " _YELLOW_ ( " %s " ) , portname ) ;
2019-03-10 06:35:06 +08:00
fflush ( stdout ) ;
int openCount = 0 ;
2020-02-12 09:26:44 +08:00
PrintAndLogEx ( INPLACE , " " ) ;
2019-03-10 06:35:06 +08:00
do {
2019-04-03 04:06:10 +08:00
sp = uart_open ( portname , speed ) ;
2019-03-10 06:35:06 +08:00
msleep ( 500 ) ;
2019-03-10 07:00:59 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-03-10 06:35:06 +08:00
} while ( + + openCount < timeout & & ( sp = = INVALID_SERIAL_PORT | | sp = = CLAIMED_SERIAL_PORT ) ) ;
}
// check result of uart opening
if ( sp = = INVALID_SERIAL_PORT ) {
2019-05-01 02:19:29 +08:00
PrintAndLogEx ( WARNING , " \n " _RED_ ( " ERROR: " ) " invalid serial port " _YELLOW_ ( " %s " ) , portname ) ;
2019-03-10 06:35:06 +08:00
sp = NULL ;
return false ;
} else if ( sp = = CLAIMED_SERIAL_PORT ) {
2019-05-01 02:19:29 +08:00
PrintAndLogEx ( WARNING , " \n " _RED_ ( " ERROR: " ) " serial port " _YELLOW_ ( " %s " ) " is claimed by another process " , portname ) ;
2019-03-10 06:35:06 +08:00
sp = NULL ;
return false ;
} else {
2019-05-06 20:11:23 +08:00
// start the communication thread
2019-05-08 07:35:51 +08:00
if ( portname ! = ( char * ) conn . serial_port_name ) {
uint16_t len = MIN ( strlen ( portname ) , FILE_PATH_SIZE - 1 ) ;
2019-05-07 21:57:22 +08:00
memset ( conn . serial_port_name , 0 , FILE_PATH_SIZE ) ;
memcpy ( conn . serial_port_name , portname , len ) ;
2020-01-29 22:16:50 +08:00
memset ( gui_serial_port_name , 0 , FILE_PATH_SIZE ) ;
memcpy ( gui_serial_port_name , portname , len ) ;
2019-05-07 21:57:22 +08:00
}
2019-03-10 06:35:06 +08:00
conn . run = true ;
conn . block_after_ACK = flash_mode ;
2019-04-27 05:16:24 +08:00
// Flags to tell where to add CRC on sent replies
conn . send_with_crc_on_usb = false ;
conn . send_with_crc_on_fpc = true ;
// "Session" flag, to tell via which interface next msgs should be sent: USB or FPC USART
2019-05-04 04:30:17 +08:00
conn . send_via_fpc_usart = false ;
2019-04-27 05:16:24 +08:00
2019-05-06 20:11:23 +08:00
pthread_create ( & communication_thread , NULL , & uart_communication , & conn ) ;
2019-05-07 18:11:36 +08:00
__atomic_clear ( & comm_thread_dead , __ATOMIC_SEQ_CST ) ;
2019-05-08 02:37:23 +08:00
session . pm3_present = true ;
2019-05-04 03:58:47 +08:00
2019-03-10 06:35:06 +08:00
fflush ( stdout ) ;
return true ;
}
2018-09-07 03:43:20 +08:00
}
2019-04-16 23:26:15 +08:00
// check if we can communicate with Pm3
2019-04-14 23:25:17 +08:00
int TestProxmark ( void ) {
2019-05-19 00:51:05 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-04-27 08:46:20 +08:00
uint16_t len = 32 ;
uint8_t data [ len ] ;
for ( uint16_t i = 0 ; i < len ; i + + )
data [ i ] = i & 0xFF ;
2019-05-08 07:35:51 +08:00
2019-08-07 18:30:44 +08:00
__atomic_store_n ( & last_packet_time , msclock ( ) , __ATOMIC_SEQ_CST ) ;
2019-05-19 00:51:05 +08:00
clearCommandBuffer ( ) ;
2019-04-27 08:46:20 +08:00
SendCommandNG ( CMD_PING , data , len ) ;
2019-05-06 20:11:23 +08:00
uint32_t timeout = 1000 ;
2019-05-08 07:35:51 +08:00
2019-04-27 07:16:43 +08:00
# ifdef USART_SLOW_LINK
// 10s timeout for slow FPC, e.g. over BT
// as this is the very first command sent to the pm3
2019-05-08 07:35:51 +08:00
// that initiates the BT connection
2019-05-19 00:51:05 +08:00
timeout = 10000 ;
2019-04-27 07:16:43 +08:00
# endif
2019-04-27 08:46:20 +08:00
2019-05-16 13:33:02 +08:00
if ( WaitForResponseTimeoutW ( CMD_PING , & resp , timeout , false ) = = 0 ) {
return PM3_ETIMEOUT ;
}
2019-05-08 07:35:51 +08:00
2019-05-16 13:33:02 +08:00
bool error = false ;
2019-06-12 21:41:23 +08:00
error = memcmp ( data , resp . data . asBytes , len ) ! = 0 ;
2019-06-08 03:40:33 +08:00
2019-05-16 13:33:02 +08:00
if ( error )
return PM3_EIO ;
2019-05-06 04:04:35 +08:00
2019-05-16 13:33:02 +08:00
SendCommandNG ( CMD_CAPABILITIES , NULL , 0 ) ;
if ( WaitForResponseTimeoutW ( CMD_CAPABILITIES , & resp , 1000 , false ) = = 0 ) {
2019-04-27 08:46:20 +08:00
return PM3_ETIMEOUT ;
2019-04-14 23:25:17 +08:00
}
2019-06-08 03:40:33 +08:00
2019-05-16 13:33:02 +08:00
if ( ( resp . length ! = sizeof ( pm3_capabilities ) ) | | ( resp . data . asBytes [ 0 ] ! = CAPABILITIES_VERSION ) ) {
PrintAndLogEx ( ERR , _RED_ ( " Capabilities structure version sent by Proxmark3 is not the same as the one used by the client! " ) ) ;
PrintAndLogEx ( ERR , _RED_ ( " Please flash the Proxmark with the same version as the client. " ) ) ;
return PM3_EDEVNOTSUPP ;
}
memcpy ( & pm3_capabilities , resp . data . asBytes , MIN ( sizeof ( capabilities_t ) , resp . length ) ) ;
conn . send_via_fpc_usart = pm3_capabilities . via_fpc ;
conn . uart_speed = pm3_capabilities . baudrate ;
2019-06-08 03:40:33 +08:00
2019-07-29 01:23:37 +08:00
PrintAndLogEx ( INFO , " Communicating with PM3 over %s%s " ,
conn . send_via_fpc_usart ? _YELLOW_ ( " FPC UART " ) : _YELLOW_ ( " USB-CDC " ) ,
memcmp ( conn . serial_port_name , " tcp: " , 4 ) = = 0 ? " over " _YELLOW_ ( " TCP " ) : " " ) ;
2019-06-08 03:40:33 +08:00
2019-05-16 13:33:02 +08:00
if ( conn . send_via_fpc_usart ) {
2019-05-19 00:51:05 +08:00
PrintAndLogEx ( INFO , " PM3 UART serial baudrate: " _YELLOW_ ( " %u " ) " \n " , conn . uart_speed ) ;
2019-05-16 13:33:02 +08:00
} else {
2019-05-16 18:35:40 +08:00
int res = uart_reconfigure_timeouts ( UART_USB_CLIENT_RX_TIMEOUT_MS ) ;
if ( res ! = PM3_SUCCESS ) {
return res ;
}
2019-05-16 13:33:02 +08:00
}
return PM3_SUCCESS ;
2019-04-14 23:25:17 +08:00
}
2019-03-10 18:20:22 +08:00
void CloseProxmark ( void ) {
2019-03-10 06:35:06 +08:00
conn . run = false ;
2018-09-15 18:00:53 +08:00
# ifdef __BIONIC__
2019-05-06 20:11:23 +08:00
if ( communication_thread ! = 0 ) {
pthread_join ( communication_thread , NULL ) ;
2019-03-10 06:35:06 +08:00
}
2018-09-15 18:00:53 +08:00
# else
2019-05-06 20:11:23 +08:00
pthread_join ( communication_thread , NULL ) ;
2018-09-15 18:00:53 +08:00
# endif
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
if ( sp ) {
uart_close ( sp ) ;
}
2018-09-07 03:43:20 +08:00
2019-03-10 06:35:06 +08:00
// Clean up our state
sp = NULL ;
2020-03-22 03:18:42 +08:00
# ifdef __BIONIC__
if ( communication_thread ! = 0 ) {
memset ( & communication_thread , 0 , sizeof ( pthread_t ) ) ;
}
# else
2019-05-06 20:11:23 +08:00
memset ( & communication_thread , 0 , sizeof ( pthread_t ) ) ;
2020-03-22 03:18:42 +08:00
# endif
2019-05-08 07:35:51 +08:00
2019-05-07 23:31:07 +08:00
session . pm3_present = false ;
2018-09-07 03:43:20 +08:00
}
2019-04-21 01:17:32 +08:00
// Gives a rough estimate of the communication delay based on channel & baudrate
// Max communication delay is when sending largest frame and receiving largest frame
// Empirical measures on FTDI with physical cable:
// "hw pingng 512"
// usb -> 6..32ms
// 460800 -> 40..70ms
// 9600 -> 1100..1150ms
// ~ = 12000000 / USART_BAUD_RATE
// Let's take 2x (maybe we need more for BT link?)
static size_t communication_delay ( void ) {
2019-05-04 04:30:17 +08:00
if ( conn . send_via_fpc_usart ) // needed also for Windows USB USART??
2019-04-27 07:15:52 +08:00
return 2 * ( 12000000 / conn . uart_speed ) ;
2019-05-29 16:00:02 +08:00
return 0 ;
2019-04-21 01:17:32 +08:00
}
2018-09-07 03:43:20 +08:00
/**
* @ brief Waits for a certain response type . This method waits for a maximum of
* ms_timeout milliseconds for a specified response command .
2019-03-09 15:59:13 +08:00
2018-09-07 03:43:20 +08:00
* @ param cmd command to wait for , or CMD_UNKNOWN to take any command .
* @ param response struct to copy received command into .
* @ param ms_timeout display message after 3 seconds
* @ param show_warning display message after 3 seconds
* @ return true if command was returned , otherwise false
*/
2019-04-18 18:43:35 +08:00
bool WaitForResponseTimeoutW ( uint32_t cmd , PacketResponseNG * response , size_t ms_timeout , bool show_warning ) {
2019-03-09 15:59:13 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2018-09-07 03:43:20 +08:00
2019-03-10 06:35:06 +08:00
if ( response = = NULL )
response = & resp ;
2018-09-07 03:43:20 +08:00
2019-04-21 01:17:32 +08:00
// Add delay depending on the communication channel & speed
2019-05-29 16:00:02 +08:00
if ( ms_timeout ! = ( size_t ) - 1 )
2019-04-22 05:26:51 +08:00
ms_timeout + = communication_delay ( ) ;
2019-05-03 23:53:32 +08:00
__atomic_store_n ( & timeout_start_time , msclock ( ) , __ATOMIC_SEQ_CST ) ;
2019-05-06 04:04:35 +08:00
2019-03-10 06:35:06 +08:00
// Wait until the command is received
while ( true ) {
2018-09-07 03:43:20 +08:00
2019-04-18 03:30:01 +08:00
while ( getReply ( response ) ) {
2019-04-21 01:17:32 +08:00
if ( cmd = = CMD_UNKNOWN | | response - > cmd = = cmd ) {
2019-03-10 06:35:06 +08:00
return true ;
2019-04-21 01:17:32 +08:00
}
2019-08-07 18:41:53 +08:00
if ( response - > cmd = = CMD_WTX & & response - > length = = sizeof ( uint16_t ) ) {
uint16_t wtx = response - > data . asDwords [ 0 ] & 0xFFFF ;
PrintAndLogEx ( DEBUG , " Got Waiting Time eXtension request %i ms " , wtx ) ;
if ( ms_timeout ! = ( size_t ) - 1 )
ms_timeout + = wtx ;
}
2019-03-10 06:35:06 +08:00
}
2018-09-07 03:43:20 +08:00
2019-06-08 00:41:39 +08:00
uint64_t tmp_clk = __atomic_load_n ( & timeout_start_time , __ATOMIC_SEQ_CST ) ;
2020-01-01 04:38:13 +08:00
if ( ( ms_timeout ! = ( size_t ) - 1 ) & & ( msclock ( ) - tmp_clk > ms_timeout ) )
2019-03-10 06:35:06 +08:00
break ;
2019-03-09 15:59:13 +08:00
2019-05-03 23:53:32 +08:00
if ( msclock ( ) - tmp_clk > 3000 & & show_warning ) {
2019-03-10 06:35:06 +08:00
// 3 seconds elapsed (but this doesn't mean the timeout was exceeded)
2019-05-19 00:51:05 +08:00
// PrintAndLogEx(INFO, "Waiting for a response from the Proxmark3...");
2019-04-16 23:26:15 +08:00
PrintAndLogEx ( INFO , " You can cancel this operation by pressing the pm3 button " ) ;
2019-03-10 06:35:06 +08:00
show_warning = false ;
}
2019-10-02 05:00:51 +08:00
// just to avoid CPU busy loop:
msleep ( 10 ) ;
2019-03-10 06:35:06 +08:00
}
return false ;
2018-09-07 03:43:20 +08:00
}
2019-04-18 18:43:35 +08:00
bool WaitForResponseTimeout ( uint32_t cmd , PacketResponseNG * response , size_t ms_timeout ) {
2019-03-10 06:35:06 +08:00
return WaitForResponseTimeoutW ( cmd , response , ms_timeout , true ) ;
2018-09-07 03:43:20 +08:00
}
2019-04-18 18:43:35 +08:00
bool WaitForResponse ( uint32_t cmd , PacketResponseNG * response ) {
2019-03-10 06:35:06 +08:00
return WaitForResponseTimeoutW ( cmd , response , - 1 , true ) ;
2018-09-07 03:43:20 +08:00
}
/**
* Data transfer from Proxmark to client . This method times out after
* ms_timeout milliseconds .
* @ brief GetFromDevice
* @ param memtype Type of memory to download from proxmark
* @ param dest Destination address for transfer
* @ param bytes number of bytes to be transferred
* @ param start_index offset into Proxmark3 BigBuf [ ]
2019-07-24 03:45:06 +08:00
* @ param data used by SPIFFS to provide filename
* @ param datalen used by SPIFFS to provide filename length
2018-09-07 03:43:20 +08:00
* @ param response struct to copy last command ( CMD_ACK ) into
* @ param ms_timeout timeout in milliseconds
* @ param show_warning display message after 2 seconds
* @ return true if command was returned , otherwise false
*/
2019-07-23 04:56:06 +08:00
bool GetFromDevice ( DeviceMemType_t memtype , uint8_t * dest , uint32_t bytes , uint32_t start_index , uint8_t * data , uint32_t datalen , PacketResponseNG * response , size_t ms_timeout , bool show_warning ) {
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
if ( dest = = NULL ) return false ;
if ( bytes = = 0 ) return true ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
if ( response = = NULL )
response = & resp ;
// clear
clearCommandBuffer ( ) ;
switch ( memtype ) {
case BIG_BUF : {
2019-05-07 21:40:01 +08:00
SendCommandMIX ( CMD_DOWNLOAD_BIGBUF , start_index , bytes , 0 , NULL , 0 ) ;
2019-10-27 01:49:46 +08:00
return dl_it ( dest , bytes , response , ms_timeout , show_warning , CMD_DOWNLOADED_BIGBUF ) ;
2019-03-10 06:35:06 +08:00
}
case BIG_BUF_EML : {
2019-05-07 21:40:01 +08:00
SendCommandMIX ( CMD_DOWNLOAD_EML_BIGBUF , start_index , bytes , 0 , NULL , 0 ) ;
2019-10-27 01:49:46 +08:00
return dl_it ( dest , bytes , response , ms_timeout , show_warning , CMD_DOWNLOADED_EML_BIGBUF ) ;
2019-03-10 06:35:06 +08:00
}
2019-07-23 04:56:06 +08:00
case SPIFFS : {
2019-07-24 03:33:52 +08:00
SendCommandMIX ( CMD_SPIFFS_DOWNLOAD , start_index , bytes , 0 , data , datalen ) ;
2019-10-27 01:49:46 +08:00
return dl_it ( dest , bytes , response , ms_timeout , show_warning , CMD_SPIFFS_DOWNLOADED ) ;
2019-07-24 03:33:52 +08:00
}
2019-03-10 06:35:06 +08:00
case FLASH_MEM : {
2019-05-07 21:40:01 +08:00
SendCommandMIX ( CMD_FLASHMEM_DOWNLOAD , start_index , bytes , 0 , NULL , 0 ) ;
2019-10-27 01:49:46 +08:00
return dl_it ( dest , bytes , response , ms_timeout , show_warning , CMD_FLASHMEM_DOWNLOADED ) ;
2019-03-10 06:35:06 +08:00
}
case SIM_MEM : {
2019-05-07 21:40:01 +08:00
//SendCommandMIX(CMD_DOWNLOAD_SIM_MEM, start_index, bytes, 0, NULL, 0);
2019-10-27 01:49:46 +08:00
//return dl_it(dest, bytes, response, ms_timeout, show_warning, CMD_DOWNLOADED_SIMMEM);
2019-03-10 06:35:06 +08:00
return false ;
}
2020-01-12 23:45:24 +08:00
case FPGA_MEM : {
SendCommandMIX ( CMD_FPGAMEM_DOWNLOAD , start_index , bytes , 0 , NULL , 0 ) ;
return dl_it ( dest , bytes , response , ms_timeout , show_warning , CMD_FPGAMEM_DOWNLOADED ) ;
}
2019-03-10 06:35:06 +08:00
}
return false ;
2018-09-07 03:43:20 +08:00
}
2019-10-27 01:49:46 +08:00
static bool dl_it ( uint8_t * dest , uint32_t bytes , PacketResponseNG * response , size_t ms_timeout , bool show_warning , uint32_t rec_cmd ) {
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
uint32_t bytes_completed = 0 ;
2019-05-03 23:53:32 +08:00
__atomic_store_n ( & timeout_start_time , msclock ( ) , __ATOMIC_SEQ_CST ) ;
2019-05-06 04:04:35 +08:00
2019-04-22 08:44:06 +08:00
// Add delay depending on the communication channel & speed
2020-01-01 04:38:13 +08:00
if ( ms_timeout ! = ( size_t ) - 1 )
2019-04-22 08:44:06 +08:00
ms_timeout + = communication_delay ( ) ;
2019-03-10 06:35:06 +08:00
while ( true ) {
2019-04-18 03:30:01 +08:00
if ( getReply ( response ) ) {
2019-03-10 06:35:06 +08:00
// sample_buf is a array pointer, located in data.c
// arg0 = offset in transfer. Startindex of this chunk
// arg1 = length bytes to transfer
// arg2 = bigbuff tracelength (?)
2019-04-18 05:44:48 +08:00
if ( response - > cmd = = rec_cmd ) {
2019-03-10 06:35:06 +08:00
2019-04-18 05:44:48 +08:00
uint32_t offset = response - > oldarg [ 0 ] ;
uint32_t copy_bytes = MIN ( bytes - bytes_completed , response - > oldarg [ 1 ] ) ;
//uint32_t tracelen = response->oldarg[2];
2019-03-10 06:35:06 +08:00
2019-05-01 03:10:11 +08:00
// extended bounds check1. upper limit is PM3_CMD_DATA_SIZE
2019-03-10 06:35:06 +08:00
// shouldn't happen
2019-05-01 03:10:11 +08:00
copy_bytes = MIN ( copy_bytes , PM3_CMD_DATA_SIZE ) ;
2019-03-10 06:35:06 +08:00
// extended bounds check2.
2019-03-10 07:00:59 +08:00
if ( offset + copy_bytes > bytes ) {
PrintAndLogEx ( FAILED , " ERROR: Out of bounds when downloading from device, offset %u | len %u | total len %u > buf_size %u " , offset , copy_bytes , offset + copy_bytes , bytes ) ;
2019-03-10 06:35:06 +08:00
break ;
}
2019-04-18 05:44:48 +08:00
memcpy ( dest + offset , response - > data . asBytes , copy_bytes ) ;
2019-03-10 06:35:06 +08:00
bytes_completed + = copy_bytes ;
2019-04-18 05:44:48 +08:00
} else if ( response - > cmd = = CMD_ACK ) {
2019-03-10 06:35:06 +08:00
return true ;
2019-08-07 18:41:53 +08:00
} else if ( response - > cmd = = CMD_WTX & & response - > length = = sizeof ( uint16_t ) ) {
uint16_t wtx = response - > data . asDwords [ 0 ] & 0xFFFF ;
PrintAndLogEx ( DEBUG , " Got Waiting Time eXtension request %i ms " , wtx ) ;
if ( ms_timeout ! = ( size_t ) - 1 )
ms_timeout + = wtx ;
2019-03-10 06:35:06 +08:00
}
}
2019-06-08 00:41:39 +08:00
uint64_t tmp_clk = __atomic_load_n ( & timeout_start_time , __ATOMIC_SEQ_CST ) ;
2019-05-03 23:53:32 +08:00
if ( msclock ( ) - tmp_clk > ms_timeout ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( FAILED , " Timed out while trying to download data from device " ) ;
break ;
}
2019-05-03 23:53:32 +08:00
if ( msclock ( ) - tmp_clk > 3000 & & show_warning ) {
2019-03-10 06:35:06 +08:00
// 3 seconds elapsed (but this doesn't mean the timeout was exceeded)
2019-04-17 02:00:25 +08:00
PrintAndLogEx ( NORMAL , " Waiting for a response from the Proxmark3... " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " You can cancel this operation by pressing the pm3 button " ) ;
show_warning = false ;
}
}
return false ;
2018-09-07 03:43:20 +08:00
}