diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f9d9f545..e646c72a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added a thread to check when device comes online again. It will connect and update prompt (@iceman1001) - Changed CLI offline prompt - replaces the old prompt when offline is detected (@iceman100) - Changed `hf mf info` - it now uses found keys to try identify Gen2 cards (@iceman1001) - Changed `hf 14a info` - disabled debug logging while performing the magic tests (@iceman1001) diff --git a/client/src/comms.c b/client/src/comms.c index 99413b0df..b05fe2180 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -29,6 +29,7 @@ #include "util.h" // g_pendingPrompt #include "util_posix.h" // msclock #include "util_darwin.h" // en/dis-ableNapp(); +#include "usart_defs.h" // #define COMMS_DEBUG // #define COMMS_DEBUG_RAW @@ -40,6 +41,10 @@ communication_arg_t g_conn; capabilities_t g_pm3_capabilities; static pthread_t communication_thread; +static pthread_t reconnect_thread; + +static bool reconnect_ok = false; + static bool comm_thread_dead = false; static bool comm_raw_mode = false; static uint8_t *comm_raw_data = NULL; @@ -334,6 +339,52 @@ static void PacketResponseReceived(PacketResponseNG *packet) { } } +// The reconnect device thread. +// When communication thread is dead, start up and try to start it again +void *uart_reconnect(void *targ) { + + communication_arg_t *connection = (communication_arg_t *)targ; + +#if defined(__MACH__) && defined(__APPLE__) + disableAppNap("Proxmark3 polling UART"); +#endif + + uint32_t speed = USART_BAUD_RATE; + if (connection->uart_speed) { + speed = connection->uart_speed; + } + + while (1) { + if (OpenProxmarkSilent(&g_session.current_device, connection->serial_port_name, speed) == false) { + continue; + } + + if (g_session.pm3_present && (TestProxmark(g_session.current_device) != PM3_SUCCESS)) { + CloseProxmark(g_session.current_device); + } else { + break; + } + } + + +#if defined(__MACH__) && defined(__APPLE__) + enableAppNap(); +#endif + + __atomic_test_and_set(&reconnect_ok, __ATOMIC_SEQ_CST); + + pthread_exit(NULL); + return NULL; +} + +void StartReconnectProxmark(void) { + pthread_create(&reconnect_thread, NULL, &uart_reconnect, &g_conn); +} + +bool IsReconnectedOk(void) { + bool ret = __atomic_load_n(&reconnect_ok, __ATOMIC_SEQ_CST); + return ret; +} // The communications thread. // signals to main thread when a response is ready to process. @@ -605,6 +656,8 @@ bool IsCommunicationThreadDead(void) { return ret; } + + // To start raw receive mode: // 1. Call SetCommunicationRawReceiveBuffer(...) // 2. Call SetCommunicationReceiveMode(true) @@ -644,6 +697,47 @@ size_t GetCommunicationRawReceiveNum(void) { return __atomic_load_n(&comm_raw_pos, __ATOMIC_SEQ_CST); } +bool OpenProxmarkSilent(pm3_device_t **dev, const char *port, uint32_t speed) { + + sp = uart_open(port, speed); + + // check result of uart opening + if (sp == INVALID_SERIAL_PORT) { + sp = NULL; + return false; + } else if (sp == CLAIMED_SERIAL_PORT) { + sp = NULL; + return false; + } else { + // start the communication thread + if (port != g_conn.serial_port_name) { + uint16_t len = MIN(strlen(port), FILE_PATH_SIZE - 1); + memset(g_conn.serial_port_name, 0, FILE_PATH_SIZE); + memcpy(g_conn.serial_port_name, port, len); + } + g_conn.run = true; + g_conn.block_after_ACK = false; + // Flags to tell where to add CRC on sent replies + g_conn.send_with_crc_on_usb = false; + g_conn.send_with_crc_on_fpc = true; + // "Session" flag, to tell via which interface next msgs should be sent: USB or FPC USART + g_conn.send_via_fpc_usart = false; + + pthread_create(&communication_thread, NULL, &uart_communication, &g_conn); + __atomic_clear(&comm_thread_dead, __ATOMIC_SEQ_CST); + __atomic_clear(&reconnect_ok, __ATOMIC_SEQ_CST); + + g_session.pm3_present = true; // TODO support for multiple devices + + fflush(stdout); + if (*dev == NULL) { + *dev = calloc(sizeof(pm3_device_t), sizeof(uint8_t)); + } + (*dev)->g_conn = &g_conn; // TODO g_conn shouldn't be global + return true; + } +} + bool OpenProxmark(pm3_device_t **dev, const char *port, bool wait_for_port, int timeout, bool flash_mode, uint32_t speed) { if (!wait_for_port) { @@ -817,8 +911,10 @@ void CloseProxmark(pm3_device_t *dev) { // ~ = 12000000 / USART_BAUD_RATE // Let's take 2x (maybe we need more for BT link?) static size_t communication_delay(void) { - if (g_conn.send_via_fpc_usart) // needed also for Windows USB USART?? + // needed also for Windows USB USART?? + if (g_conn.send_via_fpc_usart) { return 2 * (12000000 / g_conn.uart_speed); + } return 0; } diff --git a/client/src/comms.h b/client/src/comms.h index 632f0d29f..63b1af989 100644 --- a/client/src/comms.h +++ b/client/src/comms.h @@ -89,6 +89,9 @@ typedef struct pm3_device { int script_embedded; } pm3_device_t; + +void *uart_reconnect(void *targ); + void *uart_receiver(void *targ); void SendCommandBL(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len); void SendCommandOLD(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len); @@ -97,13 +100,18 @@ void SendCommandMIX(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, v void clearCommandBuffer(void); #define FLASHMODE_SPEED 460800 + +bool IsReconnectedOk(void); bool IsCommunicationThreadDead(void); bool SetCommunicationReceiveMode(bool isRawMode); void SetCommunicationRawReceiveBuffer(uint8_t *buffer, size_t len); size_t GetCommunicationRawReceiveNum(void); + +bool OpenProxmarkSilent(pm3_device_t **dev, const char *port, uint32_t speed); bool OpenProxmark(pm3_device_t **dev, const char *port, bool wait_for_port, int timeout, bool flash_mode, uint32_t speed); int TestProxmark(pm3_device_t *dev); void CloseProxmark(pm3_device_t *dev); +void StartReconnectProxmark(void); size_t WaitForRawDataTimeout(uint8_t *buffer, size_t len, size_t ms_timeout, bool show_process); bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms_timeout, bool show_warning); diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index 98532f810..3492a4ac1 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -133,10 +133,12 @@ static void prompt_compose(char *buf, size_t buflen, const char *promptctx, cons if (no_newline) { snprintf(buf, buflen - 1, PROXPROMPT_COMPOSE, promptdev, promptnet, promptctx); } else { - snprintf(buf, buflen - 1, "\r" PROXPROMPT_COMPOSE, promptdev, promptnet, promptctx); + + snprintf(buf, buflen - 1, "\r \r" PROXPROMPT_COMPOSE, promptdev, promptnet, promptctx); } } +// This function is hooked via RL_EVENT_HOOK. static int check_comm(void) { // If communications thread goes down. Device disconnected then this should hook up PM3 again. if (IsCommunicationThreadDead() && g_session.pm3_present) { @@ -148,7 +150,18 @@ static int check_comm(void) { memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !g_session.supports_colors); pm3line_update_prompt(prompt_filtered); CloseProxmark(g_session.current_device); + StartReconnectProxmark(); + } + // its alive again + if (IsReconnectedOk() && g_session.pm3_present) { + prompt_dev = PROXPROMPT_DEV_USB; + char prompt[PROXPROMPT_MAX_SIZE] = {0}; + prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev, prompt_net, false); + char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; + memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !g_session.supports_colors); + pm3line_update_prompt(prompt_filtered); } + msleep(10); return 0; }