Compare commits

..

No commits in common. "master" and "libnfc-1.8.0" have entirely different histories.

35 changed files with 324 additions and 2096 deletions

2
.gitignore vendored
View File

@ -7,8 +7,6 @@
*.lo
*.o
*~
.vs/
CMakeSettings.json
Doxyfile
INSTALL
aclocal.m4

View File

@ -1,81 +1,20 @@
language: c
matrix:
include:
- os: windows
compiler:
- clang
before_install:
- mkdir build && cd build && wget "https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/libusb-win32-bin-1.2.6.0.zip" && 7z x libusb-win32-bin-1.2.6.0.zip -o"$PROGRAMFILES" && mv "$PROGRAMFILES/libusb-win32-bin-1.2.6.0" "$PROGRAMFILES/libusb-win32"
install:
choco install doxygen.install ninja
script:
cmake -GNinja .. && cmake --build .
compiler:
- clang
- gcc
- os: linux
dist: bionic
compiler:
- clang
addons:
apt:
packages:
- libusb-dev
- doxygen
- cmake
script:
- mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install
- os: linux
dist: bionic
compiler:
- clang
addons:
apt:
packages:
- libusb-dev
- doxygen
script:
- autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install
env:
- BLD=cmake
- BLD=autoconf
- os: linux
dist: bionic
compiler:
- gcc
addons:
apt:
packages:
- libusb-dev
- doxygen
- cmake
script:
- mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install
addons:
apt:
packages:
- libusb-dev
- doxygen
- cmake
- os: linux
dist: bionic
compiler:
- gcc
addons:
apt:
packages:
- libusb-dev
- doxygen
script:
- autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install
- os: osx
osx_image: xcode12
compiler:
- clang
before_install:
- brew install doxygen libusb-compat
script:
- mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install
- os: osx
osx_image: xcode12
compiler:
- clang
before_install:
- brew install doxygen libusb-compat m4
script:
- autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install
script:
- if [ $BLD == autoconf ]; then autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install; fi
- if [ $BLD == cmake ]; then mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install; fi

View File

@ -18,12 +18,9 @@ SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
# config.h
IF(WIN32)
SET(LIBNFC_SYSCONFDIR "./config" CACHE PATH "libnfc configuration directory")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
SET(LIBNFC_SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/config" CACHE PATH "libnfc configuration directory")
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32)
IF(NOT MINGW)
SET(CMAKE_C_FLAGS "-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE ${CMAKE_C_FLAGS}")
ENDIF(NOT MINGW)
ELSE(WIN32)
SET(_XOPEN_SOURCE 600)
SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory")
@ -141,12 +138,9 @@ IF(NOT WIN32)
IF(LIBNFC_DRIVER_PN53X_USB)
SET(PKG_REQ ${PKG_REQ} "libusb")
ENDIF(LIBNFC_DRIVER_PN53X_USB)
IF(LIBNFC_DRIVER_ACR122_USB)
SET(PKG_REQ ${PKG_REQ} "libusb")
ENDIF(LIBNFC_DRIVER_ACR122_USB)
IF(LIBNFC_DRIVER_PCSC)
SET(PKG_REQ ${PKG_REQ} "libpcsclite")
ENDIF(LIBNFC_DRIVER_PCSC)
ENDIF(LIBNFC_DRIVER_ACR122)
IF(LIBNFC_DRIVER_ACR122_PCSC)
SET(PKG_REQ ${PKG_REQ} "libpcsclite")
ENDIF(LIBNFC_DRIVER_ACR122_PCSC)
@ -158,7 +152,7 @@ ENDIF(NOT WIN32)
INCLUDE(LibnfcDrivers)
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(UNIX AND NOT APPLE)
IF(I2C_REQUIRED)
# Inspired from http://cmake.3232098.n2.nabble.com/RFC-cmake-analog-to-AC-SEARCH-LIBS-td7585423.html
INCLUDE (CheckFunctionExists)
@ -172,7 +166,7 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
ENDIF (HAVE_CLOCK_GETTIME_IN_RT)
ENDIF (NOT HAVE_CLOCK_GETTIME)
ENDIF(I2C_REQUIRED)
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
ENDIF(UNIX AND NOT APPLE)
IF(PCSC_INCLUDE_DIRS)
INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS})
@ -207,8 +201,7 @@ IF(WIN32)
SET(RC_COMMENT "${PACKAGE_NAME} library")
SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}")
SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll)
# RC_FILE_TYPE: VFT_DLL
SET(RC_FILE_TYPE 0x00000002L)
SET(RC_FILE_TYPE VFT_DLL)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY)
ENDIF(WIN32)

View File

@ -2,13 +2,7 @@ ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = $(LIBNFC_CFLAGS)
SUBDIRS = libnfc utils
if EXAMPLE_ENABLED
SUBDIRS += examples
endif
SUBDIRS += include contrib cmake test
SUBDIRS = libnfc utils examples include contrib cmake test
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnfc.pc

View File

@ -40,7 +40,7 @@ Some NFC drivers depend on third party software:
* acr122_pcsc:
- pcsc-lite https://pcsclite.apdu.fr/
- pcsc-lite http://pcsclite.alioth.debian.org/
- pcsc:
- Support build with pcsc driver, which can be using all compatible readers, Feitian R502 and bR500 already passed the test.
@ -48,29 +48,12 @@ Some NFC drivers depend on third party software:
The regression test suite depends on the cutter framework:
http://cutter.sf.net
Building
========
Note: If working directly from a git clone of the repository, some of the files need to be generated first. To do this run
`autoreconf -vis`
Alternatively use a .tar.bz2 version of a packaged release (which already contains ./configure):
https://github.com/nfc-tools/libnfc/releases/
The build should be as simple as running these commands:
./configure
make
To build with specific driver(s), see option `--with-drivers=...` detailed in `./configure --help`.
Installation
============
make install
You may need to grant permissions to your user to drive your device.
See the file `INSTALL` for configure, build and install details.
Additionnally, you may need to grant permissions to your user to drive your device.
Under GNU/Linux systems, if you use udev, you could use the provided udev rules.
e.g. under Debian, Ubuntu, etc.
@ -102,17 +85,6 @@ file per device in a nfc/devices.d directory:
printf 'name = "My first device"\nconnstring = "pn532_uart:/dev/ttyACM0"\n' | sudo tee /etc/nfc/devices.d/first.conf
printf 'name = "My second device"\nconnstring = "pn532_uart:/dev/ttyACM1"\n' | sudo tee /etc/nfc/devices.d/second.conf
Environment Variables
=====================
You can override certain configuration options at runtime using the following environment variables:
+ `LIBNFC_DEFAULT_DEVICE=<connstring>`: `LIBNFC_DEFAULT_DEVICE=pn532_uart:/dev/ttyACM0` will use pn532 on /dev/ttyACM0 as default device
+ `LIBNFC_DEVICE=<connstring>` will ignore all devices in the config files and use only the one defined in the variable
+ `LIBNFC_AUTO_SCAN=<true|false>` overrides `allow_autoscan` option in the config file
+ `LIBNFC_INTRUSIVE_SCAN=<true|false>` overrides `allow_intrusive_scan` option in the config file
+ `LIBNFC_LOG_LEVEL=<0|1|2|3>` overrides `log_level` option in the config file
To obtain the connstring of a recognized device, you can use `nfc-scan-device`: `LIBNFC_AUTO_SCAN=true nfc-scan-device` will show the names & connstrings of all found devices.
How to report bugs
==================
@ -168,6 +140,18 @@ Patches can be posted to https://github.com/nfc-tools/libnfc/issues
If the patch fixes a bug, it is usually a good idea to include
all the information described in "How to Report Bugs".
Building
========
It should be as simple as running these two commands:
./configure
make
To build with specific driver(s), see option `--with-drivers=...` detailed in `./configure --help`.
Note: if you're using directly the development repository and not the release sources, you will have to execute firstly `autoreconf -vis`.
Troubleshooting
===============

View File

@ -26,15 +26,9 @@ ENDIF(CMAKE_SYSTEM_NAME MATCHES FreeBSD)
IF(NOT LIBUSB_FOUND)
IF(WIN32)
IF(MINGW)
FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/include" NO_SYSTEM_ENVIRONMENT_PATH)
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/lib/gcc")
SET(LIBUSB_LIBRARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/bin/x86/")
ELSE(MINGW)
FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "$ENV{ProgramW6432}/libusb-win32/include" NO_SYSTEM_ENVIRONMENT_PATH)
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "$ENV{ProgramW6432}/libusb-win32/lib/msvc_x64")
SET(LIBUSB_LIBRARY_DIR "$ENV{ProgramW6432}/libusb-win32/bin/amd64/")
ENDIF(MINGW)
FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "$ENV{ProgramFiles}/LibUSB-Win32/include" NO_SYSTEM_ENVIRONMENT_PATH)
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "$ENV{ProgramFiles}/LibUSB-Win32/lib/gcc")
SET(LIBUSB_LIBRARY_DIR "$ENV{ProgramFiles}/LibUSB-Win32/bin/x86/")
# Must fix up variable to avoid backslashes during packaging
STRING(REGEX REPLACE "\\\\" "/" LIBUSB_LIBRARY_DIR ${LIBUSB_LIBRARY_DIR})
ELSE(WIN32)

View File

@ -3,13 +3,13 @@ SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on
SET(LIBNFC_DRIVER_ACR122_USB ON CACHE BOOL "Enable ACR122 support (Direct USB connection)")
SET(LIBNFC_DRIVER_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)")
SET(LIBNFC_DRIVER_ARYGON ON CACHE BOOL "Enable ARYGON support (Use serial port)")
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(WIN32)
SET(LIBNFC_DRIVER_PN532_I2C OFF CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI OFF CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
ELSE(WIN32)
SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ENDIF(WIN32)
SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)")
SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)")
@ -68,11 +68,4 @@ IF(LIBNFC_DRIVER_PN53X_USB)
SET(USB_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_PN53X_USB)
IF(LIBNFC_DRIVER_ACR122_USB)
FIND_PACKAGE(LIBUSB REQUIRED)
ADD_DEFINITIONS("-DDRIVER_ACR122_USB_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb")
SET(USB_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_ACR122_USB)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers)

View File

@ -157,14 +157,6 @@ then
fi
AM_CONDITIONAL(DOC_ENABLED, [test x"$enable_doc" = xyes])
# Example build (default: yes)
AC_ARG_ENABLE([example],AS_HELP_STRING([--enable-example],[Enable example build.]),[enable_example=$enableval],[enable_example="yes"])
AC_MSG_CHECKING(for example build)
AC_MSG_RESULT($enable_example)
AM_CONDITIONAL(EXAMPLE_ENABLED, [test x"$enable_example" = xyes])
# Dependencies
PKG_CONFIG_REQUIRES=""
@ -183,10 +175,7 @@ if test x$ac_cv_with_cutter = xyes -a x$ac_cv_use_cutter = xno; then
fi
AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"])
if test x"$enable_example" = "xyes"
then
AC_CHECK_READLINE
fi
# Help us to write great code ;-)
CFLAGS="$CFLAGS -Wall -pedantic -Wextra"

View File

@ -1,870 +0,0 @@
/*
* Dirent interface for Microsoft Visual Studio
*
* Copyright (C) 2006-2012 Toni Ronkko
* This file is part of dirent. Dirent may be freely distributed
* under the MIT license. For all details and documentation, see
* https://github.com/tronkko/dirent
*/
#ifndef DIRENT_H
#define DIRENT_H
/*
* Include windows.h without Windows Sockets 1.1 to prevent conflicts with
* Windows Sockets 2.0.
*/
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
/* Indicates that d_type field is available in dirent structure */
#define _DIRENT_HAVE_D_TYPE
/* Indicates that d_namlen field is available in dirent structure */
#define _DIRENT_HAVE_D_NAMLEN
/* Entries missing from MSVC 6.0 */
#if !defined(FILE_ATTRIBUTE_DEVICE)
# define FILE_ATTRIBUTE_DEVICE 0x40
#endif
/* File type and permission flags for stat(), general mask */
#if !defined(S_IFMT)
# define S_IFMT _S_IFMT
#endif
/* Directory bit */
#if !defined(S_IFDIR)
# define S_IFDIR _S_IFDIR
#endif
/* Character device bit */
#if !defined(S_IFCHR)
# define S_IFCHR _S_IFCHR
#endif
/* Pipe bit */
#if !defined(S_IFFIFO)
# define S_IFFIFO _S_IFFIFO
#endif
/* Regular file bit */
#if !defined(S_IFREG)
# define S_IFREG _S_IFREG
#endif
/* Read permission */
#if !defined(S_IREAD)
# define S_IREAD _S_IREAD
#endif
/* Write permission */
#if !defined(S_IWRITE)
# define S_IWRITE _S_IWRITE
#endif
/* Execute permission */
#if !defined(S_IEXEC)
# define S_IEXEC _S_IEXEC
#endif
/* Pipe */
#if !defined(S_IFIFO)
# define S_IFIFO _S_IFIFO
#endif
/* Block device */
#if !defined(S_IFBLK)
# define S_IFBLK 0
#endif
/* Link */
#if !defined(S_IFLNK)
# define S_IFLNK 0
#endif
/* Socket */
#if !defined(S_IFSOCK)
# define S_IFSOCK 0
#endif
/* Read user permission */
#if !defined(S_IRUSR)
# define S_IRUSR S_IREAD
#endif
/* Write user permission */
#if !defined(S_IWUSR)
# define S_IWUSR S_IWRITE
#endif
/* Execute user permission */
#if !defined(S_IXUSR)
# define S_IXUSR 0
#endif
/* Read group permission */
#if !defined(S_IRGRP)
# define S_IRGRP 0
#endif
/* Write group permission */
#if !defined(S_IWGRP)
# define S_IWGRP 0
#endif
/* Execute group permission */
#if !defined(S_IXGRP)
# define S_IXGRP 0
#endif
/* Read others permission */
#if !defined(S_IROTH)
# define S_IROTH 0
#endif
/* Write others permission */
#if !defined(S_IWOTH)
# define S_IWOTH 0
#endif
/* Execute others permission */
#if !defined(S_IXOTH)
# define S_IXOTH 0
#endif
/* Maximum length of file name */
#if !defined(PATH_MAX)
# define PATH_MAX MAX_PATH
#endif
#if !defined(FILENAME_MAX)
# define FILENAME_MAX MAX_PATH
#endif
#if !defined(NAME_MAX)
# define NAME_MAX FILENAME_MAX
#endif
/* File type flags for d_type */
#define DT_UNKNOWN 0
#define DT_REG S_IFREG
#define DT_DIR S_IFDIR
#define DT_FIFO S_IFIFO
#define DT_SOCK S_IFSOCK
#define DT_CHR S_IFCHR
#define DT_BLK S_IFBLK
#define DT_LNK S_IFLNK
/* Macros for converting between st_mode and d_type */
#define IFTODT(mode) ((mode) & S_IFMT)
#define DTTOIF(type) (type)
/*
* File type macros. Note that block devices, sockets and links cannot be
* distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
* only defined for compatibility. These macros should always return false
* on Windows.
*/
#if !defined(S_ISFIFO)
# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#endif
#if !defined(S_ISDIR)
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#if !defined(S_ISREG)
# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISLNK)
# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#endif
#if !defined(S_ISSOCK)
# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#endif
#if !defined(S_ISCHR)
# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#endif
#if !defined(S_ISBLK)
# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#endif
/* Return the exact length of the file name without zero terminator */
#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
/* Return the maximum size of a file name */
#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
#ifdef __cplusplus
extern "C" {
#endif
/* Wide-character version */
struct _wdirent {
/* Always zero */
long d_ino;
/* File position within stream */
long d_off;
/* Structure size */
unsigned short d_reclen;
/* Length of name without \0 */
size_t d_namlen;
/* File type */
int d_type;
/* File name */
wchar_t d_name[PATH_MAX+1];
};
typedef struct _wdirent _wdirent;
struct _WDIR {
/* Current directory entry */
struct _wdirent ent;
/* Private file data */
WIN32_FIND_DATAW data;
/* True if data is valid */
int cached;
/* Win32 search handle */
HANDLE handle;
/* Initial directory name */
wchar_t *patt;
};
typedef struct _WDIR _WDIR;
/* Multi-byte character version */
struct dirent {
/* Always zero */
long d_ino;
/* File position within stream */
long d_off;
/* Structure size */
unsigned short d_reclen;
/* Length of name without \0 */
size_t d_namlen;
/* File type */
int d_type;
/* File name */
char d_name[PATH_MAX+1];
};
typedef struct dirent dirent;
struct DIR {
struct dirent ent;
struct _WDIR *wdirp;
};
typedef struct DIR DIR;
/* Dirent functions */
static DIR *opendir (const char *dirname);
static _WDIR *_wopendir (const wchar_t *dirname);
static struct dirent *readdir (DIR *dirp);
static int readdir_r(
DIR *dirp, struct dirent *entry, struct dirent **result);
static int closedir (DIR *dirp);
static int _wclosedir (_WDIR *dirp);
/* For compatibility with Symbian */
#define wdirent _wdirent
#define WDIR _WDIR
#define wopendir _wopendir
#define wreaddir _wreaddir
#define wclosedir _wclosedir
#define wrewinddir _wrewinddir
/* Internal utility functions */
static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
static int dirent_mbstowcs_s(
size_t *pReturnValue,
wchar_t *wcstr,
size_t sizeInWords,
const char *mbstr,
size_t count);
static int dirent_wcstombs_s(
size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes,
const wchar_t *wcstr,
size_t count);
static void dirent_set_errno (int error);
/*
* Open directory stream DIRNAME for read and return a pointer to the
* internal working area that is used to retrieve individual directory
* entries.
*/
static _WDIR*
_wopendir(
const wchar_t *dirname)
{
_WDIR *dirp = NULL;
int error;
/* Must have directory name */
if (dirname == NULL || dirname[0] == '\0') {
dirent_set_errno (ENOENT);
return NULL;
}
/* Allocate new _WDIR structure */
dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
if (dirp != NULL) {
DWORD n;
/* Reset _WDIR structure */
dirp->handle = INVALID_HANDLE_VALUE;
dirp->patt = NULL;
dirp->cached = 0;
/* Compute the length of full path plus zero terminator
*
* Note that on WinRT there's no way to convert relative paths
* into absolute paths, so just assume it is an absolute path.
*/
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
n = wcslen(dirname);
# else
n = GetFullPathNameW (dirname, 0, NULL, NULL);
# endif
/* Allocate room for absolute directory name and search pattern */
dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
if (dirp->patt) {
/*
* Convert relative directory name to an absolute one. This
* allows rewinddir() to function correctly even when current
* working directory is changed between opendir() and rewinddir().
*
* Note that on WinRT there's no way to convert relative paths
* into absolute paths, so just assume it is an absolute path.
*/
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
wcsncpy_s(dirp->patt, n+1, dirname, n);
# else
n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
# endif
if (n > 0) {
wchar_t *p;
/* Append search pattern \* to the directory name */
p = dirp->patt + n;
if (dirp->patt < p) {
switch (p[-1]) {
case '\\':
case '/':
case ':':
/* Directory ends in path separator, e.g. c:\temp\ */
/*NOP*/;
break;
default:
/* Directory name doesn't end in path separator */
*p++ = '\\';
}
}
*p++ = '*';
*p = '\0';
/* Open directory stream and retrieve the first entry */
if (dirent_first (dirp)) {
/* Directory stream opened successfully */
error = 0;
} else {
/* Cannot retrieve first entry */
error = 1;
dirent_set_errno (ENOENT);
}
} else {
/* Cannot retrieve full path name */
dirent_set_errno (ENOENT);
error = 1;
}
} else {
/* Cannot allocate memory for search pattern */
error = 1;
}
} else {
/* Cannot allocate _WDIR structure */
error = 1;
}
/* Clean up in case of error */
if (error && dirp) {
_wclosedir (dirp);
dirp = NULL;
}
return dirp;
}
/*
* Close directory stream opened by opendir() function. This invalidates the
* DIR structure as well as any directory entry read previously by
* _wreaddir().
*/
static int
_wclosedir(
_WDIR *dirp)
{
int ok;
if (dirp) {
/* Release search handle */
if (dirp->handle != INVALID_HANDLE_VALUE) {
FindClose (dirp->handle);
dirp->handle = INVALID_HANDLE_VALUE;
}
/* Release search pattern */
if (dirp->patt) {
free (dirp->patt);
dirp->patt = NULL;
}
/* Release directory structure */
free (dirp);
ok = /*success*/0;
} else {
/* Invalid directory stream */
dirent_set_errno (EBADF);
ok = /*failure*/-1;
}
return ok;
}
/* Get first directory entry (internal) */
static WIN32_FIND_DATAW*
dirent_first(
_WDIR *dirp)
{
WIN32_FIND_DATAW *datap;
/* Open directory and retrieve the first entry */
dirp->handle = FindFirstFileExW(
dirp->patt, FindExInfoStandard, &dirp->data,
FindExSearchNameMatch, NULL, 0);
if (dirp->handle != INVALID_HANDLE_VALUE) {
/* a directory entry is now waiting in memory */
datap = &dirp->data;
dirp->cached = 1;
} else {
/* Failed to re-open directory: no directory entry in memory */
dirp->cached = 0;
datap = NULL;
}
return datap;
}
/*
* Get next directory entry (internal).
*
* Returns
*/
static WIN32_FIND_DATAW*
dirent_next(
_WDIR *dirp)
{
WIN32_FIND_DATAW *p;
/* Get next directory entry */
if (dirp->cached != 0) {
/* A valid directory entry already in memory */
p = &dirp->data;
dirp->cached = 0;
} else if (dirp->handle != INVALID_HANDLE_VALUE) {
/* Get the next directory entry from stream */
if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
/* Got a file */
p = &dirp->data;
} else {
/* The very last entry has been processed or an error occurred */
FindClose (dirp->handle);
dirp->handle = INVALID_HANDLE_VALUE;
p = NULL;
}
} else {
/* End of directory stream reached */
p = NULL;
}
return p;
}
/*
* Open directory stream using plain old C-string.
*/
static DIR*
opendir(
const char *dirname)
{
struct DIR *dirp;
int error;
/* Must have directory name */
if (dirname == NULL || dirname[0] == '\0') {
dirent_set_errno (ENOENT);
return NULL;
}
/* Allocate memory for DIR structure */
dirp = (DIR*) malloc (sizeof (struct DIR));
if (dirp) {
wchar_t wname[PATH_MAX + 1];
size_t n;
/* Convert directory name to wide-character string */
error = dirent_mbstowcs_s(
&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
if (!error) {
/* Open directory stream using wide-character name */
dirp->wdirp = _wopendir (wname);
if (dirp->wdirp) {
/* Directory stream opened */
error = 0;
} else {
/* Failed to open directory stream */
error = 1;
}
} else {
/*
* Cannot convert file name to wide-character string. This
* occurs if the string contains invalid multi-byte sequences or
* the output buffer is too small to contain the resulting
* string.
*/
error = 1;
}
} else {
/* Cannot allocate DIR structure */
error = 1;
}
/* Clean up in case of error */
if (error && dirp) {
free (dirp);
dirp = NULL;
}
return dirp;
}
/*
* Read next directory entry.
*/
static struct dirent*
readdir(
DIR *dirp)
{
struct dirent *entry;
/*
* Read directory entry to buffer. We can safely ignore the return value
* as entry will be set to NULL in case of error.
*/
(void) readdir_r (dirp, &dirp->ent, &entry);
/* Return pointer to statically allocated directory entry */
return entry;
}
/*
* Read next directory entry into called-allocated buffer.
*
* Returns zero on success. If the end of directory stream is reached, then
* sets result to NULL and returns zero.
*/
static int
readdir_r(
DIR *dirp,
struct dirent *entry,
struct dirent **result)
{
WIN32_FIND_DATAW *datap;
/* Read next directory entry */
datap = dirent_next (dirp->wdirp);
if (datap) {
size_t n;
int error;
/* Attempt to convert file name to multi-byte string */
error = dirent_wcstombs_s(
&n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
/*
* If the file name cannot be represented by a multi-byte string,
* then attempt to use old 8+3 file name. This allows traditional
* Unix-code to access some file names despite of unicode
* characters, although file names may seem unfamiliar to the user.
*
* Be ware that the code below cannot come up with a short file
* name unless the file system provides one. At least
* VirtualBox shared folders fail to do this.
*/
if (error && datap->cAlternateFileName[0] != '\0') {
error = dirent_wcstombs_s(
&n, entry->d_name, PATH_MAX + 1,
datap->cAlternateFileName, PATH_MAX + 1);
}
if (!error) {
DWORD attr;
/* Length of file name excluding zero terminator */
entry->d_namlen = n - 1;
/* File attributes */
attr = datap->dwFileAttributes;
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
entry->d_type = DT_CHR;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
entry->d_type = DT_DIR;
} else {
entry->d_type = DT_REG;
}
/* Reset dummy fields */
entry->d_ino = 0;
entry->d_off = 0;
entry->d_reclen = sizeof (struct dirent);
} else {
/*
* Cannot convert file name to multi-byte string so construct
* an erroneous directory entry and return that. Note that
* we cannot return NULL as that would stop the processing
* of directory entries completely.
*/
entry->d_name[0] = '?';
entry->d_name[1] = '\0';
entry->d_namlen = 1;
entry->d_type = DT_UNKNOWN;
entry->d_ino = 0;
entry->d_off = -1;
entry->d_reclen = 0;
}
/* Return pointer to directory entry */
*result = entry;
} else {
/* No more directory entries */
*result = NULL;
}
return /*OK*/0;
}
/*
* Close directory stream.
*/
static int
closedir(
DIR *dirp)
{
int ok;
if (dirp) {
/* Close wide-character directory stream */
ok = _wclosedir (dirp->wdirp);
dirp->wdirp = NULL;
/* Release multi-byte character version */
free (dirp);
} else {
/* Invalid directory stream */
dirent_set_errno (EBADF);
ok = /*failure*/-1;
}
return ok;
}
/* Convert multi-byte string to wide character string */
static int
dirent_mbstowcs_s(
size_t *pReturnValue,
wchar_t *wcstr,
size_t sizeInWords,
const char *mbstr,
size_t count)
{
int error;
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 or later */
error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
#else
/* Older Visual Studio or non-Microsoft compiler */
size_t n;
/* Convert to wide-character string (or count characters) */
n = mbstowcs (wcstr, mbstr, sizeInWords);
if (!wcstr || n < count) {
/* Zero-terminate output buffer */
if (wcstr && sizeInWords) {
if (n >= sizeInWords) {
n = sizeInWords - 1;
}
wcstr[n] = 0;
}
/* Length of resulting multi-byte string WITH zero terminator */
if (pReturnValue) {
*pReturnValue = n + 1;
}
/* Success */
error = 0;
} else {
/* Could not convert string */
error = 1;
}
#endif
return error;
}
/* Convert wide-character string to multi-byte string */
static int
dirent_wcstombs_s(
size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes, /* max size of mbstr */
const wchar_t *wcstr,
size_t count)
{
int error;
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 or later */
error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
#else
/* Older Visual Studio or non-Microsoft compiler */
size_t n;
/* Convert to multi-byte string (or count the number of bytes needed) */
n = wcstombs (mbstr, wcstr, sizeInBytes);
if (!mbstr || n < count) {
/* Zero-terminate output buffer */
if (mbstr && sizeInBytes) {
if (n >= sizeInBytes) {
n = sizeInBytes - 1;
}
mbstr[n] = '\0';
}
/* Length of resulting multi-bytes string WITH zero-terminator */
if (pReturnValue) {
*pReturnValue = n + 1;
}
/* Success */
error = 0;
} else {
/* Cannot convert string */
error = 1;
}
#endif
return error;
}
/* Set errno variable */
static void
dirent_set_errno(
int error)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 and later */
_set_errno (error);
#else
/* Non-Microsoft compiler or older Microsoft compiler */
errno = error;
#endif
}
#ifdef __cplusplus
}
#endif
#endif /*DIRENT_H*/

View File

@ -1,106 +0,0 @@
#include "getopt.h" // make sure you construct the header file as dictated above
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*/
#include <string.h>
#include <stdio.h>
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int getopt(int nargc, char * const nargv[], const char *ostr)
{
static char *place = EMSG; /* option letter processing */
const char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':')
(void)printf("illegal option -- %c\n", optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)printf("option requires an argument -- %c\n", optopt);
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}

View File

@ -1,13 +0,0 @@
#ifndef GETOPT_H
#define GETOPT_H
extern int opterr; /* if error message should be printed */
extern int optind; /* index into parent argv vector */
extern int optopt; /* character checked for validity */
extern int optreset; /* reset getopt */
extern char *optarg; /* argument associated with option */
int getopt(int nargc, char * const nargv[], const char *ostr);
#endif

View File

@ -183,7 +183,7 @@ uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, i
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Timeouts are set to %lu ms", timeout_ms);
// TODO Enhance the reception method
// - According to MSDN, it could be better to implement nfc_abort_command() mechanism using Cancello()
// - According to MSDN, it could be better to implement nfc_abort_command() mecanism using Cancello()
volatile bool *abort_flag_p = (volatile bool *)abort_p;
do {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ReadFile");

View File

@ -39,7 +39,6 @@ EXPORTS
nfc_device_get_supported_baud_rate_target_mode
nfc_device_set_property_int
nfc_device_set_property_bool
nfc_emulate_target
iso14443a_crc
iso14443a_crc_append
iso14443b_crc
@ -51,7 +50,3 @@ EXPORTS
str_nfc_modulation_type
str_nfc_baud_rate
str_nfc_target
pn53x_transceive
pn532_SAMConfiguration
pn53x_read_register
pn53x_write_register

View File

@ -1,57 +0,0 @@
LIBRARY nfc
VERSION 1.7
EXPORTS
nfc_init
nfc_exit
nfc_register_driver
nfc_open
nfc_close
nfc_abort_command
nfc_list_devices
nfc_idle
nfc_initiator_init
nfc_initiator_init_secure_element
nfc_initiator_select_passive_target
nfc_initiator_list_passive_targets
nfc_initiator_poll_target
nfc_initiator_select_dep_target
nfc_initiator_poll_dep_target
nfc_initiator_deselect_target
nfc_initiator_transceive_bytes
nfc_initiator_transceive_bits
nfc_initiator_transceive_bytes_timed
nfc_initiator_transceive_bits_timed
nfc_initiator_target_is_present
nfc_target_init
nfc_target_send_bytes
nfc_target_receive_bytes
nfc_target_send_bits
nfc_target_receive_bits
nfc_strerror
nfc_strerror_r
nfc_perror
nfc_device_get_last_error
nfc_device_get_name
nfc_device_get_connstring
nfc_device_get_supported_modulation
nfc_device_get_supported_baud_rate
nfc_device_get_supported_baud_rate_target_mode
nfc_device_set_property_int
nfc_device_set_property_bool
nfc_emulate_target
iso14443a_crc
iso14443a_crc_append
iso14443b_crc
iso14443b_crc_append
iso14443a_locate_historical_bytes
nfc_free
nfc_version
nfc_device_get_information_about
str_nfc_modulation_type
str_nfc_baud_rate
str_nfc_target
pn53x_transceive
pn532_SAMConfiguration
pn53x_read_register
pn53x_write_register

View File

@ -1,9 +1,15 @@
#include "windows.h"
1 VERSIONINFO
FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x00040004L
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG|VS_FF_PRERELEASE
#else
FILEFLAGS 0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE @RC_FILE_TYPE@
FILESUBTYPE 0x0L
BEGIN

View File

@ -48,9 +48,7 @@
# define ENOTSUP WSAEOPNOTSUPP
# define ECONNABORTED WSAECONNABORTED
# else
#ifndef _MSC_VER
# define snprintf sprintf_s
#endif
# define strdup _strdup
# endif

View File

@ -8,7 +8,6 @@ SET(EXAMPLES-SOURCES
nfc-mfsetuid
nfc-poll
nfc-relay
nfc-st25tb
pn53x-diagnose
pn53x-sam
pn53x-tamashell
@ -24,15 +23,9 @@ FOREACH(source ${EXAMPLES-SOURCES})
SET(RC_COMMENT "${PACKAGE_NAME} example")
SET(RC_INTERNAL_NAME ${source})
SET(RC_ORIGINAL_NAME ${source}.exe)
# RC_FILE_TYPE: VFT_APP
SET(RC_FILE_TYPE 0x00000001L)
SET(RC_FILE_TYPE VFT_APP)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY)
LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc)
IF(${source} MATCHES "nfc-st25tb")
LIST(APPEND TARGETS ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/getopt.c)
ENDIF()
ENDIF(WIN32)
ADD_EXECUTABLE(${source} ${TARGETS})

View File

@ -10,7 +10,6 @@ bin_PROGRAMS = \
nfc-mfsetuid \
nfc-poll \
nfc-relay \
nfc-st25tb \
pn53x-diagnose \
pn53x-sam
@ -64,9 +63,6 @@ nfc_mfsetuid_SOURCES = nfc-mfsetuid.c
nfc_mfsetuid_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la
nfc_st25tb_SOURCES = nfc-st25tb.c
nfc_st25tb_LDADD = $(top_builddir)/libnfc/libnfc.la
pn53x_diagnose_SOURCES = pn53x-diagnose.c
pn53x_diagnose_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la

View File

@ -1,600 +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
* See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file:
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 HOLDER OR CONTRIBUTORS 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.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @file nfc-st25tb.c
* @brief Tool to operate on ISO-14443-B ST25TB* and legacy SR* cards
*/
/* Benjamin DELPY `gentilkiwi`
* https://blog.gentilkiwi.com
* benjamin@gentilkiwi.com
* Licence : https://creativecommons.org/licenses/by/4.0/
* Rely on : libnfc - https://github.com/nfc-tools/libnfc
*
* $ gcc -Wall -lnfc -o nfc-st25tb nfc-st25tb.c
* $ ./nfc-st25tb -h
*
* Tested with
* - ST25TB512-AC - (BE/Brussels/STIB ; AliExpress ones)
* - ST25TB512-AT - (FR/Lille/Ilevia ; FR/Reims/Citura ; FR/Dijon/Divia ; FR/Strasbourg/CTS)
* - SRT512 - legacy - (FR/Bordeaux/TBM)
* - SRI512 - legacy - (anonymous vending machine)
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <nfc/nfc.h>
#if defined(WIN32) /* mingw compiler */
#include <getopt.h>
#endif
#define ST25TB_SR_BLOCK_MAX_SIZE ((uint8_t) 4) // for static arrays
typedef void(*get_info_specific) (uint8_t * systemArea);
typedef struct _st_data {
uint8_t chipId;
bool bIsLegacy;
const char *szName;
const char *szDatasheetUrl;
uint8_t blockSize;
uint8_t nbNormalBlock;
uint8_t bnSystem;
get_info_specific pfnGetInfo;
} st_data;
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
const st_data * get_info(const nfc_target *pnt, bool bPrintIt);
void display_system_info(nfc_device *pnd, const st_data * stdata);
void print_hex(const uint8_t *pbtData, const size_t szBytes);
int main(int argc, char *argv[])
{
nfc_context *context = NULL;
nfc_device *pnd = NULL;
nfc_target nt = {0};
nfc_modulation nm = {NMT_ISO14443B2SR, NBR_106};
const st_data * stcurrent;
int opt, res;
bool bIsBlock = false, bIsRead = false, bIsWrite = false, bIsBadCli = false;
uint8_t i, blockNumber = 0, data[ST25TB_SR_BLOCK_MAX_SIZE] = {0xff, 0xff, 0xff, 0xff}; // just in case...
size_t cbData = 0;
while(!bIsBadCli && ((opt = getopt(argc, argv, ":hib:rw:")) != -1))
{
switch(opt)
{
case 'i':
break;
case 'b':
if(optarg)
{
bIsBlock = true;
blockNumber = strtoul(optarg, NULL, 0);
}
else bIsBadCli = true;
break;
case 'r':
bIsRead = true;
break;
case 'w':
if(optarg)
{
cbData = strlen(optarg);
if((cbData == (2*2)) || ((cbData == (4*2))))
{
cbData >>= 1;
if(cbData == 2) // sr176
{
res = sscanf(optarg, "%02hhx%02hhx", data, data + 1);
}
else // all others
{
res = sscanf(optarg, "%02hhx%02hhx%02hhx%02hhx", data, data + 1, data + 2, data + 3);
}
if(res == (int) cbData)
{
bIsWrite = true;
}
}
if(!bIsWrite)
{
bIsBadCli = true;
}
}
break;
default: // includes -h
bIsBadCli = true;
}
}
if(!bIsBadCli)
{
if(bIsBlock && (bIsRead || bIsWrite))
{
if(bIsRead && bIsWrite)
{
printf("|mode : read then write\n");
}
else if(bIsRead)
{
printf("|mode : read\n");
}
else if(bIsWrite)
{
printf("|mode : write\n");
}
printf("|blk num: 0x%02hhx\n", blockNumber);
if(bIsWrite)
{
printf("|data : ");
print_hex(data, cbData);
printf("\n");
}
}
else if(!bIsRead && !bIsWrite && !bIsBlock)
{
printf("|mode : info\n");
}
else bIsBadCli = true;
}
if(!bIsBadCli)
{
nfc_init(&context);
if(context)
{
pnd = nfc_open(context, NULL);
if(pnd)
{
res = nfc_initiator_init(pnd);
if(res == NFC_SUCCESS)
{
printf("Reader : %s - via %s\n ...wait for card...\n", nfc_device_get_name(pnd), nfc_device_get_connstring(pnd));
if (nfc_initiator_select_passive_target(pnd, nm, NULL, 0, &nt) > 0)
{
stcurrent = get_info(&nt, true);
if(stcurrent)
{
printf("\n");
if(bIsBlock && (bIsRead || bIsWrite))
{
if(bIsRead)
{
get_block_at(pnd, blockNumber, NULL, 0, true);
}
if(bIsWrite)
{
set_block_at_confirmed(pnd, blockNumber, data, cbData, true);
}
}
else if(!bIsRead && !bIsWrite && !bIsBlock)
{
for(i = 0; i < stcurrent->nbNormalBlock; i++)
{
get_block_at(pnd, i, NULL, 0, true);
}
display_system_info(pnd, stcurrent);
}
}
}
}
else printf("ERROR - nfc_initiator_init: %i\n", res);
nfc_close(pnd);
}
else printf("ERROR - nfc_open\n");
nfc_exit(context);
}
else printf("ERROR - nfc_init\n");
}
else
{
printf(
"Usage:\n"
" %s [-i]\n"
" %s -b N -r\n"
" %s -b N [-r] -w ABCD[EF01]\n %s -h\n"
"Options:\n"
" -i (default) information mode - will try to dump the tag content and display informations\n"
" -b N specify block number to operate on (tag dependent), needed for read (-r) and write (-w) modes\n"
" -r read mode - will try to read block (specified with -b N parameter)\n"
" -w ABCD[EF01] write mode - will try to write specicied data (2 or 4 bytes depending on tag) to block (specified with -b N parameter)\n"
" -h this help\n"
"Examples:\n"
" %s -i\n"
" Display all tag informations\n"
" %s -b 0x0e -r\n"
" Read block 0x0e (14) of the tag\n"
" %s -b 0x0d -w 0123abcd\n"
" Write block 0x0d (13) of the tag with hexadecimal value '01 23 ab cd'\n"
" %s -b 0x0c -r -w 0123abcd\n"
" Read, then write block 0x0c (12) of the tag with hexadecimal value '01 23 ab cd'\n"
"Warnings:\n"
" Be careful with: system area, counters & otp, bytes order.\n"
, argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]);
}
return 0;
}
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t tx[2] = {0x08, block}, rx[ST25TB_SR_BLOCK_MAX_SIZE]; // 4 is the maximum, SR176 (only 2) will fit
int res;
res = nfc_initiator_transceive_bytes(pnd, tx, sizeof(tx), rx, sizeof(rx), 0);
if((res == 2) || (res == 4))
{
if(data)
{
if(cbData == res)
{
memcpy(data, rx, res);
bRet = true;
}
else printf("ERROR - We got %i bytes for a %hhu buffer size?\n", res, cbData);
}
else bRet = true;
if(bPrintIt)
{
printf("[0x%02hhx] ", block);
print_hex(rx, res);
printf("\n");
}
}
else if(res > 0)
{
printf("ERROR - We got %i bytes?\n", res);
}
else printf("ERROR - nfc_initiator_transceive_bytes(get): %i\n", res);
return bRet;
}
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t tx[2 + ST25TB_SR_BLOCK_MAX_SIZE] = {0x09, block}; // 4 is the maximum, SR176 (only 2) will fit
int res;
if(cbData <= ST25TB_SR_BLOCK_MAX_SIZE)
{
memcpy(tx + 2, data, cbData);
if(bPrintIt)
{
printf(">0x%02hhx> ", block);
print_hex(data, cbData);
printf("\n");
}
res = nfc_initiator_transceive_bytes(pnd, tx, 2 + cbData, NULL, 0, 0);
if(res == NFC_ERFTRANS) // ? :')
{
bRet = true;
}
else printf("ERROR - nfc_initiator_transceive_bytes(set): %i\n", res);
}
else printf("ERROR - Wanted to write %hhu bytes, but maximum is %hhu\n", cbData, ST25TB_SR_BLOCK_MAX_SIZE);
return bRet;
}
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t buffer[ST25TB_SR_BLOCK_MAX_SIZE]; // maximum size will be checked in set_block_at
if(set_block_at(pnd, block, data, cbData, bPrintIt))
{
if(get_block_at(pnd, block, buffer, cbData, bPrintIt))
{
if(memcmp(data, buffer, cbData) == 0)
{
bRet = true;
}
else if(bPrintIt)
{
printf("WARNING - not same value readed after write\n");
}
}
}
return bRet;
}
void get_info_st25tb512(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | ST reserved : ");
for(i = 0; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
for(i = 16; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 16; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
}
}
}
void get_info_st25tb2k_4k(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | ST reserved : ");
for(i = 0; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_RegU: ", b, b ? "not " : "");
for(i = 16; i < 24; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 24; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
{
printf(" blocks 0x07 and 0x08 are write protected\n");
}
for(i = 25; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
}
}
}
void get_info_sr176_legacy(uint8_t * systemArea)
{
uint8_t i;
printf(" | Fixed Chip_ID: 0x%1x\n | ST reserved : ", systemArea[0] & 0x0f);
for(i = 4; i < 8; i++)
{
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 8; i < 16; i++)
{
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 8; i < 16; i++)
{
if(((*(uint16_t *) systemArea) >> i) & 1)
{
printf(" blocks 0x%02hhx and 0x%02hhx are write protected\n", (uint8_t) ((i - 8) * 2), (uint8_t) (((i - 8) * 2) + 1));
}
}
}
void get_info_sri_srt_512_legacy(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
for(i = 8; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
for(i = 16; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 16; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
}
}
}
void get_info_sri2k_4k_srix4k_srix512_legacy(uint8_t * systemArea)
{
uint8_t i;
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
for(i = 8; i < 24; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 24; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
{
printf(" blocks 0x07 and 0x08 are write protected\n");
}
for(i = 25; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
}
}
}
const st_data STRefs[] = {
{0x1b, false, "ST25TB512-AC", "https://www.st.com/resource/en/datasheet/st25tb512-ac.pdf", 4, 16, 255, get_info_st25tb512},
{0x33, false, "ST25TB512-AT", "https://www.st.com/resource/en/datasheet/st25tb512-at.pdf", 4, 16, 255, get_info_st25tb512},
{0x3f, false, "ST25TB02K", "https://www.st.com/resource/en/datasheet/st25tb02k.pdf", 4, 64, 255, get_info_st25tb2k_4k},
{0x1f, false, "ST25TB04K", "https://www.st.com/resource/en/datasheet/st25tb04k.pdf", 4, 128, 255, get_info_st25tb2k_4k},
};
const st_data STRefs_legacy[] = {
{ 0, true, "SRI4K(s)", NULL, 4, 128, 255, NULL},
{ 2, true, "SR176", "https://www.st.com/resource/en/datasheet/sr176.pdf", 2, 15, 15, get_info_sr176_legacy},
{ 3, true, "SRIX4K", NULL, 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{ 4, true, "SRIX512", "https://www.st.com/resource/en/datasheet/srix512.pdf", 4, 16, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{ 6, true, "SRI512", "https://www.st.com/resource/en/datasheet/sri512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
{ 7, true, "SRI4K", "https://www.st.com/resource/en/datasheet/sri4k.pdf", 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{12, true, "SRT512", "https://www.st.com/resource/en/datasheet/srt512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
{15, true, "SRI2K", "https://www.st.com/resource/en/datasheet/sri2k.pdf", 4, 64, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
};
const st_data * get_info(const nfc_target *pnt, bool bPrintIt)
{
const st_data *currentData = NULL;
const uint8_t *p;
uint8_t chipId, i;
if(pnt->nm.nmt == NMT_ISO14443B2SR)
{
printf("Target : %s (%s)\nUID : ", str_nfc_modulation_type(pnt->nm.nmt), str_nfc_baud_rate(pnt->nm.nbr));
print_hex(pnt->nti.nsi.abtUID, sizeof(pnt->nti.nsi.abtUID));
printf("\n");
p = pnt->nti.nsi.abtUID;
if(p[7] == 0xd0) // ST25TB* / SR*
{
chipId = p[5];
printf("Manuf : 0x%02hhx - %s\n", p[6], (p[6] == 0x02) ? "STMicroelectronics" : "other");
for(i = 0; i < (sizeof(STRefs) / sizeof(STRefs[0])); i++)
{
if(chipId == STRefs[i].chipId)
{
currentData = &STRefs[i];
break;
}
}
if(!currentData)
{
chipId >>= 2;
for(i = 0; i < (sizeof(STRefs_legacy) / sizeof(STRefs_legacy[0])); i++)
{
if(chipId == STRefs_legacy[i].chipId)
{
currentData = &STRefs_legacy[i];
break;
}
}
}
if(bPrintIt && currentData)
{
printf("ChipId : 0x%02hhx - %s%s\nSerial : 0x", currentData->chipId, currentData->szName, currentData->bIsLegacy ? " (legacy)" : "");
if(currentData->bIsLegacy)
{
printf("%1hhx", (uint8_t) (p[5] & 0x03));
}
printf("%02hhx%02hhx%02hhx%02hhx%02hhx\n|blk sz : %hhu bits\n|nb blks: %hhu\n|sys idx: %hhu\n", p[4], p[3], p[2], p[1], p[0], (uint8_t) (currentData->blockSize * 8), currentData->nbNormalBlock, currentData->bnSystem);
}
}
else printf("WARNI - Last byte of UID isn\'t 0xd0, but 0x%02hhx (not ST25TB / SR series?)\n", p[7]);
}
else printf("ERROR - not a NMT_ISO14443B2SR ?\n");
return currentData;
}
void display_system_info(nfc_device *pnd, const st_data * stdata)
{
uint8_t systemArea[ST25TB_SR_BLOCK_MAX_SIZE];
if(get_block_at(pnd, stdata->bnSystem, systemArea, stdata->blockSize, true))
{
if(stdata->pfnGetInfo)
{
stdata->pfnGetInfo(systemArea);
}
}
}
void print_hex(const uint8_t *pbtData, const size_t szBytes)
{
size_t szPos;
for (szPos = 0; szPos < szBytes; szPos++)
{
printf("%02hhx ", pbtData[szPos]);
}
}

View File

@ -5,9 +5,6 @@ IF(WIN32)
# Add in the rc for version information in the dll
LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../windows/libnfc.rc)
IF (NOT MINGW)
LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc_msvc.def)
ENDIF()
ENDIF(WIN32)
# Library's chips
@ -29,23 +26,23 @@ IF(UART_REQUIRED)
ENDIF(UART_REQUIRED)
IF(I2C_REQUIRED)
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
LIST(APPEND BUSES_SOURCES buses/i2c)
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Only Linux is supported at the moment
IF(WIN32)
# Windows is not supported at the moment
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c)
MESSAGE( FATAL_ERROR "I2C is only (yet) supported in Linux!" )
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
MESSAGE( FATAL_ERROR "I2C not (yet) supported under Windows!" )
ELSE(WIN32)
LIST(APPEND BUSES_SOURCES buses/i2c)
ENDIF(WIN32)
ENDIF(I2C_REQUIRED)
IF(SPI_REQUIRED)
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
LIST(APPEND BUSES_SOURCES buses/spi)
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Only Linux is supported at the moment
IF(WIN32)
# Windows is not supported at the moment
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi)
MESSAGE( FATAL_ERROR "SPI is only (yet) supported in Linux!" )
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
MESSAGE( FATAL_ERROR "SPI not (yet) supported under Windows!" )
ELSE(WIN32)
LIST(APPEND BUSES_SOURCES buses/spi)
ENDIF(WIN32)
ENDIF(SPI_REQUIRED)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
@ -66,9 +63,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
IF(LIBNFC_LOG)
IF(WIN32)
IF(MINGW)
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}")
ENDIF(MINGW)
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}")
LIST(APPEND LIBRARY_SOURCES log ../contrib/win32/libnfc/log-internal)
ELSE(WIN32)
LIST(APPEND LIBRARY_SOURCES log log-internal)
@ -93,16 +88,13 @@ SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 6 VERSION 6.0.0)
IF(WIN32)
# Libraries that are windows specific
TARGET_LINK_LIBRARIES(nfc wsock32)
IF(MINGW)
ADD_CUSTOM_COMMAND(
OUTPUT libnfc.lib
COMMAND ${DLLTOOL} -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll
DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def
)
ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib)
ELSE()
ADD_LIBRARY(win32lib ALIAS nfc)
ENDIF()
ADD_CUSTOM_COMMAND(
OUTPUT libnfc.lib
COMMAND ${DLLTOOL} -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll
DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def
)
ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib)
# On Windows the shared (runtime) library should be either in the same
# directory as the excutables or in the path, we add it to same directory

View File

@ -33,9 +33,7 @@
#ifndef __NFC_BUS_UART_H__
# define __NFC_BUS_UART_H__
#if !defined(_MSC_VER)
# include <sys/time.h>
#endif
# include <stdio.h>
# include <string.h>

View File

@ -1155,14 +1155,6 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
uint8_t abtRx[1];
uint8_t *pbtInitData = (uint8_t *) "\x0b";
size_t szInitData = 1;
if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxAuto, 0xef, 0x07)) < 0) // Initial RFOn, Tx2 RFAutoEn, Tx1 RFAutoEn
return res;
if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_CWGsP, 0x3f, 0x3f)) < 0) // Conductance of the P-Driver
return res;
if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_ModGsP, 0x3f, 0x12)) < 0) // Driver P-output conductance for the time of modulation
return res;
// Getting random Chip_ID
if ((res = pn53x_initiator_transceive_bytes(pnd, abtInitiate, szInitiateLen, abtRx, sizeof(abtRx), timeout)) < 0) {
if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
@ -1216,7 +1208,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
// send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response
uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL
uint8_t abtAnticol[11];
if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) {
if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout)) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all");
//if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
// continue;
@ -2072,7 +2064,7 @@ static int pn53x_ISO14443A_Barcode_is_present(struct nfc_device *pnd)
}
uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
if (nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar) < 1) {
if ((ret = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 1) {
failures++;
} else {
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);

View File

@ -195,8 +195,6 @@ conf_parse_file(const char *filename,
free(key);
free(value);
} else {
free(key);
free(value);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line);
}
}

View File

@ -60,9 +60,7 @@ Thanks to d18c7db and Okko for example code
#include <sys/select.h>
#include <errno.h>
#include <string.h>
#ifdef _MSC_VER
#include <sys/types.h>
#endif
#include <nfc/nfc.h>
#include "nfc-internal.h"
@ -598,7 +596,7 @@ read:
if (timeout == USB_INFINITE_TIMEOUT) {
usb_timeout = USB_TIMEOUT_PER_PASS;
} else {
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism
remaining_time -= USB_TIMEOUT_PER_PASS;
if (remaining_time <= 0) {
pnd->last_error = NFC_ETIMEOUT;
@ -612,7 +610,6 @@ read:
uint8_t attempted_response = RDR_to_PC_DataBlock;
size_t len;
int error, status;
if (res == NFC_ETIMEOUT) {
if (DRIVER_DATA(pnd)->abort_flag) {
@ -624,7 +621,7 @@ read:
goto read;
}
}
if (res < 10) {
if (res < 12) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame");
// try to interrupt current device state
acr122_usb_ack(pnd);
@ -639,16 +636,6 @@ read:
offset++;
len = abtRxBuf[offset++];
status = abtRxBuf[7];
error = abtRxBuf[8];
if (len == 0 && error == 0xFE) { // ICC_MUTE; XXX check for more errors
// Do not check status; my ACR122U seemingly has status=0 in this case,
// even though the spec says it should have had bmCommandStatus=1
// and bmICCStatus=1.
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Command timed out");
pnd->last_error = NFC_ETIMEOUT;
return pnd->last_error;
}
if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer:
if (len != 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply");
@ -677,7 +664,7 @@ read:
goto read; // FIXME May cause some trouble on Touchatag, right ?
}
}
if (res < 10) {
if (res < 12) {
// try to interrupt current device state
acr122_usb_ack(pnd);
pnd->last_error = NFC_EIO;

View File

@ -527,7 +527,7 @@ acr122s_close(nfc_device *pnd)
uart_close(DRIVER_DATA(pnd)->port);
#ifndef WIN32
// Release file descriptors used for abort mechanism
// Release file descriptors used for abort mecanism
close(DRIVER_DATA(pnd)->abort_fds[0]);
close(DRIVER_DATA(pnd)->abort_fds[1]);
#endif

View File

@ -158,7 +158,7 @@ arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size
}
#ifndef WIN32
// pipe-based abort mechanism
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
@ -211,7 +211,7 @@ arygon_close_step2(nfc_device *pnd)
uart_close(DRIVER_DATA(pnd)->port);
#ifndef WIN32
// Release file descriptors used for abort mechanism
// Release file descriptors used for abort mecanism
close(DRIVER_DATA(pnd)->iAbortFds[0]);
close(DRIVER_DATA(pnd)->iAbortFds[1]);
#endif
@ -304,7 +304,7 @@ arygon_open(const nfc_context *context, const nfc_connstring connstring)
pnd->driver = &arygon_driver;
#ifndef WIN32
// pipe-based abort mechanism
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);

View File

@ -5,7 +5,7 @@
* Copyright (C) 2019 Frank Morgner
* See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file:
* Copyright (C) 2020 Feitian Technologies
*
* 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
@ -34,7 +34,6 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <nfc/nfc.h>
@ -73,11 +72,6 @@
#include <winscard.h>
#endif
#ifdef WIN32
#include <windows.h>
#define usleep(x) Sleep((x + 999) / 1000)
#endif
#define PCSC_DRIVER_NAME "pcsc"
#include <nfc/nfc.h>
@ -144,14 +138,8 @@ static int pcsc_transmit(struct nfc_device *pnd, const uint8_t *tx, const size_t
DWORD dw_rx_len = *rx_len;
//in libfreefare, tx_len = 1, and it leads to 0x80100008 error, with PC/SC reader, the input tx_len at least two bytes for the SW value
//so if found the reader is Feitian reader, we set to 2
if (is_pcsc_reader_vendor_feitian(pnd))
{
if (dw_rx_len == 1)
{
dw_rx_len = 2;
} else {
dw_rx_len += 2;//in libfreefare, some data length send not include sw1 and sw2, so add it.
}
if (dw_rx_len == 1 && is_pcsc_reader_vendor_feitian(pnd)) {
dw_rx_len = 2;
}
LOG_HEX(NFC_LOG_GROUP_COM, "TX", tx, tx_len);
@ -264,7 +252,7 @@ static int pcsc_get_ats(struct nfc_device *pnd, uint8_t *ats, size_t ats_len)
if (pnd->last_error != NFC_SUCCESS)
return pnd->last_error;
if (resp_len <= 2) {
if (resp_len < 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for ATS");
pnd->last_error = NFC_EDEVNOTSUPP;
return pnd->last_error;
@ -275,7 +263,8 @@ static int pcsc_get_ats(struct nfc_device *pnd, uint8_t *ats, size_t ats_len)
return pnd->last_error;
}
memcpy(ats, resp + 1, resp_len - 2 - 1);//data expect TL and SW1SW2
//memcpy(ats, resp + 1, resp_len - 2 - 1);
memcpy(ats, resp + 1, resp[0] - 1);
return resp_len - 2 - 1;
}
@ -352,23 +341,17 @@ static int pcsc_props_to_target(struct nfc_device *pnd, uint8_t it, const uint8_
if (is_pcsc_reader_vendor_feitian(pnd)) {
uint8_t atqa[2];
pcsc_get_atqa(pnd, atqa, sizeof(atqa));
//ATQA Coding of NXP Contactless Card ICs
if(atqa[0] == 0x00 || atqa[0] == 0x03)
{
memcpy(pnt->nti.nai.abtAtqa,atqa,2);
}else {
pnt->nti.nai.abtAtqa[0] = atqa[1];
pnt->nti.nai.abtAtqa[1] = atqa[0];
}
//memcpy(pnt->nti.nai.abtAtqa,atqa,2);
pnt->nti.nai.abtAtqa[0] = atqa[1];
pnt->nti.nai.abtAtqa[1] = atqa[0];
uint8_t sak[1];
pcsc_get_sak(pnd, sak, sizeof(sak));
pnt->nti.nai.btSak = sak[0];
uint8_t ats[256];
int ats_len = pcsc_get_ats(pnd, ats, sizeof(ats));
ats_len = (ats_len > 0 ? ats_len : 0);//The reader may not support to get ATS
memcpy(pnt->nti.nai.abtAts, ats, ats_len);
pnt->nti.nai.szAtsLen = ats_len;
//memcpy(pnt->nti.nai.abtAts + ats_len, patr + 4, (uint8_t)(szatr - 5));
pnt->nti.nai.szAtsLen = ats_len;// + szatr - 5;
} else {
/* SAK_ISO14443_4_COMPLIANT */
pnt->nti.nai.btSak = 0x20;
@ -538,7 +521,7 @@ pcsc_open(const nfc_context *context, const nfc_connstring connstring)
// Test if context succeeded
if (!(pscc = pcsc_get_scardcontext()))
goto error;
DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0 | 1, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol));
DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol));
if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) {
// We can not connect to this device.
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed");
@ -814,21 +797,6 @@ static int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t
memcpy(apdu_data + 5, pbtTx + 2, szTx - 2);
send_size = 5 + szTx - 2;
} else if (pbtTx[0] == 0x60 || pbtTx[0] == 0x61 || pbtTx[0] == 0x1A) { //Auth command
//load pin first
{
apdu_data[0] = 0xFF;
apdu_data[1] = 0x82;
apdu_data[2] = 0x00;
apdu_data[3] = 0x01;
apdu_data[4] = 0x06;
memcpy(apdu_data + 5, pbtTx + 2, 6);
send_size = 11;
pnd->last_error = pcsc_transmit(pnd, apdu_data, send_size, resp, &resp_len);
memset(apdu_data, 0, sizeof(apdu_data));
memset(resp, 0, sizeof(resp));
usleep(500000);//delay 500ms
}
// then auth
apdu_data[0] = 0xFF;
apdu_data[1] = 0x86;
apdu_data[2] = 0x00;
@ -916,9 +884,6 @@ static int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_prope
// ignore
return NFC_SUCCESS;
case NP_AUTO_ISO14443_4:
if ((bEnable == true) || (is_pcsc_reader_vendor_feitian(pnd)))
return NFC_SUCCESS;
break;
case NP_EASY_FRAMING:
if ((bEnable == true) || (is_pcsc_reader_vendor_feitian(pnd)))
return NFC_SUCCESS;
@ -971,13 +936,8 @@ pcsc_get_information_about(nfc_device *pnd, char **pbuf)
{
struct pcsc_data *data = pnd->driver_data;
LPBYTE name = NULL, version = NULL, type = NULL, serial = NULL;
#ifdef __APPLE__
DWORD name_len = 0, version_len = 0,
type_len = 0, serial_len = 0;
#else
DWORD name_len = SCARD_AUTOALLOCATE, version_len = SCARD_AUTOALLOCATE,
type_len = SCARD_AUTOALLOCATE, serial_len = SCARD_AUTOALLOCATE;
#endif
int res = NFC_SUCCESS;
SCARDCONTEXT *pscc;

View File

@ -136,7 +136,7 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
CHIP_DATA(pnd)->power_mode = LOWVBAT;
#ifndef WIN32
// pipe-based abort mechanism
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
@ -191,7 +191,7 @@ pn532_uart_close(nfc_device *pnd)
uart_close(DRIVER_DATA(pnd)->port);
#ifndef WIN32
// Release file descriptors used for abort mechanism
// Release file descriptors used for abort mecanism
close(DRIVER_DATA(pnd)->iAbortFds[0]);
close(DRIVER_DATA(pnd)->iAbortFds[1]);
#endif
@ -277,7 +277,7 @@ pn532_uart_open(const nfc_context *context, const nfc_connstring connstring)
pnd->driver = &pn532_uart_driver;
#ifndef WIN32
// pipe-based abort mechanism
// pipe-based abort mecanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);

View File

@ -43,9 +43,7 @@ Thanks to d18c7db and Okko for example code
#include <sys/select.h>
#include <errno.h>
#include <string.h>
#ifdef _MSC_VER
#include <sys/types.h>
#endif
#include <nfc/nfc.h>
#include "nfc-internal.h"
@ -623,7 +621,7 @@ read:
if (timeout == USB_INFINITE_TIMEOUT) {
usb_timeout = USB_TIMEOUT_PER_PASS;
} else {
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism
remaining_time -= USB_TIMEOUT_PER_PASS;
if (remaining_time <= 0) {
pnd->last_error = NFC_ETIMEOUT;
@ -819,7 +817,7 @@ pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const
if (NP_ACTIVATE_FIELD == property) {
/* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Switch progressive field %s", bEnable ? "On" : "Off");
if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0)
if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31))) < 0)
return NFC_ECHIP;
}
break;

View File

@ -34,9 +34,7 @@
#include <stdbool.h>
#include <err.h>
#if !defined(_MSC_VER)
# include <sys/time.h>
#endif
#include "nfc/nfc.h"

View File

@ -565,30 +565,24 @@ nfc_initiator_select_passive_target(nfc_device *pnd,
nfc_target *pnt)
{
uint8_t *abtInit = NULL;
uint8_t maxAbt = MAX(12, szInitData);
uint8_t *abtTmpInit = malloc(sizeof(uint8_t) * maxAbt);
uint8_t abtTmpInit[MAX(12, szInitData)];
size_t szInit = 0;
int res;
if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) {
free(abtTmpInit);
if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS)
return res;
}
if (szInitData == 0) {
// Provide default values, if any
prepare_initiator_data(nm, &abtInit, &szInit);
free(abtTmpInit);
} else if (nm.nmt == NMT_ISO14443A) {
abtInit = abtTmpInit;
iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit);
} else {
abtInit = abtTmpInit;
memcpy(abtInit, pbtInitData, szInitData);
free(abtTmpInit);
szInit = szInitData;
}
HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
free(abtTmpInit);
HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
}
/** @ingroup initiator

View File

@ -23,8 +23,7 @@ FOREACH(source ${UTILS-SOURCES})
SET(RC_COMMENT "${PACKAGE_NAME} utility")
SET(RC_INTERNAL_NAME ${source})
SET(RC_ORIGINAL_NAME ${source}.exe)
# RC_FILE_TYPE: VFT_APP
SET(RC_FILE_TYPE 0x00000001L)
SET(RC_FILE_TYPE VFT_APP)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY)
LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc)
ENDIF(WIN32)
@ -42,9 +41,6 @@ FOREACH(source ${UTILS-SOURCES})
LIST(APPEND TARGETS ../contrib/win32/stdlib)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32)
ENDIF(${source} MATCHES "nfc-scan-device")
IF(${source} MATCHES "nfc-read-forum-tag3")
LIST(APPEND TARGETS ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/getopt.c)
ENDIF()
ENDIF(WIN32)
ADD_EXECUTABLE(${source} ${TARGETS})

View File

@ -97,6 +97,10 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE);
}
// Display libnfc version
acLibnfcVersion = nfc_version();
printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
// Get commandline options
for (arg = 1; arg < argc; arg++) {
if (0 == strcmp(argv[arg], "-h")) {
@ -113,7 +117,7 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE);
}
// Force TypeB for all derivatives of B
if (mask & 0xd0)
if (mask & 0xf0)
mask |= 0x08;
} else {
ERR("%s is not supported option.", argv[arg]);
@ -122,13 +126,6 @@ main(int argc, const char *argv[])
}
}
// Display libnfc version
if (verbose) {
acLibnfcVersion = nfc_version();
printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
}
/* Lazy way to open an NFC device */
#if 0
pnd = nfc_open(context, NULL);

View File

@ -54,12 +54,6 @@
#include <string.h>
#include <ctype.h>
#ifndef _WIN32
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#include <nfc/nfc.h>
#include "mifare.h"
@ -76,7 +70,8 @@ static bool bUseKeyFile;
static bool bForceKeyFile;
static bool bTolerateFailures;
static bool bFormatCard;
static bool dWrite = false;
static bool magic2 = false;
static bool magic3 = false;
static bool unlocked = false;
static uint8_t uiBlocks;
static uint8_t keys[] = {
@ -216,6 +211,15 @@ authenticate(uint32_t uiBlock)
if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp))
return true;
} else if (magic3) {
//If it's a One Time Write card, we're gonna authenticate with the default keys
memcpy(mp.mpa.abtKey, default_key, sizeof(default_key));
// Try to authenticate for the current sector
if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) {
return true;
}
// If formatting or not using key file, try to guess the right key
} else if (bFormatCard || !bUseKeyFile) {
for (size_t key_index = 0; key_index < num_keys; key_index++) {
@ -238,7 +242,7 @@ authenticate(uint32_t uiBlock)
}
static bool
unlock_card(bool write)
unlock_card(void)
{
// Configure the CRC
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) {
@ -256,10 +260,6 @@ unlock_card(bool write)
// now send unlock
if (!transmit_bits(abtUnlock1, 7)) {
printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n");
dWrite = true;
if (write) {
printf("Trying to rewrite block 0 on a direct write tag.\n");
}
} else {
if (transmit_bytes(abtUnlock2, 1)) {
printf("Card unlocked\n");
@ -270,15 +270,6 @@ unlock_card(bool write)
}
// reset reader
if (!unlocked) {
if (nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL) <= 0) {
printf("Error: tag was removed\n");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
return true;
}
// Configure the CRC
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool");
@ -325,19 +316,23 @@ get_rats(void)
}
static bool
read_card(bool read_unlocked)
read_card(int read_unlocked)
{
int32_t iBlock;
bool bFailure = false;
uint32_t uiReadBlocks = 0;
if (read_unlocked) {
unlock_card(false);
//If the user is attempting an unlocked read, but has a direct-write type magic card, they don't
//need to use the R mode. We'll trigger a warning and let them proceed.
if (dWrite) {
printf("Note: This card can't do an unlocked read (R) \n");
if (magic2) {
printf("Note: This card does not require an unlocked read (R) \n");
read_unlocked = 0;
} else {
//If User has requested an unlocked read, but we're unable to unlock the card, we'll error out.
if (!unlock_card()) {
return false;
}
}
}
@ -367,11 +362,18 @@ read_card(bool read_unlocked)
if (read_unlocked) {
memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData));
} else {
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA));
memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits));
memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB));
//If we're using a One Time Write ('Magic 3') Badge - we'll use default keys + ACL
if (magic3) {
memcpy(mtDump.amb[iBlock].mbt.abtKeyA, default_key, sizeof(default_key));
memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits));
memcpy(mtDump.amb[iBlock].mbt.abtKeyB, default_key, sizeof(default_key));
} else {
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA));
memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits));
memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB));
}
}
} else {
printf("!\nfailed to read trailer block 0x%02x\n", iBlock);
bFailure = true;
@ -401,7 +403,7 @@ read_card(bool read_unlocked)
}
static bool
write_card(bool write_block_zero)
write_card(int write_block_zero)
{
uint32_t uiBlock;
bool bFailure = false;
@ -409,18 +411,24 @@ write_card(bool write_block_zero)
//Determine if we have to unlock the card
if (write_block_zero) {
unlock_card(true);
//If the user is attempting an unlocked write, but has a direct-write type magic card, they don't
//need to use the W mode. We'll trigger a warning and let them proceed.
if (magic2) {
printf("Note: This card does not require an unlocked write (W) \n");
write_block_zero = 0;
} else {
//If User has requested an unlocked write, but we're unable to unlock the card, we'll error out.
if (!unlock_card()) {
return false;
}
}
}
printf("Writing %d blocks |", uiBlocks + write_block_zero);
// Completely write the card, but skipping block 0 if we don't need to write on it
for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
//Determine if we have to write block 0
if (!write_block_zero && uiBlock == 0) {
continue;
}
printf("Writing %d blocks |", uiBlocks + 1);
// Completely write the card, end to start, but skipping block 0
for (uiBlock = 4; uiBlock <= uiBlocks; uiBlock++) {
// Authenticate everytime we reach the first sector of a new block
if (uiBlock == 1 || is_first_block(uiBlock)) {
if (is_first_block(uiBlock)) {
if (bFailure) {
// When a failure occured we need to redo the anti-collision
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
@ -434,15 +442,14 @@ write_card(bool write_block_zero)
// Try to authenticate for the current sector
// If we are are writing to a chinese magic card, we've already unlocked
// If we're writing to a direct write card, we need to authenticate
// If we're writing to a One Time Write card, we need to authenticate
// If we're writing something else, we'll need to authenticate
if ((write_block_zero && dWrite) || !write_block_zero) {
if ((write_block_zero && magic3) || !write_block_zero) {
if (!authenticate(uiBlock) && !bTolerateFailures) {
printf("!\nError: authentication failed for block %02x\n", uiBlock);
return false;
}
}
}
if (is_trailer_block(uiBlock)) {
if (bFormatCard) {
@ -463,6 +470,10 @@ write_card(bool write_block_zero)
bFailure = true;
}
} else {
// The first block 0x00 is read only, skip this
if (uiBlock == 0 && !write_block_zero && !magic2)
continue;
// Make sure a earlier write did not fail
if (!bFailure) {
// Try to write the data block
@ -473,7 +484,7 @@ write_card(bool write_block_zero)
memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData));
// do not write a block 0 with incorrect BCC - card will be made invalid!
if (uiBlock == 0) {
if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00) {
if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) {
printf("!\nError: incorrect BCC in MFD file!\n");
printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]);
return false;
@ -483,29 +494,88 @@ write_card(bool write_block_zero)
bFailure = true;
printf("Failure to write to data block %i\n", uiBlock);
}
if (uiBlock == 0 && dWrite) {
if (nfc_initiator_init(pnd) < 0) {
nfc_perror(pnd, "nfc_initiator_init");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
};
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
printf("!\nError: tag was removed\n");
return false;
}
}
} else {
printf("Failure during write process.\n");
}
}
//}
}
// Show if the write went well for each block
print_success_or_failure(bFailure, &uiWriteBlocks);
if ((! bTolerateFailures) && bFailure)
return false;
}
//Write Block 0 if necessary
if (write_block_zero || magic2 || magic3) {
for (uiBlock = 0; uiBlock < 4; uiBlock++) {
// The first block 0x00 is read only, skip this
if (uiBlock == 0) {
//If the card is not magic, we're gonna skip over
if (write_block_zero || magic2 || magic3) {
//NOP
} else {
continue;
}
}
if (is_first_block(uiBlock)) {
if (bFailure) {
// When a failure occured we need to redo the anti-collision
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
printf("!\nError: tag was removed\n");
return false;
}
bFailure = false;
}
fflush(stdout);
// Try to authenticate for the current sector
// If we are are writing to a chinese magic card, we've already unlocked
// If we're writing to a One Time Write, we need to authenticate
// If we're writing something else, we'll need to authenticate
if ((write_block_zero && magic3) || !write_block_zero) {
if (!authenticate(uiBlock) && !bTolerateFailures) {
printf("!\nError: authentication failed for block %02x\n", uiBlock);
return false;
}
}
}
// Make sure a earlier write did not fail
if (!bFailure) {
// Try to write the data block
if (bFormatCard && uiBlock)
memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData));
else
memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData));
// do not write a block 0 with incorrect BCC - card will be made invalid!
if (uiBlock == 0) {
if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) {
printf("!\nError: incorrect BCC in MFD file!\n");
printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]);
return false;
}
}
if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) {
bFailure = true;
printf("Failure to write to data block %i\n", uiBlock);
}
} else {
printf("Failure during write process.\n");
}
// Show if the write went well for each block
print_success_or_failure(bFailure, &uiWriteBlocks);
if ((! bTolerateFailures) && bFailure)
return false;
}
}
printf("|\n");
printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
fflush(stdout);
@ -523,24 +593,18 @@ static void
print_usage(const char *pcProgramName)
{
printf("Usage: ");
#ifndef _WIN32
printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f] [v]]\n", pcProgramName);
#else
printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName);
#endif
printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or block 0 write to (W) card\n");
printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n");
printf(" *** unlocked read does not require authentication and will reveal A and B keys\n");
printf(" *** note that block 0 write will attempt to overwrite block 0 including UID\n");
printf(" *** block 0 write only works with special Mifare cards (Chinese clones)\n");
printf(" *** note that unlocked write will attempt to overwrite block 0 including UID\n");
printf(" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n");
printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n");
printf(" u|U - Use any (u) uid or supply a uid specifically as U01ab23cd.\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");
#ifndef _WIN32
printf(" v - Sends libnfc log output to console (optional)\n");
#endif
printf("Examples: \n\n");
printf(" Read card to file, using key A:\n\n");
printf(" %s r a u mycard.mfd\n\n", pcProgramName);
@ -556,6 +620,54 @@ print_usage(const char *pcProgramName)
}
static bool is_directwrite(void)
{
printf("Checking if Badge is DirectWrite...\n");
// Set default keys
memcpy(mtDump.amb[0].mbt.abtKeyA, default_key, sizeof(default_key));
memcpy(mtDump.amb[0].mbt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits));
memcpy(mtDump.amb[0].mbt.abtKeyB, default_key, sizeof(default_key));
// Temporarly override bUseKeyFile
bool orig_bUseKeyFile = bUseKeyFile;
bUseKeyFile = false;
// Try to authenticate for the current sector
if (!authenticate(0)) {
printf("!\nError: authentication failed for block 0x%02x\n", 0);
bUseKeyFile = orig_bUseKeyFile;
return false;
}
// restore bUseKeyFile
bUseKeyFile = orig_bUseKeyFile;
// Try to read block 0
uint8_t original_b0[16];
if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) {
memcpy(original_b0, mp.mpd.abtData, sizeof(mp.mpd.abtData));
printf(" Original Block 0: ");
for (int i = 0; i < 16; i++) {
printf("%02x", original_b0[i]);
}
printf("\n");
printf(" Original UID: %02x%02x%02x%02x\n",
original_b0[0], original_b0[1], original_b0[2], original_b0[3]);
} else {
printf("!\nError: unable to read block 0x%02x\n", 0);
return false;
}
printf(" Attempt to write Block 0 ...\n");
memcpy(mp.mpd.abtData, original_b0, sizeof(original_b0));
if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, 0, &mp)) {
printf("Failure to write to data block %i\n", 0);
return false;
}
printf(" Block 0 written successfully\n");
return true;
}
int
main(int argc, const char *argv[])
{
@ -564,7 +676,7 @@ main(int argc, const char *argv[])
uint8_t _tag_uid[4];
uint8_t *tag_uid = _tag_uid;
bool unlock = false;
int unlock = 0;
if (argc < 2) {
print_usage(argv[0]);
@ -579,19 +691,19 @@ main(int argc, const char *argv[])
if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) {
atAction = ACTION_READ;
if (strcmp(command, "R") == 0)
unlock = true;
unlock = 1;
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
bUseKeyFile = (argc > 5);
bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
} else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) {
atAction = ACTION_WRITE;
if (strcmp(command, "W") == 0)
unlock = true;
unlock = 1;
bFormatCard = (strcmp(command, "f") == 0);
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
bUseKeyFile = (argc > 5);
bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
}
if (argv[3][0] == 'U') {
@ -613,21 +725,6 @@ main(int argc, const char *argv[])
tag_uid = NULL;
}
#ifndef _WIN32
// Send noise from lib to /dev/null
bool verbose = false;
if (argv[7]) {
if (strcmp(argv[7], "v") == 0) verbose = true;
} else {
if ((strcmp(argv[6], "v")) || (strcmp(argv[5], "v")) == 0) verbose = true;
}
if (!verbose) {
int fd = open("/dev/null", O_WRONLY);
dup2(fd, 2);
close(fd);
}
#endif
if (atAction == ACTION_USAGE) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
@ -667,14 +764,6 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE);
};
// Drop the field for a while, so can be reset
if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool activate field");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
// Let the reader only try once to find a tag
if (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool");
@ -690,24 +779,11 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE);
}
// Configure the CRC and Parity settings
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool crc");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
if (nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool parity");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
// Try to find a MIFARE Classic tag
int tags;
tags = nfc_initiator_select_passive_target(pnd, nmMifare, tag_uid, tag_uid == NULL ? 0 : 4, &nt);
if (tags <= 0) {
printf("Error: no tag was found\n");
@ -716,8 +792,7 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE);
}
// Test if we are dealing with a MIFARE compatible tag
if (((nt.nti.nai.btSak & 0x08) == 0) && (nt.nti.nai.btSak != 0x01)) {
// if ((nt.nti.nai.btSak & 0x08) == 0) {
if ((nt.nti.nai.btSak & 0x08) == 0) {
printf("Warning: tag is probably not a MFC!\n");
}
@ -764,10 +839,35 @@ main(int argc, const char *argv[])
// MIFARE Plus 2K
uiBlocks = 0x7f;
}
// Chinese magic emulation card, ATS=0978009102:dabc1910
if ((res == 9) && (abtRx[5] == 0xda) && (abtRx[6] == 0xbc)
&& (abtRx[7] == 0x19) && (abtRx[8] == 0x10)) {
magic2 = true;
}
} else
printf("RATS support: no\n");
printf("Guessing size: seems to be a %lu-byte card\n", (unsigned long)((uiBlocks + 1) * sizeof(mifare_classic_block)));
//If size is 4k check for direct-write card
if (uiBlocks == 0xff) {
if (is_directwrite()) {
printf("Card is DirectWrite\n");
magic3 = true;
unlock = 0;
} else {
printf("Card is not DirectWrite\n");
}
}
//Check to see if we have a One Time Write badge (magic3)
if (pbtUID[0] == 0xaa && pbtUID[1] == 0x55 &&
pbtUID[2] == 0xc3 && pbtUID[3] == 0x96) {
printf("Card appears to be a One Time Write Card..\n");
magic3 = true;
unlock = 0;
}
if (bUseKeyFile) {
FILE *pfKeys = fopen(argv[5], "rb");
if (pfKeys == NULL) {
@ -822,17 +922,9 @@ main(int argc, const char *argv[])
}
printf("Done.\n");
fclose(pfDump);
} else {
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
} else if (atAction == ACTION_WRITE) {
if (!write_card(unlock)) {
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
write_card(unlock);
}
nfc_close(pnd);

View File

@ -62,7 +62,7 @@
#include "nfc-utils.h"
#if defined(WIN32) /* mingw compiler */
#if defined(WIN32) && defined(__GNUC__) /* mingw compiler */
#include <getopt.h>
#endif