mirror of
https://github.com/nfc-tools/libnfc.git
synced 2025-12-23 18:50:05 +00:00
Compare commits
79 Commits
libnfc-1.8
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fa0751ad5 | ||
|
|
3379466e33 | ||
|
|
b7bec39cd4 | ||
|
|
0e8cd450e1 | ||
|
|
fe4ee8e07e | ||
|
|
0bfcd9cdd6 | ||
|
|
3f0101bd3f | ||
|
|
df0a3beca9 | ||
|
|
c6657c7c00 | ||
|
|
92cc3b1ed1 | ||
|
|
9dc65e4075 | ||
|
|
d40cbef104 | ||
|
|
1f77bcec17 | ||
|
|
72262133f1 | ||
|
|
42de50f2b7 | ||
|
|
5b9ae7ee51 | ||
|
|
3df7f25f11 | ||
|
|
16671bd0a3 | ||
|
|
6d0e8a5d9b | ||
|
|
a884a45ab1 | ||
|
|
c8185c9eca | ||
|
|
56f6bd4fbb | ||
|
|
1b8c244e38 | ||
|
|
fb290be070 | ||
|
|
a9cb26b28f | ||
|
|
c924e5e00c | ||
|
|
ba14d10e79 | ||
|
|
9a94f20050 | ||
|
|
180fbabfe1 | ||
|
|
1dc9dcb664 | ||
|
|
1f4d2fb3d4 | ||
|
|
2b5ad9ce0b | ||
|
|
7ebf9b92d6 | ||
|
|
3af2e14acc | ||
|
|
b5180a6a70 | ||
|
|
0cd314c514 | ||
|
|
c3f739dea3 | ||
|
|
126cf9c1be | ||
|
|
d9a04a54ff | ||
|
|
cc4311acab | ||
|
|
e37d24e691 | ||
|
|
1077228fbd | ||
|
|
5c09dc180a | ||
|
|
d5fcd08d41 | ||
|
|
f56bbabf6c | ||
|
|
9cece8b55d | ||
|
|
7ad18a2120 | ||
|
|
e21fab3685 | ||
|
|
82f23c411d | ||
|
|
66d3560608 | ||
|
|
fc51c8662b | ||
|
|
db081ed12d | ||
|
|
6fb61d3c1e | ||
|
|
f2677da74c | ||
|
|
0bf4cec661 | ||
|
|
0de55961c4 | ||
|
|
c8fcaea8ab | ||
|
|
6921e57fb8 | ||
|
|
01bc5693d9 | ||
|
|
db957aabdf | ||
|
|
f7b9b0eafa | ||
|
|
709ef8381f | ||
|
|
3c55b8746b | ||
|
|
02f0f6b290 | ||
|
|
7a5e654309 | ||
|
|
2b21d87e8e | ||
|
|
4e922e8194 | ||
|
|
3f4b7a037a | ||
|
|
dd96571f88 | ||
|
|
5a87f1f3db | ||
|
|
7b6ff73c4b | ||
|
|
e560689f60 | ||
|
|
a28a537610 | ||
|
|
4b7791f845 | ||
|
|
1f6f75af38 | ||
|
|
435e2ffc81 | ||
|
|
874d9605aa | ||
|
|
53eccd4be4 | ||
|
|
b02f94d7da |
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,6 +7,8 @@
|
||||
*.lo
|
||||
*.o
|
||||
*~
|
||||
.vs/
|
||||
CMakeSettings.json
|
||||
Doxyfile
|
||||
INSTALL
|
||||
aclocal.m4
|
||||
|
||||
91
.travis.yml
91
.travis.yml
@ -1,20 +1,81 @@
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
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 .
|
||||
|
||||
env:
|
||||
- BLD=cmake
|
||||
- BLD=autoconf
|
||||
- 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
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libusb-dev
|
||||
- doxygen
|
||||
- cmake
|
||||
- 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
|
||||
|
||||
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
|
||||
- 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
|
||||
|
||||
@ -18,9 +18,12 @@ 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")
|
||||
@ -101,13 +104,6 @@ ADD_DEFINITIONS(-Du_int8_t=uint8_t -Du_int16_t=uint16_t)
|
||||
|
||||
IF(MINGW)
|
||||
IF (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
# force MinGW-w64 in 32bit mode
|
||||
SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}")
|
||||
SET(CMAKE_MODULE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}")
|
||||
ELSE(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
|
||||
# force MinGW-w64 in 32bit mode
|
||||
MESSAGE("Building 32-bit Windows DLL")
|
||||
@ -116,7 +112,7 @@ IF(MINGW)
|
||||
#SET(CMAKE_SHARED_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
#SET(CMAKE_EXE_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}")
|
||||
ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
||||
ELSEIF((CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") OR (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64"))
|
||||
MESSAGE("Building 64-bit Windows DLL")
|
||||
SET(CMAKE_RC_FLAGS "--target=pe-x86-64 --output-format=coff ${CMAKE_RC_FLAGS}")
|
||||
ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
|
||||
@ -138,9 +134,12 @@ 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_ACR122)
|
||||
ENDIF(LIBNFC_DRIVER_PCSC)
|
||||
IF(LIBNFC_DRIVER_ACR122_PCSC)
|
||||
SET(PKG_REQ ${PKG_REQ} "libpcsclite")
|
||||
ENDIF(LIBNFC_DRIVER_ACR122_PCSC)
|
||||
@ -152,7 +151,7 @@ ENDIF(NOT WIN32)
|
||||
|
||||
INCLUDE(LibnfcDrivers)
|
||||
|
||||
IF(UNIX AND NOT APPLE)
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
IF(I2C_REQUIRED)
|
||||
# Inspired from http://cmake.3232098.n2.nabble.com/RFC-cmake-analog-to-AC-SEARCH-LIBS-td7585423.html
|
||||
INCLUDE (CheckFunctionExists)
|
||||
@ -166,7 +165,7 @@ IF(UNIX AND NOT APPLE)
|
||||
ENDIF (HAVE_CLOCK_GETTIME_IN_RT)
|
||||
ENDIF (NOT HAVE_CLOCK_GETTIME)
|
||||
ENDIF(I2C_REQUIRED)
|
||||
ENDIF(UNIX AND NOT APPLE)
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
IF(PCSC_INCLUDE_DIRS)
|
||||
INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS})
|
||||
@ -182,26 +181,13 @@ ENDIF(LIBUSB_INCLUDE_DIRS)
|
||||
# version.rc for Windows
|
||||
IF(WIN32)
|
||||
# Date for filling in rc file information
|
||||
IF (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
MACRO (GET_CURRENT_YEAR RESULT)
|
||||
EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT})
|
||||
STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}})
|
||||
STRING(REGEX REPLACE ".*(..)/(..)/(....).*" "\\3" ${RESULT} ${${RESULT}})
|
||||
ENDMACRO (GET_CURRENT_YEAR)
|
||||
ELSE(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
MACRO (GET_CURRENT_YEAR RESULT)
|
||||
EXECUTE_PROCESS(COMMAND "date" "+%Y" OUTPUT_VARIABLE ${RESULT})
|
||||
STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}})
|
||||
ENDMACRO (GET_CURRENT_YEAR)
|
||||
ENDIF(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
GET_CURRENT_YEAR(CURRENT_YEAR)
|
||||
MESSAGE("Year for copyright is " ${CURRENT_YEAR})
|
||||
|
||||
STRING(TIMESTAMP CURRENT_YEAR %Y)
|
||||
SET(prefix ${CMAKE_INSTALL_PREFIX})
|
||||
SET(RC_COMMENT "${PACKAGE_NAME} library")
|
||||
SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}")
|
||||
SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll)
|
||||
SET(RC_FILE_TYPE VFT_DLL)
|
||||
# RC_FILE_TYPE: VFT_DLL
|
||||
SET(RC_FILE_TYPE 0x00000002L)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY)
|
||||
ENDIF(WIN32)
|
||||
|
||||
|
||||
@ -2,7 +2,13 @@ ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
AM_CFLAGS = $(LIBNFC_CFLAGS)
|
||||
|
||||
SUBDIRS = libnfc utils examples include contrib cmake test
|
||||
SUBDIRS = libnfc utils
|
||||
|
||||
if EXAMPLE_ENABLED
|
||||
SUBDIRS += examples
|
||||
endif
|
||||
|
||||
SUBDIRS += include contrib cmake test
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libnfc.pc
|
||||
|
||||
54
README.md
54
README.md
@ -18,11 +18,9 @@ General Information
|
||||
|
||||
libnfc is a library which allows userspace application access to NFC devices.
|
||||
|
||||
The official web site is:
|
||||
http://www.nfc-tools.org/
|
||||
The official web site is gone, browse a copy via the [WayBackMachine](https://web.archive.org/web/20210815064122/http://nfc-tools.org/index.php/Main_Page).
|
||||
|
||||
The official forum site is:
|
||||
http://www.libnfc.org/community/
|
||||
The official forum site is gone, browse a copy via the [WayBackMachine](https://web.archive.org/web/20210225042232/http://forums.nfc-tools.org/).
|
||||
|
||||
The official development site is:
|
||||
https://github.com/nfc-tools/libnfc
|
||||
@ -40,7 +38,7 @@ Some NFC drivers depend on third party software:
|
||||
|
||||
* acr122_pcsc:
|
||||
|
||||
- pcsc-lite http://pcsclite.alioth.debian.org/
|
||||
- pcsc-lite https://pcsclite.apdu.fr/
|
||||
- pcsc:
|
||||
|
||||
- Support build with pcsc driver, which can be using all compatible readers, Feitian R502 and bR500 already passed the test.
|
||||
@ -48,12 +46,29 @@ 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
|
||||
|
||||
See the file `INSTALL` for configure, build and install details.
|
||||
|
||||
Additionnally, you may need to grant permissions to your user to drive your device.
|
||||
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.
|
||||
|
||||
@ -85,6 +100,17 @@ 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
|
||||
==================
|
||||
|
||||
@ -140,18 +166,6 @@ 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
|
||||
===============
|
||||
|
||||
|
||||
@ -26,9 +26,15 @@ ENDIF(CMAKE_SYSTEM_NAME MATCHES FreeBSD)
|
||||
|
||||
IF(NOT LIBUSB_FOUND)
|
||||
IF(WIN32)
|
||||
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/")
|
||||
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)
|
||||
# Must fix up variable to avoid backslashes during packaging
|
||||
STRING(REGEX REPLACE "\\\\" "/" LIBUSB_LIBRARY_DIR ${LIBUSB_LIBRARY_DIR})
|
||||
ELSE(WIN32)
|
||||
|
||||
@ -3,69 +3,76 @@ 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(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)")
|
||||
ELSE(WIN32)
|
||||
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)")
|
||||
ENDIF(WIN32)
|
||||
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
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")
|
||||
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)")
|
||||
|
||||
IF(LIBNFC_DRIVER_PCSC)
|
||||
FIND_PACKAGE(PCSC REQUIRED)
|
||||
ADD_DEFINITIONS("-DDRIVER_PCSC_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pcsc")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pcsc.c")
|
||||
ENDIF(LIBNFC_DRIVER_PCSC)
|
||||
|
||||
IF(LIBNFC_DRIVER_ACR122_PCSC)
|
||||
FIND_PACKAGE(PCSC REQUIRED)
|
||||
ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_pcsc")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_pcsc.c")
|
||||
ENDIF(LIBNFC_DRIVER_ACR122_PCSC)
|
||||
|
||||
IF(LIBNFC_DRIVER_ACR122_USB)
|
||||
FIND_PACKAGE(LIBUSB REQUIRED)
|
||||
ADD_DEFINITIONS("-DDRIVER_ACR122_USB_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb.c")
|
||||
ENDIF(LIBNFC_DRIVER_ACR122_USB)
|
||||
|
||||
IF(LIBNFC_DRIVER_ACR122S)
|
||||
ADD_DEFINITIONS("-DDRIVER_ACR122S_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122s")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122s.c")
|
||||
SET(UART_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_ACR122S)
|
||||
|
||||
IF(LIBNFC_DRIVER_ARYGON)
|
||||
ADD_DEFINITIONS("-DDRIVER_ARYGON_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/arygon")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/arygon.c")
|
||||
SET(UART_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_ARYGON)
|
||||
|
||||
IF(LIBNFC_DRIVER_PN532_I2C)
|
||||
ADD_DEFINITIONS("-DDRIVER_PN532_I2C_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_i2c")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_i2c.c")
|
||||
SET(I2C_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_PN532_I2C)
|
||||
|
||||
IF(LIBNFC_DRIVER_PN532_SPI)
|
||||
ADD_DEFINITIONS("-DDRIVER_PN532_SPI_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_spi")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_spi.c")
|
||||
SET(SPI_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_PN532_SPI)
|
||||
|
||||
IF(LIBNFC_DRIVER_PN532_UART)
|
||||
ADD_DEFINITIONS("-DDRIVER_PN532_UART_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_uart")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_uart.c")
|
||||
SET(UART_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_PN532_UART)
|
||||
|
||||
IF(LIBNFC_DRIVER_PN53X_USB)
|
||||
FIND_PACKAGE(LIBUSB REQUIRED)
|
||||
ADD_DEFINITIONS("-DDRIVER_PN53X_USB_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn53x_usb")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn53x_usb.c")
|
||||
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.c")
|
||||
SET(USB_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_ACR122_USB)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers)
|
||||
|
||||
11
configure.ac
11
configure.ac
@ -157,6 +157,14 @@ 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=""
|
||||
|
||||
@ -175,7 +183,10 @@ 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"
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
## Typical configuration file for PN532 device on R-Pi connected using UART
|
||||
## Note: to use UART port on R-Pi, you have to disable linux serial console:
|
||||
## http://learn.adafruit.com/adafruit-nfc-rfid-on-raspberry-pi/freeing-uart-on-the-pi
|
||||
##
|
||||
## For more information about UART differences between R-Pi models, visit:
|
||||
## https://www.raspberrypi.com/documentation/computers/configuration.html#configure-uarts
|
||||
##
|
||||
name = "PN532 board via UART"
|
||||
connstring = pn532_uart:/dev/ttyAMA0
|
||||
|
||||
@ -4,19 +4,27 @@
|
||||
## use the PN532 device with the "mini UART", which is still hijacked by the linux kernel
|
||||
## as a serial console
|
||||
##
|
||||
## For more information about UART differences between R-Pi models, visit:
|
||||
## https://www.raspberrypi.com/documentation/computers/configuration.html#configure-uarts
|
||||
##
|
||||
## Tested recipe with PN532 breakout from Adafruit
|
||||
##
|
||||
## To enable uart on GPIO, add this line to bottom of /boot/config.txt
|
||||
## To enable uart on GPIO, add this line to bottom of /boot/firmware/config.txt
|
||||
## enable_uart=1
|
||||
##
|
||||
## If you are using an earlier version of Raspberry Pi OS (prior to Bookworm),
|
||||
## the config file is available instead on /boot/config.txt.
|
||||
##
|
||||
## Stop and disable serial console:
|
||||
## $ sudo systemctl stop serial-getty@ttyS0.service
|
||||
## $ sudo systemctl disable serial-getty@ttyS0.service
|
||||
##
|
||||
## Remove console from /boot/cmdline.txt by removing:
|
||||
## Remove console from /boot/firmware/cmdline.txt by removing:
|
||||
## console=serial0,115200 Save and reboot for changes to take effect.
|
||||
##
|
||||
## If you are using an earlier version of Raspberry Pi OS (prior to Bookworm),
|
||||
## the config file is available instead on /boot/cmdline.txt.
|
||||
##
|
||||
name = "PN532 board via UART"
|
||||
connstring = pn532_uart:/dev/ttyS0
|
||||
allow_intrusive_scan = true
|
||||
|
||||
|
||||
22
contrib/libnfc/pn532_uart_on_rpi_5.conf.sample
Normal file
22
contrib/libnfc/pn532_uart_on_rpi_5.conf.sample
Normal file
@ -0,0 +1,22 @@
|
||||
## Typical configuration file for PN532 device on R-Pi 5
|
||||
## Note: Changes have been made to R-Pi 5 with the removal of the mini UART
|
||||
## (/dev/ttyS0), hence the module can be accessed through the original R-Pi
|
||||
## UART address (/dev/ttyAMA0).
|
||||
##
|
||||
## For more information about UART differences between R-Pi models, visit:
|
||||
## https://www.raspberrypi.com/documentation/computers/configuration.html#configure-uarts
|
||||
##
|
||||
## This configuration is almost identical to pn532_uart_on_rpi.conf.sample
|
||||
## except the allow_intrusive_scan option from the R-Pi 3 sample.
|
||||
##
|
||||
## Tested recipe with generic PN532 module (common Elechouse module clones)
|
||||
##
|
||||
## To enable uart on GPIO, add this line to bottom of /boot/firmware/config.txt
|
||||
## enable_uart=1
|
||||
##
|
||||
## If you are using an earlier version of Raspberry Pi OS (prior to Bookworm),
|
||||
## the config file is available instead on /boot/config.txt.
|
||||
##
|
||||
name = "PN532 board via UART"
|
||||
connstring = pn532_uart:/dev/ttyAMA0
|
||||
allow_intrusive_scan = true
|
||||
870
contrib/win32/dirent.h
Normal file
870
contrib/win32/dirent.h
Normal file
@ -0,0 +1,870 @@
|
||||
/*
|
||||
* 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*/
|
||||
|
||||
106
contrib/win32/getopt.c
Normal file
106
contrib/win32/getopt.c
Normal file
@ -0,0 +1,106 @@
|
||||
#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 */
|
||||
}
|
||||
13
contrib/win32/getopt.h
Normal file
13
contrib/win32/getopt.h
Normal file
@ -0,0 +1,13 @@
|
||||
#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
|
||||
@ -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() mecanism using Cancello()
|
||||
// - According to MSDN, it could be better to implement nfc_abort_command() mechanism using Cancello()
|
||||
volatile bool *abort_flag_p = (volatile bool *)abort_p;
|
||||
do {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ReadFile");
|
||||
|
||||
@ -39,6 +39,7 @@ 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
|
||||
@ -50,3 +51,7 @@ EXPORTS
|
||||
str_nfc_modulation_type
|
||||
str_nfc_baud_rate
|
||||
str_nfc_target
|
||||
pn53x_transceive
|
||||
pn532_SAMConfiguration
|
||||
pn53x_read_register
|
||||
pn53x_write_register
|
||||
|
||||
57
contrib/win32/nfc_msvc.def
Normal file
57
contrib/win32/nfc_msvc.def
Normal file
@ -0,0 +1,57 @@
|
||||
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
|
||||
@ -1,15 +1,9 @@
|
||||
#include "windows.h"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
|
||||
PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG|VS_FF_PRERELEASE
|
||||
#else
|
||||
FILEFLAGS 0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS 0x00040004L
|
||||
FILETYPE @RC_FILE_TYPE@
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
|
||||
@ -48,7 +48,9 @@
|
||||
# define ENOTSUP WSAEOPNOTSUPP
|
||||
# define ECONNABORTED WSAECONNABORTED
|
||||
# else
|
||||
#ifndef _MSC_VER
|
||||
# define snprintf sprintf_s
|
||||
#endif
|
||||
# define strdup _strdup
|
||||
# endif
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ SET(EXAMPLES-SOURCES
|
||||
nfc-mfsetuid
|
||||
nfc-poll
|
||||
nfc-relay
|
||||
nfc-st25tb
|
||||
pn53x-diagnose
|
||||
pn53x-sam
|
||||
pn53x-tamashell
|
||||
@ -23,9 +24,15 @@ FOREACH(source ${EXAMPLES-SOURCES})
|
||||
SET(RC_COMMENT "${PACKAGE_NAME} example")
|
||||
SET(RC_INTERNAL_NAME ${source})
|
||||
SET(RC_ORIGINAL_NAME ${source}.exe)
|
||||
SET(RC_FILE_TYPE VFT_APP)
|
||||
# RC_FILE_TYPE: VFT_APP
|
||||
SET(RC_FILE_TYPE 0x00000001L)
|
||||
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})
|
||||
|
||||
@ -10,6 +10,7 @@ bin_PROGRAMS = \
|
||||
nfc-mfsetuid \
|
||||
nfc-poll \
|
||||
nfc-relay \
|
||||
nfc-st25tb \
|
||||
pn53x-diagnose \
|
||||
pn53x-sam
|
||||
|
||||
@ -63,6 +64,9 @@ 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
|
||||
|
||||
602
examples/nfc-st25tb.c
Normal file
602
examples/nfc-st25tb.c
Normal file
@ -0,0 +1,602 @@
|
||||
/*-
|
||||
* 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));
|
||||
|
||||
res = nfc_initiator_select_passive_target(pnd, nm, NULL, 0, &nt);
|
||||
if (res > 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_select_passive_target: %i\n", res);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,48 +1,51 @@
|
||||
# Windows MinGW workarounds
|
||||
IF(WIN32)
|
||||
SET(WINDOWS_SOURCES ../contrib/win32/stdlib)
|
||||
SET(WINDOWS_SOURCES ../contrib/win32/stdlib.c)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/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
|
||||
SET(CHIPS_SOURCES chips/pn53x)
|
||||
SET(CHIPS_SOURCES chips/pn53x.c)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/chips)
|
||||
|
||||
# Library's buses
|
||||
IF(USB_REQUIRED)
|
||||
LIST(APPEND BUSES_SOURCES buses/usbbus)
|
||||
LIST(APPEND BUSES_SOURCES buses/usbbus.c)
|
||||
ENDIF(USB_REQUIRED)
|
||||
|
||||
IF(UART_REQUIRED)
|
||||
IF(WIN32)
|
||||
# Windows have a special implementation for UART
|
||||
LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/uart)
|
||||
LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/uart.c)
|
||||
ELSE(WIN32)
|
||||
LIST(APPEND BUSES_SOURCES buses/uart)
|
||||
LIST(APPEND BUSES_SOURCES buses/uart.c)
|
||||
ENDIF(WIN32)
|
||||
ENDIF(UART_REQUIRED)
|
||||
|
||||
IF(I2C_REQUIRED)
|
||||
IF(WIN32)
|
||||
# Windows is not supported at the moment
|
||||
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c)
|
||||
MESSAGE( FATAL_ERROR "I2C not (yet) supported under Windows!" )
|
||||
ELSE(WIN32)
|
||||
LIST(APPEND BUSES_SOURCES buses/i2c)
|
||||
ENDIF(WIN32)
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
LIST(APPEND BUSES_SOURCES buses/i2c.c)
|
||||
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
# Only Linux is supported at the moment
|
||||
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c.c)
|
||||
MESSAGE( FATAL_ERROR "I2C is only (yet) supported in Linux!" )
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
ENDIF(I2C_REQUIRED)
|
||||
|
||||
IF(SPI_REQUIRED)
|
||||
IF(WIN32)
|
||||
# Windows is not supported at the moment
|
||||
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi)
|
||||
MESSAGE( FATAL_ERROR "SPI not (yet) supported under Windows!" )
|
||||
ELSE(WIN32)
|
||||
LIST(APPEND BUSES_SOURCES buses/spi)
|
||||
ENDIF(WIN32)
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
LIST(APPEND BUSES_SOURCES buses/spi.c)
|
||||
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
# Only Linux is supported at the moment
|
||||
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi.c)
|
||||
MESSAGE( FATAL_ERROR "SPI is only (yet) supported in Linux!" )
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
ENDIF(SPI_REQUIRED)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
|
||||
@ -58,15 +61,17 @@ IF(LIBUSB_FOUND)
|
||||
ENDIF(LIBUSB_FOUND)
|
||||
|
||||
# Library
|
||||
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})
|
||||
SET(LIBRARY_SOURCES nfc.c nfc-device.c nfc-emulation.c nfc-internal.c conf.c iso14443-subr.c mirror-subr.c target-subr.c ${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 ../contrib/win32/libnfc/log-internal)
|
||||
IF(MINGW)
|
||||
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}")
|
||||
ENDIF(MINGW)
|
||||
LIST(APPEND LIBRARY_SOURCES log.c ../contrib/win32/libnfc/log-internal.c)
|
||||
ELSE(WIN32)
|
||||
LIST(APPEND LIBRARY_SOURCES log log-internal)
|
||||
LIST(APPEND LIBRARY_SOURCES log.c log-internal.c)
|
||||
ENDIF(WIN32)
|
||||
ENDIF(LIBNFC_LOG)
|
||||
ADD_LIBRARY(nfc SHARED ${LIBRARY_SOURCES})
|
||||
@ -88,13 +93,16 @@ SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 6 VERSION 6.0.0)
|
||||
IF(WIN32)
|
||||
# Libraries that are windows specific
|
||||
TARGET_LINK_LIBRARIES(nfc wsock32)
|
||||
|
||||
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)
|
||||
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()
|
||||
|
||||
# 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
|
||||
|
||||
@ -33,7 +33,9 @@
|
||||
#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>
|
||||
|
||||
@ -1155,6 +1155,14 @@ 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
|
||||
@ -1208,7 +1216,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 ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout)) < 0) {
|
||||
if (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;
|
||||
@ -1259,6 +1267,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
szTargetsData = (size_t)res;
|
||||
}
|
||||
found = true;
|
||||
res = 1; // TargetCount to 1 as only one target is supported here
|
||||
break;
|
||||
} while (pnd->bInfiniteSelect);
|
||||
if (! found)
|
||||
@ -1339,6 +1348,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
return res;
|
||||
}
|
||||
found = true;
|
||||
res = 1; // TargetCount to 1 as only one target is supported here
|
||||
break;
|
||||
} while (pnd->bInfiniteSelect);
|
||||
if (! found) {
|
||||
@ -1369,6 +1379,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
return res;
|
||||
}
|
||||
}
|
||||
res = abtTargetsData[0]; // TargetCount to abtTargetsData[0] (Tg from InListPassiveTarget answer)
|
||||
}
|
||||
if (pn53x_current_target_new(pnd, &nttmp) == NULL) {
|
||||
pnd->last_error = NFC_ESOFT;
|
||||
@ -1378,7 +1389,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
if (pnt) {
|
||||
memcpy(pnt, &nttmp, sizeof(nfc_target));
|
||||
}
|
||||
return abtTargetsData[0];
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
@ -2064,7 +2075,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 ((ret = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 1) {
|
||||
if (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);
|
||||
|
||||
@ -195,6 +195,8 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +60,9 @@ 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"
|
||||
@ -596,7 +598,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() mecanism
|
||||
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
|
||||
remaining_time -= USB_TIMEOUT_PER_PASS;
|
||||
if (remaining_time <= 0) {
|
||||
pnd->last_error = NFC_ETIMEOUT;
|
||||
@ -610,6 +612,7 @@ 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) {
|
||||
@ -621,7 +624,7 @@ read:
|
||||
goto read;
|
||||
}
|
||||
}
|
||||
if (res < 12) {
|
||||
if (res < 10) {
|
||||
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);
|
||||
@ -636,6 +639,17 @@ 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");
|
||||
@ -664,7 +678,7 @@ read:
|
||||
goto read; // FIXME May cause some trouble on Touchatag, right ?
|
||||
}
|
||||
}
|
||||
if (res < 12) {
|
||||
if (res < 10) {
|
||||
// try to interrupt current device state
|
||||
acr122_usb_ack(pnd);
|
||||
pnd->last_error = NFC_EIO;
|
||||
@ -703,7 +717,7 @@ read:
|
||||
|
||||
// Skip CCID remaining bytes
|
||||
offset += 2; // bSlot and bSeq are not used
|
||||
offset += 2; // XXX bStatus and bError should maybe checked ?
|
||||
offset += 2; // bStatus and bError is partially checked
|
||||
offset += 1; // bRFU should be 0x00
|
||||
|
||||
// TFI + PD0 (CC+1)
|
||||
|
||||
@ -527,7 +527,7 @@ acr122s_close(nfc_device *pnd)
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
|
||||
#ifndef WIN32
|
||||
// Release file descriptors used for abort mecanism
|
||||
// Release file descriptors used for abort mechanism
|
||||
close(DRIVER_DATA(pnd)->abort_fds[0]);
|
||||
close(DRIVER_DATA(pnd)->abort_fds[1]);
|
||||
#endif
|
||||
|
||||
@ -158,7 +158,7 @@ arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
// pipe-based abort mecanism
|
||||
// pipe-based abort mechanism
|
||||
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 mecanism
|
||||
// Release file descriptors used for abort mechanism
|
||||
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 mecanism
|
||||
// pipe-based abort mechanism
|
||||
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
pn53x_data_free(pnd);
|
||||
|
||||
@ -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,6 +34,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
@ -72,6 +73,11 @@
|
||||
#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>
|
||||
@ -138,8 +144,14 @@ 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 (dw_rx_len == 1 && is_pcsc_reader_vendor_feitian(pnd)) {
|
||||
dw_rx_len = 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.
|
||||
}
|
||||
}
|
||||
|
||||
LOG_HEX(NFC_LOG_GROUP_COM, "TX", tx, tx_len);
|
||||
@ -252,7 +264,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;
|
||||
@ -263,8 +275,7 @@ 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);
|
||||
memcpy(ats, resp + 1, resp[0] - 1);
|
||||
memcpy(ats, resp + 1, resp_len - 2 - 1);//data expect TL and SW1SW2
|
||||
return resp_len - 2 - 1;
|
||||
}
|
||||
|
||||
@ -341,17 +352,23 @@ 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));
|
||||
//memcpy(pnt->nti.nai.abtAtqa,atqa,2);
|
||||
pnt->nti.nai.abtAtqa[0] = atqa[1];
|
||||
pnt->nti.nai.abtAtqa[1] = atqa[0];
|
||||
//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];
|
||||
}
|
||||
|
||||
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);
|
||||
//memcpy(pnt->nti.nai.abtAts + ats_len, patr + 4, (uint8_t)(szatr - 5));
|
||||
pnt->nti.nai.szAtsLen = ats_len;// + szatr - 5;
|
||||
pnt->nti.nai.szAtsLen = ats_len;
|
||||
} else {
|
||||
/* SAK_ISO14443_4_COMPLIANT */
|
||||
pnt->nti.nai.btSak = 0x20;
|
||||
@ -521,7 +538,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, &(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 | 1, &(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");
|
||||
@ -797,6 +814,21 @@ 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;
|
||||
@ -884,6 +916,9 @@ 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;
|
||||
@ -936,8 +971,13 @@ 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;
|
||||
|
||||
|
||||
@ -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 mecanism
|
||||
// pipe-based abort mechanism
|
||||
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 mecanism
|
||||
// Release file descriptors used for abort mechanism
|
||||
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 mecanism
|
||||
// pipe-based abort mechanism
|
||||
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
|
||||
uart_close(DRIVER_DATA(pnd)->port);
|
||||
pn53x_data_free(pnd);
|
||||
|
||||
@ -43,7 +43,9 @@ 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"
|
||||
@ -621,7 +623,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() mecanism
|
||||
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
|
||||
remaining_time -= USB_TIMEOUT_PER_PASS;
|
||||
if (remaining_time <= 0) {
|
||||
pnd->last_error = NFC_ETIMEOUT;
|
||||
@ -817,7 +819,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 ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31))) < 0)
|
||||
if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0)
|
||||
return NFC_ECHIP;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -34,7 +34,9 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <err.h>
|
||||
#if !defined(_MSC_VER)
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "nfc/nfc.h"
|
||||
|
||||
@ -44,13 +46,15 @@
|
||||
* @macro HAL
|
||||
* @brief Execute corresponding driver function if exists.
|
||||
*/
|
||||
#define HAL( FUNCTION, ... ) pnd->last_error = 0; \
|
||||
#define HAL( FUNCTION, ... ) __extension__ ({int res; \
|
||||
pnd->last_error = 0; \
|
||||
if (pnd->driver->FUNCTION) { \
|
||||
return pnd->driver->FUNCTION( __VA_ARGS__ ); \
|
||||
res = pnd->driver->FUNCTION( __VA_ARGS__ ); \
|
||||
} else { \
|
||||
pnd->last_error = NFC_EDEVNOTSUPP; \
|
||||
return false; \
|
||||
}
|
||||
res = false; \
|
||||
} \
|
||||
res;})
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
64
libnfc/nfc.c
64
libnfc/nfc.c
@ -446,7 +446,7 @@ int
|
||||
nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value)
|
||||
{
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_int %s %s", nfc_property_name[property], value ? "True" : "False");
|
||||
HAL(device_set_property_int, pnd, property, value);
|
||||
return HAL(device_set_property_int, pnd, property, value);
|
||||
}
|
||||
|
||||
|
||||
@ -466,7 +466,7 @@ int
|
||||
nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable)
|
||||
{
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_bool %s %s", nfc_property_name[property], bEnable ? "True" : "False");
|
||||
HAL(device_set_property_bool, pnd, property, bEnable);
|
||||
return HAL(device_set_property_bool, pnd, property, bEnable);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -517,7 +517,7 @@ nfc_initiator_init(nfc_device *pnd)
|
||||
// Disallow multiple frames
|
||||
if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_MULTIPLE_FRAMES, false)) < 0)
|
||||
return res;
|
||||
HAL(initiator_init, pnd);
|
||||
return HAL(initiator_init, pnd);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -532,7 +532,7 @@ nfc_initiator_init(nfc_device *pnd)
|
||||
int
|
||||
nfc_initiator_init_secure_element(nfc_device *pnd)
|
||||
{
|
||||
HAL(initiator_init_secure_element, pnd);
|
||||
return HAL(initiator_init_secure_element, pnd);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -565,24 +565,28 @@ nfc_initiator_select_passive_target(nfc_device *pnd,
|
||||
nfc_target *pnt)
|
||||
{
|
||||
uint8_t *abtInit = NULL;
|
||||
uint8_t abtTmpInit[MAX(12, szInitData)];
|
||||
uint8_t maxAbt = MAX(12, szInitData);
|
||||
size_t szInit = 0;
|
||||
int res;
|
||||
if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS)
|
||||
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);
|
||||
} else if (nm.nmt == NMT_ISO14443A) {
|
||||
abtInit = abtTmpInit;
|
||||
return HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
|
||||
}
|
||||
|
||||
abtInit = malloc(sizeof(uint8_t) * maxAbt);
|
||||
if (nm.nmt == NMT_ISO14443A) {
|
||||
iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit);
|
||||
} else {
|
||||
abtInit = abtTmpInit;
|
||||
memcpy(abtInit, pbtInitData, szInitData);
|
||||
szInit = szInitData;
|
||||
}
|
||||
|
||||
HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
|
||||
res = HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
|
||||
free(abtInit);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -674,7 +678,7 @@ nfc_initiator_poll_target(nfc_device *pnd,
|
||||
const uint8_t uiPollNr, const uint8_t uiPeriod,
|
||||
nfc_target *pnt)
|
||||
{
|
||||
HAL(initiator_poll_target, pnd, pnmModulations, szModulations, uiPollNr, uiPeriod, pnt);
|
||||
return HAL(initiator_poll_target, pnd, pnmModulations, szModulations, uiPollNr, uiPeriod, pnt);
|
||||
}
|
||||
|
||||
|
||||
@ -703,7 +707,7 @@ nfc_initiator_select_dep_target(nfc_device *pnd,
|
||||
const nfc_dep_mode ndm, const nfc_baud_rate nbr,
|
||||
const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout)
|
||||
{
|
||||
HAL(initiator_select_dep_target, pnd, ndm, nbr, pndiInitiator, pnt, timeout);
|
||||
return HAL(initiator_select_dep_target, pnd, ndm, nbr, pndiInitiator, pnt, timeout);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -774,7 +778,7 @@ end:
|
||||
int
|
||||
nfc_initiator_deselect_target(nfc_device *pnd)
|
||||
{
|
||||
HAL(initiator_deselect_target, pnd);
|
||||
return HAL(initiator_deselect_target, pnd);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -809,7 +813,7 @@ int
|
||||
nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx,
|
||||
const size_t szRx, int timeout)
|
||||
{
|
||||
HAL(initiator_transceive_bytes, pnd, pbtTx, szTx, pbtRx, szRx, timeout)
|
||||
return HAL(initiator_transceive_bytes, pnd, pbtTx, szTx, pbtRx, szRx, timeout);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -855,7 +859,7 @@ nfc_initiator_transceive_bits(nfc_device *pnd,
|
||||
uint8_t *pbtRxPar)
|
||||
{
|
||||
(void)szRx;
|
||||
HAL(initiator_transceive_bits, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar);
|
||||
return HAL(initiator_transceive_bits, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -890,7 +894,7 @@ nfc_initiator_transceive_bytes_timed(nfc_device *pnd,
|
||||
uint8_t *pbtRx, const size_t szRx,
|
||||
uint32_t *cycles)
|
||||
{
|
||||
HAL(initiator_transceive_bytes_timed, pnd, pbtTx, szTx, pbtRx, szRx, cycles);
|
||||
return HAL(initiator_transceive_bytes_timed, pnd, pbtTx, szTx, pbtRx, szRx, cycles);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -906,7 +910,7 @@ nfc_initiator_transceive_bytes_timed(nfc_device *pnd,
|
||||
int
|
||||
nfc_initiator_target_is_present(nfc_device *pnd, const nfc_target *pnt)
|
||||
{
|
||||
HAL(initiator_target_is_present, pnd, pnt);
|
||||
return HAL(initiator_target_is_present, pnd, pnt);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -938,7 +942,7 @@ nfc_initiator_transceive_bits_timed(nfc_device *pnd,
|
||||
uint32_t *cycles)
|
||||
{
|
||||
(void)szRx;
|
||||
HAL(initiator_transceive_bits_timed, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar, cycles);
|
||||
return HAL(initiator_transceive_bits_timed, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar, cycles);
|
||||
}
|
||||
|
||||
/** @ingroup target
|
||||
@ -1002,7 +1006,7 @@ nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t s
|
||||
if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0)
|
||||
return res;
|
||||
|
||||
HAL(target_init, pnd, pnt, pbtRx, szRx, timeout);
|
||||
return HAL(target_init, pnd, pnt, pbtRx, szRx, timeout);
|
||||
}
|
||||
|
||||
/** @ingroup dev
|
||||
@ -1018,7 +1022,7 @@ nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t s
|
||||
int
|
||||
nfc_idle(nfc_device *pnd)
|
||||
{
|
||||
HAL(idle, pnd);
|
||||
return HAL(idle, pnd);
|
||||
}
|
||||
|
||||
/** @ingroup dev
|
||||
@ -1035,7 +1039,7 @@ nfc_idle(nfc_device *pnd)
|
||||
int
|
||||
nfc_abort_command(nfc_device *pnd)
|
||||
{
|
||||
HAL(abort_command, pnd);
|
||||
return HAL(abort_command, pnd);
|
||||
}
|
||||
|
||||
/** @ingroup target
|
||||
@ -1056,7 +1060,7 @@ nfc_abort_command(nfc_device *pnd)
|
||||
int
|
||||
nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout)
|
||||
{
|
||||
HAL(target_send_bytes, pnd, pbtTx, szTx, timeout);
|
||||
return HAL(target_send_bytes, pnd, pbtTx, szTx, timeout);
|
||||
}
|
||||
|
||||
/** @ingroup target
|
||||
@ -1076,7 +1080,7 @@ nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx,
|
||||
int
|
||||
nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout)
|
||||
{
|
||||
HAL(target_receive_bytes, pnd, pbtRx, szRx, timeout);
|
||||
return HAL(target_receive_bytes, pnd, pbtRx, szRx, timeout);
|
||||
}
|
||||
|
||||
/** @ingroup target
|
||||
@ -1093,7 +1097,7 @@ nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int
|
||||
int
|
||||
nfc_target_send_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar)
|
||||
{
|
||||
HAL(target_send_bits, pnd, pbtTx, szTxBits, pbtTxPar);
|
||||
return HAL(target_send_bits, pnd, pbtTx, szTxBits, pbtTxPar);
|
||||
}
|
||||
|
||||
/** @ingroup target
|
||||
@ -1115,7 +1119,7 @@ nfc_target_send_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBit
|
||||
int
|
||||
nfc_target_receive_bits(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar)
|
||||
{
|
||||
HAL(target_receive_bits, pnd, pbtRx, szRx, pbtRxPar);
|
||||
return HAL(target_receive_bits, pnd, pbtRx, szRx, pbtRxPar);
|
||||
}
|
||||
|
||||
static struct sErrorMessage {
|
||||
@ -1234,7 +1238,7 @@ nfc_device_get_connstring(nfc_device *pnd)
|
||||
int
|
||||
nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt)
|
||||
{
|
||||
HAL(get_supported_modulation, pnd, mode, supported_mt);
|
||||
return HAL(get_supported_modulation, pnd, mode, supported_mt);
|
||||
}
|
||||
|
||||
/** @ingroup data
|
||||
@ -1248,7 +1252,7 @@ nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const
|
||||
int
|
||||
nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br)
|
||||
{
|
||||
HAL(get_supported_baud_rate, pnd, N_INITIATOR, nmt, supported_br);
|
||||
return HAL(get_supported_baud_rate, pnd, N_INITIATOR, nmt, supported_br);
|
||||
}
|
||||
|
||||
/** @ingroup data
|
||||
@ -1262,7 +1266,7 @@ nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nm
|
||||
int
|
||||
nfc_device_get_supported_baud_rate_target_mode(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br)
|
||||
{
|
||||
HAL(get_supported_baud_rate, pnd, N_TARGET, nmt, supported_br);
|
||||
return HAL(get_supported_baud_rate, pnd, N_TARGET, nmt, supported_br);
|
||||
}
|
||||
|
||||
/** @ingroup data
|
||||
@ -1347,7 +1351,7 @@ nfc_free(void *p)
|
||||
int
|
||||
nfc_device_get_information_about(nfc_device *pnd, char **buf)
|
||||
{
|
||||
HAL(device_get_information_about, pnd, buf);
|
||||
return HAL(device_get_information_about, pnd, buf);
|
||||
}
|
||||
|
||||
/** @ingroup string-converter
|
||||
|
||||
@ -23,24 +23,28 @@ FOREACH(source ${UTILS-SOURCES})
|
||||
SET(RC_COMMENT "${PACKAGE_NAME} utility")
|
||||
SET(RC_INTERNAL_NAME ${source})
|
||||
SET(RC_ORIGINAL_NAME ${source}.exe)
|
||||
SET(RC_FILE_TYPE VFT_APP)
|
||||
# RC_FILE_TYPE: VFT_APP
|
||||
SET(RC_FILE_TYPE 0x00000001L)
|
||||
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)
|
||||
|
||||
IF(${source} MATCHES "nfc-jewel")
|
||||
LIST(APPEND TARGETS jewel)
|
||||
LIST(APPEND TARGETS jewel.c)
|
||||
ENDIF(${source} MATCHES "nfc-jewel")
|
||||
|
||||
IF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic"))
|
||||
LIST(APPEND TARGETS mifare)
|
||||
LIST(APPEND TARGETS mifare.c)
|
||||
ENDIF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic"))
|
||||
|
||||
IF(WIN32)
|
||||
IF(${source} MATCHES "nfc-scan-device")
|
||||
LIST(APPEND TARGETS ../contrib/win32/stdlib)
|
||||
LIST(APPEND TARGETS ../contrib/win32/stdlib.c)
|
||||
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})
|
||||
|
||||
@ -62,7 +62,7 @@ print_usage(char *argv[])
|
||||
printf("Usage: %s [OPTIONS]\n", argv[0]);
|
||||
printf("Options:\n");
|
||||
printf("\t-h\tHelp. Print this message.\n");
|
||||
printf("\t-q\tVerbose mode.\n");
|
||||
printf("\t-v\tVerbose mode.\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -97,10 +97,6 @@ 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")) {
|
||||
@ -117,7 +113,7 @@ main(int argc, const char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Force TypeB for all derivatives of B
|
||||
if (mask & 0xf0)
|
||||
if (mask & 0xd0)
|
||||
mask |= 0x08;
|
||||
} else {
|
||||
ERR("%s is not supported option.", argv[arg]);
|
||||
@ -126,6 +122,13 @@ 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);
|
||||
|
||||
@ -54,6 +54,12 @@
|
||||
#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"
|
||||
@ -70,8 +76,7 @@ static bool bUseKeyFile;
|
||||
static bool bForceKeyFile;
|
||||
static bool bTolerateFailures;
|
||||
static bool bFormatCard;
|
||||
static bool magic2 = false;
|
||||
static bool magic3 = false;
|
||||
static bool dWrite = false;
|
||||
static bool unlocked = false;
|
||||
static uint8_t uiBlocks;
|
||||
static uint8_t keys[] = {
|
||||
@ -211,15 +216,6 @@ 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++) {
|
||||
@ -242,7 +238,7 @@ authenticate(uint32_t uiBlock)
|
||||
}
|
||||
|
||||
static bool
|
||||
unlock_card(void)
|
||||
unlock_card(bool write)
|
||||
{
|
||||
// Configure the CRC
|
||||
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) {
|
||||
@ -260,6 +256,10 @@ unlock_card(void)
|
||||
// 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,6 +270,15 @@ unlock_card(void)
|
||||
}
|
||||
|
||||
// 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");
|
||||
@ -316,23 +325,19 @@ get_rats(void)
|
||||
}
|
||||
|
||||
static bool
|
||||
read_card(int read_unlocked)
|
||||
read_card(bool 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 (magic2) {
|
||||
printf("Note: This card does not require an unlocked read (R) \n");
|
||||
if (dWrite) {
|
||||
printf("Note: This card can't do 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,18 +367,11 @@ read_card(int read_unlocked)
|
||||
if (read_unlocked) {
|
||||
memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData));
|
||||
} else {
|
||||
//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));
|
||||
// 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;
|
||||
@ -403,7 +401,7 @@ read_card(int read_unlocked)
|
||||
}
|
||||
|
||||
static bool
|
||||
write_card(int write_block_zero)
|
||||
write_card(bool write_block_zero)
|
||||
{
|
||||
uint32_t uiBlock;
|
||||
bool bFailure = false;
|
||||
@ -411,24 +409,18 @@ write_card(int write_block_zero)
|
||||
|
||||
//Determine if we have to unlock the card
|
||||
if (write_block_zero) {
|
||||
//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;
|
||||
}
|
||||
}
|
||||
unlock_card(true);
|
||||
}
|
||||
|
||||
printf("Writing %d blocks |", uiBlocks + 1);
|
||||
// Completely write the card, end to start, but skipping block 0
|
||||
for (uiBlock = 4; uiBlock <= uiBlocks; uiBlock++) {
|
||||
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;
|
||||
}
|
||||
// Authenticate everytime we reach the first sector of a new block
|
||||
if (is_first_block(uiBlock)) {
|
||||
if (uiBlock == 1 || 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) {
|
||||
@ -442,14 +434,15 @@ write_card(int 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 One Time Write card, we need to authenticate
|
||||
// If we're writing to a direct write card, we need to authenticate
|
||||
// If we're writing something else, we'll need to authenticate
|
||||
if ((write_block_zero && magic3) || !write_block_zero) {
|
||||
if ((write_block_zero && dWrite) || !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) {
|
||||
@ -470,10 +463,6 @@ write_card(int 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
|
||||
@ -484,7 +473,7 @@ write_card(int 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 && !magic2) {
|
||||
if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00) {
|
||||
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;
|
||||
@ -494,88 +483,29 @@ write_card(int 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);
|
||||
@ -593,18 +523,24 @@ 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);
|
||||
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");
|
||||
#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(" *** 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 unlocked write will attempt to overwrite block 0 including UID\n");
|
||||
printf(" *** unlocking only works with special Mifare 1K cards (Chinese clones)\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(" 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);
|
||||
@ -620,54 +556,6 @@ 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[])
|
||||
{
|
||||
@ -676,7 +564,7 @@ main(int argc, const char *argv[])
|
||||
uint8_t _tag_uid[4];
|
||||
uint8_t *tag_uid = _tag_uid;
|
||||
|
||||
int unlock = 0;
|
||||
bool unlock = false;
|
||||
|
||||
if (argc < 2) {
|
||||
print_usage(argv[0]);
|
||||
@ -691,19 +579,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 = 1;
|
||||
unlock = true;
|
||||
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
|
||||
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
|
||||
bUseKeyFile = (argc > 5);
|
||||
bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
|
||||
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 = 1;
|
||||
unlock = true;
|
||||
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);
|
||||
bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
|
||||
bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
|
||||
}
|
||||
if (argv[3][0] == 'U') {
|
||||
@ -725,6 +613,21 @@ 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);
|
||||
@ -764,6 +667,14 @@ 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");
|
||||
@ -779,11 +690,24 @@ 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");
|
||||
@ -792,7 +716,8 @@ 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) {
|
||||
if (((nt.nti.nai.btSak & 0x08) == 0) && (nt.nti.nai.btSak != 0x01)) {
|
||||
// if ((nt.nti.nai.btSak & 0x08) == 0) {
|
||||
printf("Warning: tag is probably not a MFC!\n");
|
||||
}
|
||||
|
||||
@ -839,35 +764,10 @@ 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) {
|
||||
@ -922,9 +822,17 @@ 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) {
|
||||
write_card(unlock);
|
||||
if (!write_card(unlock)) {
|
||||
nfc_close(pnd);
|
||||
nfc_exit(context);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
nfc_close(pnd);
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
#if defined(WIN32) && defined(__GNUC__) /* mingw compiler */
|
||||
#if defined(WIN32) /* mingw compiler */
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user