]> cvs.zerfleddert.de Git - proxmark3-svn/blame - client/comms.c
Fix some printf/scanf format strings
[proxmark3-svn] / client / comms.c
CommitLineData
f5ecd97b 1//-----------------------------------------------------------------------------
2// Copyright (C) 2009 Michael Gernoth <michael at gernoth.net>
3// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
4//
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
7// the license.
8//-----------------------------------------------------------------------------
9// Code for communicating with the proxmark3 hardware.
10//-----------------------------------------------------------------------------
11
852ecedc 12#define _POSIX_C_SOURCE 199309L // need clock_gettime()
13
f5ecd97b 14#include "comms.h"
ad939de5 15
929b61c6 16#include <stdio.h>
ac37ee81 17#include <stddef.h>
18#include <string.h>
ad939de5 19#include <pthread.h>
b8ed9975 20#include <inttypes.h>
3458bb27 21#include <time.h>
852ecedc 22#include <sys/time.h>
b8ed9975 23
f5ecd97b 24#include "uart.h"
25#include "ui.h"
26#include "common.h"
2a537311 27#include "util_darwin.h"
f5ecd97b 28#include "util_posix.h"
29
f5ecd97b 30
31// Serial port that we are communicating with the PM3 on.
ad939de5 32static serial_port sp = NULL;
33static char *serial_port_name = NULL;
f5ecd97b 34
35// If TRUE, then there is no active connection to the PM3, and we will drop commands sent.
61aaee35 36static bool offline;
f5ecd97b 37
ad939de5 38typedef struct {
39 bool run; // If TRUE, continue running the uart_communication thread
ad939de5 40} communication_arg_t;
41
42static communication_arg_t conn;
43static pthread_t USB_communication_thread;
44
f5ecd97b 45// Transmit buffer.
ad939de5 46static UsbCommand txBuffer;
47static bool txBuffer_pending = false;
48static pthread_mutex_t txBufferMutex = PTHREAD_MUTEX_INITIALIZER;
49static pthread_cond_t txBufferSig = PTHREAD_COND_INITIALIZER;
f5ecd97b 50
51// Used by UsbReceiveCommand as a ring buffer for messages that are yet to be
52// processed by a command handler (WaitForResponse{,Timeout})
b8ed9975 53#define CMD_BUFFER_SIZE 50
01aa068b 54#define CMD_BUFFER_CHECK_TIME 10 // maximum time (in ms) to wait in getCommand()
55
ad939de5 56static UsbCommand rxBuffer[CMD_BUFFER_SIZE];
f5ecd97b 57
58// Points to the next empty position to write to
59static int cmd_head = 0;
60
61// Points to the position of the last unread command
62static int cmd_tail = 0;
63
ad939de5 64// to lock rxBuffer operations from different threads
65static pthread_mutex_t rxBufferMutex = PTHREAD_MUTEX_INITIALIZER;
3458bb27 66static pthread_cond_t rxBufferSig = PTHREAD_COND_INITIALIZER;
f5ecd97b 67
61aaee35 68// These wrappers are required because it is not possible to access a static
69// global variable outside of the context of a single file.
70
71void SetOffline(bool new_offline) {
72 offline = new_offline;
73}
74
75bool IsOffline() {
76 return offline;
77}
f5ecd97b 78
79void SendCommand(UsbCommand *c) {
61aaee35 80 #ifdef COMMS_DEBUG
d2ca5dbf 81 printf("Sending %04" PRIx64 " cmd\n", c->cmd);
f5ecd97b 82 #endif
83
84 if (offline) {
85 PrintAndLog("Sending bytes to proxmark failed - offline");
86 return;
929b61c6 87 }
ad939de5 88
89 pthread_mutex_lock(&txBufferMutex);
f5ecd97b 90 /**
929b61c6 91 This causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive,
ad939de5 92 but comm thread just spins here. Not good.../holiman
f5ecd97b 93 **/
ad939de5 94 while (txBuffer_pending) {
95 pthread_cond_wait(&txBufferSig, &txBufferMutex); // wait for communication thread to complete sending a previous commmand
96 }
97
98 txBuffer = *c;
99 txBuffer_pending = true;
100 pthread_cond_signal(&txBufferSig); // tell communication thread that a new command can be send
101
102 pthread_mutex_unlock(&txBufferMutex);
818efbeb 103
f5ecd97b 104}
105
106
107/**
108 * @brief This method should be called when sending a new command to the pm3. In case any old
109 * responses from previous commands are stored in the buffer, a call to this method should clear them.
110 * A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which
111 * operation. Right now we'll just have to live with this.
112 */
d2ca5dbf 113void clearCommandBuffer() {
f5ecd97b 114 //This is a very simple operation
ad939de5 115 pthread_mutex_lock(&rxBufferMutex);
f5ecd97b 116 cmd_tail = cmd_head;
ad939de5 117 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 118}
119
120/**
121 * @brief storeCommand stores a USB command in a circular buffer
122 * @param UC
123 */
d2ca5dbf 124static void storeCommand(UsbCommand *command) {
ad939de5 125 pthread_mutex_lock(&rxBufferMutex);
d2ca5dbf 126 if ((cmd_head + 1) % CMD_BUFFER_SIZE == cmd_tail) {
f5ecd97b 127 // If these two are equal, we're about to overwrite in the
128 // circular buffer.
129 PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!");
130 }
131
132 // Store the command at the 'head' location
ad939de5 133 UsbCommand* destination = &rxBuffer[cmd_head];
f5ecd97b 134 memcpy(destination, command, sizeof(UsbCommand));
135
d2ca5dbf 136 cmd_head = (cmd_head + 1) % CMD_BUFFER_SIZE; //increment head and wrap
3458bb27 137 pthread_cond_signal(&rxBufferSig); // tell main thread that a new command can be retreived
ad939de5 138 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 139}
140
141
142/**
143 * @brief getCommand gets a command from an internal circular buffer.
144 * @param response location to write command
3458bb27 145 * @return 1 if response was returned, 0 if nothing has been received in time
f5ecd97b 146 */
3458bb27 147static int getCommand(UsbCommand* response, uint32_t ms_timeout) {
148
149 struct timespec end_time;
150 clock_gettime(CLOCK_REALTIME, &end_time);
151 end_time.tv_sec += ms_timeout / 1000;
152 end_time.tv_nsec += (ms_timeout % 1000) * 1000000;
153 if (end_time.tv_nsec > 1000000000) {
154 end_time.tv_nsec -= 1000000000;
155 end_time.tv_sec += 1;
156 }
ad939de5 157 pthread_mutex_lock(&rxBufferMutex);
3458bb27 158 int res = 0;
159 while (cmd_head == cmd_tail && !res) {
160 res = pthread_cond_timedwait(&rxBufferSig, &rxBufferMutex, &end_time);
161 }
162 if (res) { // timeout
ad939de5 163 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 164 return 0;
165 }
166
d2ca5dbf 167 // Pick out the next unread command
ad939de5 168 UsbCommand* last_unread = &rxBuffer[cmd_tail];
f5ecd97b 169 memcpy(response, last_unread, sizeof(UsbCommand));
d2ca5dbf 170 // Increment tail - this is a circular buffer, so modulo buffer size
f5ecd97b 171 cmd_tail = (cmd_tail + 1) % CMD_BUFFER_SIZE;
172
ad939de5 173 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 174 return 1;
175}
176
177
babca445 178//----------------------------------------------------------------------------------
179// Entry point into our code: called whenever we received a packet over USB.
180// Handle debug commands directly, store all other commands in circular buffer.
181//----------------------------------------------------------------------------------
d2ca5dbf 182static void UsbCommandReceived(UsbCommand *UC) {
183 switch (UC->cmd) {
f5ecd97b 184 // First check if we are handling a debug message
185 case CMD_DEBUG_PRINT_STRING: {
186 char s[USB_CMD_DATA_SIZE+1];
187 memset(s, 0x00, sizeof(s));
d2ca5dbf 188 size_t len = MIN(UC->arg[0], USB_CMD_DATA_SIZE);
189 memcpy(s, UC->d.asBytes,len);
f5ecd97b 190 PrintAndLog("#db# %s", s);
191 return;
192 } break;
193
194 case CMD_DEBUG_PRINT_INTEGERS: {
195 PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]);
196 return;
197 } break;
198
f5ecd97b 199 default:
929b61c6 200 storeCommand(UC);
f5ecd97b 201 break;
202 }
203
204}
205
206
b8ed9975 207static bool receive_from_serial(serial_port sp, uint8_t *rx_buf, size_t len, size_t *received_len) {
208 size_t bytes_read = 0;
209 *received_len = 0;
3458bb27 210 // we eventually need to call uart_receive several times because it may timeout in the middle of a transfer
b8ed9975 211 while (uart_receive(sp, rx_buf + *received_len, len - *received_len, &bytes_read) && bytes_read && *received_len < len) {
929b61c6 212 #ifdef COMMS_DEBUG
b8ed9975 213 if (bytes_read != len - *received_len) {
d2ca5dbf 214 printf("uart_receive() returned true but not enough bytes could be received. received: %zd, wanted to receive: %zd, already received before: %zd\n",
b8ed9975 215 bytes_read, len - *received_len, *received_len);
216 }
929b61c6 217 #endif
b8ed9975 218 *received_len += bytes_read;
219 bytes_read = 0;
220 }
221 return (*received_len == len);
222}
929b61c6 223
b8ed9975 224
ad939de5 225static void
f5ecd97b 226#ifdef __has_attribute
227#if __has_attribute(force_align_arg_pointer)
929b61c6 228__attribute__((force_align_arg_pointer))
f5ecd97b 229#endif
230#endif
ad939de5 231*uart_communication(void *targ) {
232 communication_arg_t *conn = (communication_arg_t*)targ;
b8ed9975 233 uint8_t rx[sizeof(UsbCommand)];
234 size_t rxlen = 0;
235 uint8_t *prx = rx;
236 UsbCommand *command = (UsbCommand*)rx;
237 UsbResponse *response = (UsbResponse*)rx;
f5ecd97b 238
2a537311
A
239#if defined(__MACH__) && defined(__APPLE__)
240 disableAppNap("Proxmark3 polling UART");
241#endif
242
818efbeb 243 while (conn->run) {
ad939de5 244 bool ACK_received = false;
b8ed9975 245 prx = rx;
246 size_t bytes_to_read = offsetof(UsbResponse, d); // the fixed part of a new style UsbResponse. Otherwise this will be cmd and arg[0] (64 bit each)
247 if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
f5ecd97b 248 prx += rxlen;
b8ed9975 249 if (response->cmd & CMD_VARIABLE_SIZE_FLAG) { // new style response with variable size
d2ca5dbf 250#ifdef COMMS_DEBUG
251 PrintAndLog("received new style response %04" PRIx16 ", datalen = %zd, arg[0] = %08" PRIx32 ", arg[1] = %08" PRIx32 ", arg[2] = %08" PRIx32,
252 response->cmd, response->datalen, response->arg[0], response->arg[1], response->arg[2]);
253#endif
b8ed9975 254 bytes_to_read = response->datalen;
255 if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
256 UsbCommand resp;
929b61c6 257 resp.cmd = response->cmd & ~CMD_VARIABLE_SIZE_FLAG; // remove the flag
b8ed9975 258 resp.arg[0] = response->arg[0];
259 resp.arg[1] = response->arg[1];
260 resp.arg[2] = response->arg[2];
261 memcpy(&resp.d.asBytes, &response->d.asBytes, response->datalen);
262 UsbCommandReceived(&resp);
263 if (resp.cmd == CMD_ACK) {
264 ACK_received = true;
265 }
266 }
267 } else { // old style response uses same data structure as commands. Fixed size.
d2ca5dbf 268#ifdef COMMS_DEBUG
269 PrintAndLog("received old style response %016" PRIx64 ", arg[0] = %016" PRIx64, command->cmd, command->arg[0]);
270#endif
b8ed9975 271 bytes_to_read = sizeof(UsbCommand) - bytes_to_read;
929b61c6 272 if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
b8ed9975 273 UsbCommandReceived(command);
274 if (command->cmd == CMD_ACK) {
275 ACK_received = true;
276 }
277 }
ad939de5 278 }
f5ecd97b 279 }
f5ecd97b 280
929b61c6 281 pthread_mutex_lock(&txBufferMutex);
282 // if we received an ACK the PM has done its job and waits for another command.
283 // We therefore can wait here as well until a new command is to be transmitted.
284 // The advantage is that the next command will be transmitted immediately without the need to wait for a receive timeout
285 if (ACK_received) {
286 while (!txBuffer_pending) {
287 pthread_cond_wait(&txBufferSig, &txBufferMutex);
ad939de5 288 }
289 }
929b61c6 290 if (txBuffer_pending) {
ad939de5 291 if (!uart_send(sp, (uint8_t*) &txBuffer, sizeof(UsbCommand))) {
f5ecd97b 292 PrintAndLog("Sending bytes to proxmark failed");
293 }
ad939de5 294 txBuffer_pending = false;
f5ecd97b 295 }
929b61c6 296 pthread_cond_signal(&txBufferSig); // tell main thread that txBuffer is empty
ad939de5 297 pthread_mutex_unlock(&txBufferMutex);
f5ecd97b 298 }
299
2a537311
A
300#if defined(__MACH__) && defined(__APPLE__)
301 enableAppNap();
302#endif
303
f5ecd97b 304 pthread_exit(NULL);
305 return NULL;
306}
307
308
babca445 309/**
310 * Data transfer from Proxmark to client. This method times out after
311 * ms_timeout milliseconds.
312 * @brief GetFromBigBuf
313 * @param dest Destination address for transfer
314 * @param bytes number of bytes to be transferred
315 * @param start_index offset into Proxmark3 BigBuf[]
316 * @param response struct to copy last command (CMD_ACK) into
317 * @param ms_timeout timeout in milliseconds
318 * @param show_warning display message after 2 seconds
319 * @return true if command was returned, otherwise false
320 */
d2ca5dbf 321bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) {
babca445 322
323 uint64_t start_time = msclock();
3458bb27 324
325 UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}};
326 SendCommand(&c);
babca445 327
328 UsbCommand resp;
929b61c6 329 if (response == NULL) {
babca445 330 response = &resp;
331 }
332
333 int bytes_completed = 0;
d2ca5dbf 334 while (true) {
3458bb27 335 if (msclock() - start_time > ms_timeout) {
336 break; // timeout
337 }
338 if (msclock() - start_time > 2000 && show_warning) {
339 // 2 seconds elapsed (but this doesn't mean the timeout was exceeded)
340 PrintAndLog("Waiting for a response from the proxmark...");
341 PrintAndLog("You can cancel this operation by pressing the pm3 button");
342 show_warning = false;
343 }
01aa068b 344 if (getCommand(response, CMD_BUFFER_CHECK_TIME)) {
babca445 345 if (response->cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
346 int copy_bytes = MIN(bytes - bytes_completed, response->arg[1]);
347 memcpy(dest + response->arg[0], response->d.asBytes, copy_bytes);
348 bytes_completed += copy_bytes;
349 } else if (response->cmd == CMD_ACK) {
350 return true;
351 }
352 }
babca445 353 }
354
355 return false;
356}
357
929b61c6 358
d2ca5dbf 359bool GetFromFpgaRAM(uint8_t *dest, int bytes) {
fc52fbd4 360
361 uint64_t start_time = msclock();
3458bb27 362
363 UsbCommand c = {CMD_HF_PLOT, {0, 0, 0}};
364 SendCommand(&c);
fc52fbd4 365
366 UsbCommand response;
929b61c6 367
fc52fbd4 368 int bytes_completed = 0;
369 bool show_warning = true;
d2ca5dbf 370 while (true) {
3458bb27 371 if (msclock() - start_time > 2000 && show_warning) {
372 PrintAndLog("Waiting for a response from the proxmark...");
373 PrintAndLog("You can cancel this operation by pressing the pm3 button");
374 show_warning = false;
375 }
01aa068b 376 if (getCommand(&response, CMD_BUFFER_CHECK_TIME)) {
fc52fbd4 377 if (response.cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
378 int copy_bytes = MIN(bytes - bytes_completed, response.arg[1]);
379 memcpy(dest + response.arg[0], response.d.asBytes, copy_bytes);
380 bytes_completed += copy_bytes;
381 } else if (response.cmd == CMD_ACK) {
382 return true;
383 }
384 }
fc52fbd4 385 }
386
387 return false;
388}
389
390
929b61c6 391bool OpenProxmark(void *port, bool wait_for_port, int timeout) {
ad939de5 392 char *portname = (char *)port;
393 if (!wait_for_port) {
394 sp = uart_open(portname);
395 } else {
396 printf("Waiting for Proxmark to appear on %s ", portname);
397 fflush(stdout);
398 int openCount = 0;
399 do {
400 sp = uart_open(portname);
401 msleep(1000);
402 printf(".");
403 fflush(stdout);
d2ca5dbf 404 } while (++openCount < timeout && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT));
ad939de5 405 printf("\n");
406 }
407
408 // check result of uart opening
409 if (sp == INVALID_SERIAL_PORT) {
410 printf("ERROR: invalid serial port\n");
411 sp = NULL;
412 serial_port_name = NULL;
413 return false;
414 } else if (sp == CLAIMED_SERIAL_PORT) {
415 printf("ERROR: serial port is claimed by another process\n");
416 sp = NULL;
417 serial_port_name = NULL;
418 return false;
419 } else {
420 // start the USB communication thread
421 serial_port_name = portname;
422 conn.run = true;
ad939de5 423 pthread_create(&USB_communication_thread, NULL, &uart_communication, &conn);
424 return true;
425 }
426}
427
428
429void CloseProxmark(void) {
430 conn.run = false;
7b2cd970
MF
431
432#ifdef __BIONIC__
433 // In Android O and later, if an invalid pthread_t is passed to pthread_join, it calls fatal().
434 // https://github.com/aosp-mirror/platform_bionic/blob/ed16b344e75f422fb36fbfd91fb30de339475880/libc/bionic/pthread_internal.cpp#L116-L128
435 //
436 // In Bionic libc, pthread_t is an integer.
437
438 if (USB_communication_thread != 0) {
439 pthread_join(USB_communication_thread, NULL);
440 }
441#else
442 // pthread_t is a struct on other libc, treat as an opaque memory reference
ad939de5 443 pthread_join(USB_communication_thread, NULL);
7b2cd970 444#endif
2bb7f7e3
MF
445
446 if (sp) {
447 uart_close(sp);
448 }
449
2bb7f7e3
MF
450 // Clean up our state
451 sp = NULL;
452 serial_port_name = NULL;
eed83b91 453#ifdef __BIONIC__
7b2cd970 454 memset(&USB_communication_thread, 0, sizeof(pthread_t));
eed83b91 455#endif
ad939de5 456}
457
babca445 458
f5ecd97b 459/**
460 * Waits for a certain response type. This method waits for a maximum of
461 * ms_timeout milliseconds for a specified response command.
462 *@brief WaitForResponseTimeout
61aaee35 463 * @param cmd command to wait for, or CMD_UNKNOWN to take any command.
f5ecd97b 464 * @param response struct to copy received command into.
465 * @param ms_timeout
babca445 466 * @param show_warning display message after 2 seconds
f5ecd97b 467 * @return true if command was returned, otherwise false
468 */
469bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning) {
470
471 UsbCommand resp;
472
61aaee35 473 #ifdef COMMS_DEBUG
474 printf("Waiting for %04x cmd\n", cmd);
475 #endif
476
3458bb27 477 uint64_t start_time = msclock();
3458bb27 478
f5ecd97b 479 if (response == NULL) {
480 response = &resp;
481 }
482
f5ecd97b 483 // Wait until the command is received
484 while (true) {
df7b80fe 485 if (ms_timeout != -1 && msclock() > start_time + ms_timeout) {
3458bb27 486 break; // timeout
f5ecd97b 487 }
f5ecd97b 488 if (msclock() - start_time > 2000 && show_warning) {
61aaee35 489 // 2 seconds elapsed (but this doesn't mean the timeout was exceeded)
f5ecd97b 490 PrintAndLog("Waiting for a response from the proxmark...");
491 PrintAndLog("You can cancel this operation by pressing the pm3 button");
492 show_warning = false;
493 }
01aa068b 494 if (getCommand(response, CMD_BUFFER_CHECK_TIME)) {
3458bb27 495 if (cmd == CMD_UNKNOWN || response->cmd == cmd) {
496 return true;
497 }
498 }
f5ecd97b 499 }
500 return false;
501}
502
503
504bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
505 return WaitForResponseTimeoutW(cmd, response, ms_timeout, true);
506}
507
508bool WaitForResponse(uint32_t cmd, UsbCommand* response) {
509 return WaitForResponseTimeoutW(cmd, response, -1, true);
510}
511
Impressum, Datenschutz