Refactoring uart interface (#341)
authorMichael Farrell <micolous+gh@gmail.com>
Wed, 5 Jul 2017 18:22:02 +0000 (04:22 +1000)
committerpwpiwi <pwpiwi@users.noreply.github.com>
Wed, 5 Jul 2017 18:22:02 +0000 (20:22 +0200)
* uart: Major cleanups
- Adds documentation to the uart API.
- Fixes a buffer overflow issue in `uart_receive`, where the maximum parameter was ignored.
- Splits the maximum length and bytes recieved variables in `uart_receive`.
- Downsizes the receive buffer to the minimum required, saving 16MiB of RAM at runtime.
- Refactors the POSIX and Win32 implementations of uart into separate files.
- Removes the unused `uart_{get,set}_parity` functions, which were not implemented on Win32.

client/Makefile
client/flasher.c
client/proxmark3.c
client/uart.c [deleted file]
client/uart.h [deleted file]
uart/README.md [new file with mode: 0644]
uart/uart.h [new file with mode: 0644]
uart/uart_posix.c [new file with mode: 0644]
uart/uart_win32.c [new file with mode: 0644]

index a1d4f8d8de4053c49ac675b1ba2749ff1aeb6f74..d05bdc447ad87a6572b76dc691e506903986220b 100644 (file)
@@ -13,13 +13,13 @@ RM = rm -f
 MV = mv
 
 #COMMON_FLAGS = -m32
-VPATH = ../common ../zlib
+VPATH = ../common ../zlib ../uart
 OBJDIR = obj
 
 LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
 LUALIB = ../liblua/liblua.a
 LDFLAGS = $(COMMON_FLAGS)
-CFLAGS = -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../zlib -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O3
+CFLAGS = -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O3
 CXXFLAGS = -I../include -Wall -O3
 
 LUAPLATFORM = generic
@@ -78,7 +78,8 @@ DEPFLAGS = -MT $@ -MMD -MP -MF $(OBJDIR)/$*.Td
 # make temporary to final dependeny files after successful compilation
 POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d
 
-CORESRCS =     uart.c \
+CORESRCS =     uart_posix.c \
+                       uart_win32.c \
                        util.c \
                        util_posix.c
 
index 48317c1ee1eb8e5bd105a70e54d830d2f38ee404..f257d994517b4c6a7a5675a83c5f4f13890cfac7 100644 (file)
@@ -19,6 +19,8 @@
 
 #ifdef _WIN32
 # define unlink(x)
+#else
+# include <unistd.h>
 #endif
 
 static serial_port sp;
@@ -52,8 +54,7 @@ void ReceiveCommand(UsbCommand* rxcmd) {
   byte_t* prx = prxcmd;
   size_t rxlen;
   while (true) {
-    rxlen = sizeof(UsbCommand) - (prx-prxcmd);
-    if (uart_receive(sp,prx,&rxlen)) {
+    if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-prxcmd), &rxlen)) {
       prx += rxlen;
       if ((prx-prxcmd) >= sizeof(UsbCommand)) {
         return;
@@ -129,7 +130,7 @@ int main(int argc, char **argv)
   
   fprintf(stderr,"Waiting for Proxmark to appear on %s",serial_port_name);
   do {
-    sleep(1);
+    msleep(1000);
     fprintf(stderr, ".");
   } while (!OpenProxmark(0));
   fprintf(stderr," Found.\n");
index 460aea29d65a9484d01006c10a62c2a2a9c9f0b5..fa389dd1678d35afd13def5ce2960961b88b1591 100644 (file)
@@ -57,26 +57,22 @@ struct receiver_arg {
        int run;
 };
 
-byte_t rx[0x1000000];
+byte_t rx[sizeof(UsbCommand)];
 byte_t* prx = rx;
 
 static void *uart_receiver(void *targ) {
        struct receiver_arg *arg = (struct receiver_arg*)targ;
        size_t rxlen;
-       size_t cmd_count;
 
        while (arg->run) {
-               rxlen = sizeof(UsbCommand);
-               if (uart_receive(sp, prx, &rxlen)) {
+               rxlen = 0;
+               if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-rx), &rxlen)) {
                        prx += rxlen;
-                       if (((prx-rx) % sizeof(UsbCommand)) != 0) {
+                       if (prx-rx < sizeof(UsbCommand)) {
                                continue;
                        }
-                       cmd_count = (prx-rx) / sizeof(UsbCommand);
-
-                       for (size_t i = 0; i < cmd_count; i++) {
-                               UsbCommandReceived((UsbCommand*)(rx+(i*sizeof(UsbCommand))));
-                       }
+                       
+                       UsbCommandReceived((UsbCommand*)rx);
                }
                prx = rx;
 
diff --git a/client/uart.c b/client/uart.c
deleted file mode 100644 (file)
index 4b2fee9..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Generic uart / rs232/ serial port library
- *
- * Copyright (c) 2013, Roel Verdult
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @file uart.c
- * @brief
- *
- */
-
-#include "uart.h"
-
-// Test if we are dealing with unix operating systems
-#ifndef _WIN32
-
-#include <termios.h>
-typedef struct termios term_info;
-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
-} serial_port_unix;
-
-// Set time-out on 30 miliseconds
-const struct timeval timeout = {
-  .tv_sec  =     0, // 0 second
-  .tv_usec = 30000  // 30000 micro seconds
-};
-
-serial_port uart_open(const char* pcPortName)
-{
-  serial_port_unix* sp = malloc(sizeof(serial_port_unix));
-  if (sp == 0) return INVALID_SERIAL_PORT;
-  
-  sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
-  if(sp->fd == -1) {
-    uart_close(sp);
-    return INVALID_SERIAL_PORT;
-  }
-
-  // Finally figured out a way to claim a serial port interface under unix
-  // We just try to set a (advisory) lock on the file descriptor
-  struct flock fl;
-  fl.l_type   = F_WRLCK;
-  fl.l_whence = SEEK_SET;
-  fl.l_start  = 0;
-  fl.l_len    = 0;
-  fl.l_pid    = getpid();
-  
-  // Does the system allows us to place a lock on this file descriptor
-  if (fcntl(sp->fd, F_SETLK, &fl) == -1) {
-    // A conflicting lock is held by another process
-    free(sp);
-    return CLAIMED_SERIAL_PORT;
-  }
-
-  // Try to retrieve the old (current) terminal info struct
-  if(tcgetattr(sp->fd,&sp->tiOld) == -1) {
-    uart_close(sp);
-    return INVALID_SERIAL_PORT;
-  }
-  
-  // Duplicate the (old) terminal info struct
-  sp->tiNew = sp->tiOld;
-  
-  // Configure the serial port
-  sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
-  sp->tiNew.c_iflag = IGNPAR;
-  sp->tiNew.c_oflag = 0;
-  sp->tiNew.c_lflag = 0;
-    
-  // Block until n bytes are received
-  sp->tiNew.c_cc[VMIN] = 0;
-  // Block until a timer expires (n * 100 mSec.)
-  sp->tiNew.c_cc[VTIME] = 0;
-  
-  // Try to set the new terminal info struct
-  if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) {
-    uart_close(sp);
-    return INVALID_SERIAL_PORT;
-  }
-  
-  // Flush all lingering data that may exist
-  tcflush(sp->fd, TCIOFLUSH);
-
-  return sp;
-}
-
-void uart_close(const serial_port sp) {
-  serial_port_unix* spu = (serial_port_unix*)sp;
-  tcflush(spu->fd,TCIOFLUSH);
-  tcsetattr(spu->fd,TCSANOW,&(spu->tiOld));
-  struct flock fl;
-  fl.l_type   = F_UNLCK;
-  fl.l_whence = SEEK_SET;
-  fl.l_start  = 0;
-  fl.l_len    = 0;
-  fl.l_pid    = getpid();
-  fcntl(spu->fd, F_SETLK, &fl);
-  close(spu->fd);
-  free(sp);
-}
-
-bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
-  const serial_port_unix* spu = (serial_port_unix*)sp;
-  speed_t stPortSpeed;
-  switch (uiPortSpeed) {
-    case 0: stPortSpeed = B0; break;
-    case 50: stPortSpeed = B50; break;
-    case 75: stPortSpeed = B75; break;
-    case 110: stPortSpeed = B110; break;
-    case 134: stPortSpeed = B134; break;
-    case 150: stPortSpeed = B150; break;
-    case 300: stPortSpeed = B300; break;
-    case 600: stPortSpeed = B600; break;
-    case 1200: stPortSpeed = B1200; break;
-    case 1800: stPortSpeed = B1800; break;
-    case 2400: stPortSpeed = B2400; break;
-    case 4800: stPortSpeed = B4800; break;
-    case 9600: stPortSpeed = B9600; break;
-    case 19200: stPortSpeed = B19200; break;
-    case 38400: stPortSpeed = B38400; break;
-#  ifdef B57600
-    case 57600: stPortSpeed = B57600; break;
-#  endif
-#  ifdef B115200
-    case 115200: stPortSpeed = B115200; break;
-#  endif
-#  ifdef B230400
-    case 230400: stPortSpeed = B230400; break;
-#  endif
-#  ifdef B460800
-    case 460800: stPortSpeed = B460800; break;
-#  endif
-#  ifdef B921600
-    case 921600: stPortSpeed = B921600; break;
-#  endif
-    default: return false;
-  };
-  struct termios ti;
-  if (tcgetattr(spu->fd,&ti) == -1) return false;
-  // Set port speed (Input and Output)
-  cfsetispeed(&ti,stPortSpeed);
-  cfsetospeed(&ti,stPortSpeed);
-  return (tcsetattr(spu->fd,TCSANOW,&ti) != -1);
-}
-
-uint32_t uart_get_speed(const serial_port sp) {
-  struct termios ti;
-  uint32_t uiPortSpeed;
-  const serial_port_unix* spu = (serial_port_unix*)sp;
-  if (tcgetattr(spu->fd,&ti) == -1) return 0;
-  // Set port speed (Input)
-  speed_t stPortSpeed = cfgetispeed(&ti);
-  switch (stPortSpeed) {
-    case B0: uiPortSpeed = 0; break;
-    case B50: uiPortSpeed = 50; break;
-    case B75: uiPortSpeed = 75; break;
-    case B110: uiPortSpeed = 110; break;
-    case B134: uiPortSpeed = 134; break;
-    case B150: uiPortSpeed = 150; break;
-    case B300: uiPortSpeed = 300; break;
-    case B600: uiPortSpeed = 600; break;
-    case B1200: uiPortSpeed = 1200; break;
-    case B1800: uiPortSpeed = 1800; break;
-    case B2400: uiPortSpeed = 2400; break;
-    case B4800: uiPortSpeed = 4800; break;
-    case B9600: uiPortSpeed = 9600; break;
-    case B19200: uiPortSpeed = 19200; break;
-    case B38400: uiPortSpeed = 38400; break;
-#  ifdef B57600
-    case B57600: uiPortSpeed = 57600; break;
-#  endif
-#  ifdef B115200
-    case B115200: uiPortSpeed = 115200; break;
-#  endif
-#  ifdef B230400
-    case B230400: uiPortSpeed = 230400; break;
-#  endif
-#  ifdef B460800
-    case B460800: uiPortSpeed = 460800; break;
-#  endif
-#  ifdef B921600
-    case B921600: uiPortSpeed = 921600; break;
-#  endif
-    default: return 0;
-  };
-  return uiPortSpeed;
-}
-
-bool uart_set_parity(serial_port sp, serial_port_parity spp) {
-  struct termios ti;
-  const serial_port_unix* spu = (serial_port_unix*)sp;
-  if (tcgetattr(spu->fd,&ti) == -1) return false;
-  switch(spp) {
-    case SP_INVALID: return false;
-    case SP_NONE: ti.c_cflag &= ~(PARENB | PARODD); break;
-    case SP_EVEN: ti.c_cflag |= PARENB; ti.c_cflag &= ~(PARODD); break;
-    case SP_ODD: ti.c_cflag |= PARENB | PARODD; break;
-  }
-  return (tcsetattr(spu->fd,TCSANOW,&ti) != -1);
-}
-
-serial_port_parity uart_get_parity(const serial_port sp) {
-  struct termios ti;
-  const serial_port_unix* spu = (serial_port_unix*)sp;
-  if (tcgetattr(spu->fd,&ti) == -1) return SP_INVALID;
-  
-  if (ti.c_cflag & PARENB) {
-    if (ti.c_cflag & PARODD) {
-      return SP_ODD;
-    } else {
-      return SP_EVEN;
-    }
-  } else {
-    return SP_NONE;
-  }
-}
-
-bool uart_cts(const serial_port sp) {
-  char status;
-  if (ioctl(((serial_port_unix*)sp)->fd,TIOCMGET,&status) < 0) return false;
-  return (status & TIOCM_CTS);
-}
-
-bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen) {
-
-  int res;
-  int byteCount;
-  fd_set rfds;
-  struct timeval tv;
-  
-  // Reset the output count
-  *pszRxLen = 0;
-  
-  do {
-    // Reset file descriptor
-    FD_ZERO(&rfds);
-    FD_SET(((serial_port_unix*)sp)->fd,&rfds);
-    tv = timeout;
-    res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv);
-    
-    // Read error
-    if (res < 0) {
-      return false;
-    }
-    // Read time-out
-    if (res == 0) {
-      if (*pszRxLen == 0) {
-        // Error, we received no data
-        return false;
-      } else {
-        // We received some data, but nothing more is available
-        return true;
-      }
-    }
-    // Retrieve the count of the incoming bytes
-    res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
-    if (res < 0) return false;
-
-    // There is something available, read the data
-    res = read(((serial_port_unix*)sp)->fd,pbtRx+(*pszRxLen),byteCount);
-
-    // Stop if the OS has some troubles reading the data
-    if (res <= 0) return false;
-    *pszRxLen += res;
-
-    if(res==byteCount)
-        return true;
-    
-  } while (byteCount);
-
-  return true;
-}
-
-bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen) {
-  int32_t res;
-  size_t szPos = 0;
-  fd_set rfds;
-  struct timeval tv;
-  
-  while (szPos < szTxLen) {
-    // Reset file descriptor
-    FD_ZERO(&rfds);
-    FD_SET(((serial_port_unix*)sp)->fd,&rfds);
-    tv = timeout;
-    res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv);
-    
-    // Write error
-    if (res < 0) {
-      return false;
-    }
-    
-    // Write time-out
-    if (res == 0) {
-      return false;
-    }
-    
-    // Send away the bytes
-    res = write(((serial_port_unix*)sp)->fd,pbtTx+szPos,szTxLen-szPos);
-    
-    // Stop if the OS has some troubles sending the data
-    if (res <= 0) return false;
-    
-    szPos += res;
-  }
-  return true;
-}
-
-#else
-// The windows serial port implementation
-
-typedef struct {
-  HANDLE hPort;     // Serial port handle
-  DCB dcb;          // Device control settings
-  COMMTIMEOUTS ct;  // Serial port time-out configuration
-} serial_port_windows;
-
-void upcase(char *p) {
-  while(*p != '\0') {
-    if(*p >= 97 && *p <= 122) {
-      *p -= 32;
-    }
-    ++p;
-  }
-}
-
-serial_port uart_open(const char* pcPortName) {
-  char acPortName[255];
-  serial_port_windows* sp = malloc(sizeof(serial_port_windows));
-  
-  // Copy the input "com?" to "\\.\COM?" format
-  sprintf(acPortName,"\\\\.\\%s",pcPortName);
-  upcase(acPortName);
-  
-  // Try to open the serial port
-  sp->hPort = CreateFileA(acPortName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
-  if (sp->hPort == INVALID_HANDLE_VALUE) {
-    uart_close(sp);
-    return INVALID_SERIAL_PORT;
-  }
-  
-  // Prepare the device control
-  memset(&sp->dcb, 0, sizeof(DCB));
-  sp->dcb.DCBlength = sizeof(DCB);
-  if(!BuildCommDCBA("baud=9600 data=8 parity=N stop=1",&sp->dcb)) {
-    uart_close(sp);
-    return INVALID_SERIAL_PORT;
-  }
-  
-  // Update the active serial port
-  if(!SetCommState(sp->hPort,&sp->dcb)) {
-    uart_close(sp);
-    return INVALID_SERIAL_PORT;
-  }
-  
-  sp->ct.ReadIntervalTimeout         = 0;
-  sp->ct.ReadTotalTimeoutMultiplier  = 0;
-  sp->ct.ReadTotalTimeoutConstant    = 30;
-  sp->ct.WriteTotalTimeoutMultiplier = 0;
-  sp->ct.WriteTotalTimeoutConstant   = 30;
-  
-  if(!SetCommTimeouts(sp->hPort,&sp->ct)) {
-    uart_close(sp);
-    return INVALID_SERIAL_PORT;
-  }
-  
-  PurgeComm(sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
-  
-  return sp;
-}
-
-void uart_close(const serial_port sp) {
-  CloseHandle(((serial_port_windows*)sp)->hPort);
-  free(sp);
-}
-
-bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
-  serial_port_windows* spw;
-  spw = (serial_port_windows*)sp;
-  spw->dcb.BaudRate = uiPortSpeed;
-  return SetCommState(spw->hPort, &spw->dcb);
-}
-
-uint32_t uart_get_speed(const serial_port sp) {
-  const serial_port_windows* spw = (serial_port_windows*)sp;
-  if (!GetCommState(spw->hPort, (serial_port)&spw->dcb)) {
-    return spw->dcb.BaudRate;
-  }
-  return 0;
-}
-
-bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen) {
-  ReadFile(((serial_port_windows*)sp)->hPort,pbtRx,*pszRxLen,(LPDWORD)pszRxLen,NULL);
-  return (*pszRxLen != 0);
-}
-
-bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen) {
-  DWORD dwTxLen = 0;
-  return WriteFile(((serial_port_windows*)sp)->hPort,pbtTx,szTxLen,&dwTxLen,NULL);
-  return (dwTxLen != 0);
-}
-
-#endif
diff --git a/client/uart.h b/client/uart.h
deleted file mode 100644 (file)
index 747c0f2..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Generic uart / rs232/ serial port library
- *
- * Copyright (c) 2013, Roel Verdult
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @file uart.h
- * @brief
- *
- */
-
-#ifndef _RS232_H_
-#define _RS232_H_
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-
-typedef unsigned char byte_t;
-
-// Handle platform specific includes
-#ifndef _WIN32
-  #include <termios.h>
-  #include <sys/ioctl.h>
-  #include <unistd.h>
-  #include <fcntl.h>
-  #include <sys/types.h>
-  #include <sys/stat.h>
-  #include <limits.h>
-  #include <sys/time.h>
-  #include <errno.h>
-#else
-  #include <windows.h>
-#endif
-
-typedef enum {
-  SP_INVALID = 0x00, // invalid value, error occured
-  SP_NONE    = 0x01, // no parity (default)
-  SP_EVEN    = 0x02, // even parity
-  SP_ODD     = 0x03  // odd parity
-} serial_port_parity;
-
-// Define shortcut to types to make code more readable
-typedef void* serial_port;
-#define INVALID_SERIAL_PORT (void*)(~1)
-#define CLAIMED_SERIAL_PORT (void*)(~2)
-
-serial_port uart_open(const char* pcPortName);
-void uart_close(const serial_port sp);
-
-bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed);
-uint32_t uart_get_speed(const serial_port sp);
-
-bool uart_set_parity(serial_port sp, serial_port_parity spp);
-serial_port_parity uart_get_parity(const serial_port sp);
-
-bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen);
-bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen);
-
-#endif // _PROXMARK3_RS232_H_
-
-
diff --git a/uart/README.md b/uart/README.md
new file mode 100644 (file)
index 0000000..218e983
--- /dev/null
@@ -0,0 +1,13 @@
+# uart
+
+This contains functionality for talking to UART/Serial devices on different platforms. The official client will build either `uart_posix.c` and `uart_win32.c`.  Build targets for these files are contained in `client/Makefile`.
+
+If you want to implement support for other platforms, you need to implement the methods provided in `uart.h`.
+
+## Implementing a new driver
+
+Each driver is called with a string, typically containing a path or other reference to a serial port on the host.  The methods outlined in `uart.h` need to be implemented.
+
+The hardware uses `common/usb_cdc.c` to implement a USB CDC endpoint exposed by the Atmel MCU.
+
+
diff --git a/uart/uart.h b/uart/uart.h
new file mode 100644 (file)
index 0000000..fe75a68
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Generic uart / rs232/ serial port library
+ *
+ * Copyright (c) 2013, Roel Verdult
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @file uart.h
+ */
+
+#ifndef _PM3_UART_H_
+#define _PM3_UART_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef unsigned char byte_t;
+
+/* serial_port is declared as a void*, which you should cast to whatever type
+ * makes sense to your connection method. Both the posix and win32
+ * implementations define their own structs in place.
+ */
+typedef void* serial_port;
+
+/* Returned by uart_open if the serial port specified was invalid.
+ */
+#define INVALID_SERIAL_PORT (void*)(~1)
+
+/* Returned by uart_open if the serial port specified is in use by another
+ * process.
+ */
+#define CLAIMED_SERIAL_PORT (void*)(~2)
+
+/* Given a user-specified port name, connect to the port and return a structure
+ * used for future references to that port.
+ *
+ * On errors, this method returns INVALID_SERIAL_PORT or CLAIMED_SERIAL_PORT.
+ */
+serial_port uart_open(const char* pcPortName);
+
+/* Closes the given port.
+ */
+void uart_close(const serial_port sp);
+
+/* Reads from the given serial port for up to 30ms.
+ *   pbtRx: A pointer to a buffer for the returned data to be written to.
+ *   pszMaxRxLen: The maximum data size we want to be sent.
+ *   pszRxLen: The number of bytes that we were actually sent.
+ *
+ * Returns TRUE if any data was fetched, even if it was less than pszMaxRxLen.
+ *
+ * Returns FALSE if there was an error reading from the device. Note that a
+ * partial read may have completed into the buffer by the corresponding
+ * implementation, so pszRxLen should be checked to see if any data was written. 
+ */
+bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen);
+
+/* Sends a buffer to a given serial port.
+ *   pbtTx: A pointer to a buffer containing the data to send.
+ *   szTxLen: The amount of data to be sent.
+ */
+bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen);
+
+/* Sets the current speed of the serial port, in baud.
+ */
+bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed);
+
+/* Gets the current speed of the serial port, in baud.
+ */
+uint32_t uart_get_speed(const serial_port sp);
+
+#endif // _PM3_UART_H_
+
diff --git a/uart/uart_posix.c b/uart/uart_posix.c
new file mode 100644 (file)
index 0000000..45e0d3d
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Generic uart / rs232/ serial port library
+ *
+ * Copyright (c) 2013, Roel Verdult
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @file uart_posix.c
+ *
+ * This version of the library has functionality removed which was not used by
+ * proxmark3 project.
+ */
+
+#include "uart.h"
+
+// Test if we are dealing with posix operating systems
+#ifndef _WIN32
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <sys/time.h>
+#include <errno.h>
+
+typedef struct termios term_info;
+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
+} serial_port_unix;
+
+// Set time-out on 30 miliseconds
+const struct timeval timeout = {
+  .tv_sec  =     0, // 0 second
+  .tv_usec = 30000  // 30000 micro seconds
+};
+
+serial_port uart_open(const char* pcPortName)
+{
+  serial_port_unix* sp = malloc(sizeof(serial_port_unix));
+  if (sp == 0) return INVALID_SERIAL_PORT;
+  
+  sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
+  if(sp->fd == -1) {
+    uart_close(sp);
+    return INVALID_SERIAL_PORT;
+  }
+
+  // Finally figured out a way to claim a serial port interface under unix
+  // We just try to set a (advisory) lock on the file descriptor
+  struct flock fl;
+  fl.l_type   = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+  fl.l_start  = 0;
+  fl.l_len    = 0;
+  fl.l_pid    = getpid();
+  
+  // Does the system allows us to place a lock on this file descriptor
+  if (fcntl(sp->fd, F_SETLK, &fl) == -1) {
+    // A conflicting lock is held by another process
+    free(sp);
+    return CLAIMED_SERIAL_PORT;
+  }
+
+  // Try to retrieve the old (current) terminal info struct
+  if(tcgetattr(sp->fd,&sp->tiOld) == -1) {
+    uart_close(sp);
+    return INVALID_SERIAL_PORT;
+  }
+  
+  // Duplicate the (old) terminal info struct
+  sp->tiNew = sp->tiOld;
+  
+  // Configure the serial port
+  sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
+  sp->tiNew.c_iflag = IGNPAR;
+  sp->tiNew.c_oflag = 0;
+  sp->tiNew.c_lflag = 0;
+    
+  // Block until n bytes are received
+  sp->tiNew.c_cc[VMIN] = 0;
+  // Block until a timer expires (n * 100 mSec.)
+  sp->tiNew.c_cc[VTIME] = 0;
+  
+  // Try to set the new terminal info struct
+  if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) {
+    uart_close(sp);
+    return INVALID_SERIAL_PORT;
+  }
+  
+  // Flush all lingering data that may exist
+  tcflush(sp->fd, TCIOFLUSH);
+
+  return sp;
+}
+
+void uart_close(const serial_port sp) {
+  serial_port_unix* spu = (serial_port_unix*)sp;
+  tcflush(spu->fd,TCIOFLUSH);
+  tcsetattr(spu->fd,TCSANOW,&(spu->tiOld));
+  struct flock fl;
+  fl.l_type   = F_UNLCK;
+  fl.l_whence = SEEK_SET;
+  fl.l_start  = 0;
+  fl.l_len    = 0;
+  fl.l_pid    = getpid();
+  fcntl(spu->fd, F_SETLK, &fl);
+  close(spu->fd);
+  free(sp);
+}
+
+bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) {
+  int res;
+  int byteCount;
+  fd_set rfds;
+  struct timeval tv;
+  
+  // Reset the output count
+  *pszRxLen = 0;
+  
+  do {
+    // Reset file descriptor
+    FD_ZERO(&rfds);
+    FD_SET(((serial_port_unix*)sp)->fd,&rfds);
+    tv = timeout;
+    res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv);
+    
+    // Read error
+    if (res < 0) {
+      return false;
+    }
+    // Read time-out
+    if (res == 0) {
+      if (*pszRxLen == 0) {
+        // Error, we received no data
+        return false;
+      } else {
+        // We received some data, but nothing more is available
+        return true;
+      }
+    }
+    // Retrieve the count of the incoming bytes
+    res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
+    if (res < 0) return false;
+    
+    // Cap the number of bytes, so we don't overrun the buffer
+    if (pszMaxRxLen - (*pszRxLen) < byteCount) {
+       byteCount = pszMaxRxLen - (*pszRxLen);
+    }
+
+    // There is something available, read the data
+    res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount);
+
+    // Stop if the OS has some troubles reading the data
+    if (res <= 0) return false;
+    *pszRxLen += res;
+
+    if (*pszRxLen == pszMaxRxLen) {
+       // We have all the data we wanted.
+      return true;
+    }
+    
+  } while (byteCount);
+
+  return true;
+}
+
+bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen) {
+  int32_t res;
+  size_t szPos = 0;
+  fd_set rfds;
+  struct timeval tv;
+  
+  while (szPos < szTxLen) {
+    // Reset file descriptor
+    FD_ZERO(&rfds);
+    FD_SET(((serial_port_unix*)sp)->fd,&rfds);
+    tv = timeout;
+    res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv);
+    
+    // Write error
+    if (res < 0) {
+      return false;
+    }
+    
+    // Write time-out
+    if (res == 0) {
+      return false;
+    }
+    
+    // Send away the bytes
+    res = write(((serial_port_unix*)sp)->fd,pbtTx+szPos,szTxLen-szPos);
+    
+    // Stop if the OS has some troubles sending the data
+    if (res <= 0) return false;
+    
+    szPos += res;
+  }
+  return true;
+}
+
+bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
+  const serial_port_unix* spu = (serial_port_unix*)sp;
+  speed_t stPortSpeed;
+  switch (uiPortSpeed) {
+    case 0: stPortSpeed = B0; break;
+    case 50: stPortSpeed = B50; break;
+    case 75: stPortSpeed = B75; break;
+    case 110: stPortSpeed = B110; break;
+    case 134: stPortSpeed = B134; break;
+    case 150: stPortSpeed = B150; break;
+    case 300: stPortSpeed = B300; break;
+    case 600: stPortSpeed = B600; break;
+    case 1200: stPortSpeed = B1200; break;
+    case 1800: stPortSpeed = B1800; break;
+    case 2400: stPortSpeed = B2400; break;
+    case 4800: stPortSpeed = B4800; break;
+    case 9600: stPortSpeed = B9600; break;
+    case 19200: stPortSpeed = B19200; break;
+    case 38400: stPortSpeed = B38400; break;
+#  ifdef B57600
+    case 57600: stPortSpeed = B57600; break;
+#  endif
+#  ifdef B115200
+    case 115200: stPortSpeed = B115200; break;
+#  endif
+#  ifdef B230400
+    case 230400: stPortSpeed = B230400; break;
+#  endif
+#  ifdef B460800
+    case 460800: stPortSpeed = B460800; break;
+#  endif
+#  ifdef B921600
+    case 921600: stPortSpeed = B921600; break;
+#  endif
+    default: return false;
+  };
+  struct termios ti;
+  if (tcgetattr(spu->fd,&ti) == -1) return false;
+  // Set port speed (Input and Output)
+  cfsetispeed(&ti,stPortSpeed);
+  cfsetospeed(&ti,stPortSpeed);
+  return (tcsetattr(spu->fd,TCSANOW,&ti) != -1);
+}
+
+uint32_t uart_get_speed(const serial_port sp) {
+  struct termios ti;
+  uint32_t uiPortSpeed;
+  const serial_port_unix* spu = (serial_port_unix*)sp;
+  if (tcgetattr(spu->fd,&ti) == -1) return 0;
+  // Set port speed (Input)
+  speed_t stPortSpeed = cfgetispeed(&ti);
+  switch (stPortSpeed) {
+    case B0: uiPortSpeed = 0; break;
+    case B50: uiPortSpeed = 50; break;
+    case B75: uiPortSpeed = 75; break;
+    case B110: uiPortSpeed = 110; break;
+    case B134: uiPortSpeed = 134; break;
+    case B150: uiPortSpeed = 150; break;
+    case B300: uiPortSpeed = 300; break;
+    case B600: uiPortSpeed = 600; break;
+    case B1200: uiPortSpeed = 1200; break;
+    case B1800: uiPortSpeed = 1800; break;
+    case B2400: uiPortSpeed = 2400; break;
+    case B4800: uiPortSpeed = 4800; break;
+    case B9600: uiPortSpeed = 9600; break;
+    case B19200: uiPortSpeed = 19200; break;
+    case B38400: uiPortSpeed = 38400; break;
+#  ifdef B57600
+    case B57600: uiPortSpeed = 57600; break;
+#  endif
+#  ifdef B115200
+    case B115200: uiPortSpeed = 115200; break;
+#  endif
+#  ifdef B230400
+    case B230400: uiPortSpeed = 230400; break;
+#  endif
+#  ifdef B460800
+    case B460800: uiPortSpeed = 460800; break;
+#  endif
+#  ifdef B921600
+    case B921600: uiPortSpeed = 921600; break;
+#  endif
+    default: return 0;
+  };
+  return uiPortSpeed;
+}
+
+#endif
+
diff --git a/uart/uart_win32.c b/uart/uart_win32.c
new file mode 100644 (file)
index 0000000..af521ea
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Generic uart / rs232/ serial port library
+ *
+ * Copyright (c) 2013, Roel Verdult
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @file uart_win32.c
+ *
+ * Note: the win32 version of this library has also been seen under the GPLv3+
+ * license as part of the libnfc project, which appears to have additional
+ * contributors.
+ *
+ * This version of the library has functionality removed which was not used by
+ * proxmark3 project.
+ */
+
+#include "uart.h"
+
+// The windows serial port implementation
+#ifdef _WIN32
+#include <windows.h>
+
+typedef struct {
+  HANDLE hPort;     // Serial port handle
+  DCB dcb;          // Device control settings
+  COMMTIMEOUTS ct;  // Serial port time-out configuration
+} serial_port_windows;
+
+void upcase(char *p) {
+  while(*p != '\0') {
+    if(*p >= 97 && *p <= 122) {
+      *p -= 32;
+    }
+    ++p;
+  }
+}
+
+serial_port uart_open(const char* pcPortName) {
+  char acPortName[255];
+  serial_port_windows* sp = malloc(sizeof(serial_port_windows));
+  
+  // Copy the input "com?" to "\\.\COM?" format
+  sprintf(acPortName,"\\\\.\\%s",pcPortName);
+  upcase(acPortName);
+  
+  // Try to open the serial port
+  sp->hPort = CreateFileA(acPortName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
+  if (sp->hPort == INVALID_HANDLE_VALUE) {
+    uart_close(sp);
+    return INVALID_SERIAL_PORT;
+  }
+  
+  // Prepare the device control
+  memset(&sp->dcb, 0, sizeof(DCB));
+  sp->dcb.DCBlength = sizeof(DCB);
+  if(!BuildCommDCBA("baud=9600 data=8 parity=N stop=1",&sp->dcb)) {
+    uart_close(sp);
+    return INVALID_SERIAL_PORT;
+  }
+  
+  // Update the active serial port
+  if(!SetCommState(sp->hPort,&sp->dcb)) {
+    uart_close(sp);
+    return INVALID_SERIAL_PORT;
+  }
+  
+  sp->ct.ReadIntervalTimeout         = 0;
+  sp->ct.ReadTotalTimeoutMultiplier  = 0;
+  sp->ct.ReadTotalTimeoutConstant    = 30;
+  sp->ct.WriteTotalTimeoutMultiplier = 0;
+  sp->ct.WriteTotalTimeoutConstant   = 30;
+  
+  if(!SetCommTimeouts(sp->hPort,&sp->ct)) {
+    uart_close(sp);
+    return INVALID_SERIAL_PORT;
+  }
+  
+  PurgeComm(sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
+  
+  return sp;
+}
+
+void uart_close(const serial_port sp) {
+  CloseHandle(((serial_port_windows*)sp)->hPort);
+  free(sp);
+}
+
+bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) {
+  ReadFile(((serial_port_windows*)sp)->hPort,pbtRx,pszMaxRxLen,(LPDWORD)pszRxLen,NULL);
+  return (*pszRxLen != 0);
+}
+
+bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen) {
+  DWORD dwTxLen = 0;
+  return WriteFile(((serial_port_windows*)sp)->hPort,pbtTx,szTxLen,&dwTxLen,NULL);
+  return (dwTxLen != 0);
+}
+
+bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
+  serial_port_windows* spw;
+  spw = (serial_port_windows*)sp;
+  spw->dcb.BaudRate = uiPortSpeed;
+  return SetCommState(spw->hPort, &spw->dcb);
+}
+
+uint32_t uart_get_speed(const serial_port sp) {
+  const serial_port_windows* spw = (serial_port_windows*)sp;
+  if (!GetCommState(spw->hPort, (serial_port)&spw->dcb)) {
+    return spw->dcb.BaudRate;
+  }
+  return 0;
+}
+
+#endif
Impressum, Datenschutz