2018-09-06 21:43:20 +02: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-04-16 20:00:17 +02:00
# include "crc16.h"
2018-09-06 21:43:20 +02:00
// Serial port that we are communicating with the PM3 on.
static serial_port sp = NULL ;
static char * serial_port_name = NULL ;
// If TRUE, then there is no active connection to the PM3, and we will drop commands sent.
static bool offline ;
2019-04-18 21:39:35 +02:00
// Flags to tell where to add CRC on sent replies
bool send_with_crc_on_usb = false ;
bool send_with_crc_on_fpc = true ;
// "Session" flag, to tell via which interface next msgs should be sent: USB or FPC USART
bool send_via_fpc = false ;
2018-09-06 21:43:20 +02:00
static communication_arg_t conn ;
static pthread_t USB_communication_thread ;
//static pthread_t FPC_communication_thread;
// Transmit buffer.
2019-04-18 12:43:35 +02:00
static PacketCommandOLD txBuffer ;
static PacketCommandNGRaw txBufferNG ;
2019-04-16 10:01:08 +02:00
size_t txBufferNGLen ;
2018-09-06 21:43:20 +02:00
static bool txBuffer_pending = false ;
static pthread_mutex_t txBufferMutex = PTHREAD_MUTEX_INITIALIZER ;
static pthread_cond_t txBufferSig = PTHREAD_COND_INITIALIZER ;
2019-04-16 20:49:32 +02:00
2019-04-18 12:43:35 +02:00
// Used by PacketResponseReceived as a ring buffer for messages that are yet to be
2018-09-06 21:43:20 +02:00
// processed by a command handler (WaitForResponse{,Timeout})
2019-04-18 12:43:35 +02:00
static PacketResponseNG rxBuffer [ CMD_BUFFER_SIZE ] ;
2018-09-06 21:43:20 +02: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-21 23:56:04 +02:00
// Global start time for WaitForResponseTimeout, so we can reset timeout when we get Dbprintf packets
// as sending lot of these packets can slow down things wuite a lot on slow links (e.g. hw status at 9600)
static uint64_t WaitForResponseTimeout_start_time ;
2019-04-18 12:43:35 +02:00
static bool dl_it ( uint8_t * dest , uint32_t bytes , uint32_t start_index , PacketResponseNG * response , size_t ms_timeout , bool show_warning , uint32_t rec_cmd ) ;
2019-04-17 21:30:01 +02:00
2018-09-06 21:43:20 +02:00
// These wrappers are required because it is not possible to access a static
// global variable outside of the context of a single file.
2019-03-10 11:20:22 +01:00
void SetOffline ( bool value ) {
2019-03-09 23:35:06 +01:00
offline = value ;
2018-09-06 21:43:20 +02:00
}
2019-03-10 11:20:22 +01:00
bool IsOffline ( ) {
2019-03-09 23:35:06 +01:00
return offline ;
2018-09-06 21:43:20 +02:00
}
2019-04-18 12:43:35 +02:00
void SendCommand ( PacketCommandOLD * c ) {
2018-09-06 21:43:20 +02:00
2019-03-10 00:00:59 +01:00
# ifdef COMMS_DEBUG
2019-04-18 12:43:35 +02:00
PrintAndLogEx ( NORMAL , " Sending %d bytes | cmd %04x \n " , sizeof ( PacketCommandOLD ) , c - > cmd ) ;
2019-03-10 00:00:59 +01:00
# endif
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
if ( offline ) {
2019-04-17 14:54:42 +02:00
PrintAndLogEx ( WARNING , " Sending bytes to Proxmark3 failed. " _YELLOW_ ( " offline " ) ) ;
2019-03-09 23:35:06 +01:00
return ;
}
2018-09-06 21:43:20 +02:00
2019-03-09 23:35:06 +01: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-06 21:43:20 +02:00
2019-03-09 23:35:06 +01:00
txBuffer = * c ;
txBuffer_pending = true ;
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
// tell communication thread that a new command can be send
pthread_cond_signal ( & txBufferSig ) ;
2018-09-06 21:43:20 +02:00
2019-03-09 23:35:06 +01:00
pthread_mutex_unlock ( & txBufferMutex ) ;
2019-03-09 08:59:13 +01:00
2018-09-06 21:43:20 +02:00
//__atomic_test_and_set(&txcmd_pending, __ATOMIC_SEQ_CST);
}
2019-04-18 22:19:28 +02:00
// Let's move slowly to an API closer to SendCommandNG
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 ) ;
SendCommand ( & c ) ;
}
2019-04-20 02:41:40 +02:00
static void SendCommandNG_internal ( uint16_t cmd , uint8_t * data , size_t len , bool ng ) {
2019-04-16 10:01:08 +02:00
# ifdef COMMS_DEBUG
2019-04-16 20:00:17 +02:00
PrintAndLogEx ( NORMAL , " Sending %d bytes of payload | cmd %04x \n " , len , cmd ) ;
2019-04-16 10:01:08 +02:00
# endif
if ( offline ) {
PrintAndLogEx ( NORMAL , " Sending bytes to proxmark failed - offline " ) ;
return ;
}
2019-04-17 23:44:48 +02:00
if ( len > USB_CMD_DATA_SIZE ) {
2019-04-16 10:01:08 +02:00
PrintAndLogEx ( WARNING , " Sending %d bytes of payload is too much, abort " , len ) ;
return ;
}
2019-04-18 12:43:35 +02:00
PacketCommandNGPostamble * tx_post = ( PacketCommandNGPostamble * ) ( ( uint8_t * ) & txBufferNG + sizeof ( PacketCommandNGPreamble ) + len ) ;
2019-04-16 10:01:08 +02: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-18 21:49:32 +02:00
txBufferNG . pre . magic = COMMANDNG_PREAMBLE_MAGIC ;
2019-04-20 02:41:40 +02:00
txBufferNG . pre . ng = ng ;
2019-04-18 00:12:52 +02:00
txBufferNG . pre . length = len ;
txBufferNG . pre . cmd = cmd ;
memcpy ( & txBufferNG . data , data , len ) ;
2019-04-18 21:41:48 +02:00
2019-04-18 21:39:35 +02:00
if ( ( send_via_fpc & & send_with_crc_on_fpc ) | | ( ( ! send_via_fpc ) & & send_with_crc_on_usb ) ) {
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-18 21:49:32 +02:00
tx_post - > crc = COMMANDNG_POSTAMBLE_MAGIC ;
2019-04-18 21:39:35 +02:00
}
2019-04-18 12:43:35 +02:00
txBufferNGLen = sizeof ( PacketCommandNGPreamble ) + len + sizeof ( PacketCommandNGPostamble ) ;
2019-04-16 10:01:08 +02: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 02:41:40 +02: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 } ;
if ( len > USB_CMD_DATA_SIZE - sizeof ( arg ) ) {
PrintAndLogEx ( WARNING , " Sending %d bytes of payload is too much for MIX frames, abort " , len ) ;
return ;
}
uint8_t cmddata [ USB_CMD_DATA_SIZE ] ;
memcpy ( cmddata , arg , sizeof ( arg ) ) ;
if ( len & & data )
memcpy ( cmddata + sizeof ( arg ) , data , len ) ;
SendCommandNG_internal ( cmd , cmddata , len + sizeof ( arg ) , false ) ;
}
2018-09-06 21:43:20 +02: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 11:20:22 +01:00
void clearCommandBuffer ( ) {
2019-03-09 23:35:06 +01:00
//This is a very simple operation
pthread_mutex_lock ( & rxBufferMutex ) ;
cmd_tail = cmd_head ;
pthread_mutex_unlock ( & rxBufferMutex ) ;
2018-09-06 21:43:20 +02:00
}
/**
* @ brief storeCommand stores a USB command in a circular buffer
* @ param UC
*/
2019-04-18 12:43:35 +02:00
static void storeReply ( PacketResponseNG * packet ) {
2019-03-09 23:35:06 +01:00
pthread_mutex_lock ( & rxBufferMutex ) ;
2019-03-10 00:00:59 +01:00
if ( ( cmd_head + 1 ) % CMD_BUFFER_SIZE = = cmd_tail ) {
2018-09-06 21:43:20 +02: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-09 23:35:06 +01:00
fflush ( stdout ) ;
2018-09-06 21:43:20 +02:00
}
//Store the command at the 'head' location
2019-04-18 12:43:35 +02:00
PacketResponseNG * destination = & rxBuffer [ cmd_head ] ;
memcpy ( destination , packet , sizeof ( PacketResponseNG ) ) ;
2018-09-06 21:43:20 +02:00
2019-03-10 00:00:59 +01:00
//increment head and wrap
cmd_head = ( cmd_head + 1 ) % CMD_BUFFER_SIZE ;
2019-03-09 23:35:06 +01:00
pthread_mutex_unlock ( & rxBufferMutex ) ;
2018-09-06 21:43:20 +02: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 12:43:35 +02:00
static int getReply ( PacketResponseNG * packet ) {
2019-03-09 23:35:06 +01:00
pthread_mutex_lock ( & rxBufferMutex ) ;
2018-09-06 21:43:20 +02:00
//If head == tail, there's nothing to read, or if we just got initialized
if ( cmd_head = = cmd_tail ) {
2019-03-09 23:35:06 +01:00
pthread_mutex_unlock ( & rxBufferMutex ) ;
return 0 ;
}
2019-03-09 08:59:13 +01:00
2018-09-06 21:43:20 +02:00
//Pick out the next unread command
2019-04-18 12:43:35 +02:00
memcpy ( packet , & rxBuffer [ cmd_tail ] , sizeof ( PacketResponseNG ) ) ;
2018-09-06 21:43:20 +02:00
//Increment tail - this is a circular buffer, so modulo buffer size
2019-03-10 00:00:59 +01:00
cmd_tail = ( cmd_tail + 1 ) % CMD_BUFFER_SIZE ;
2018-09-06 21:43:20 +02:00
2019-03-09 23:35:06 +01:00
pthread_mutex_unlock ( & rxBufferMutex ) ;
2018-09-06 21:43:20 +02: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 12:43:35 +02:00
static void PacketResponseReceived ( PacketResponseNG * packet ) {
2019-04-17 01:06:26 +02:00
2019-04-20 01:49:37 +02:00
// PrintAndLogEx(NORMAL, "RECV %s magic %08x length %04x status %04x crc %04x cmd %04x",
// packet->ng ? "NG" : "OLD", packet->magic, packet->length, packet->status, packet->crc, packet->cmd);
2019-04-17 21:30:01 +02:00
2019-04-21 23:56:04 +02:00
// we got a packet, reset WaitForResponseTimeout timeout
WaitForResponseTimeout_start_time = msclock ( ) ;
2019-04-17 23:44:48 +02:00
switch ( packet - > cmd ) {
2019-03-09 23:35:06 +01:00
// First check if we are handling a debug message
case CMD_DEBUG_PRINT_STRING : {
2019-03-10 00:00:59 +01:00
char s [ USB_CMD_DATA_SIZE + 1 ] ;
2019-03-09 23:35:06 +01:00
memset ( s , 0x00 , sizeof ( s ) ) ;
2019-04-22 01:33:32 +02:00
size_t len ;
uint16_t flag ;
if ( packet - > ng ) {
struct d {
uint16_t flag ;
uint8_t buf [ USB_CMD_DATA_SIZE - sizeof ( uint16_t ) ] ;
} PACKED ;
struct d * data = ( struct d * ) & packet - > data . asBytes ;
len = packet - > length - sizeof ( data - > flag ) ;
memcpy ( s , data - > buf , len ) ;
flag = data - > flag ;
} else {
len = MIN ( packet - > oldarg [ 0 ] , USB_CMD_DATA_SIZE ) ;
memcpy ( s , packet - > data . asBytes , len ) ;
flag = packet - > oldarg [ 1 ] ;
}
2019-03-09 23:35:06 +01:00
switch ( flag ) {
case FLAG_RAWPRINT :
printf ( " %s " , s ) ;
break ;
case FLAG_NONEWLINE :
printf ( " \r %s " , s ) ;
break ;
case FLAG_NOLOG :
printf ( " %s \r \n " , s ) ;
break ;
//case FLAG_NOPROMPT:
// break;
case FLAG_NOOPT :
default :
PrintAndLogEx ( NORMAL , " #db# %s " , s ) ;
break ;
}
fflush ( stdout ) ;
break ;
}
case CMD_DEBUG_PRINT_INTEGERS : {
2019-04-17 23:44:48 +02:00
PrintAndLogEx ( NORMAL , " #db# % " PRIx64 " , % " PRIx64 " , % " PRIx64 " " , packet - > oldarg [ 0 ] , packet - > oldarg [ 1 ] , packet - > oldarg [ 2 ] ) ;
2019-03-09 23:35:06 +01:00
break ;
}
// iceman: hw status - down the path on device, runs printusbspeed which starts sending a lot of
// CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K packages which is not dealt with. I wonder if simply ignoring them will
// work. lets try it.
default : {
2019-04-17 01:06:26 +02:00
storeReply ( packet ) ;
2019-03-09 23:35:06 +01:00
break ;
}
}
2018-09-06 21:43:20 +02:00
}
/*
2019-03-09 08:59:13 +01:00
bool hookUpPM3 ( ) {
2019-03-09 23:35:06 +01:00
bool ret = false ;
2019-04-02 22:06:10 +02:00
sp = uart_open ( comport , speed ) ;
2019-03-09 23:35:06 +01:00
if ( sp = = INVALID_SERIAL_PORT ) {
PrintAndLogEx ( WARNING , " Reconnect failed, retrying... (reason: invalid serial port) \n " ) ;
sp = NULL ;
serial_port_name = NULL ;
ret = false ;
offline = 1 ;
} else if ( sp = = CLAIMED_SERIAL_PORT ) {
PrintAndLogEx ( WARNING , " Reconnect failed, retrying... (reason: serial port is claimed by another process) \n " ) ;
sp = NULL ;
serial_port_name = NULL ;
ret = false ;
offline = 1 ;
} else {
2019-04-16 20:00:25 +02:00
PrintAndLogEx ( SUCCESS , " Proxmark3 reconnected \n " ) ;
2019-03-09 23:35:06 +01:00
serial_port_name = ;
ret = true ;
offline = 0 ;
}
return ret ;
2018-09-06 21:43:20 +02:00
}
*/
2019-04-13 00:25:43 +02:00
static void
2018-09-06 21:43:20 +02:00
# ifdef __has_attribute
# if __has_attribute(force_align_arg_pointer)
2019-03-09 08:59:13 +01:00
__attribute__ ( ( force_align_arg_pointer ) )
2018-09-06 21:43:20 +02:00
# endif
# endif
2019-03-10 11:20:22 +01:00
* uart_communication ( void * targ ) {
2019-04-08 10:13:15 +02:00
communication_arg_t * connection = ( communication_arg_t * ) targ ;
2019-04-21 01:05:02 +02:00
uint32_t rxlen ;
2019-03-09 08:59:13 +01:00
2019-04-18 12:43:35 +02:00
PacketResponseNG rx ;
PacketResponseNGRaw rx_raw ;
2019-03-09 23:35:06 +01:00
//int counter_to_offline = 0;
2018-10-06 13:29:20 +02:00
# if defined(__MACH__) && defined(__APPLE__)
2019-03-09 23:35:06 +01:00
disableAppNap ( " Proxmark3 polling UART " ) ;
2018-10-06 13:29:20 +02:00
# endif
2019-03-09 08:59:13 +01:00
2019-04-08 10:13:15 +02:00
while ( connection - > run ) {
2019-03-09 23:35:06 +01:00
rxlen = 0 ;
bool ACK_received = false ;
2019-04-17 01:06:26 +02:00
bool error = false ;
2019-04-18 12:43:35 +02:00
if ( uart_receive ( sp , ( uint8_t * ) & rx_raw . pre , sizeof ( PacketResponseNGPreamble ) , & rxlen ) & & ( rxlen = = sizeof ( PacketResponseNGPreamble ) ) ) {
2019-04-17 23:44:48 +02:00
rx . magic = rx_raw . pre . magic ;
2019-04-20 03:17:19 +02:00
uint16_t length = rx_raw . pre . length ;
rx . ng = rx_raw . pre . ng ;
2019-04-17 23:44:48 +02:00
rx . status = rx_raw . pre . status ;
rx . cmd = rx_raw . pre . cmd ;
2019-04-18 21:49:32 +02:00
if ( rx . magic = = RESPONSENG_PREAMBLE_MAGIC ) { // New style NG reply
2019-04-20 03:17:19 +02:00
if ( length > USB_CMD_DATA_SIZE ) {
PrintAndLogEx ( WARNING , " Received packet frame with incompatible length: 0x%04x " , length ) ;
2019-04-17 01:06:26 +02:00
error = true ;
}
2019-04-20 03:17:19 +02:00
if ( ( ! error ) & & ( length > 0 ) ) { // Get the variable length payload
if ( ( ! uart_receive ( sp , ( uint8_t * ) & rx_raw . data , length , & rxlen ) ) | | ( rxlen ! = length ) ) {
PrintAndLogEx ( WARNING , " Received packet frame error variable part too short? %d/%d " , rxlen , length ) ;
2019-04-17 01:06:26 +02:00
error = true ;
2019-04-17 23:44:48 +02:00
} else {
2019-04-20 03:17:19 +02:00
if ( rx . ng ) {
memcpy ( & rx . data , & rx_raw . data , length ) ;
rx . length = length ;
} else {
uint64_t arg [ 3 ] ;
if ( length < sizeof ( arg ) ) {
PrintAndLogEx ( WARNING , " Received MIX packet frame with incompatible length: 0x%04x " , length ) ;
error = true ;
}
if ( ! error ) {
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-17 01:06:26 +02:00
}
}
if ( ! error ) { // Get the postamble
2019-04-18 12:43:35 +02:00
if ( ( ! uart_receive ( sp , ( uint8_t * ) & rx_raw . foopost , sizeof ( PacketResponseNGPostamble ) , & rxlen ) ) | | ( rxlen ! = sizeof ( PacketResponseNGPostamble ) ) ) {
2019-04-17 01:06:26 +02:00
PrintAndLogEx ( WARNING , " Received packet frame error fetching postamble " ) ;
error = true ;
}
2019-04-17 23:44:48 +02:00
}
2019-04-18 21:39:35 +02:00
if ( ! error ) { // Check CRC, accept MAGIC as placeholder
2019-04-18 00:12:52 +02:00
rx . crc = rx_raw . foopost . crc ;
2019-04-18 21:49:32 +02:00
if ( rx . crc ! = RESPONSENG_POSTAMBLE_MAGIC ) {
2019-04-18 21:39:35 +02:00
uint8_t first , second ;
2019-04-20 03:17:19 +02:00
compute_crc ( CRC_14443_A , ( uint8_t * ) & rx_raw , sizeof ( PacketResponseNGPreamble ) + length , & first , & second ) ;
2019-04-18 21:39:35 +02:00
if ( ( first < < 8 ) + second ! = rx . crc ) {
PrintAndLogEx ( WARNING , " Received packet frame CRC error %02X%02X <> %04X " , first , second , rx . crc ) ;
error = true ;
}
2019-04-17 01:06:26 +02:00
}
}
if ( ! error ) {
// PrintAndLogEx(NORMAL, "Received reply NG full !!");
2019-04-18 12:43:35 +02:00
PacketResponseReceived ( & rx ) ;
2019-04-17 21:30:01 +02:00
//TODO DOEGOX NG don't send ACK anymore but reply with the corresponding cmd, still things seem to work fine...
2019-04-17 23:44:48 +02:00
if ( rx . cmd = = CMD_ACK ) {
2019-04-17 01:06:26 +02:00
ACK_received = true ;
}
}
} else { // Old style reply
2019-04-18 12:43:35 +02:00
PacketResponseOLD rx_old ;
memcpy ( & rx_old , & rx_raw . pre , sizeof ( PacketResponseNGPreamble ) ) ;
if ( ( ! uart_receive ( sp , ( ( uint8_t * ) & rx_old ) + sizeof ( PacketResponseNGPreamble ) , sizeof ( PacketResponseOLD ) - sizeof ( PacketResponseNGPreamble ) , & rxlen ) ) | | ( rxlen ! = sizeof ( PacketResponseOLD ) - sizeof ( PacketResponseNGPreamble ) ) ) {
PrintAndLogEx ( WARNING , " Received packet frame error var part too short? %d/%d " , rxlen , sizeof ( PacketResponseOLD ) - sizeof ( PacketResponseNGPreamble ) ) ;
2019-04-17 01:06:26 +02:00
error = true ;
}
if ( ! error ) {
2019-04-17 21:30:01 +02:00
// PrintAndLogEx(NORMAL, "Received reply old full !!");
rx . ng = false ;
rx . magic = 0 ;
rx . status = 0 ;
rx . crc = 0 ;
2019-04-17 23:44:48 +02: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 ] ;
rx . length = USB_CMD_DATA_SIZE ;
memcpy ( & rx . data , & rx_old . d , rx . length ) ;
2019-04-18 12:43:35 +02:00
PacketResponseReceived ( & rx ) ;
2019-04-17 23:44:48 +02:00
if ( rx . cmd = = CMD_ACK ) {
2019-04-17 01:06:26 +02:00
ACK_received = true ;
}
}
2019-03-09 23:35:06 +01:00
}
2019-04-17 01:06:26 +02:00
} else {
if ( rxlen > 0 ) {
2019-04-18 12:43:35 +02:00
PrintAndLogEx ( WARNING , " Received packet frame preamble too short: %d/%d " , rxlen , sizeof ( PacketResponseNGPreamble ) ) ;
2019-04-17 01:06:26 +02:00
error = true ;
2019-03-09 23:35:06 +01:00
}
}
2019-04-17 21:30:01 +02:00
// TODO DOEGOX if error, shall we resync ?
2019-03-09 23:35:06 +01:00
pthread_mutex_lock ( & txBufferMutex ) ;
2019-04-08 10:13:15 +02:00
if ( connection - > block_after_ACK ) {
2019-03-09 23:35:06 +01:00
// if we just received an ACK, wait here until a new command is to be transmitted
if ( ACK_received ) {
while ( ! txBuffer_pending ) {
pthread_cond_wait ( & txBufferSig , & txBufferMutex ) ;
}
}
}
if ( txBuffer_pending ) {
2019-04-16 10:01:08 +02:00
if ( txBufferNGLen ) { // NG packet
if ( ! uart_send ( sp , ( uint8_t * ) & txBufferNG , txBufferNGLen ) ) {
//counter_to_offline++;
2019-04-18 22:42:15 +02:00
PrintAndLogEx ( WARNING , " sending bytes to Proxmark3 device " _RED_ ( " failed " ) ) ;
2019-04-16 10:01:08 +02:00
}
txBufferNGLen = 0 ;
} else {
2019-04-18 12:43:35 +02:00
if ( ! uart_send ( sp , ( uint8_t * ) & txBuffer , sizeof ( PacketCommandOLD ) ) ) {
2019-04-16 10:01:08 +02:00
//counter_to_offline++;
2019-04-18 22:42:15 +02:00
PrintAndLogEx ( WARNING , " sending bytes to Proxmark3 device " _RED_ ( " failed " ) ) ;
2019-04-16 10:01:08 +02:00
}
2019-03-09 23:35:06 +01:00
}
txBuffer_pending = false ;
// tell main thread that txBuffer is empty
pthread_cond_signal ( & txBufferSig ) ;
}
pthread_mutex_unlock ( & txBufferMutex ) ;
}
2018-09-06 21:43:20 +02:00
2019-03-09 23:35:06 +01:00
// when this reader thread dies, we close the serial port.
uart_close ( sp ) ;
sp = NULL ;
2018-10-06 13:29:20 +02:00
# if defined(__MACH__) && defined(__APPLE__)
2019-03-09 23:35:06 +01:00
enableAppNap ( ) ;
2018-10-06 13:29:20 +02:00
# endif
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
pthread_exit ( NULL ) ;
return NULL ;
2018-09-06 21:43:20 +02:00
}
2019-04-02 22:06:10 +02:00
bool OpenProxmark ( void * port , bool wait_for_port , int timeout , bool flash_mode , uint32_t speed ) {
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
char * portname = ( char * ) port ;
if ( ! wait_for_port ) {
2019-04-14 18:51:07 +02:00
PrintAndLogEx ( INFO , " Using UART port " _YELLOW_ ( " %s " ) , portname ) ;
2019-04-02 22:06:10 +02:00
sp = uart_open ( portname , speed ) ;
2019-03-09 23:35:06 +01:00
} else {
2019-04-16 20:00:25 +02:00
PrintAndLogEx ( SUCCESS , " Waiting for Proxmark3 to appear on " _YELLOW_ ( " %s " ) , portname ) ;
2019-03-09 23:35:06 +01:00
fflush ( stdout ) ;
int openCount = 0 ;
do {
2019-04-02 22:06:10 +02:00
sp = uart_open ( portname , speed ) ;
2019-03-09 23:35:06 +01:00
msleep ( 500 ) ;
2019-03-10 00:00:59 +01:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-03-09 23:35:06 +01:00
} while ( + + openCount < timeout & & ( sp = = INVALID_SERIAL_PORT | | sp = = CLAIMED_SERIAL_PORT ) ) ;
//PrintAndLogEx(NORMAL, "\n");
}
// check result of uart opening
if ( sp = = INVALID_SERIAL_PORT ) {
2019-04-14 12:54:13 +02:00
PrintAndLogEx ( WARNING , _RED_ ( " ERROR: " ) " invalid serial port " _YELLOW_ ( " %s " ) , portname ) ;
2019-03-09 23:35:06 +01:00
sp = NULL ;
serial_port_name = NULL ;
return false ;
} else if ( sp = = CLAIMED_SERIAL_PORT ) {
2019-04-14 12:54:13 +02:00
PrintAndLogEx ( WARNING , _RED_ ( " ERROR: " ) " serial port " _YELLOW_ ( " %s " ) " is claimed by another process " , portname ) ;
2019-03-09 23:35:06 +01:00
sp = NULL ;
serial_port_name = NULL ;
return false ;
} else {
// start the USB communication thread
serial_port_name = portname ;
conn . run = true ;
conn . block_after_ACK = flash_mode ;
pthread_create ( & USB_communication_thread , NULL , & uart_communication , & conn ) ;
//pthread_create(&FPC_communication_thread, NULL, &uart_communication, &conn);
fflush ( stdout ) ;
// create a mutex to avoid interlacing print commands from our different threads
//pthread_mutex_init(&print_lock, NULL);
return true ;
}
2018-09-06 21:43:20 +02:00
}
2019-04-16 17:26:15 +02:00
// check if we can communicate with Pm3
2019-04-14 17:25:17 +02:00
int TestProxmark ( void ) {
clearCommandBuffer ( ) ;
2019-04-18 12:43:35 +02:00
PacketResponseNG resp ;
2019-04-19 02:01:47 +02:00
SendCommandOLD ( CMD_PING , 0 , 0 , 0 , NULL , 0 ) ;
2019-04-16 17:26:15 +02:00
if ( WaitForResponseTimeout ( CMD_ACK , & resp , 5000 ) ) {
2019-04-18 21:39:35 +02:00
send_via_fpc = resp . oldarg [ 0 ] = = 1 ;
PrintAndLogEx ( INFO , " Communicating with PM3 over %s. " , send_via_fpc ? " FPC " : " USB " ) ;
2019-04-14 17:25:17 +02:00
return 1 ;
} else {
return 0 ;
}
}
2019-03-10 11:20:22 +01:00
void CloseProxmark ( void ) {
2019-03-09 23:35:06 +01:00
conn . run = false ;
2018-09-15 12:00:53 +02:00
# ifdef __BIONIC__
2019-03-09 23:35:06 +01:00
if ( USB_communication_thread ! = 0 ) {
pthread_join ( USB_communication_thread , NULL ) ;
}
2018-09-15 12:00:53 +02:00
# else
2019-03-09 23:35:06 +01:00
pthread_join ( USB_communication_thread , NULL ) ;
//pthread_join(FPC_communication_thread, NULL);
2018-09-15 12:00:53 +02:00
# endif
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
if ( sp ) {
uart_close ( sp ) ;
}
2018-09-06 21:43:20 +02:00
# if defined(__linux__) && !defined(NO_UNLINK)
2019-03-09 23:35:06 +01:00
// Fix for linux, it seems that it is extremely slow to release the serial port file descriptor /dev/*
//
// This may be disabled at compile-time with -DNO_UNLINK (used for a JNI-based serial port on Android).
if ( serial_port_name ) {
unlink ( serial_port_name ) ;
}
2018-09-06 21:43:20 +02:00
# endif
2019-03-09 23:35:06 +01:00
// Clean up our state
sp = NULL ;
serial_port_name = NULL ;
memset ( & USB_communication_thread , 0 , sizeof ( pthread_t ) ) ;
2018-09-06 21:43:20 +02:00
}
2019-04-20 19:17:32 +02: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 ) {
if ( send_via_fpc ) // needed also for Windows USB USART??
return 2 * ( 12000000 / uart_speed ) ;
return 100 ;
}
2018-09-06 21:43:20 +02: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 08:59:13 +01:00
2018-09-06 21:43:20 +02: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 12:43:35 +02:00
bool WaitForResponseTimeoutW ( uint32_t cmd , PacketResponseNG * response , size_t ms_timeout , bool show_warning ) {
2019-03-09 08:59:13 +01:00
2019-04-18 12:43:35 +02:00
PacketResponseNG resp ;
2018-09-06 21:43:20 +02:00
2019-03-09 23:35:06 +01:00
if ( response = = NULL )
response = & resp ;
2018-09-06 21:43:20 +02:00
2019-04-20 19:17:32 +02:00
// Add delay depending on the communication channel & speed
2019-04-21 23:26:51 +02:00
if ( ms_timeout ! = ( size_t ) - 1 )
ms_timeout + = communication_delay ( ) ;
2019-04-21 23:56:04 +02:00
WaitForResponseTimeout_start_time = msclock ( ) ;
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
// Wait until the command is received
while ( true ) {
2018-09-06 21:43:20 +02:00
2019-04-17 21:30:01 +02:00
while ( getReply ( response ) ) {
2019-04-20 19:17:32 +02:00
if ( cmd = = CMD_UNKNOWN | | response - > cmd = = cmd ) {
2019-04-21 23:56:04 +02:00
// PrintAndLogEx(INFO, "Waited %i ms", msclock() - WaitForResponseTimeout_start_time);
2019-03-09 23:35:06 +01:00
return true ;
2019-04-20 19:17:32 +02:00
}
2019-03-09 23:35:06 +01:00
}
2018-09-06 21:43:20 +02:00
2019-04-21 23:56:04 +02:00
if ( msclock ( ) - WaitForResponseTimeout_start_time > ms_timeout )
2019-03-09 23:35:06 +01:00
break ;
2019-03-09 08:59:13 +01:00
2019-04-21 23:56:04 +02:00
if ( msclock ( ) - WaitForResponseTimeout_start_time > 3000 & & show_warning ) {
2019-03-09 23:35:06 +01:00
// 3 seconds elapsed (but this doesn't mean the timeout was exceeded)
2019-04-16 20:00:25 +02:00
PrintAndLogEx ( INFO , " Waiting for a response from the proxmark3... " ) ;
2019-04-16 17:26:15 +02:00
PrintAndLogEx ( INFO , " You can cancel this operation by pressing the pm3 button " ) ;
2019-03-09 23:35:06 +01:00
show_warning = false ;
}
}
2019-04-21 23:56:04 +02:00
// PrintAndLogEx(INFO, "Wait timeout after %i ms", msclock() - WaitForResponseTimeout_start_time);
2019-03-09 23:35:06 +01:00
return false ;
2018-09-06 21:43:20 +02:00
}
2019-04-18 12:43:35 +02:00
bool WaitForResponseTimeout ( uint32_t cmd , PacketResponseNG * response , size_t ms_timeout ) {
2019-03-09 23:35:06 +01:00
return WaitForResponseTimeoutW ( cmd , response , ms_timeout , true ) ;
2018-09-06 21:43:20 +02:00
}
2019-04-18 12:43:35 +02:00
bool WaitForResponse ( uint32_t cmd , PacketResponseNG * response ) {
2019-03-09 23:35:06 +01:00
return WaitForResponseTimeoutW ( cmd , response , - 1 , true ) ;
2018-09-06 21:43:20 +02: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 [ ]
* @ 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-04-18 12:43:35 +02:00
bool GetFromDevice ( DeviceMemType_t memtype , uint8_t * dest , uint32_t bytes , uint32_t start_index , PacketResponseNG * response , size_t ms_timeout , bool show_warning ) {
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
if ( dest = = NULL ) return false ;
if ( bytes = = 0 ) return true ;
2019-04-18 12:43:35 +02:00
PacketResponseNG resp ;
2019-03-09 23:35:06 +01:00
if ( response = = NULL )
response = & resp ;
// clear
clearCommandBuffer ( ) ;
switch ( memtype ) {
case BIG_BUF : {
2019-04-19 02:01:47 +02:00
SendCommandOLD ( CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K , start_index , bytes , 0 , NULL , 0 ) ;
2019-03-09 23:35:06 +01:00
return dl_it ( dest , bytes , start_index , response , ms_timeout , show_warning , CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K ) ;
}
case BIG_BUF_EML : {
2019-04-19 02:01:47 +02:00
SendCommandOLD ( CMD_DOWNLOAD_EML_BIGBUF , start_index , bytes , 0 , NULL , 0 ) ;
2019-03-09 23:35:06 +01:00
return dl_it ( dest , bytes , start_index , response , ms_timeout , show_warning , CMD_DOWNLOADED_EML_BIGBUF ) ;
}
case FLASH_MEM : {
2019-04-19 02:01:47 +02:00
SendCommandOLD ( CMD_FLASHMEM_DOWNLOAD , start_index , bytes , 0 , NULL , 0 ) ;
2019-03-09 23:35:06 +01:00
return dl_it ( dest , bytes , start_index , response , ms_timeout , show_warning , CMD_FLASHMEM_DOWNLOADED ) ;
}
case SIM_MEM : {
2019-04-19 02:01:47 +02:00
//SendCommandOLD(CMD_DOWNLOAD_SIM_MEM, start_index, bytes, 0, NULL, 0);
2019-03-09 23:35:06 +01:00
//return dl_it(dest, bytes, start_index, response, ms_timeout, show_warning, CMD_DOWNLOADED_SIMMEM);
return false ;
}
}
return false ;
2018-09-06 21:43:20 +02:00
}
2019-04-18 12:43:35 +02:00
static bool dl_it ( uint8_t * dest , uint32_t bytes , uint32_t start_index , PacketResponseNG * response , size_t ms_timeout , bool show_warning , uint32_t rec_cmd ) {
2019-03-09 08:59:13 +01:00
2019-03-09 23:35:06 +01:00
uint32_t bytes_completed = 0 ;
uint64_t start_time = msclock ( ) ;
while ( true ) {
2019-04-17 21:30:01 +02:00
if ( getReply ( response ) ) {
2019-03-09 23:35:06 +01: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-17 23:44:48 +02:00
if ( response - > cmd = = rec_cmd ) {
2019-03-09 23:35:06 +01:00
2019-04-17 23:44:48 +02: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-09 23:35:06 +01:00
// extended bounds check1. upper limit is USB_CMD_DATA_SIZE
// shouldn't happen
copy_bytes = MIN ( copy_bytes , USB_CMD_DATA_SIZE ) ;
// extended bounds check2.
2019-03-10 00:00:59 +01: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-09 23:35:06 +01:00
break ;
}
2019-04-17 23:44:48 +02:00
memcpy ( dest + offset , response - > data . asBytes , copy_bytes ) ;
2019-03-09 23:35:06 +01:00
bytes_completed + = copy_bytes ;
2019-04-17 23:44:48 +02:00
} else if ( response - > cmd = = CMD_ACK ) {
2019-03-09 23:35:06 +01:00
return true ;
}
}
if ( msclock ( ) - start_time > ms_timeout ) {
PrintAndLogEx ( FAILED , " Timed out while trying to download data from device " ) ;
break ;
}
if ( msclock ( ) - start_time > 3000 & & show_warning ) {
// 3 seconds elapsed (but this doesn't mean the timeout was exceeded)
2019-04-16 20:00:25 +02:00
PrintAndLogEx ( NORMAL , " Waiting for a response from the Proxmark3... " ) ;
2019-03-09 23:35:06 +01:00
PrintAndLogEx ( NORMAL , " You can cancel this operation by pressing the pm3 button " ) ;
show_warning = false ;
}
}
return false ;
2018-09-06 21:43:20 +02:00
}