Merge branch 'master' into pn532_spi

* master: (28 commits)
  Update Changelog
  Add missing windows files in archive
  Move log implementation for Windows in dedicated directory
  Move UART implementation for Windows in dedicated directory
  CMake: only compile usbbus.c when (at least) one USB driver is enabled
  CMake: only include UART related files when (at least) one UART driver is enabled
  Only include UART related files when (at least) one UART driver is enabled
  Fix environment vars usage when compiling with CMake
  Remove unsed code section in log.c (was commented)
  pn53x_current_target_new() now returns null ptr upon malloc() error
  fix missing tests on malloc() return
  pn53x_data_new() now returns null ptr upon malloc() error
  uart drivers: missing pn53x_data_free() on some error handling branches
  uart drivers: missing nfc_device_free() on some error handling branches
  uart drivers: missing uart_close() on some error handling branches
  uart drivers: fix missing free(ndd.port)
  config parser: missing fclose()
  UART drivers: fix double free() of serial port info
  Fix cmake build failure under linux
  quick_start_example1.c: avoid using warnx() to remove err.h dependency
  ...

Conflicts:
	libnfc/buses/Makefile.am
This commit is contained in:
Philippe Teuwen 2013-03-27 11:44:29 +01:00
commit 1417bdc164
29 changed files with 645 additions and 512 deletions

View file

@ -34,6 +34,11 @@ IF(LIBNFC_LOG)
ADD_DEFINITIONS(-DLOG)
ENDIF(LIBNFC_LOG)
SET(LIBNFC_ENVVARS ON CACHE BOOL "Enable envvars facility")
IF(LIBNFC_ENVVARS)
ADD_DEFINITIONS(-DENVVARS)
ENDIF(LIBNFC_ENVVARS)
SET(LIBNFC_DEBUG_MODE OFF CACHE BOOL "Debug mode")
IF(LIBNFC_DEBUG_MODE)
ADD_DEFINITIONS(-DDEBUG)
@ -111,6 +116,8 @@ IF (WIN32)
ENDIF(PCRE_INCLUDE_DIRS)
ENDIF(WIN32)
INCLUDE(LibnfcDrivers)
IF(PCSC_INCLUDE_DIRS)
INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS})
LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS})

View file

@ -14,15 +14,24 @@ Fixes:
- scanf without field width limits can crash with huge input data
- Resource leaks: missing fclose()
- Dead code, unused vars & vars scopes warnings
- Unify copyright notices & update authors lists
- Windows: Fix compilation due to new usbbus file
- Windows: Clean up compiler/linker warnings
- Fixed the suppression of the auto-fixup for linking against MS built libs
- Fixed all the formatting warnings by shifting to inttypes.h specifiers
- shifted to %lu for DWORD printf
- nfc-anticol: fix ATS length
- nfc-mfclassic: fix reporting of processed blocks total
- nfc-mfclassic: detect MIFARE Plus 2K as 2K instead of 1K
Improvements:
- Devels HACKING file: introduce clang/scan-build & cppcheck for better code
- Better internal dependencies handling (bus <> drivers)
- Cleaner handling of portability patches
- Windows: logging via OutputDebugString(), ease debugging
- nfc-mfclassic: use smaller files for cards < 4k
- nfc-mfclassic: by defaut don't authorise wrong keyfile, use "f" to force
- quick_start_example1.c: remove err.h dependency, easier for Windowsians
Changes:
- Upon malloc error, nfc_init() doesn't force exit() anymore

View file

@ -14,16 +14,19 @@ IF(LIBNFC_DRIVER_PN53X_USB)
FIND_PACKAGE(LIBUSB REQUIRED)
ADD_DEFINITIONS("-DDRIVER_PN53X_USB_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn53x_usb")
SET(USB_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_PN53X_USB)
IF(LIBNFC_DRIVER_ARYGON)
ADD_DEFINITIONS("-DDRIVER_ARYGON_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/arygon")
SET(UART_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_ARYGON)
IF(LIBNFC_DRIVER_PN532_UART)
ADD_DEFINITIONS("-DDRIVER_PN532_UART_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_uart")
SET(UART_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_PN532_UART)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/drivers)

View file

@ -118,6 +118,9 @@ fi
# Handle --with-drivers option
LIBNFC_ARG_WITH_DRIVERS
# Enable UART if
AM_CONDITIONAL(UART_ENABLED, [test x"$uart_required" = x"yes"])
# Documentation (default: no)
AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"])
@ -175,6 +178,8 @@ AC_CONFIG_FILES([
contrib/udev/Makefile
contrib/win32/Makefile
contrib/win32/sys/Makefile
contrib/win32/libnfc/Makefile
contrib/win32/libnfc/buses/Makefile
examples/Makefile
examples/pn53x-tamashell-scripts/Makefile
include/Makefile

View file

@ -1,4 +1,4 @@
SUBDIRS = sys .
SUBDIRS = libnfc sys .
EXTRA_DIST = \
err.h \

View file

@ -0,0 +1,4 @@
SUBDIRS = buses .
EXTRA_DIST = \
log-internal.c

View file

@ -0,0 +1,2 @@
EXTRA_DIST = \
uart.c

View file

@ -25,10 +25,19 @@
*/
/**
* @file uart_win32.c
* @file uart.c
* @brief Windows UART driver
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include "uart.h"
#include <nfc/nfc.h>
#include "nfc-internal.h"
#include <inttypes.h>
#include "log.h"
@ -250,11 +259,19 @@ char **
uart_list_ports(void)
{
char **availablePorts = malloc((1 + MAX_SERIAL_PORT_WIN) * sizeof(char *));
if (!availablePorts) {
perror("malloc");
return availablePorts;
}
int curIndex = 0;
int i;
for (i = 1; i <= MAX_SERIAL_PORT_WIN; i++) {
if (is_port_available(i)) {
availablePorts[curIndex] = (char *)malloc(10);
if (!availablePorts[curIndex]) {
perror("malloc");
break;
}
sprintf(availablePorts[curIndex], "COM%d", i);
// printf("found candidate port: %s\n", availablePorts[curIndex]);
curIndex++;

View file

@ -6,12 +6,7 @@
// To compile this simple example:
// $ gcc -o quick_start_example1 quick_start_example1.c -lnfc
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include <stdlib.h>
#include <err.h>
#include <nfc/nfc.h>
static void
@ -37,7 +32,7 @@ main(int argc, const char *argv[])
// Initialize libnfc and set the nfc_context
nfc_init(&context);
if (context == NULL) {
warnx("Unable to init libnfc (malloc)\n");
printf("Unable to init libnfc (malloc)\n");
exit(EXIT_FAILURE);
}
@ -53,7 +48,7 @@ main(int argc, const char *argv[])
pnd = nfc_open(context, NULL);
if (pnd == NULL) {
warnx("ERROR: %s", "Unable to open NFC device.");
printf("ERROR: %s", "Unable to open NFC device.");
exit(EXIT_FAILURE);
}
// Set opened NFC device to initiator mode

View file

@ -114,11 +114,11 @@ transmit_bytes(const uint8_t *pbtTx, const size_t szTx)
// Transmit the command bytes
if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0)
return false;
szRx = res;
// Show received answer
if (!quiet_output) {
printf("Received bits: ");
print_hex(abtRx, res);
print_hex(abtRx, szRx);
}
// Succesful transfer
return true;

View file

@ -12,14 +12,20 @@ SET(CHIPS_SOURCES chips/pn53x)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/chips)
# Library's buses
IF(LIBUSB_FOUND)
SET(BUSES_SOURCES buses/uart buses/usbbus)
ELSE(LIBUSB_FOUND)
SET(BUSES_SOURCES buses/uart)
ENDIF(LIBUSB_FOUND)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
IF(USB_REQUIRED)
LIST(APPEND BUSES_SOURCES buses/usbbus)
ENDIF(USB_REQUIRED)
INCLUDE(LibnfcDrivers)
IF(UART_REQUIRED)
IF(WIN32)
# Windows have a special implementation for UART
LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/uart)
ELSE(WIN32)
LIST(APPEND BUSES_SOURCES buses/uart)
ENDIF(WIN32)
ENDIF(UART_REQUIRED)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
IF(WIN32)
# Windows now requires regex, so we utilize PCRE
@ -42,15 +48,15 @@ IF(LIBUSB_FOUND)
ENDIF(LIBUSB_FOUND)
# Library
SET(LIBRARY_SOURCES nfc nfc-device nfc-emulation nfc-internal conf iso14443-subr mirror-subr target-subr log ${DRIVERS_SOURCES} ${BUSES_SOURCES} ${CHIPS_SOURCES} ${WINDOWS_SOURCES})
SET(LIBRARY_SOURCES nfc nfc-device nfc-emulation nfc-internal conf iso14443-subr mirror-subr target-subr ${DRIVERS_SOURCES} ${BUSES_SOURCES} ${CHIPS_SOURCES} ${WINDOWS_SOURCES})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
IF(LIBNFC_LOG)
IF(WIN32)
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}")
LIST(APPEND LIBRARY_SOURCES log_win32)
LIST(APPEND LIBRARY_SOURCES log ../contrib/win32/libnfc/log-internal)
ELSE(WIN32)
LIST(APPEND LIBRARY_SOURCES log_posix)
LIST(APPEND LIBRARY_SOURCES log log-internal)
ENDIF(WIN32)
ENDIF(LIBNFC_LOG)
ADD_LIBRARY(nfc SHARED ${LIBRARY_SOURCES})

View file

@ -7,7 +7,6 @@ lib_LTLIBRARIES = libnfc.la
libnfc_la_SOURCES = \
conf.c \
iso14443-subr.c \
log.c \
mirror-subr.c \
nfc.c \
nfc-device.c \
@ -41,10 +40,8 @@ if LIBUSB_ENABLED
endif
if WITH_LOG
libnfc_la_SOURCES += log_posix.c
libnfc_la_SOURCES += log.c log-internal.c
endif
EXTRA_DIST = \
CMakeLists.txt \
log_posix.c \
log_win32.c
CMakeLists.txt

View file

@ -6,6 +6,7 @@ noinst_LTLIBRARIES = libnfcbuses.la
libnfcbuses_la_SOURCES =
libnfcbuses_la_CFLAGS = -I$(top_srcdir)/libnfc
libnfcbuses_la_LIBADD =
EXTRA_DIST =
# SPI_ENABLED
libnfcbuses_la_SOURCES += spi.c spi.h
@ -13,11 +14,12 @@ libnfcbuses_la_CFLAGS +=
libnfcbuses_la_LIBADD +=
EXTRA_DIST = spi_posix.c
# UART_ENABLED
libnfcbuses_la_SOURCES += uart.c uart.h
libnfcbuses_la_CFLAGS +=
libnfcbuses_la_LIBADD +=
EXTRA_DIST = uart_posix.c uart_win32.c
if UART_ENABLED
libnfcbuses_la_SOURCES += uart.c uart.h
libnfcbuses_la_CFLAGS +=
libnfcbuses_la_LIBADD +=
endif
EXTRA_DIST += uart.c uart.h
if LIBUSB_ENABLED
libnfcbuses_la_SOURCES += usbbus.c usbbus.h

View file

@ -26,7 +26,7 @@
/**
* @file uart.c
* @brief UART driver wrapper
* @brief UART driver
*/
#ifdef HAVE_CONFIG_H
@ -35,14 +35,362 @@
#include "uart.h"
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <nfc/nfc.h>
#include "nfc-internal.h"
// Test if we are dealing with unix operating systems
#ifndef _WIN32
// The POSIX serial port implementation
# include "uart_posix.c"
#else
// The windows serial port implementation
# include "uart_win32.c"
#endif /* _WIN32 */
#define LOG_GROUP NFC_LOG_GROUP_COM
#define LOG_CATEGORY "libnfc.bus.uart"
# if defined(__APPLE__)
const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial-", NULL };
# elif defined (__FreeBSD__) || defined (__OpenBSD__)
const char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL };
# elif defined (__linux__)
const char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", "ttyACM", "ttyAMA", NULL };
# else
# error "Can't determine serial string for your system"
# endif
// Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
# define CCLAIMED 0x80000000
struct serial_port_unix {
int fd; // Serial port file descriptor
struct termios termios_backup; // Terminal info before using the port
struct termios termios_new; // Terminal info during the transaction
};
#define UART_DATA( X ) ((struct serial_port_unix *) X)
void uart_close_ext(const serial_port sp, const bool restore_termios);
serial_port
uart_open(const char *pcPortName)
{
struct serial_port_unix *sp = malloc(sizeof(struct serial_port_unix));
if (sp == 0)
return INVALID_SERIAL_PORT;
sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (sp->fd == -1) {
uart_close_ext(sp, false);
return INVALID_SERIAL_PORT;
}
if (tcgetattr(sp->fd, &sp->termios_backup) == -1) {
uart_close_ext(sp, false);
return INVALID_SERIAL_PORT;
}
// Make sure the port is not claimed already
if (sp->termios_backup.c_iflag & CCLAIMED) {
uart_close_ext(sp, false);
return CLAIMED_SERIAL_PORT;
}
// Copy the old terminal info struct
sp->termios_new = sp->termios_backup;
sp->termios_new.c_cflag = CS8 | CLOCAL | CREAD;
sp->termios_new.c_iflag = CCLAIMED | IGNPAR;
sp->termios_new.c_oflag = 0;
sp->termios_new.c_lflag = 0;
sp->termios_new.c_cc[VMIN] = 0; // block until n bytes are received
sp->termios_new.c_cc[VTIME] = 0; // block until a timer expires (n * 100 mSec.)
if (tcsetattr(sp->fd, TCSANOW, &sp->termios_new) == -1) {
uart_close_ext(sp, true);
return INVALID_SERIAL_PORT;
}
return sp;
}
void
uart_flush_input(serial_port sp)
{
// This line seems to produce absolutely no effect on my system (GNU/Linux 2.6.35)
tcflush(UART_DATA(sp)->fd, TCIFLUSH);
// So, I wrote this byte-eater
// Retrieve the count of the incoming bytes
int available_bytes_count = 0;
int res;
res = ioctl(UART_DATA(sp)->fd, FIONREAD, &available_bytes_count);
if (res != 0) {
return;
}
if (available_bytes_count == 0) {
return;
}
char *rx = malloc(available_bytes_count);
if (!rx) {
perror("malloc");
return;
}
// There is something available, read the data
(void)read(UART_DATA(sp)->fd, rx, available_bytes_count);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d bytes have eatten.", available_bytes_count);
free(rx);
}
void
uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed);
// Portability note: on some systems, B9600 != 9600 so we have to do
// uint32_t <=> speed_t associations by hand.
speed_t stPortSpeed = B9600;
switch (uiPortSpeed) {
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
default:
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).",
uiPortSpeed);
return;
};
// Set port speed (Input and Output)
cfsetispeed(&(UART_DATA(sp)->termios_new), stPortSpeed);
cfsetospeed(&(UART_DATA(sp)->termios_new), stPortSpeed);
if (tcsetattr(UART_DATA(sp)->fd, TCSADRAIN, &(UART_DATA(sp)->termios_new)) == -1) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to apply new speed settings.");
}
}
uint32_t
uart_get_speed(serial_port sp)
{
uint32_t uiPortSpeed = 0;
switch (cfgetispeed(&UART_DATA(sp)->termios_new)) {
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
}
return uiPortSpeed;
}
void
uart_close_ext(const serial_port sp, const bool restore_termios)
{
if (UART_DATA(sp)->fd >= 0) {
if (restore_termios)
tcsetattr(UART_DATA(sp)->fd, TCSANOW, &UART_DATA(sp)->termios_backup);
close(UART_DATA(sp)->fd);
}
free(sp);
}
void
uart_close(const serial_port sp)
{
uart_close_ext(sp, true);
}
/**
* @brief Receive data from UART and copy data to \a pbtRx
*
* @return 0 on success, otherwise driver error code
*/
int
uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout)
{
int iAbortFd = abort_p ? *((int *)abort_p) : 0;
int received_bytes_count = 0;
int available_bytes_count = 0;
const int expected_bytes_count = (int)szRx;
int res;
fd_set rfds;
do {
select:
// Reset file descriptor
FD_ZERO(&rfds);
FD_SET(UART_DATA(sp)->fd, &rfds);
if (iAbortFd) {
FD_SET(iAbortFd, &rfds);
}
struct timeval timeout_tv;
if (timeout > 0) {
timeout_tv.tv_sec = (timeout / 1000);
timeout_tv.tv_usec = ((timeout % 1000) * 1000);
}
res = select(MAX(UART_DATA(sp)->fd, iAbortFd) + 1, &rfds, NULL, NULL, timeout ? &timeout_tv : NULL);
if ((res < 0) && (EINTR == errno)) {
// The system call was interupted by a signal and a signal handler was
// run. Restart the interupted system call.
goto select;
}
// Read error
if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error: %s", strerror(errno));
return NFC_EIO;
}
// Read time-out
if (res == 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Timeout!");
return NFC_ETIMEOUT;
}
if (FD_ISSET(iAbortFd, &rfds)) {
// Abort requested
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Abort!");
close(iAbortFd);
return NFC_EOPABORTED;
}
// Retrieve the count of the incoming bytes
res = ioctl(UART_DATA(sp)->fd, FIONREAD, &available_bytes_count);
if (res != 0) {
return NFC_EIO;
}
// There is something available, read the data
res = read(UART_DATA(sp)->fd, pbtRx + received_bytes_count, MIN(available_bytes_count, (expected_bytes_count - received_bytes_count)));
// Stop if the OS has some troubles reading the data
if (res <= 0) {
return NFC_EIO;
}
received_bytes_count += res;
} while (expected_bytes_count > received_bytes_count);
LOG_HEX(LOG_GROUP, "RX", pbtRx, szRx);
return NFC_SUCCESS;
}
/**
* @brief Send \a pbtTx content to UART
*
* @return 0 on success, otherwise a driver error is returned
*/
int
uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout)
{
(void) timeout;
LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx);
if ((int) szTx == write(UART_DATA(sp)->fd, pbtTx, szTx))
return NFC_SUCCESS;
else
return NFC_EIO;
}
char **
uart_list_ports(void)
{
char **res = malloc(sizeof(char *));
if (!res) {
perror("malloc");
return res;
}
size_t szRes = 1;
res[0] = NULL;
DIR *dir;
if ((dir = opendir("/dev")) == NULL) {
perror("opendir error: /dev");
return res;
}
struct dirent entry;
struct dirent *result;
while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) {
#if !defined(__APPLE__)
if (!isdigit(entry.d_name[strlen(entry.d_name) - 1]))
continue;
#endif
const char **p = serial_ports_device_radix;
while (*p) {
if (!strncmp(entry.d_name, *p, strlen(*p))) {
char **res2 = realloc(res, (szRes + 1) * sizeof(char *));
if (!res2) {
perror("malloc");
goto oom;
}
res = res2;
if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) {
perror("malloc");
goto oom;
}
sprintf(res[szRes - 1], "/dev/%s", entry.d_name);
szRes++;
res[szRes - 1] = NULL;
}
p++;
}
}
oom:
closedir(dir);
return res;
}

View file

@ -1,381 +0,0 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors of this file:
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
/**
* @file uart_posix.c
* @brief POSIX UART driver
*/
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include "nfc-internal.h"
#define LOG_GROUP NFC_LOG_GROUP_COM
#define LOG_CATEGORY "libnfc.bus.uart"
# if defined(__APPLE__)
const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial-", NULL };
# elif defined (__FreeBSD__) || defined (__OpenBSD__)
const char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL };
# elif defined (__linux__)
const char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", "ttyACM", "ttyAMA", NULL };
# else
# error "Can't determine serial string for your system"
# endif
// Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
# define CCLAIMED 0x80000000
struct serial_port_unix {
int fd; // Serial port file descriptor
struct termios termios_backup; // Terminal info before using the port
struct termios termios_new; // Terminal info during the transaction
};
#define UART_DATA( X ) ((struct serial_port_unix *) X)
void uart_close_ext(const serial_port sp, const bool restore_termios);
serial_port
uart_open(const char *pcPortName)
{
struct serial_port_unix *sp = malloc(sizeof(struct serial_port_unix));
if (sp == 0)
return INVALID_SERIAL_PORT;
sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (sp->fd == -1) {
uart_close_ext(sp, false);
return INVALID_SERIAL_PORT;
}
if (tcgetattr(sp->fd, &sp->termios_backup) == -1) {
uart_close_ext(sp, false);
return INVALID_SERIAL_PORT;
}
// Make sure the port is not claimed already
if (sp->termios_backup.c_iflag & CCLAIMED) {
uart_close_ext(sp, false);
return CLAIMED_SERIAL_PORT;
}
// Copy the old terminal info struct
sp->termios_new = sp->termios_backup;
sp->termios_new.c_cflag = CS8 | CLOCAL | CREAD;
sp->termios_new.c_iflag = CCLAIMED | IGNPAR;
sp->termios_new.c_oflag = 0;
sp->termios_new.c_lflag = 0;
sp->termios_new.c_cc[VMIN] = 0; // block until n bytes are received
sp->termios_new.c_cc[VTIME] = 0; // block until a timer expires (n * 100 mSec.)
if (tcsetattr(sp->fd, TCSANOW, &sp->termios_new) == -1) {
uart_close_ext(sp, true);
return INVALID_SERIAL_PORT;
}
return sp;
}
void
uart_flush_input(serial_port sp)
{
// This line seems to produce absolutely no effect on my system (GNU/Linux 2.6.35)
tcflush(UART_DATA(sp)->fd, TCIFLUSH);
// So, I wrote this byte-eater
// Retrieve the count of the incoming bytes
int available_bytes_count = 0;
int res;
res = ioctl(UART_DATA(sp)->fd, FIONREAD, &available_bytes_count);
if (res != 0) {
return;
}
if (available_bytes_count == 0) {
return;
}
char *rx = malloc(available_bytes_count);
// There is something available, read the data
(void)read(UART_DATA(sp)->fd, rx, available_bytes_count);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d bytes have eatten.", available_bytes_count);
free(rx);
}
void
uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed);
// Portability note: on some systems, B9600 != 9600 so we have to do
// uint32_t <=> speed_t associations by hand.
speed_t stPortSpeed = B9600;
switch (uiPortSpeed) {
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
default:
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).",
uiPortSpeed);
return;
};
// Set port speed (Input and Output)
cfsetispeed(&(UART_DATA(sp)->termios_new), stPortSpeed);
cfsetospeed(&(UART_DATA(sp)->termios_new), stPortSpeed);
if (tcsetattr(UART_DATA(sp)->fd, TCSADRAIN, &(UART_DATA(sp)->termios_new)) == -1) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to apply new speed settings.");
}
}
uint32_t
uart_get_speed(serial_port sp)
{
uint32_t uiPortSpeed = 0;
switch (cfgetispeed(&UART_DATA(sp)->termios_new)) {
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
}
return uiPortSpeed;
}
void
uart_close_ext(const serial_port sp, const bool restore_termios)
{
if (UART_DATA(sp)->fd >= 0) {
if (restore_termios)
tcsetattr(UART_DATA(sp)->fd, TCSANOW, &UART_DATA(sp)->termios_backup);
close(UART_DATA(sp)->fd);
}
free(sp);
}
void
uart_close(const serial_port sp)
{
uart_close_ext(sp, true);
}
/**
* @brief Receive data from UART and copy data to \a pbtRx
*
* @return 0 on success, otherwise driver error code
*/
int
uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout)
{
int iAbortFd = abort_p ? *((int *)abort_p) : 0;
int received_bytes_count = 0;
int available_bytes_count = 0;
const int expected_bytes_count = (int)szRx;
int res;
fd_set rfds;
do {
select:
// Reset file descriptor
FD_ZERO(&rfds);
FD_SET(UART_DATA(sp)->fd, &rfds);
if (iAbortFd) {
FD_SET(iAbortFd, &rfds);
}
struct timeval timeout_tv;
if (timeout > 0) {
timeout_tv.tv_sec = (timeout / 1000);
timeout_tv.tv_usec = ((timeout % 1000) * 1000);
}
res = select(MAX(UART_DATA(sp)->fd, iAbortFd) + 1, &rfds, NULL, NULL, timeout ? &timeout_tv : NULL);
if ((res < 0) && (EINTR == errno)) {
// The system call was interupted by a signal and a signal handler was
// run. Restart the interupted system call.
goto select;
}
// Read error
if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error: %s", strerror(errno));
return NFC_EIO;
}
// Read time-out
if (res == 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Timeout!");
return NFC_ETIMEOUT;
}
if (FD_ISSET(iAbortFd, &rfds)) {
// Abort requested
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Abort!");
close(iAbortFd);
return NFC_EOPABORTED;
}
// Retrieve the count of the incoming bytes
res = ioctl(UART_DATA(sp)->fd, FIONREAD, &available_bytes_count);
if (res != 0) {
return NFC_EIO;
}
// There is something available, read the data
res = read(UART_DATA(sp)->fd, pbtRx + received_bytes_count, MIN(available_bytes_count, (expected_bytes_count - received_bytes_count)));
// Stop if the OS has some troubles reading the data
if (res <= 0) {
return NFC_EIO;
}
received_bytes_count += res;
} while (expected_bytes_count > received_bytes_count);
LOG_HEX(LOG_GROUP, "RX", pbtRx, szRx);
return NFC_SUCCESS;
}
/**
* @brief Send \a pbtTx content to UART
*
* @return 0 on success, otherwise a driver error is returned
*/
int
uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout)
{
(void) timeout;
LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx);
if ((int) szTx == write(UART_DATA(sp)->fd, pbtTx, szTx))
return NFC_SUCCESS;
else
return NFC_EIO;
}
char **
uart_list_ports(void)
{
char **res = malloc(sizeof(char *));
size_t szRes = 1;
res[0] = NULL;
DIR *dir;
if ((dir = opendir("/dev")) == NULL) {
perror("opendir error: /dev");
return res;
}
struct dirent entry;
struct dirent *result;
while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) {
#if !defined(__APPLE__)
if (!isdigit(entry.d_name[strlen(entry.d_name) - 1]))
continue;
#endif
const char **p = serial_ports_device_radix;
while (*p) {
if (!strncmp(entry.d_name, *p, strlen(*p))) {
char **res2 = realloc(res, (szRes + 1) * sizeof(char *));
if (!res2) {
perror("malloc");
goto oom;
}
res = res2;
if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) {
perror("malloc");
goto oom;
}
sprintf(res[szRes - 1], "/dev/%s", entry.d_name);
szRes++;
res[szRes - 1] = NULL;
}
p++;
}
}
oom:
closedir(dir);
return res;
}

View file

@ -67,7 +67,7 @@ nfc_modulation pn53x_ptt_to_nm(const pn53x_target_type ptt);
pn53x_modulation pn53x_nm_to_pm(const nfc_modulation nm);
pn53x_target_type pn53x_nm_to_ptt(const nfc_modulation nm);
void pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt);
void *pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt);
void pn53x_current_target_free(const struct nfc_device *pnd);
bool pn53x_current_target_is(const struct nfc_device *pnd, const nfc_target *pnt);
@ -1126,7 +1126,10 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
if ((res = pn53x_decode_target_data(abtTargetsData + 1, szTargetsData - 1, CHIP_DATA(pnd)->type, nm.nmt, &(pnt->nti))) < 0) {
return res;
}
pn53x_current_target_new(pnd, pnt);
if (pn53x_current_target_new(pnd, pnt) == NULL) {
pnd->last_error = NFC_ESOFT;
return pnd->last_error;
}
}
return abtTargetsData[0];
}
@ -1181,7 +1184,9 @@ pn53x_initiator_poll_target(struct nfc_device *pnd,
return NFC_ECHIP;
break;
}
pn53x_current_target_new(pnd, pnt);
if (pn53x_current_target_new(pnd, pnt) == NULL) {
return NFC_ESOFT;
}
} else {
pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, true);
// FIXME It does not support DEP targets
@ -1243,7 +1248,9 @@ pn53x_initiator_select_dep_target(struct nfc_device *pnd,
res = pn53x_InJumpForDEP(pnd, ndm, nbr, pbtPassiveInitiatorData, NULL, NULL, 0, pnt, timeout);
}
if (res >= 0)
pn53x_current_target_new(pnd, pnt);
if (pn53x_current_target_new(pnd, pnt) == NULL) {
return NFC_ESOFT;
}
return res;
}
@ -1909,7 +1916,10 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
if (pnt->nm.nmt == NMT_DEP) {
pnt->nti.ndi.ndm = ndm; // Update DEP mode
}
pn53x_current_target_new(pnd, pnt);
if (pn53x_current_target_new(pnd, pnt) == NULL) {
pnd->last_error = NFC_ESOFT;
return pnd->last_error;
}
if (ptm & PTM_ISO14443_4_PICC_ONLY) {
// When PN532 is in PICC target mode, it automatically reply to RATS so
@ -3089,7 +3099,7 @@ pn53x_get_information_about(nfc_device *pnd, char **pbuf)
return NFC_SUCCESS;
}
void
void *
pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt)
{
// Keep the current nfc_target for further commands
@ -3097,7 +3107,11 @@ pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt)
free(CHIP_DATA(pnd)->current_target);
}
CHIP_DATA(pnd)->current_target = malloc(sizeof(nfc_target));
if (!CHIP_DATA(pnd)->current_target) {
return NULL;
}
memcpy(CHIP_DATA(pnd)->current_target, pnt, sizeof(nfc_target));
return CHIP_DATA(pnd)->current_target;
}
void
@ -3122,11 +3136,13 @@ pn53x_current_target_is(const struct nfc_device *pnd, const nfc_target *pnt)
return true;
}
void
void *
pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io)
{
pnd->chip_data = malloc(sizeof(struct pn53x_data));
if (!pnd->chip_data) {
return NULL;
}
// Keep I/O functions
CHIP_DATA(pnd)->io = io;
@ -3165,6 +3181,8 @@ pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io)
CHIP_DATA(pnd)->supported_modulation_as_initiator = NULL;
CHIP_DATA(pnd)->supported_modulation_as_target = NULL;
return pnd->chip_data;
}
void

View file

@ -394,7 +394,7 @@ int pn53x_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, cons
int pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
int pn53x_get_information_about(nfc_device *pnd, char **pbuf);
void pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io);
void *pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io);
void pn53x_data_free(struct nfc_device *pnd);
#endif // __NFC_CHIPS_PN53X_H__

View file

@ -68,6 +68,7 @@ conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const ch
regex_t preg;
if (regcomp(&preg, str_regex, REG_EXTENDED | REG_NOTEOL) != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Regular expression used for configuration file parsing is not valid.");
fclose(f);
return false;
}
size_t nmatch = preg.re_nsub + 1;
@ -75,6 +76,7 @@ conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const ch
if (!pmatch) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not enough memory: malloc failed.");
regfree(&preg);
fclose(f);
return false;
}
@ -108,6 +110,7 @@ conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const ch
free(pmatch);
regfree(&preg);
fclose(f);
return false;
}

View file

@ -264,7 +264,10 @@ acr122_pcsc_open(const nfc_context *context, const nfc_connstring connstring)
}
// Alloc and init chip's data
pn53x_data_new(pnd, &acr122_pcsc_io);
if (pn53x_data_new(pnd, &acr122_pcsc_io) == NULL) {
perror("malloc");
goto error;
}
SCARDCONTEXT *pscc;

View file

@ -452,7 +452,10 @@ acr122_usb_open(const nfc_context *context, const nfc_connstring connstring)
*DRIVER_DATA(pnd) = data;
// Alloc and init chip's data
pn53x_data_new(pnd, &acr122_usb_io);
if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) {
perror("malloc");
goto error;
}
memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template));
memcpy(&(DRIVER_DATA(pnd)->apdu_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template));

View file

@ -429,6 +429,7 @@ acr122s_scan(const nfc_context *context, nfc_connstring connstrings[], const siz
nfc_device *pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
uart_close(sp);
return -1;
}
@ -436,6 +437,8 @@ acr122s_scan(const nfc_context *context, nfc_connstring connstrings[], const siz
pnd->driver_data = malloc(sizeof(struct acr122s_data));
if (!pnd->driver_data) {
perror("malloc");
uart_close(sp);
nfc_device_free(pnd);
return -1;
}
DRIVER_DATA(pnd)->port = sp;
@ -443,13 +446,20 @@ acr122s_scan(const nfc_context *context, nfc_connstring connstrings[], const siz
#ifndef WIN32
if (pipe(DRIVER_DATA(pnd)->abort_fds) < 0) {
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return 0;
}
#else
DRIVER_DATA(pnd)->abort_flag = false;
#endif
pn53x_data_new(pnd, &acr122s_io);
if (pn53x_data_new(pnd, &acr122s_io) == NULL) {
perror("malloc");
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return 0;
}
CHIP_DATA(pnd)->type = PN532;
CHIP_DATA(pnd)->power_mode = NORMAL;
@ -459,9 +469,9 @@ acr122s_scan(const nfc_context *context, nfc_connstring connstrings[], const siz
ret = -1;
}
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
uart_close(sp);
if (ret != 0)
continue;
@ -497,7 +507,6 @@ acr122s_close(nfc_device *pnd)
close(DRIVER_DATA(pnd)->abort_fds[1]);
#endif
free(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
}
@ -550,16 +559,19 @@ acr122s_open(const nfc_context *context, const nfc_connstring connstring)
pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
acr122s_close(pnd);
free(ndd.port);
uart_close(sp);
return NULL;
}
pnd->driver = &acr122s_driver;
strcpy(pnd->name, ACR122S_DRIVER_NAME);
free(ndd.port);
pnd->driver_data = malloc(sizeof(struct acr122s_data));
if (!pnd->driver_data) {
perror("malloc");
acr122s_close(pnd);
uart_close(sp);
nfc_device_free(pnd);
return NULL;
}
@ -568,14 +580,20 @@ acr122s_open(const nfc_context *context, const nfc_connstring connstring)
#ifndef WIN32
if (pipe(DRIVER_DATA(pnd)->abort_fds) < 0) {
acr122s_close(pnd);
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return NULL;
}
#else
DRIVER_DATA(pnd)->abort_flag = false;
#endif
pn53x_data_new(pnd, &acr122s_io);
if (pn53x_data_new(pnd, &acr122s_io) == NULL) {
perror("malloc");
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return NULL;
}
CHIP_DATA(pnd)->type = PN532;
#if 1

View file

@ -120,6 +120,7 @@ arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size
nfc_device *pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
uart_close(sp);
return 0;
}
@ -127,16 +128,26 @@ arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size
pnd->driver_data = malloc(sizeof(struct arygon_data));
if (!pnd->driver_data) {
perror("malloc");
uart_close(sp);
nfc_device_free(pnd);
return 0;
}
DRIVER_DATA(pnd)->port = sp;
// Alloc and init chip's data
pn53x_data_new(pnd, &arygon_tama_io);
if (pn53x_data_new(pnd, &arygon_tama_io) == NULL) {
perror("malloc");
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return 0;
}
#ifndef WIN32
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
return 0;
}
#else
@ -144,9 +155,9 @@ arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size
#endif
int res = arygon_reset_tama(pnd);
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
uart_close(sp);
if (res < 0) {
continue;
}
@ -187,7 +198,6 @@ arygon_close(nfc_device *pnd)
close(DRIVER_DATA(pnd)->iAbortFds[1]);
#endif
free(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
}
@ -238,20 +248,28 @@ arygon_open(const nfc_context *context, const nfc_connstring connstring)
if (!pnd) {
perror("malloc");
free(ndd.port);
uart_close(sp);
return NULL;
}
snprintf(pnd->name, sizeof(pnd->name), "%s:%s", ARYGON_DRIVER_NAME, ndd.port);
free(ndd.port);
pnd->driver_data = malloc(sizeof(struct arygon_data));
if (!pnd->driver_data) {
perror("malloc");
free(ndd.port);
uart_close(sp);
nfc_device_free(pnd);
return NULL;
}
DRIVER_DATA(pnd)->port = sp;
// Alloc and init chip's data
pn53x_data_new(pnd, &arygon_tama_io);
if (pn53x_data_new(pnd, &arygon_tama_io) == NULL) {
perror("malloc");
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return NULL;
}
// The PN53x chip opened to ARYGON MCU doesn't seems to be in LowVBat mode
CHIP_DATA(pnd)->power_mode = NORMAL;
@ -263,7 +281,9 @@ arygon_open(const nfc_context *context, const nfc_connstring connstring)
#ifndef WIN32
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
free(ndd.port);
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
return NULL;
}
#else

View file

@ -90,18 +90,26 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
nfc_device *pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
uart_close(sp);
return 0;
}
pnd->driver = &pn532_uart_driver;
pnd->driver_data = malloc(sizeof(struct pn532_uart_data));
if (!pnd->driver_data) {
perror("malloc");
uart_close(sp);
nfc_device_free(pnd);
return 0;
}
DRIVER_DATA(pnd)->port = sp;
// Alloc and init chip's data
pn53x_data_new(pnd, &pn532_uart_io);
if (pn53x_data_new(pnd, &pn532_uart_io) == NULL) {
perror("malloc");
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return 0;
}
// SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532
CHIP_DATA(pnd)->type = PN532;
// This device starts in LowVBat power mode
@ -110,6 +118,9 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
#ifndef WIN32
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
return 0;
}
#else
@ -118,9 +129,9 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
// Check communication using "Diagnose" command, with "Communication test" (0x00)
int res = pn53x_check_communication(pnd);
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
uart_close(sp);
if (res < 0) {
continue;
}
@ -160,7 +171,6 @@ pn532_uart_close(nfc_device *pnd)
close(DRIVER_DATA(pnd)->iAbortFds[1]);
#endif
free(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
}
@ -210,20 +220,28 @@ pn532_uart_open(const nfc_context *context, const nfc_connstring connstring)
if (!pnd) {
perror("malloc");
free(ndd.port);
uart_close(sp);
return NULL;
}
snprintf(pnd->name, sizeof(pnd->name), "%s:%s", PN532_UART_DRIVER_NAME, ndd.port);
free(ndd.port);
pnd->driver_data = malloc(sizeof(struct pn532_uart_data));
if (!pnd->driver_data) {
perror("malloc");
free(ndd.port);
uart_close(sp);
nfc_device_free(pnd);
return NULL;
}
DRIVER_DATA(pnd)->port = sp;
// Alloc and init chip's data
pn53x_data_new(pnd, &pn532_uart_io);
if (pn53x_data_new(pnd, &pn532_uart_io) == NULL) {
perror("malloc");
uart_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return NULL;
}
// SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532
CHIP_DATA(pnd)->type = PN532;
// This device starts in LowVBat mode
@ -236,7 +254,9 @@ pn532_uart_open(const nfc_context *context, const nfc_connstring connstring)
#ifndef WIN32
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
free(ndd.port);
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
return NULL;
}
#else
@ -247,7 +267,6 @@ pn532_uart_open(const nfc_context *context, const nfc_connstring connstring)
if (pn53x_check_communication(pnd) < 0) {
nfc_perror(pnd, "pn53x_check_communication");
pn532_uart_close(pnd);
free(ndd.port);
return NULL;
}

View file

@ -337,7 +337,10 @@ pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring)
*DRIVER_DATA(pnd) = data;
// Alloc and init chip's data
pn53x_data_new(pnd, &pn53x_usb_io);
if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) {
perror("malloc");
goto error;
}
switch (DRIVER_DATA(pnd)->model) {
// empirical tuning

View file

@ -32,37 +32,6 @@
#include <stdarg.h>
#include <fcntl.h>
/*
int
log_priority_to_int(const char* priority)
{
if (strcmp("none", priority) == 0) {
return -1;
} else if (strcmp("fatal", priority) == 0) {
return NFC_LOG_PRIORITY_FATAL;
} else if (strcmp("alert", priority) == 0) {
return NFC_LOG_PRIORITY_ALERT;
} else if (strcmp("critical", priority) == 0) {
return NFC_LOG_PRIORITY_CRIT;
} else if (strcmp("error", priority) == 0) {
return NFC_LOG_PRIORITY_ERROR;
} else if (strcmp("warning", priority) == 0) {
return NFC_LOG_PRIORITY_WARN;
} else if (strcmp("notice", priority) == 0) {
return NFC_LOG_PRIORITY_NOTICE;
} else if (strcmp("info", priority) == 0) {
return NFC_LOG_PRIORITY_INFO;
} else if (strcmp("debug", priority) == 0) {
return NFC_LOG_PRIORITY_DEBUG;
} else if (strcmp("trace", priority) == 0) {
return NFC_LOG_PRIORITY_TRACE;
}
// if priority is string is not recognized, we set maximal verbosity
return NFC_LOG_PRIORITY_TRACE;
}
*/
const char *
log_priority_to_str(const int priority)
{

View file

@ -56,6 +56,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_ACR122_USB_ENABLED"
;;
acr122s)
uart_required="yes"
driver_acr122s_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_ACR122S_ENABLED"
;;
@ -65,10 +66,12 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN53X_USB_ENABLED"
;;
arygon)
uart_required="yes"
driver_arygon_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_ARYGON_ENABLED"
;;
pn532_uart)
uart_required="yes"
driver_pn532_uart_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_UART_ENABLED"
;;

View file

@ -65,6 +65,7 @@ static mifare_classic_tag mtKeys;
static mifare_classic_tag mtDump;
static bool bUseKeyA;
static bool bUseKeyFile;
static bool bForceKeyFile;
static bool bTolerateFailures;
static uint8_t uiBlocks;
static uint8_t keys[] = {
@ -138,7 +139,7 @@ print_success_or_failure(bool bFailure, uint32_t *uiBlockCounter)
{
printf("%c", (bFailure) ? 'x' : '.');
if (uiBlockCounter && !bFailure)
*uiBlockCounter += (*uiBlockCounter < 128) ? 4 : 16;
*uiBlockCounter += 1;
}
static bool
@ -261,6 +262,32 @@ unlock_card(void)
return true;
}
static int
get_rats(void)
{
int res;
uint8_t abtRats[2] = { 0xe0, 0x50};
// Use raw send/receive methods
if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) {
nfc_perror(pnd, "nfc_configure");
return -1;
}
res = nfc_initiator_transceive_bytes(pnd, abtRats, sizeof(abtRats), abtRx, sizeof(abtRx), 0);
if (res > 0) {
// ISO14443-4 card, turn RF field off/on to access ISO14443-3 again
nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false);
nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true);
}
// Reselect tag
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
printf("Error: tag disappeared\n");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
return res;
}
static bool
read_card(int read_unlocked)
{
@ -419,7 +446,7 @@ static void
print_usage(const char *pcProgramName)
{
printf("Usage: ");
printf("%s r|R|w|W a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
printf("%s r|R|w|W a|b <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName);
printf(" r|R|w|W - Perform read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
printf(" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
printf(" *** unlocked read does not require authentication and will reveal A and B keys\n");
@ -427,6 +454,7 @@ print_usage(const char *pcProgramName)
printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n");
printf(" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
printf(" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
printf(" f - Force using the keyfile even if UID does not match (optional)\n");
}
int
@ -464,46 +492,27 @@ main(int argc, const char *argv[])
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
bUseKeyFile = (argc > 4);
bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0));
}
if (atAction == ACTION_USAGE) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
// We don't know yet the card size so let's read only the UID from the keyfile for the moment
if (bUseKeyFile) {
FILE *pfKeys = fopen(argv[4], "rb");
if (pfKeys == NULL) {
printf("Could not open keys file: %s\n", argv[4]);
exit(EXIT_FAILURE);
}
if (fread(&mtKeys, 1, sizeof(mtKeys), pfKeys) != sizeof(mtKeys)) {
printf("Could not read keys file: %s\n", argv[4]);
if (fread(&mtKeys, 1, 4, pfKeys) != 4) {
printf("Could not read UID from key file: %s\n", argv[4]);
fclose(pfKeys);
exit(EXIT_FAILURE);
}
fclose(pfKeys);
}
if (atAction == ACTION_READ) {
memset(&mtDump, 0x00, sizeof(mtDump));
} else {
FILE *pfDump = fopen(argv[3], "rb");
if (pfDump == NULL) {
printf("Could not open dump file: %s\n", argv[3]);
exit(EXIT_FAILURE);
}
if (fread(&mtDump, 1, sizeof(mtDump), pfDump) != sizeof(mtDump)) {
printf("Could not read dump file: %s\n", argv[3]);
fclose(pfDump);
exit(EXIT_FAILURE);
}
fclose(pfDump);
}
// printf("Successfully opened required files\n");
nfc_init(&context);
if (context == NULL) {
ERR("Unable to init libnfc (malloc)");
@ -559,6 +568,14 @@ main(int argc, const char *argv[])
if (memcmp(pbtUID, fileUid, 4) != 0) {
printf("Expected MIFARE Classic card with UID starting as: %02x%02x%02x%02x\n",
fileUid[0], fileUid[1], fileUid[2], fileUid[3]);
printf("Got card with UID starting as: %02x%02x%02x%02x\n",
pbtUID[0], pbtUID[1], pbtUID[2], pbtUID[3]);
if (! bForceKeyFile) {
printf("Aborting!\n");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
}
}
printf("Found MIFARE Classic card:\n");
@ -572,11 +589,54 @@ main(int argc, const char *argv[])
// 320b
uiBlocks = 0x13;
else
// 1K
// TODO: for MFP it is 0x7f (2K) but how to be sure it's a MFP? Try to get RATS?
// 1K/2K, checked through RATS
uiBlocks = 0x3f;
// Testing RATS
int res;
if ((res = get_rats()) > 0) {
if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05)
&& (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f)
&& ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) {
// MIFARE Plus 2K
uiBlocks = 0x7f;
}
}
printf("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16);
if (bUseKeyFile) {
FILE *pfKeys = fopen(argv[4], "rb");
if (pfKeys == NULL) {
printf("Could not open keys file: %s\n", argv[4]);
exit(EXIT_FAILURE);
}
if (fread(&mtKeys, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfKeys) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
printf("Could not read keys file: %s\n", argv[4]);
fclose(pfKeys);
exit(EXIT_FAILURE);
}
fclose(pfKeys);
}
if (atAction == ACTION_READ) {
memset(&mtDump, 0x00, sizeof(mtDump));
} else {
FILE *pfDump = fopen(argv[3], "rb");
if (pfDump == NULL) {
printf("Could not open dump file: %s\n", argv[3]);
exit(EXIT_FAILURE);
}
if (fread(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
printf("Could not read dump file: %s\n", argv[3]);
fclose(pfDump);
exit(EXIT_FAILURE);
}
fclose(pfDump);
}
// printf("Successfully opened required files\n");
if (atAction == ACTION_READ) {
if (read_card(unlock)) {
printf("Writing data to file: %s ...", argv[3]);
@ -588,7 +648,7 @@ main(int argc, const char *argv[])
nfc_exit(context);
exit(EXIT_FAILURE);
}
if (fwrite(&mtDump, 1, sizeof(mtDump), pfDump) != sizeof(mtDump)) {
if (fwrite(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != ((uiBlocks + 1) * sizeof(mifare_classic_block))) {
printf("\nCould not write to file: %s\n", argv[3]);
fclose(pfDump);
nfc_close(pnd);