From 7aef669e594126123811d4356f3ec4573fc59e11 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Mon, 16 Oct 2023 01:52:27 +0800 Subject: [PATCH 1/3] Add ringbuffer This is used in the UDP connection --- client/CMakeLists.txt | 1 + client/Makefile | 1 + client/experimental_lib/CMakeLists.txt | 1 + client/src/uart/ringbuffer.c | 102 +++++++++++++++++++++++++ client/src/uart/ringbuffer.h | 26 +++++++ 5 files changed, 131 insertions(+) create mode 100644 client/src/uart/ringbuffer.c create mode 100644 client/src/uart/ringbuffer.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index eaee2f0f0..acf079f70 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -286,6 +286,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/gallaghercore.c + ${PM3_ROOT}/client/src/uart/ringbuffer.c ${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/ui/overlays.ui diff --git a/client/Makefile b/client/Makefile index b63fdf329..d45e958f7 100644 --- a/client/Makefile +++ b/client/Makefile @@ -707,6 +707,7 @@ SRCS = mifare/aiddesfire.c \ pm3line.c \ proxmark3.c \ scandir.c \ + uart/ringbuffer.c \ uart/uart_posix.c \ uart/uart_win32.c \ scripting.c \ diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index a5caeb014..04198cf88 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -286,6 +286,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/gallaghercore.c + ${PM3_ROOT}/client/src/uart/ringbuffer.c ${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/ui/overlays.ui diff --git a/client/src/uart/ringbuffer.c b/client/src/uart/ringbuffer.c new file mode 100644 index 000000000..4a3b01f74 --- /dev/null +++ b/client/src/uart/ringbuffer.c @@ -0,0 +1,102 @@ +#include "ringbuffer.h" +#include + +RingBuffer* RingBuf_create(int capacity) { + RingBuffer* buffer = (RingBuffer*)malloc(sizeof(RingBuffer)); + if (!buffer) { + return NULL; + } + + buffer->data = (uint8_t*)calloc(capacity, sizeof(uint8_t)); + if (!buffer->data) { + free(buffer); + return NULL; + } + + buffer->capacity = capacity; + buffer->size = 0; + buffer->front = 0; + buffer->rear = 0; + + return buffer; +} + +inline bool RingBuf_isFull(RingBuffer* buffer) { + return buffer->size == buffer->capacity; +} + +inline bool RingBuf_isEmpty(RingBuffer* buffer) { + return buffer->size == 0; +} + +bool RingBuf_enqueue(RingBuffer* buffer, uint8_t value) { + if (RingBuf_isFull(buffer)) { + return false; + } + + buffer->data[buffer->rear] = value; + buffer->rear = (buffer->rear + 1) % buffer->capacity; + buffer->size++; + return true; +} + +bool RingBuf_dequeue(RingBuffer* buffer, uint8_t* value) { + if (RingBuf_isEmpty(buffer)) { + return false; + } + + *value = buffer->data[buffer->front]; + buffer->front = (buffer->front + 1) % buffer->capacity; + buffer->size--; + return true; +} + +int RingBuf_enqueueBatch(RingBuffer* buffer, const uint8_t* values, int count) { + int processed = 0; + + if (RingBuf_getAvailableSize(buffer) < count) { + count = RingBuf_getAvailableSize(buffer); + } + + for (int i = 0; i < count; i++) { + buffer->data[buffer->rear] = values[i]; + buffer->rear = (buffer->rear + 1) % buffer->capacity; + processed++; + } + + buffer->size += processed; + + return processed; +} + +int RingBuf_dequeueBatch(RingBuffer* buffer, uint8_t* values, int count) { + int processed = 0; + + if (buffer->size < count) { + count = buffer->size; + } + + for (int i = 0; i < count; i++) { + values[i] = buffer->data[buffer->front]; + buffer->front = (buffer->front + 1) % buffer->capacity; + processed++; + } + + buffer->size -= processed; + + return processed; +} + +inline int RingBuf_getUsedSize(RingBuffer* buffer) { + return buffer->size; +} + +inline int RingBuf_getAvailableSize(RingBuffer* buffer) { + return (buffer->capacity) - (buffer->size); +} + +void RingBuf_destroy(RingBuffer* buffer) { + if (buffer != NULL) + free(buffer->data); + free(buffer); +} diff --git a/client/src/uart/ringbuffer.h b/client/src/uart/ringbuffer.h new file mode 100644 index 000000000..e78e284b4 --- /dev/null +++ b/client/src/uart/ringbuffer.h @@ -0,0 +1,26 @@ +#ifndef _RINGBUFFER_H_ +#define _RINGBUFFER_H_ + +#include +#include + +typedef struct { + uint8_t* data; + int capacity; + int size; + int front; + int rear; +} RingBuffer; + +RingBuffer* RingBuf_create(int capacity); +bool RingBuf_isFull(RingBuffer* buffer); +bool RingBuf_isEmpty(RingBuffer* buffer); +bool RingBuf_enqueue(RingBuffer* buffer, uint8_t value); +bool RingBuf_dequeue(RingBuffer* buffer, uint8_t* value); +int RingBuf_enqueueBatch(RingBuffer* buffer, const uint8_t* values, int count); +int RingBuf_dequeueBatch(RingBuffer* buffer, uint8_t* values, int count); +int RingBuf_getUsedSize(RingBuffer* buffer); +int RingBuf_getAvailableSize(RingBuffer* buffer); +void RingBuf_destroy(RingBuffer* buffer); + +#endif From 5775b53078f0429e83622918c57bce03d2b6748b Mon Sep 17 00:00:00 2001 From: wh201906 Date: Mon, 16 Oct 2023 01:56:03 +0800 Subject: [PATCH 2/3] UDP support on Linux --- CHANGELOG.md | 2 +- client/src/uart/uart_posix.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22335394d..9d1f80ba5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Fixed `lf hid clone --bin` - now correctly handles sentinel bits (@iceman1001) - - Experimental UDP support in linux (@iceman1001) + - Experimental UDP support in linux (@iceman1001, @wh201906) - Changed CI scripts to speed up the builds (@wh201906) - Changed the timeout of local TCP connections (@wh201906) - Finalized implementation of configcard generation for keyroll when cardhelper is not present (@Antiklesys) diff --git a/client/src/uart/uart_posix.c b/client/src/uart/uart_posix.c index c7cdc27a6..cff3b7453 100644 --- a/client/src/uart/uart_posix.c +++ b/client/src/uart/uart_posix.c @@ -21,6 +21,7 @@ #define _DEFAULT_SOURCE #include "uart.h" +#include "ringbuffer.h" #include #include @@ -55,6 +56,7 @@ typedef struct { int fd; // Serial port file descriptor term_info tiOld; // Terminal info before using the port term_info tiNew; // Terminal info during the transaction + RingBuffer* udpBuffer; } serial_port_unix_t_t; // see pm3_cmd.h @@ -84,6 +86,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { return INVALID_SERIAL_PORT; } + sp->udpBuffer = NULL; // init timeouts timeout.tv_usec = UART_FPC_CLIENT_RX_TIMEOUT_MS * 1000; @@ -239,6 +242,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { } sp->fd = sfd; + sp->udpBuffer = RingBuf_create(MAX(sizeof(PacketResponseNGRaw), sizeof(PacketResponseOLD)) * 20); return sp; } @@ -427,6 +431,7 @@ void uart_close(const serial_port sp) { //silent error message as it can be called from uart_open failing modes, e.g. when waiting for port to appear //PrintAndLogEx(ERR, "UART error while closing port"); } + RingBuf_destroy(spu->udpBuffer); close(spu->fd); free(sp); } @@ -435,6 +440,7 @@ int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uin uint32_t byteCount; // FIONREAD returns size on 32b fd_set rfds; struct timeval tv; + const serial_port_unix_t_t *spu = (serial_port_unix_t_t *)sp; if (newtimeout_pending) { timeout.tv_usec = newtimeout_value * 1000; @@ -443,11 +449,30 @@ int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uin // Reset the output count *pszRxLen = 0; do { + int res; + if(spu->udpBuffer != NULL) { + // for UDP connection, try to use the data from the buffer + + byteCount = RingBuf_getAvailableSize(spu->udpBuffer); + // Cap the number of bytes, so we don't overrun the buffer + if (pszMaxRxLen - (*pszRxLen) < byteCount) { +// PrintAndLogEx(ERR, "UART:: RX prevent overrun (have %u, need %u)", pszMaxRxLen - (*pszRxLen), byteCount); + byteCount = pszMaxRxLen - (*pszRxLen); + } + res = RingBuf_dequeueBatch(spu->udpBuffer, pbtRx + (*pszRxLen), byteCount); + *pszRxLen += res; + + if (*pszRxLen == pszMaxRxLen) { + // We have all the data we wanted. + return PM3_SUCCESS; + } + } + // Reset file descriptor FD_ZERO(&rfds); FD_SET(((serial_port_unix_t_t *)sp)->fd, &rfds); tv = timeout; - int res = select(((serial_port_unix_t_t *)sp)->fd + 1, &rfds, NULL, NULL, &tv); + res = select(((serial_port_unix_t_t *)sp)->fd + 1, &rfds, NULL, NULL, &tv); // Read error if (res < 0) { @@ -470,6 +495,14 @@ int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uin // PrintAndLogEx(ERR, "UART:: RX ioctl res %d byteCount %u", res, byteCount); if (res < 0) return PM3_ENOTTY; + // For UDP connection, put the incoming data into the buffer and handle them in the next round + if (spu->udpBuffer != NULL) { + uint8_t recvBuf[MAX(sizeof(PacketResponseNGRaw), sizeof(PacketResponseOLD)) * 20]; + res = read(spu->fd, recvBuf, RingBuf_getAvailableSize(spu->udpBuffer)); + RingBuf_enqueueBatch(spu->udpBuffer, recvBuf, res); + continue; + } + // Cap the number of bytes, so we don't overrun the buffer if (pszMaxRxLen - (*pszRxLen) < byteCount) { // PrintAndLogEx(ERR, "UART:: RX prevent overrun (have %u, need %u)", pszMaxRxLen - (*pszRxLen), byteCount); From 3df58f3a9eb853df944c8b045f4bac7c8e15412a Mon Sep 17 00:00:00 2001 From: wh201906 Date: Mon, 16 Oct 2023 02:07:32 +0800 Subject: [PATCH 3/3] Clean up --- client/src/uart/uart_posix.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/client/src/uart/uart_posix.c b/client/src/uart/uart_posix.c index cff3b7453..05a728ada 100644 --- a/client/src/uart/uart_posix.c +++ b/client/src/uart/uart_posix.c @@ -470,9 +470,9 @@ int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uin // Reset file descriptor FD_ZERO(&rfds); - FD_SET(((serial_port_unix_t_t *)sp)->fd, &rfds); + FD_SET(spu->fd, &rfds); tv = timeout; - res = select(((serial_port_unix_t_t *)sp)->fd + 1, &rfds, NULL, NULL, &tv); + res = select(spu->fd + 1, &rfds, NULL, NULL, &tv); // Read error if (res < 0) { @@ -491,7 +491,7 @@ int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uin } // Retrieve the count of the incoming bytes - res = ioctl(((serial_port_unix_t_t *)sp)->fd, FIONREAD, &byteCount); + res = ioctl(spu->fd, FIONREAD, &byteCount); // PrintAndLogEx(ERR, "UART:: RX ioctl res %d byteCount %u", res, byteCount); if (res < 0) return PM3_ENOTTY; @@ -510,7 +510,7 @@ int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uin } // There is something available, read the data - res = read(((serial_port_unix_t_t *)sp)->fd, pbtRx + (*pszRxLen), byteCount); + res = read(spu->fd, pbtRx + (*pszRxLen), byteCount); // Stop if the OS has some troubles reading the data if (res <= 0) { @@ -532,13 +532,14 @@ int uart_send(const serial_port sp, const uint8_t *pbtTx, const uint32_t len) { uint32_t pos = 0; fd_set rfds; struct timeval tv; + const serial_port_unix_t_t *spu = (serial_port_unix_t_t *)sp; while (pos < len) { // Reset file descriptor FD_ZERO(&rfds); - FD_SET(((serial_port_unix_t_t *)sp)->fd, &rfds); + FD_SET(spu->fd, &rfds); tv = timeout; - int res = select(((serial_port_unix_t_t *)sp)->fd + 1, NULL, &rfds, NULL, &tv); + int res = select(spu->fd + 1, NULL, &rfds, NULL, &tv); // Write error if (res < 0) { @@ -553,7 +554,7 @@ int uart_send(const serial_port sp, const uint8_t *pbtTx, const uint32_t len) { } // Send away the bytes - res = write(((serial_port_unix_t_t *)sp)->fd, pbtTx + pos, len - pos); + res = write(spu->fd, pbtTx + pos, len - pos); // Stop if the OS has some troubles sending the data if (res <= 0)