1 //----------------------------------------------------------------------------- 
   2 // Copyright (C) 2009 Michael Gernoth <michael at gernoth.net> 
   3 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com> 
   5 // This code is licensed to you under the terms of the GNU GPL, version 2 or, 
   6 // at your option, any later version. See the LICENSE.txt file for the text of 
   8 //----------------------------------------------------------------------------- 
   9 // Code for communicating with the proxmark3 hardware. 
  10 //----------------------------------------------------------------------------- 
  16 #include <unistd.h>             // for unlink() 
  21 #include "util_posix.h" 
  24 // Serial port that we are communicating with the PM3 on. 
  25 static serial_port sp 
= NULL
; 
  26 static char *serial_port_name 
= NULL
; 
  28 // If TRUE, then there is no active connection to the PM3, and we will drop commands sent. 
  32         bool run
; // If TRUE, continue running the uart_communication thread 
  33         bool block_after_ACK
; // if true, block after receiving an ACK package 
  34 } communication_arg_t
; 
  36 static communication_arg_t conn
; 
  37 static pthread_t USB_communication_thread
; 
  40 static UsbCommand txBuffer
; 
  41 static bool txBuffer_pending 
= false; 
  42 static pthread_mutex_t txBufferMutex 
= PTHREAD_MUTEX_INITIALIZER
; 
  43 static pthread_cond_t txBufferSig 
= PTHREAD_COND_INITIALIZER
; 
  45 // Used by UsbReceiveCommand as a ring buffer for messages that are yet to be 
  46 // processed by a command handler (WaitForResponse{,Timeout}) 
  47 static UsbCommand rxBuffer
[CMD_BUFFER_SIZE
]; 
  49 // Points to the next empty position to write to 
  50 static int cmd_head 
= 0; 
  52 // Points to the position of the last unread command 
  53 static int cmd_tail 
= 0; 
  55 // to lock rxBuffer operations from different threads 
  56 static pthread_mutex_t rxBufferMutex 
= PTHREAD_MUTEX_INITIALIZER
; 
  58 // These wrappers are required because it is not possible to access a static 
  59 // global variable outside of the context of a single file. 
  61 void SetOffline(bool new_offline
) { 
  62         offline 
= new_offline
; 
  69 void SendCommand(UsbCommand 
*c
) { 
  71         printf("Sending %04x cmd\n", c
->cmd
); 
  75                 PrintAndLog("Sending bytes to proxmark failed - offline"); 
  79         pthread_mutex_lock(&txBufferMutex
); 
  81         This causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive,  
  82         but comm thread just spins here. Not good.../holiman 
  84         while (txBuffer_pending
) { 
  85                 pthread_cond_wait(&txBufferSig
, &txBufferMutex
); // wait for communication thread to complete sending a previous commmand 
  89         txBuffer_pending 
= true; 
  90         pthread_cond_signal(&txBufferSig
); // tell communication thread that a new command can be send 
  92         pthread_mutex_unlock(&txBufferMutex
); 
  98  * @brief This method should be called when sending a new command to the pm3. In case any old 
  99  *  responses from previous commands are stored in the buffer, a call to this method should clear them. 
 100  *  A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which 
 101  *  operation. Right now we'll just have to live with this. 
 103 void clearCommandBuffer() 
 105         //This is a very simple operation 
 106         pthread_mutex_lock(&rxBufferMutex
); 
 108         pthread_mutex_unlock(&rxBufferMutex
); 
 112  * @brief storeCommand stores a USB command in a circular buffer 
 115 static void storeCommand(UsbCommand 
*command
) 
 117         pthread_mutex_lock(&rxBufferMutex
); 
 118         if( (cmd_head
+1) % CMD_BUFFER_SIZE 
== cmd_tail
) 
 120                 // If these two are equal, we're about to overwrite in the 
 122                 PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!"); 
 125         // Store the command at the 'head' location 
 126         UsbCommand
* destination 
= &rxBuffer
[cmd_head
]; 
 127         memcpy(destination
, command
, sizeof(UsbCommand
)); 
 129         cmd_head 
= (cmd_head 
+1) % CMD_BUFFER_SIZE
; //increment head and wrap 
 130         pthread_mutex_unlock(&rxBufferMutex
); 
 135  * @brief getCommand gets a command from an internal circular buffer. 
 136  * @param response location to write command 
 137  * @return 1 if response was returned, 0 if nothing has been received 
 139 static int getCommand(UsbCommand
* response
) 
 141         pthread_mutex_lock(&rxBufferMutex
); 
 142         //If head == tail, there's nothing to read, or if we just got initialized 
 143         if (cmd_head 
== cmd_tail
){ 
 144                 pthread_mutex_unlock(&rxBufferMutex
); 
 148         //Pick out the next unread command 
 149         UsbCommand
* last_unread 
= &rxBuffer
[cmd_tail
]; 
 150         memcpy(response
, last_unread
, sizeof(UsbCommand
)); 
 151         //Increment tail - this is a circular buffer, so modulo buffer size 
 152         cmd_tail 
= (cmd_tail 
+ 1) % CMD_BUFFER_SIZE
; 
 154         pthread_mutex_unlock(&rxBufferMutex
); 
 159 //---------------------------------------------------------------------------------- 
 160 // Entry point into our code: called whenever we received a packet over USB. 
 161 // Handle debug commands directly, store all other commands in circular buffer. 
 162 //---------------------------------------------------------------------------------- 
 163 static void UsbCommandReceived(UsbCommand 
*UC
) 
 166                 // First check if we are handling a debug message 
 167                 case CMD_DEBUG_PRINT_STRING
: { 
 168                         char s
[USB_CMD_DATA_SIZE
+1]; 
 169                         memset(s
, 0x00, sizeof(s
)); 
 170                         size_t len 
= MIN(UC
->arg
[0],USB_CMD_DATA_SIZE
); 
 171                         memcpy(s
,UC
->d
.asBytes
,len
); 
 172                         PrintAndLog("#db# %s", s
); 
 176                 case CMD_DEBUG_PRINT_INTEGERS
: { 
 177                         PrintAndLog("#db# %08x, %08x, %08x       \r\n", UC
->arg
[0], UC
->arg
[1], UC
->arg
[2]); 
 190 #ifdef __has_attribute 
 191 #if __has_attribute(force_align_arg_pointer) 
 192 __attribute__((force_align_arg_pointer
))  
 195 *uart_communication(void *targ
) { 
 196         communication_arg_t 
*conn 
= (communication_arg_t
*)targ
; 
 199         UsbCommand 
*prx 
= &rx
; 
 203                 bool ACK_received 
= false; 
 204                 if (uart_receive(sp
, (uint8_t *)prx
, sizeof(UsbCommand
) - (prx
-&rx
), &rxlen
) && rxlen
) { 
 206                         if (prx
-&rx 
< sizeof(UsbCommand
)) { 
 209                         UsbCommandReceived(&rx
); 
 210                         if (rx
.cmd 
== CMD_ACK
) { 
 217                 pthread_mutex_lock(&txBufferMutex
); 
 219                 if (conn
->block_after_ACK
) { 
 220                         // if we just received an ACK, wait here until a new command is to be transmitted 
 222                                 while (!txBuffer_pending
) { 
 223                                         pthread_cond_wait(&txBufferSig
, &txBufferMutex
); 
 228                 if(txBuffer_pending
) { 
 229                         if (!uart_send(sp
, (uint8_t*) &txBuffer
, sizeof(UsbCommand
))) { 
 230                                 PrintAndLog("Sending bytes to proxmark failed"); 
 232                         txBuffer_pending 
= false; 
 233                         pthread_cond_signal(&txBufferSig
); // tell main thread that txBuffer is empty 
 236                 pthread_mutex_unlock(&txBufferMutex
); 
 245  * Data transfer from Proxmark to client. This method times out after 
 246  * ms_timeout milliseconds. 
 247  * @brief GetFromBigBuf 
 248  * @param dest Destination address for transfer 
 249  * @param bytes number of bytes to be transferred 
 250  * @param start_index offset into Proxmark3 BigBuf[] 
 251  * @param response struct to copy last command (CMD_ACK) into 
 252  * @param ms_timeout timeout in milliseconds 
 253  * @param show_warning display message after 2 seconds 
 254  * @return true if command was returned, otherwise false 
 256 bool GetFromBigBuf(uint8_t *dest
, int bytes
, int start_index
, UsbCommand 
*response
, size_t ms_timeout
, bool show_warning
) 
 258         UsbCommand c 
= {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K
, {start_index
, bytes
, 0}}; 
 261         uint64_t start_time 
= msclock(); 
 264         if (response 
== NULL
) { 
 268         int bytes_completed 
= 0; 
 270                 if (getCommand(response
)) { 
 271                         if (response
->cmd 
== CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K
) { 
 272                                 int copy_bytes 
= MIN(bytes 
- bytes_completed
, response
->arg
[1]); 
 273                                 memcpy(dest 
+ response
->arg
[0], response
->d
.asBytes
, copy_bytes
); 
 274                                 bytes_completed 
+= copy_bytes
; 
 275                         } else if (response
->cmd 
== CMD_ACK
) { 
 280                 if (msclock() - start_time 
> ms_timeout
) { 
 284                 if (msclock() - start_time 
> 2000 && show_warning
) { 
 285                         PrintAndLog("Waiting for a response from the proxmark..."); 
 286                         PrintAndLog("You can cancel this operation by pressing the pm3 button"); 
 287                         show_warning 
= false; 
 295 bool OpenProxmark(void *port
, bool wait_for_port
, int timeout
, bool flash_mode
) { 
 296         char *portname 
= (char *)port
; 
 297         if (!wait_for_port
) { 
 298                 sp 
= uart_open(portname
); 
 300                 printf("Waiting for Proxmark to appear on %s ", portname
); 
 304                         sp 
= uart_open(portname
); 
 308                 } while(++openCount 
< timeout 
&& (sp 
== INVALID_SERIAL_PORT 
|| sp 
== CLAIMED_SERIAL_PORT
)); 
 312         // check result of uart opening 
 313         if (sp 
== INVALID_SERIAL_PORT
) { 
 314                 printf("ERROR: invalid serial port\n"); 
 316                 serial_port_name 
= NULL
; 
 318         } else if (sp 
== CLAIMED_SERIAL_PORT
) { 
 319                 printf("ERROR: serial port is claimed by another process\n"); 
 321                 serial_port_name 
= NULL
; 
 324                 // start the USB communication thread 
 325                 serial_port_name 
= portname
; 
 327                 conn
.block_after_ACK 
= flash_mode
; 
 328                 pthread_create(&USB_communication_thread
, NULL
, &uart_communication
, &conn
); 
 334 void CloseProxmark(void) { 
 336         pthread_join(USB_communication_thread
, NULL
); 
 339         // Fix for linux, it seems that it is extremely slow to release the serial port file descriptor /dev/* 
 340         if (serial_port_name
) { 
 341                 unlink(serial_port_name
); 
 348  * Waits for a certain response type. This method waits for a maximum of 
 349  * ms_timeout milliseconds for a specified response command. 
 350  *@brief WaitForResponseTimeout 
 351  * @param cmd command to wait for, or CMD_UNKNOWN to take any command. 
 352  * @param response struct to copy received command into. 
 354  * @param show_warning display message after 2 seconds 
 355  * @return true if command was returned, otherwise false 
 357 bool WaitForResponseTimeoutW(uint32_t cmd
, UsbCommand
* response
, size_t ms_timeout
, bool show_warning
) { 
 362         printf("Waiting for %04x cmd\n", cmd
); 
 365         if (response 
== NULL
) { 
 369         uint64_t start_time 
= msclock(); 
 371         // Wait until the command is received 
 373                 while(getCommand(response
)) { 
 374                         if (cmd 
== CMD_UNKNOWN 
|| response
->cmd 
== cmd
) { 
 379                 if (msclock() - start_time 
> ms_timeout
) { 
 383                 if (msclock() - start_time 
> 2000 && show_warning
) { 
 384                         // 2 seconds elapsed (but this doesn't mean the timeout was exceeded) 
 385                         PrintAndLog("Waiting for a response from the proxmark..."); 
 386                         PrintAndLog("You can cancel this operation by pressing the pm3 button"); 
 387                         show_warning 
= false; 
 394 bool WaitForResponseTimeout(uint32_t cmd
, UsbCommand
* response
, size_t ms_timeout
) { 
 395         return WaitForResponseTimeoutW(cmd
, response
, ms_timeout
, true); 
 398 bool WaitForResponse(uint32_t cmd
, UsbCommand
* response
) { 
 399         return WaitForResponseTimeoutW(cmd
, response
, -1, true);