Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28ce753431 | |||
| 80ef76fdda | |||
|
|
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 | ||
|
|
f02ff51449 | ||
|
|
5c3c468a6a | ||
|
|
63cf0acb0b | ||
|
|
5294c0290f | ||
|
|
fa78e8b883 | ||
|
|
357ae384af | ||
|
|
c8692aa239 | ||
|
|
91d7c5d32f | ||
|
|
4525cd1c32 | ||
|
|
f52d04e0a7 | ||
|
|
5a059db901 | ||
|
|
730f705c0d | ||
|
|
6b4f6249bd | ||
|
|
d29b3170d9 | ||
|
|
4a2c764961 | ||
|
|
020f5317a6 | ||
|
|
675c30eb93 | ||
|
|
beb8fdd759 | ||
|
|
6f41ea3ad3 | ||
|
|
8352c80679 | ||
|
|
66176016ed | ||
|
|
f1bb27d1af | ||
|
|
c884f36b94 | ||
|
|
17e615e8b1 | ||
|
|
a07d879496 | ||
|
|
10f880374c | ||
|
|
96568a1023 | ||
|
|
dcc52cd4d5 | ||
|
|
19a51dc2bd | ||
|
|
61e93c1cdf | ||
|
|
cbc4e7b5c4 | ||
|
|
692038ceaf | ||
|
|
f3f588671c | ||
|
|
fbae17186b | ||
|
|
004eff8e96 | ||
|
|
7908d405dd | ||
|
|
ff4e1efa7b | ||
|
|
c34c446831 | ||
|
|
54ba7359ce | ||
|
|
fba969472d | ||
|
|
a85f003d91 | ||
|
|
8a1e14901d | ||
|
|
2a6a8e6e29 | ||
|
|
07f918283b | ||
|
|
6e035c33f3 | ||
|
|
a77a2a8497 | ||
|
|
6f793da1c1 | ||
|
|
8e7a8e1b61 | ||
|
|
959a992a81 | ||
|
|
75e5e23c81 | ||
|
|
f8b28523d7 | ||
|
|
ad695d0a18 | ||
|
|
454a8c4d70 | ||
|
|
fbdbe6eff3 | ||
|
|
c109d37783 | ||
|
|
141907e127 | ||
|
|
48d5f6b666 | ||
|
|
a4af2be66c | ||
|
|
91f7db5b4d | ||
|
|
ebb13d8965 | ||
|
|
c42e2502d4 | ||
|
|
793d5adde6 | ||
|
|
7a0a469c8a | ||
|
|
f9f03fa7fa | ||
|
|
4a10d0f21b | ||
|
|
7eae55e929 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,6 +7,8 @@
|
||||
*.lo
|
||||
*.o
|
||||
*~
|
||||
.vs/
|
||||
CMakeSettings.json
|
||||
Doxyfile
|
||||
INSTALL
|
||||
aclocal.m4
|
||||
|
||||
92
.travis.yml
92
.travis.yml
@ -1,21 +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
|
||||
- libcutter-dev
|
||||
- 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
|
||||
|
||||
@ -7,8 +7,8 @@ endif ()
|
||||
project (libnfc C)
|
||||
|
||||
SET(VERSION_MAJOR "1")
|
||||
SET(VERSION_MINOR "7")
|
||||
SET(VERSION_PATCH "1")
|
||||
SET(VERSION_MINOR "8")
|
||||
SET(VERSION_PATCH "0")
|
||||
|
||||
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
|
||||
@ -18,14 +18,18 @@ SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
||||
|
||||
# config.h
|
||||
IF(WIN32)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
|
||||
SET(LIBNFC_SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/config" CACHE PATH "libnfc configuration directory")
|
||||
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)
|
||||
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")
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
ENDIF(WIN32)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
ADD_DEFINITIONS("-DHAVE_CONFIG_H")
|
||||
|
||||
@ -137,9 +141,15 @@ IF(NOT WIN32)
|
||||
IF(LIBNFC_DRIVER_PN53X_USB)
|
||||
SET(PKG_REQ ${PKG_REQ} "libusb")
|
||||
ENDIF(LIBNFC_DRIVER_PN53X_USB)
|
||||
IF(LIBNFC_DRIVER_ACR122)
|
||||
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)
|
||||
# CMake lists are separated by a semi colon, replace with colon
|
||||
STRING(REPLACE ";" "," PKG_CONFIG_REQUIRES "${PKG_REQ}")
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libnfc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc @ONLY)
|
||||
@ -148,7 +158,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)
|
||||
@ -162,7 +172,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})
|
||||
@ -197,7 +207,8 @@ IF(WIN32)
|
||||
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)
|
||||
|
||||
|
||||
35
ChangeLog
35
ChangeLog
@ -1,5 +1,16 @@
|
||||
TBD - 1.7.x
|
||||
-----------
|
||||
May 22, 2020 - 1.8.0
|
||||
--------------------
|
||||
|
||||
Fixes:
|
||||
- Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1
|
||||
|
||||
Changes:
|
||||
- Bump revision due to changes in API introduced in v1.7.2
|
||||
- Bump library version to 6.0.0
|
||||
|
||||
May 21, 2020 - 1.7.2 (avoid using it, incompatible with 1.7.1)
|
||||
--------------------
|
||||
|
||||
Fixes:
|
||||
- Remove unreachable code
|
||||
- nfc_emulate_uid: cleaner exit on interrupt
|
||||
@ -13,6 +24,7 @@ Fixes:
|
||||
- Fix improper device name initialization
|
||||
- Fix setenv()/unsetenv() for Windows
|
||||
- Fix win32/nfc.def according to nfc.h
|
||||
- Fix missing timeout in pn53x_initiator_select_passive_target()
|
||||
- nfc-mfclassic: fix option to tolerate write errors
|
||||
- nfc-poll: fix card removing check
|
||||
- nfc-relay-picc: fix wrong open mode for file descriptor
|
||||
@ -27,28 +39,37 @@ Improvements:
|
||||
- Drop PCRE dependency on Windows
|
||||
- Remove deprecated readdir_r
|
||||
- Markdown conversion of the text files
|
||||
- Use hardcoded PN533 descriptors to be more robust on Windows
|
||||
- Add support for SCL3712
|
||||
- Add support for ACR1222U-C1
|
||||
- Add support for NetBSD
|
||||
- Add support for PN532 on RPi3 UART
|
||||
- Add support for cross-compilation of 32b & 64b versions of the library for Windows
|
||||
- Add pn533_usb to the kernel modules blacklist
|
||||
- Add support for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested)
|
||||
- Add support for contactless PC/SC readers (only as initiator)
|
||||
- Add support for Feitian R502 and bR500 into pcsc driver
|
||||
- Add support for HID iClass (Picopass) support (nfc-iclass tool in external nfc-tools repo)
|
||||
- Allows for sending empty data in nfc_initiator_transceive_bits
|
||||
- driver i2c: respect proper timing specifications
|
||||
- driver i2c: add retry on error mechanism
|
||||
- nfc-mfclassic: improvements fo magic cards
|
||||
- nfc-mfclassic: add option to specify UID
|
||||
- nfc-mfclassic/nfc-mfsetuid: add support for new gen (1b) of magic 4K cards
|
||||
- nfc-mfclassic: Add RATS support indicator
|
||||
- nfc-mfsetuid: allow to write complete Block0, instead of only UID
|
||||
- nfc-mfultralight: add automatic modes and --check-magic
|
||||
- nfc-mfultralight: add support for magic gen2 cards
|
||||
- nfc-mfultralight: add option to specify UID
|
||||
- nfc-mfultralight: add support for Ultralight NTAG213/215/216
|
||||
- nfc-barcode: new command to read and decode NFC Barcodes (Tag-Talks-First)
|
||||
|
||||
Changes:
|
||||
- nfc_get_supported_baud_rate() takes now a "mode" parameter
|
||||
- New nfc_get_supported_baud_rate_target_mode()
|
||||
- New NFC modulation type NMT_BARCODE to support Thinfilm NFC Barcode protocol
|
||||
- nfc_device_get_supported_baud_rate() takes now a "mode" parameter
|
||||
- New nfc_device_get_supported_baud_rate_target_mode()
|
||||
- New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol
|
||||
- New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass)
|
||||
- pn53x_transceive() is now part of public API
|
||||
|
||||
Special thanks to:
|
||||
- Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus,
|
||||
@ -56,7 +77,9 @@ Special thanks to:
|
||||
Alexander Inyukhin, Arnaud Kapp, David Kreitschmann, Adam Laurie, Ray Lee,
|
||||
Maxim Martyanov, Paul Menzel, Boris Moiseev, Yerzhan Mukhamejan,
|
||||
Olliver Shinagl, Jairo Andres Suarez, Mati Vait, Marcos Vives Del Sol,
|
||||
Hidde Wieringa, Simon Yorkston, timzi, usk-johnny-s, xantares
|
||||
Hidde Wieringa, Simon Yorkston, timzi, usk-johnny-s, xantares, Hanno
|
||||
Heinrichs, jgeslin, Mikolaj Stawiski, rstular, Khem Raj, Frank Morgner, jpwidera,
|
||||
Feitian Technologies
|
||||
|
||||
Feb 24, 2014 - 1.7.1
|
||||
--------------------
|
||||
|
||||
2480
Doxyfile.in
2480
Doxyfile.in
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
18
NEWS.md
18
NEWS.md
@ -1,9 +1,23 @@
|
||||
New in 1.7.x:
|
||||
New in 1.8.0:
|
||||
|
||||
API Changes:
|
||||
- Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1
|
||||
- Bump library version to 6.0.0
|
||||
|
||||
New in 1.7.2:
|
||||
|
||||
Drivers:
|
||||
|
||||
* New driver for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested)
|
||||
* New driver for contactless PC/SC readers (only as initiator)
|
||||
|
||||
API Changes:
|
||||
|
||||
* nfc_device_get_supported_baud_rate() now takes also "mode" as argument
|
||||
* New nfc_get_supported_baud_rate_target_mode()
|
||||
* New nfc_device_get_supported_baud_rate_target_mode()
|
||||
* New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol
|
||||
* New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass)
|
||||
* pn53x_transceive() is now part of public API
|
||||
|
||||
New in 1.7.1:
|
||||
|
||||
|
||||
106
README.md
106
README.md
@ -35,22 +35,42 @@ Requirements
|
||||
Some NFC drivers depend on third party software:
|
||||
|
||||
* pn53x_usb & acr122_usb:
|
||||
|
||||
- libusb-0.1 http://libusb.sf.net
|
||||
|
||||
- libusb-0.1 http://libusb.sf.net
|
||||
|
||||
* 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.
|
||||
|
||||
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.
|
||||
|
||||
@ -82,6 +102,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
|
||||
==================
|
||||
|
||||
@ -97,32 +128,36 @@ Please make sure to include:
|
||||
* The version of libnfc
|
||||
|
||||
* Information about your system. For instance:
|
||||
|
||||
- What operating system and version
|
||||
- For Linux, what version of the C library
|
||||
|
||||
|
||||
- What operating system and version
|
||||
- For Linux, what version of the C library
|
||||
|
||||
And anything else you think is relevant.
|
||||
|
||||
* A trace with debug activated.
|
||||
|
||||
|
||||
Reproduce the bug with debug, e.g. if it was:
|
||||
|
||||
|
||||
$ nfc-list -v
|
||||
|
||||
|
||||
run it as:
|
||||
|
||||
|
||||
$ LIBNFC_LOG_LEVEL=3 nfc-list -v
|
||||
|
||||
* How to reproduce the bug.
|
||||
|
||||
|
||||
Please include a short test program that exhibits the behavior.
|
||||
|
||||
As a last resort, you can also provide a pointer to a larger piece
|
||||
|
||||
of software that can be downloaded.
|
||||
|
||||
* If the bug was a crash, the exact text that was printed out
|
||||
|
||||
when the crash occured.
|
||||
|
||||
* Further information such as stack traces may be useful, but
|
||||
|
||||
is not necessary.
|
||||
|
||||
Patches
|
||||
@ -133,19 +168,12 @@ 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
|
||||
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
Touchatag/ACR122:
|
||||
-----------------
|
||||
|
||||
If your Touchatag or ACR122 device fails being detected by libnfc, make sure
|
||||
that PCSC-lite daemon (`pcscd`) is installed and is running.
|
||||
|
||||
@ -158,6 +186,7 @@ pcscd daemon.
|
||||
|
||||
ACR122:
|
||||
-------
|
||||
|
||||
Using an ACR122 device with libnfc and without tag (e.g. to use NFCIP modes or
|
||||
card emulation) needs yet another PCSC-lite tweak: You need to allow usage of
|
||||
CCID Exchange command. To do this, edit `libccid_Info.plist` configuration file
|
||||
@ -171,13 +200,16 @@ in something like: `/usr/lib/pcsc/drivers/ifd-acsccid.bundle/Contents/Info.plist
|
||||
|
||||
SCL3711:
|
||||
--------
|
||||
|
||||
Libnfc cannot be used concurrently with the PCSC proprietary driver of SCL3711.
|
||||
Two possible solutions:
|
||||
|
||||
* Either you don't install SCL3711 driver at all
|
||||
* Or you stop the PCSC daemon when you want to use libnfc-based tools
|
||||
|
||||
PN533 USB device on Linux >= 3.1:
|
||||
---------------------------------
|
||||
|
||||
Since Linux kernel version 3.1, a few kernel-modules must not be loaded in order
|
||||
to use libnfc : "nfc", "pn533" and "pn533_usb".
|
||||
To prevent kernel from loading automatically these modules, you can blacklist
|
||||
@ -185,9 +217,33 @@ them in a modprobe conf file. This file is provided within libnfc archive:
|
||||
|
||||
sudo cp contrib/linux/blacklist-libnfc.conf /etc/modprobe.d/blacklist-libnfc.conf
|
||||
|
||||
FEITIAN bR500 and R502:
|
||||
-----------------------
|
||||
|
||||
Libnfc can work with PCSC proprietary driver of bR500 and R502, which is already available on most Linux setups.
|
||||
To activate the PCSC support: `./configure --with-drivers=pcsc`.
|
||||
Readers known to work:
|
||||
|
||||
- Feitian bR500
|
||||
- Feitian R502 Dual interface reader
|
||||
- Feitian R502 CL(Contactless) reader
|
||||
|
||||
These readers are support by CCID since v1.4.25, make sure your CCID driver version higher or equal to 1.4.25.
|
||||
|
||||
On MacOS, you can check your CCID version with the following command, and if required, you can install latest CCID driver from [https://github.com/martinpaljak/osx-ccid-installer/releases](https://github.com/martinpaljak/osx-ccid-installer/releases)
|
||||
|
||||
```
|
||||
grep -A 1 CFBundleShortVersionString /usr/local/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
|
||||
```
|
||||
|
||||
On Linux, you can check your CCID version with the following command, and if required, you can install latest CCID driver from [https://ccid.apdu.fr/](https://ccid.apdu.fr/)
|
||||
|
||||
```
|
||||
grep -A 1 CFBundleShortVersionString /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist
|
||||
```
|
||||
|
||||
Proprietary Notes
|
||||
=================
|
||||
|
||||
FeliCa is a registered trademark of the Sony Corporation.
|
||||
MIFARE is a trademark of NXP Semiconductors.
|
||||
Jewel Topaz is a trademark of Innovision Research & Technology.
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
SET(LIBNFC_DRIVER_PCSC OFF CACHE BOOL "Enable PC/SC reader support (Depends on PC/SC)")
|
||||
SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on PC/SC)")
|
||||
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")
|
||||
ENDIF(LIBNFC_DRIVER_PCSC)
|
||||
|
||||
IF(LIBNFC_DRIVER_ACR122_PCSC)
|
||||
FIND_PACKAGE(PCSC REQUIRED)
|
||||
ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED")
|
||||
@ -61,4 +68,11 @@ IF(LIBNFC_DRIVER_PN53X_USB)
|
||||
SET(USB_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_PN53X_USB)
|
||||
|
||||
IF(LIBNFC_DRIVER_ACR122_USB)
|
||||
FIND_PACKAGE(LIBUSB REQUIRED)
|
||||
ADD_DEFINITIONS("-DDRIVER_ACR122_USB_ENABLED")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb")
|
||||
SET(USB_REQUIRED TRUE)
|
||||
ENDIF(LIBNFC_DRIVER_ACR122_USB)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers)
|
||||
|
||||
24
configure.ac
24
configure.ac
@ -1,7 +1,7 @@
|
||||
# General init
|
||||
|
||||
# /!\ Don't forget to update 'CMakeLists.txt' too /!\
|
||||
AC_INIT([libnfc],[1.7.1],[nfc-tools@googlegroups.com])
|
||||
AC_INIT([libnfc],[1.8.0],[nfc-tools@googlegroups.com])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
@ -47,6 +47,7 @@ AC_HEADER_STDBOOL
|
||||
AC_CHECK_HEADERS([fcntl.h limits.h stdio.h stdlib.h stdint.h stddef.h stdbool.h sys/ioctl.h sys/param.h sys/time.h termios.h])
|
||||
AC_CHECK_HEADERS([linux/spi/spidev.h], [spi_available="yes"])
|
||||
AC_CHECK_HEADERS([linux/i2c-dev.h], [i2c_available="yes"])
|
||||
AC_CHECK_HEADERS([linux_nfc_api.h], [nfc_nci_available="yes"])
|
||||
AC_CHECK_FUNCS([memmove memset select strdup strerror strstr strtol usleep],
|
||||
[AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])])
|
||||
|
||||
@ -130,6 +131,16 @@ then
|
||||
AC_SEARCH_LIBS([clock_gettime], [rt])
|
||||
fi
|
||||
|
||||
# Enable Libnfc-NCI if required
|
||||
if test x"$nfc_nci_required" = x"yes"
|
||||
then
|
||||
PKG_CHECK_MODULES([LIBNFC_NCI], [libnfc-nci],
|
||||
[AC_MSG_NOTICE([libnfc-nci present])],
|
||||
[AC_MSG_ERROR([libnfc-nci not present but required for some drivers configuration])]
|
||||
)
|
||||
CFLAGS="$CFLAGS $LIBNFC_NCI_CFLAGS"
|
||||
fi
|
||||
|
||||
# Documentation (default: no)
|
||||
AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"])
|
||||
|
||||
@ -146,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=""
|
||||
|
||||
@ -164,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"
|
||||
|
||||
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
|
||||
|
||||
@ -14,7 +14,7 @@ fully customized UID but only of "random" UIDs, which always start with 0x08.
|
||||
The nfc-emulate-uid tool demonstrates that this can still be done using
|
||||
transmission of raw frames, and the desired UID can be optionally specified.
|
||||
|
||||
This makes it a serious thread for security systems that rely only on the
|
||||
This makes it a serious threat for security systems that rely only on the
|
||||
uniqueness of the UID.
|
||||
|
||||
Unfortunately, this example can't directly start in fully customisable
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@ -101,14 +102,15 @@ main(int argc, const char *argv[])
|
||||
|
||||
const uint8_t uiPollNr = 20;
|
||||
const uint8_t uiPeriod = 2;
|
||||
const nfc_modulation nmModulations[5] = {
|
||||
const nfc_modulation nmModulations[6] = {
|
||||
{ .nmt = NMT_ISO14443A, .nbr = NBR_106 },
|
||||
{ .nmt = NMT_ISO14443B, .nbr = NBR_106 },
|
||||
{ .nmt = NMT_FELICA, .nbr = NBR_212 },
|
||||
{ .nmt = NMT_FELICA, .nbr = NBR_424 },
|
||||
{ .nmt = NMT_JEWEL, .nbr = NBR_106 },
|
||||
{ .nmt = NMT_ISO14443BICLASS, .nbr = NBR_106 },
|
||||
};
|
||||
const size_t szModulations = 5;
|
||||
const size_t szModulations = 6;
|
||||
|
||||
nfc_target nt;
|
||||
int res = 0;
|
||||
|
||||
600
examples/nfc-st25tb.c
Normal file
600
examples/nfc-st25tb.c
Normal file
@ -0,0 +1,600 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* Libnfc historical contributors:
|
||||
* Copyright (C) 2009 Roel Verdult
|
||||
* Copyright (C) 2009-2013 Romuald Conty
|
||||
* Copyright (C) 2010-2012 Romain Tartière
|
||||
* Copyright (C) 2010-2013 Philippe Teuwen
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-st25tb.c
|
||||
* @brief Tool to operate on ISO-14443-B ST25TB* and legacy SR* cards
|
||||
*/
|
||||
|
||||
/* Benjamin DELPY `gentilkiwi`
|
||||
* https://blog.gentilkiwi.com
|
||||
* benjamin@gentilkiwi.com
|
||||
* Licence : https://creativecommons.org/licenses/by/4.0/
|
||||
* Rely on : libnfc - https://github.com/nfc-tools/libnfc
|
||||
*
|
||||
* $ gcc -Wall -lnfc -o nfc-st25tb nfc-st25tb.c
|
||||
* $ ./nfc-st25tb -h
|
||||
*
|
||||
* Tested with
|
||||
* - ST25TB512-AC - (BE/Brussels/STIB ; AliExpress ones)
|
||||
* - ST25TB512-AT - (FR/Lille/Ilevia ; FR/Reims/Citura ; FR/Dijon/Divia ; FR/Strasbourg/CTS)
|
||||
* - SRT512 - legacy - (FR/Bordeaux/TBM)
|
||||
* - SRI512 - legacy - (anonymous vending machine)
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#if defined(WIN32) /* mingw compiler */
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#define ST25TB_SR_BLOCK_MAX_SIZE ((uint8_t) 4) // for static arrays
|
||||
typedef void(*get_info_specific) (uint8_t * systemArea);
|
||||
|
||||
typedef struct _st_data {
|
||||
uint8_t chipId;
|
||||
bool bIsLegacy;
|
||||
const char *szName;
|
||||
const char *szDatasheetUrl;
|
||||
uint8_t blockSize;
|
||||
uint8_t nbNormalBlock;
|
||||
uint8_t bnSystem;
|
||||
get_info_specific pfnGetInfo;
|
||||
} st_data;
|
||||
|
||||
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
|
||||
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
|
||||
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
|
||||
const st_data * get_info(const nfc_target *pnt, bool bPrintIt);
|
||||
void display_system_info(nfc_device *pnd, const st_data * stdata);
|
||||
void print_hex(const uint8_t *pbtData, const size_t szBytes);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
nfc_context *context = NULL;
|
||||
nfc_device *pnd = NULL;
|
||||
nfc_target nt = {0};
|
||||
nfc_modulation nm = {NMT_ISO14443B2SR, NBR_106};
|
||||
const st_data * stcurrent;
|
||||
int opt, res;
|
||||
bool bIsBlock = false, bIsRead = false, bIsWrite = false, bIsBadCli = false;
|
||||
uint8_t i, blockNumber = 0, data[ST25TB_SR_BLOCK_MAX_SIZE] = {0xff, 0xff, 0xff, 0xff}; // just in case...
|
||||
size_t cbData = 0;
|
||||
|
||||
while(!bIsBadCli && ((opt = getopt(argc, argv, ":hib:rw:")) != -1))
|
||||
{
|
||||
switch(opt)
|
||||
{
|
||||
case 'i':
|
||||
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
if(optarg)
|
||||
{
|
||||
bIsBlock = true;
|
||||
blockNumber = strtoul(optarg, NULL, 0);
|
||||
}
|
||||
else bIsBadCli = true;
|
||||
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
bIsRead = true;
|
||||
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if(optarg)
|
||||
{
|
||||
cbData = strlen(optarg);
|
||||
if((cbData == (2*2)) || ((cbData == (4*2))))
|
||||
{
|
||||
cbData >>= 1;
|
||||
if(cbData == 2) // sr176
|
||||
{
|
||||
res = sscanf(optarg, "%02hhx%02hhx", data, data + 1);
|
||||
}
|
||||
else // all others
|
||||
{
|
||||
res = sscanf(optarg, "%02hhx%02hhx%02hhx%02hhx", data, data + 1, data + 2, data + 3);
|
||||
}
|
||||
|
||||
if(res == (int) cbData)
|
||||
{
|
||||
bIsWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!bIsWrite)
|
||||
{
|
||||
bIsBadCli = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: // includes -h
|
||||
bIsBadCli = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(!bIsBadCli)
|
||||
{
|
||||
if(bIsBlock && (bIsRead || bIsWrite))
|
||||
{
|
||||
if(bIsRead && bIsWrite)
|
||||
{
|
||||
printf("|mode : read then write\n");
|
||||
}
|
||||
else if(bIsRead)
|
||||
{
|
||||
printf("|mode : read\n");
|
||||
}
|
||||
else if(bIsWrite)
|
||||
{
|
||||
printf("|mode : write\n");
|
||||
}
|
||||
|
||||
printf("|blk num: 0x%02hhx\n", blockNumber);
|
||||
if(bIsWrite)
|
||||
{
|
||||
printf("|data : ");
|
||||
print_hex(data, cbData);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
else if(!bIsRead && !bIsWrite && !bIsBlock)
|
||||
{
|
||||
printf("|mode : info\n");
|
||||
}
|
||||
else bIsBadCli = true;
|
||||
}
|
||||
|
||||
if(!bIsBadCli)
|
||||
{
|
||||
nfc_init(&context);
|
||||
if(context)
|
||||
{
|
||||
pnd = nfc_open(context, NULL);
|
||||
if(pnd)
|
||||
{
|
||||
res = nfc_initiator_init(pnd);
|
||||
if(res == NFC_SUCCESS)
|
||||
{
|
||||
printf("Reader : %s - via %s\n ...wait for card...\n", nfc_device_get_name(pnd), nfc_device_get_connstring(pnd));
|
||||
|
||||
if (nfc_initiator_select_passive_target(pnd, nm, NULL, 0, &nt) > 0)
|
||||
{
|
||||
stcurrent = get_info(&nt, true);
|
||||
if(stcurrent)
|
||||
{
|
||||
printf("\n");
|
||||
|
||||
if(bIsBlock && (bIsRead || bIsWrite))
|
||||
{
|
||||
if(bIsRead)
|
||||
{
|
||||
get_block_at(pnd, blockNumber, NULL, 0, true);
|
||||
}
|
||||
|
||||
if(bIsWrite)
|
||||
{
|
||||
set_block_at_confirmed(pnd, blockNumber, data, cbData, true);
|
||||
}
|
||||
}
|
||||
else if(!bIsRead && !bIsWrite && !bIsBlock)
|
||||
{
|
||||
for(i = 0; i < stcurrent->nbNormalBlock; i++)
|
||||
{
|
||||
get_block_at(pnd, i, NULL, 0, true);
|
||||
}
|
||||
display_system_info(pnd, stcurrent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else printf("ERROR - nfc_initiator_init: %i\n", res);
|
||||
|
||||
nfc_close(pnd);
|
||||
}
|
||||
else printf("ERROR - nfc_open\n");
|
||||
|
||||
nfc_exit(context);
|
||||
}
|
||||
else printf("ERROR - nfc_init\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(
|
||||
"Usage:\n"
|
||||
" %s [-i]\n"
|
||||
" %s -b N -r\n"
|
||||
" %s -b N [-r] -w ABCD[EF01]\n %s -h\n"
|
||||
"Options:\n"
|
||||
" -i (default) information mode - will try to dump the tag content and display informations\n"
|
||||
" -b N specify block number to operate on (tag dependent), needed for read (-r) and write (-w) modes\n"
|
||||
" -r read mode - will try to read block (specified with -b N parameter)\n"
|
||||
" -w ABCD[EF01] write mode - will try to write specicied data (2 or 4 bytes depending on tag) to block (specified with -b N parameter)\n"
|
||||
" -h this help\n"
|
||||
"Examples:\n"
|
||||
" %s -i\n"
|
||||
" Display all tag informations\n"
|
||||
" %s -b 0x0e -r\n"
|
||||
" Read block 0x0e (14) of the tag\n"
|
||||
" %s -b 0x0d -w 0123abcd\n"
|
||||
" Write block 0x0d (13) of the tag with hexadecimal value '01 23 ab cd'\n"
|
||||
" %s -b 0x0c -r -w 0123abcd\n"
|
||||
" Read, then write block 0x0c (12) of the tag with hexadecimal value '01 23 ab cd'\n"
|
||||
"Warnings:\n"
|
||||
" Be careful with: system area, counters & otp, bytes order.\n"
|
||||
, argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
|
||||
{
|
||||
bool bRet = false;
|
||||
uint8_t tx[2] = {0x08, block}, rx[ST25TB_SR_BLOCK_MAX_SIZE]; // 4 is the maximum, SR176 (only 2) will fit
|
||||
int res;
|
||||
|
||||
res = nfc_initiator_transceive_bytes(pnd, tx, sizeof(tx), rx, sizeof(rx), 0);
|
||||
if((res == 2) || (res == 4))
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
if(cbData == res)
|
||||
{
|
||||
memcpy(data, rx, res);
|
||||
bRet = true;
|
||||
}
|
||||
else printf("ERROR - We got %i bytes for a %hhu buffer size?\n", res, cbData);
|
||||
}
|
||||
else bRet = true;
|
||||
|
||||
if(bPrintIt)
|
||||
{
|
||||
printf("[0x%02hhx] ", block);
|
||||
print_hex(rx, res);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
else if(res > 0)
|
||||
{
|
||||
printf("ERROR - We got %i bytes?\n", res);
|
||||
}
|
||||
else printf("ERROR - nfc_initiator_transceive_bytes(get): %i\n", res);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
|
||||
{
|
||||
bool bRet = false;
|
||||
uint8_t tx[2 + ST25TB_SR_BLOCK_MAX_SIZE] = {0x09, block}; // 4 is the maximum, SR176 (only 2) will fit
|
||||
int res;
|
||||
|
||||
if(cbData <= ST25TB_SR_BLOCK_MAX_SIZE)
|
||||
{
|
||||
memcpy(tx + 2, data, cbData);
|
||||
|
||||
if(bPrintIt)
|
||||
{
|
||||
printf(">0x%02hhx> ", block);
|
||||
print_hex(data, cbData);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
res = nfc_initiator_transceive_bytes(pnd, tx, 2 + cbData, NULL, 0, 0);
|
||||
if(res == NFC_ERFTRANS) // ? :')
|
||||
{
|
||||
bRet = true;
|
||||
}
|
||||
else printf("ERROR - nfc_initiator_transceive_bytes(set): %i\n", res);
|
||||
}
|
||||
else printf("ERROR - Wanted to write %hhu bytes, but maximum is %hhu\n", cbData, ST25TB_SR_BLOCK_MAX_SIZE);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
|
||||
{
|
||||
bool bRet = false;
|
||||
uint8_t buffer[ST25TB_SR_BLOCK_MAX_SIZE]; // maximum size will be checked in set_block_at
|
||||
|
||||
if(set_block_at(pnd, block, data, cbData, bPrintIt))
|
||||
{
|
||||
if(get_block_at(pnd, block, buffer, cbData, bPrintIt))
|
||||
{
|
||||
if(memcmp(data, buffer, cbData) == 0)
|
||||
{
|
||||
bRet = true;
|
||||
}
|
||||
else if(bPrintIt)
|
||||
{
|
||||
printf("WARNING - not same value readed after write\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
void get_info_st25tb512(uint8_t * systemArea)
|
||||
{
|
||||
uint8_t b, i;
|
||||
|
||||
b = ((*(uint32_t *) systemArea) >> 15) & 1;
|
||||
|
||||
printf(" | ST reserved : ");
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
|
||||
for(i = 16; i < 32; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n");
|
||||
for(i = 16; i < 32; i++)
|
||||
{
|
||||
if(!(((*(uint32_t *) systemArea) >> i) & 1))
|
||||
{
|
||||
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_info_st25tb2k_4k(uint8_t * systemArea)
|
||||
{
|
||||
uint8_t b, i;
|
||||
|
||||
b = ((*(uint32_t *) systemArea) >> 15) & 1;
|
||||
|
||||
printf(" | ST reserved : ");
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_RegU: ", b, b ? "not " : "");
|
||||
for(i = 16; i < 24; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n | OTP_Lock_Reg : ");
|
||||
for(i = 24; i < 32; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n");
|
||||
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
|
||||
{
|
||||
printf(" blocks 0x07 and 0x08 are write protected\n");
|
||||
}
|
||||
for(i = 25; i < 32; i++)
|
||||
{
|
||||
if(!(((*(uint32_t *) systemArea) >> i) & 1))
|
||||
{
|
||||
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_info_sr176_legacy(uint8_t * systemArea)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
printf(" | Fixed Chip_ID: 0x%1x\n | ST reserved : ", systemArea[0] & 0x0f);
|
||||
for(i = 4; i < 8; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n | OTP_Lock_Reg : ");
|
||||
for(i = 8; i < 16; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n");
|
||||
for(i = 8; i < 16; i++)
|
||||
{
|
||||
if(((*(uint16_t *) systemArea) >> i) & 1)
|
||||
{
|
||||
printf(" blocks 0x%02hhx and 0x%02hhx are write protected\n", (uint8_t) ((i - 8) * 2), (uint8_t) (((i - 8) * 2) + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_info_sri_srt_512_legacy(uint8_t * systemArea)
|
||||
{
|
||||
uint8_t b, i;
|
||||
|
||||
b = ((*(uint32_t *) systemArea) >> 15) & 1;
|
||||
|
||||
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
|
||||
for(i = 8; i < 15; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
|
||||
for(i = 16; i < 32; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n");
|
||||
for(i = 16; i < 32; i++)
|
||||
{
|
||||
if(!(((*(uint32_t *) systemArea) >> i) & 1))
|
||||
{
|
||||
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_info_sri2k_4k_srix4k_srix512_legacy(uint8_t * systemArea)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
|
||||
for(i = 8; i < 24; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n | OTP_Lock_Reg : ");
|
||||
for(i = 24; i < 32; i++)
|
||||
{
|
||||
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
|
||||
}
|
||||
printf("\n");
|
||||
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
|
||||
{
|
||||
printf(" blocks 0x07 and 0x08 are write protected\n");
|
||||
}
|
||||
for(i = 25; i < 32; i++)
|
||||
{
|
||||
if(!(((*(uint32_t *) systemArea) >> i) & 1))
|
||||
{
|
||||
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const st_data STRefs[] = {
|
||||
{0x1b, false, "ST25TB512-AC", "https://www.st.com/resource/en/datasheet/st25tb512-ac.pdf", 4, 16, 255, get_info_st25tb512},
|
||||
{0x33, false, "ST25TB512-AT", "https://www.st.com/resource/en/datasheet/st25tb512-at.pdf", 4, 16, 255, get_info_st25tb512},
|
||||
{0x3f, false, "ST25TB02K", "https://www.st.com/resource/en/datasheet/st25tb02k.pdf", 4, 64, 255, get_info_st25tb2k_4k},
|
||||
{0x1f, false, "ST25TB04K", "https://www.st.com/resource/en/datasheet/st25tb04k.pdf", 4, 128, 255, get_info_st25tb2k_4k},
|
||||
};
|
||||
const st_data STRefs_legacy[] = {
|
||||
{ 0, true, "SRI4K(s)", NULL, 4, 128, 255, NULL},
|
||||
{ 2, true, "SR176", "https://www.st.com/resource/en/datasheet/sr176.pdf", 2, 15, 15, get_info_sr176_legacy},
|
||||
{ 3, true, "SRIX4K", NULL, 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
|
||||
{ 4, true, "SRIX512", "https://www.st.com/resource/en/datasheet/srix512.pdf", 4, 16, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
|
||||
{ 6, true, "SRI512", "https://www.st.com/resource/en/datasheet/sri512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
|
||||
{ 7, true, "SRI4K", "https://www.st.com/resource/en/datasheet/sri4k.pdf", 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
|
||||
{12, true, "SRT512", "https://www.st.com/resource/en/datasheet/srt512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
|
||||
{15, true, "SRI2K", "https://www.st.com/resource/en/datasheet/sri2k.pdf", 4, 64, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
|
||||
};
|
||||
|
||||
const st_data * get_info(const nfc_target *pnt, bool bPrintIt)
|
||||
{
|
||||
const st_data *currentData = NULL;
|
||||
const uint8_t *p;
|
||||
uint8_t chipId, i;
|
||||
|
||||
if(pnt->nm.nmt == NMT_ISO14443B2SR)
|
||||
{
|
||||
printf("Target : %s (%s)\nUID : ", str_nfc_modulation_type(pnt->nm.nmt), str_nfc_baud_rate(pnt->nm.nbr));
|
||||
print_hex(pnt->nti.nsi.abtUID, sizeof(pnt->nti.nsi.abtUID));
|
||||
printf("\n");
|
||||
|
||||
p = pnt->nti.nsi.abtUID;
|
||||
if(p[7] == 0xd0) // ST25TB* / SR*
|
||||
{
|
||||
chipId = p[5];
|
||||
printf("Manuf : 0x%02hhx - %s\n", p[6], (p[6] == 0x02) ? "STMicroelectronics" : "other");
|
||||
|
||||
for(i = 0; i < (sizeof(STRefs) / sizeof(STRefs[0])); i++)
|
||||
{
|
||||
if(chipId == STRefs[i].chipId)
|
||||
{
|
||||
currentData = &STRefs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!currentData)
|
||||
{
|
||||
chipId >>= 2;
|
||||
for(i = 0; i < (sizeof(STRefs_legacy) / sizeof(STRefs_legacy[0])); i++)
|
||||
{
|
||||
if(chipId == STRefs_legacy[i].chipId)
|
||||
{
|
||||
currentData = &STRefs_legacy[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(bPrintIt && currentData)
|
||||
{
|
||||
printf("ChipId : 0x%02hhx - %s%s\nSerial : 0x", currentData->chipId, currentData->szName, currentData->bIsLegacy ? " (legacy)" : "");
|
||||
if(currentData->bIsLegacy)
|
||||
{
|
||||
printf("%1hhx", (uint8_t) (p[5] & 0x03));
|
||||
}
|
||||
printf("%02hhx%02hhx%02hhx%02hhx%02hhx\n|blk sz : %hhu bits\n|nb blks: %hhu\n|sys idx: %hhu\n", p[4], p[3], p[2], p[1], p[0], (uint8_t) (currentData->blockSize * 8), currentData->nbNormalBlock, currentData->bnSystem);
|
||||
}
|
||||
}
|
||||
else printf("WARNI - Last byte of UID isn\'t 0xd0, but 0x%02hhx (not ST25TB / SR series?)\n", p[7]);
|
||||
}
|
||||
else printf("ERROR - not a NMT_ISO14443B2SR ?\n");
|
||||
|
||||
return currentData;
|
||||
}
|
||||
|
||||
void display_system_info(nfc_device *pnd, const st_data * stdata)
|
||||
{
|
||||
uint8_t systemArea[ST25TB_SR_BLOCK_MAX_SIZE];
|
||||
|
||||
if(get_block_at(pnd, stdata->bnSystem, systemArea, stdata->blockSize, true))
|
||||
{
|
||||
if(stdata->pfnGetInfo)
|
||||
{
|
||||
stdata->pfnGetInfo(systemArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_hex(const uint8_t *pbtData, const size_t szBytes)
|
||||
{
|
||||
size_t szPos;
|
||||
for (szPos = 0; szPos < szBytes; szPos++)
|
||||
{
|
||||
printf("%02hhx ", pbtData[szPos]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* 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
|
||||
@ -234,6 +235,14 @@ typedef struct {
|
||||
uint8_t abtAtr[33];
|
||||
} nfc_iso14443bi_info;
|
||||
|
||||
/**
|
||||
* @struct nfc_iso14443biclass_info
|
||||
* @brief NFC ISO14443BiClass tag information
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t abtUID[8];
|
||||
} nfc_iso14443biclass_info;
|
||||
|
||||
/**
|
||||
* @struct nfc_iso14443b2sr_info
|
||||
* @brief NFC ISO14443-2B ST SRx tag information
|
||||
@ -282,8 +291,9 @@ typedef union {
|
||||
nfc_iso14443b2sr_info nsi;
|
||||
nfc_iso14443b2ct_info nci;
|
||||
nfc_jewel_info nji;
|
||||
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
|
||||
nfc_dep_info ndi;
|
||||
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
|
||||
nfc_iso14443biclass_info nhi; // hid iclass / picopass - nii already used
|
||||
} nfc_target_info;
|
||||
|
||||
/**
|
||||
@ -305,13 +315,15 @@ typedef enum {
|
||||
typedef enum {
|
||||
NMT_ISO14443A = 1,
|
||||
NMT_JEWEL,
|
||||
NMT_BARCODE, // Thinfilm NFC Barcode
|
||||
NMT_ISO14443B,
|
||||
NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
|
||||
NMT_ISO14443B2SR, // ISO14443-2B ST SRx
|
||||
NMT_ISO14443B2CT, // ISO14443-2B ASK CTx
|
||||
NMT_FELICA,
|
||||
NMT_DEP, // DEP should be kept last one as it's used as end-of-enum
|
||||
NMT_DEP,
|
||||
NMT_BARCODE, // Thinfilm NFC Barcode
|
||||
NMT_ISO14443BICLASS, // HID iClass 14443B mode
|
||||
NMT_END_ENUM = NMT_ISO14443BICLASS, // dummy for sizing - always should alias last
|
||||
} nfc_modulation_type;
|
||||
|
||||
/**
|
||||
|
||||
@ -5,6 +5,9 @@ IF(WIN32)
|
||||
|
||||
# Add in the rc for version information in the dll
|
||||
LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../windows/libnfc.rc)
|
||||
IF (NOT MINGW)
|
||||
LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc_msvc.def)
|
||||
ENDIF()
|
||||
ENDIF(WIN32)
|
||||
|
||||
# Library's chips
|
||||
@ -26,23 +29,23 @@ IF(UART_REQUIRED)
|
||||
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)
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
LIST(APPEND BUSES_SOURCES buses/i2c)
|
||||
ENDIF(WIN32)
|
||||
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
# Only Linux is supported at the moment
|
||||
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c)
|
||||
MESSAGE( FATAL_ERROR "I2C is only (yet) supported in Linux!" )
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
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)
|
||||
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
LIST(APPEND BUSES_SOURCES buses/spi)
|
||||
ENDIF(WIN32)
|
||||
ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
# Only Linux is supported at the moment
|
||||
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi)
|
||||
MESSAGE( FATAL_ERROR "SPI is only (yet) supported in Linux!" )
|
||||
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
ENDIF(SPI_REQUIRED)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
|
||||
@ -63,7 +66,9 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
IF(LIBNFC_LOG)
|
||||
IF(WIN32)
|
||||
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}")
|
||||
IF(MINGW)
|
||||
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}")
|
||||
ENDIF(MINGW)
|
||||
LIST(APPEND LIBRARY_SOURCES log ../contrib/win32/libnfc/log-internal)
|
||||
ELSE(WIN32)
|
||||
LIST(APPEND LIBRARY_SOURCES log log-internal)
|
||||
@ -83,18 +88,21 @@ IF(LIBRT_FOUND)
|
||||
TARGET_LINK_LIBRARIES(nfc ${LIBRT_LIBRARIES})
|
||||
ENDIF(LIBRT_FOUND)
|
||||
|
||||
SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 5 VERSION 5.0.1)
|
||||
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
|
||||
|
||||
@ -22,7 +22,7 @@ libnfc_la_SOURCES = \
|
||||
nfc-internal.h \
|
||||
target-subr.h
|
||||
|
||||
libnfc_la_LDFLAGS = -no-undefined -version-info 5:1:0 -export-symbols-regex '^nfc_|^iso14443a_|^iso14443b_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register'
|
||||
libnfc_la_LDFLAGS = -no-undefined -version-info 6:0:0 -export-symbols-regex '^nfc_|^iso14443a_|^iso14443b_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register'
|
||||
libnfc_la_CFLAGS = @DRIVERS_CFLAGS@
|
||||
libnfc_la_LIBADD = \
|
||||
$(top_builddir)/libnfc/chips/libnfcchips.la \
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
// Under POSIX system, we use libusb (>= 0.1.12)
|
||||
#include <stdint.h>
|
||||
#include <usb.h>
|
||||
#define USB_TIMEDOUT ETIMEDOUT
|
||||
#define _usb_strerror( X ) strerror(-X)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* 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
|
||||
@ -85,7 +86,7 @@ pn53x_init(struct nfc_device *pnd)
|
||||
}
|
||||
|
||||
if (!CHIP_DATA(pnd)->supported_modulation_as_initiator) {
|
||||
CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * (NMT_DEP + 1));
|
||||
CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * (NMT_END_ENUM + 1));
|
||||
if (! CHIP_DATA(pnd)->supported_modulation_as_initiator)
|
||||
return NFC_ESOFT;
|
||||
int nbSupportedModulation = 0;
|
||||
@ -104,6 +105,8 @@ pn53x_init(struct nfc_device *pnd)
|
||||
nbSupportedModulation++;
|
||||
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B2CT;
|
||||
nbSupportedModulation++;
|
||||
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443BICLASS;
|
||||
nbSupportedModulation++;
|
||||
}
|
||||
if (CHIP_DATA(pnd)->type != PN531) {
|
||||
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL;
|
||||
@ -575,6 +578,12 @@ pn53x_decode_target_data(const uint8_t *pbtRawData, size_t szRawData, pn53x_type
|
||||
memcpy(pnti->nsi.abtUID, pbtRawData, 8);
|
||||
break;
|
||||
|
||||
case NMT_ISO14443BICLASS:
|
||||
// Store the UID
|
||||
for (uint8_t i = 0 ; i < 8 ; ++i)
|
||||
pnti->nhi.abtUID[7 - i] = pbtRawData[i];
|
||||
break;
|
||||
|
||||
case NMT_ISO14443B2CT:
|
||||
// Store UID LSB
|
||||
memcpy(pnti->nci.abtUID, pbtRawData, 2);
|
||||
@ -1048,6 +1057,56 @@ pn53x_initiator_init(struct nfc_device *pnd)
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
// iclass requires special modulation settings
|
||||
void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd)
|
||||
{
|
||||
// send a bunch of low level commands reverse engineered from a working iClass reader
|
||||
// original device was using a PN512
|
||||
//
|
||||
// // TxModeReg - Defines the data rate and framing during transmission.
|
||||
//// set bit 4 for target mode? - RxWaitRF Set to logic 1, the counter for RxWait starts only if an external RF field is detected in Target mode for NFCIP-1 or in Card Communication mode
|
||||
//pn512_write_register(0x12, "\x03", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_TxMode, 0x03);
|
||||
//
|
||||
// // RxModeReg - Defines the data rate and framing during reception.
|
||||
//pn512_write_register(0x13, "\x03", 1, false);
|
||||
// addy changed to set bit 3 - RxNoErr (put data in fifo before flagging read end)
|
||||
//pn512_write_register(0x13, "\x0B", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_RxMode, 0x0B);
|
||||
|
||||
// ManualRCVReg - Allows manual fine tuning of the internal receiver.
|
||||
//pn512_write_register(0x1d, "\x10", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_ManualRCV, 0x10);
|
||||
|
||||
// RFCfgReg - Configures the receiver gain and RF level detector sensitivity.
|
||||
//pn512_write_register(0x26, "\x70", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_RFCfg, 0x70);
|
||||
|
||||
// GsNOffReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched off.
|
||||
//pn512_write_register(0x23, "\x88", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOFF, 0x88);
|
||||
|
||||
// GsNOnReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched on.
|
||||
//pn512_write_register(0x27, "\xf8", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOn, 0xf8);
|
||||
|
||||
// CWGsPReg - Defines the conductance of the P-driver during times of no modulation.
|
||||
//pn512_write_register(0x28, "\x3f", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_CWGsP, 0x3f);
|
||||
|
||||
// ModGsPReg - Defines the driver P-output conductance during modulation.
|
||||
//pn512_write_register(0x29, "\x10", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_ModGsP, 0x10);
|
||||
|
||||
// TReloadReg (MSB) - Describes the MSB of the 16-bit long timer reload value.
|
||||
//pn512_write_register(0x2c, "\x69", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_hi, 0x69);
|
||||
|
||||
// TReloadReg (LSB) - Describes the LSB of the 16-bit long timer reload value.
|
||||
//pn512_write_register(0x2d, "\xf0", 1, false);
|
||||
pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_lo, 0xf0);
|
||||
}
|
||||
|
||||
int
|
||||
pn532_initiator_init_secure_element(struct nfc_device *pnd)
|
||||
{
|
||||
@ -1067,7 +1126,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
nfc_target nttmp;
|
||||
memset(&nttmp, 0x00, sizeof(nfc_target));
|
||||
|
||||
if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT) {
|
||||
if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT || nm.nmt == NMT_ISO14443BICLASS) {
|
||||
if (CHIP_DATA(pnd)->type == RCS360) {
|
||||
// TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select
|
||||
pnd->last_error = NFC_ENOTIMPL;
|
||||
@ -1094,6 +1153,16 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
size_t szInitiateLen = 2;
|
||||
uint8_t abtSelect[] = { 0x0e, 0x00 };
|
||||
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
|
||||
@ -1106,9 +1175,18 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
return res;
|
||||
}
|
||||
szTargetsData = (size_t)res;
|
||||
if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) {
|
||||
if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
|
||||
continue;
|
||||
} else
|
||||
return res;
|
||||
}
|
||||
szTargetsData = (size_t)res;
|
||||
} else if (nm.nmt == NMT_ISO14443B2CT) {
|
||||
// Some work to do before getting the UID...
|
||||
const uint8_t abtReqt[] = { 0x10 };
|
||||
uint8_t *pbtInitData = (uint8_t *) "\x9F\xFF\xFF";
|
||||
size_t szInitData = 3;
|
||||
// Getting product code / fab code & store it in output buffer after the serial nr we'll obtain later
|
||||
if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), abtTargetsData + 2, sizeof(abtTargetsData) - 2, timeout)) < 0) {
|
||||
if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
|
||||
@ -1117,16 +1195,13 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
return res;
|
||||
}
|
||||
szTargetsData = (size_t)res;
|
||||
}
|
||||
|
||||
if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) {
|
||||
if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
|
||||
continue;
|
||||
} else
|
||||
return res;
|
||||
}
|
||||
szTargetsData = (size_t)res;
|
||||
if (nm.nmt == NMT_ISO14443B2CT) {
|
||||
if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) {
|
||||
if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
|
||||
continue;
|
||||
} else
|
||||
return res;
|
||||
}
|
||||
szTargetsData = (size_t)res;
|
||||
if (szTargetsData != 2)
|
||||
return 0; // Target is not ISO14443B2CT
|
||||
uint8_t abtRead[] = { 0xC4 }; // Reading UID_MSB (Read address 4)
|
||||
@ -1134,7 +1209,49 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
|
||||
return res;
|
||||
}
|
||||
szTargetsData = 6; // u16 UID_LSB, u8 prod code, u8 fab code, u16 UID_MSB
|
||||
} else if (nm.nmt == NMT_ISO14443BICLASS) {
|
||||
pn53x_initiator_init_iclass_modulation(pnd);
|
||||
//
|
||||
// Some work to do before getting the UID...
|
||||
// send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response
|
||||
uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL
|
||||
uint8_t abtAnticol[11];
|
||||
if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) {
|
||||
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;
|
||||
//} else
|
||||
// return res;
|
||||
}
|
||||
// do select - returned anticol contains 'handle' for tag if present
|
||||
abtReqt[0] = 0x0c; // iClass SELECT
|
||||
abtAnticol[0] = 0x81; // iClass ANTICOL
|
||||
if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout)) < 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol");
|
||||
return res;
|
||||
}
|
||||
// write back anticol handle to get UID
|
||||
if ((res = pn53x_initiator_transceive_bytes(pnd, abtAnticol, 9, abtTargetsData, 10, timeout)) < 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass get UID");
|
||||
return res;
|
||||
}
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "iClass raw UID: %02x %02x %02x %02x %02x %02x %02x %02x", abtTargetsData[0], abtTargetsData[1], abtTargetsData[2], abtTargetsData[3], abtTargetsData[4], abtTargetsData[5], abtTargetsData[6], abtTargetsData[7]);
|
||||
szTargetsData = 8;
|
||||
nttmp.nm = nm;
|
||||
if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) {
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
|
||||
if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) {
|
||||
if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
|
||||
continue;
|
||||
} else
|
||||
return res;
|
||||
}
|
||||
szTargetsData = (size_t)res;
|
||||
}
|
||||
|
||||
nttmp.nm = nm;
|
||||
if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) {
|
||||
return res;
|
||||
@ -1955,7 +2072,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);
|
||||
@ -2138,6 +2255,29 @@ static int pn53x_ISO14443B_SR_is_present(struct nfc_device *pnd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pn53x_ISO14443B_ICLASS_is_present(struct nfc_device *pnd)
|
||||
{
|
||||
int timeout = 300;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B iClass");
|
||||
pn53x_initiator_init_iclass_modulation(pnd);
|
||||
//
|
||||
// Some work to do before getting the UID...
|
||||
// send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response
|
||||
uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL
|
||||
uint8_t abtAnticol[11];
|
||||
if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all");
|
||||
}
|
||||
// do select - returned anticol contains 'handle' for tag if present
|
||||
abtReqt[0] = 0x0c; // iClass SELECT
|
||||
abtAnticol[0] = 0x81; // iClass ANTICOL
|
||||
if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout) < 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol");
|
||||
return NFC_ETGRELEASED;;
|
||||
}
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
static int pn53x_ISO14443B_CT_is_present(struct nfc_device *pnd)
|
||||
{
|
||||
int ret;
|
||||
@ -2218,6 +2358,9 @@ pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
|
||||
case NMT_ISO14443B2CT:
|
||||
ret = pn53x_ISO14443B_CT_is_present(pnd);
|
||||
break;
|
||||
case NMT_ISO14443BICLASS:
|
||||
ret = pn53x_ISO14443B_ICLASS_is_present(pnd);
|
||||
break;
|
||||
}
|
||||
if (ret == NFC_ETGRELEASED)
|
||||
pn53x_current_target_free(pnd);
|
||||
@ -2268,6 +2411,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
|
||||
case NMT_ISO14443BI:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_ISO14443BICLASS:
|
||||
case NMT_JEWEL:
|
||||
case NMT_BARCODE:
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
@ -2370,6 +2514,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
|
||||
case NMT_ISO14443BI:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_ISO14443BICLASS:
|
||||
case NMT_JEWEL:
|
||||
case NMT_BARCODE:
|
||||
pnd->last_error = NFC_EDEVNOTSUPP;
|
||||
@ -2518,13 +2663,15 @@ pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t
|
||||
return pnd->last_error;
|
||||
}
|
||||
}
|
||||
// NO BREAK
|
||||
abtCmd[0] = TgGetInitiatorCommand;
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
case NMT_BARCODE:
|
||||
case NMT_ISO14443B:
|
||||
case NMT_ISO14443BI:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_ISO14443BICLASS:
|
||||
case NMT_FELICA:
|
||||
abtCmd[0] = TgGetInitiatorCommand;
|
||||
break;
|
||||
@ -2624,13 +2771,15 @@ pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size
|
||||
return pnd->last_error;
|
||||
}
|
||||
}
|
||||
// NO BREAK
|
||||
abtCmd[0] = TgResponseToInitiator;
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
case NMT_BARCODE:
|
||||
case NMT_ISO14443B:
|
||||
case NMT_ISO14443BI:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_ISO14443BICLASS:
|
||||
case NMT_FELICA:
|
||||
abtCmd[0] = TgResponseToInitiator;
|
||||
break;
|
||||
@ -3253,6 +3402,7 @@ pn53x_nm_to_pm(const nfc_modulation nm)
|
||||
return PM_ISO14443A_106;
|
||||
|
||||
case NMT_ISO14443B:
|
||||
case NMT_ISO14443BICLASS:
|
||||
switch (nm.nbr) {
|
||||
case NBR_106:
|
||||
return PM_ISO14443B_106;
|
||||
@ -3351,6 +3501,7 @@ pn53x_nm_to_ptt(const nfc_modulation nm)
|
||||
// return PTT_ISO14443_4A_106;
|
||||
|
||||
case NMT_ISO14443B:
|
||||
case NMT_ISO14443BICLASS:
|
||||
switch (nm.nbr) {
|
||||
case NBR_106:
|
||||
return PTT_ISO14443_4B_106;
|
||||
@ -3436,6 +3587,7 @@ pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_mo
|
||||
case NMT_ISO14443BI:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_ISO14443BICLASS:
|
||||
*supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates;
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* 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
|
||||
@ -322,6 +323,7 @@ int pn53x_idle(struct nfc_device *pnd);
|
||||
|
||||
// NFC device as Initiator functions
|
||||
int pn53x_initiator_init(struct nfc_device *pnd);
|
||||
void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd);
|
||||
int pn532_initiator_init_secure_element(struct nfc_device *pnd);
|
||||
int pn53x_initiator_select_passive_target(struct nfc_device *pnd,
|
||||
const nfc_modulation nm,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,10 @@ libnfcdrivers_la_SOURCES =
|
||||
libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses
|
||||
libnfcdrivers_la_LIBADD =
|
||||
|
||||
if DRIVER_PCSC_ENABLED
|
||||
libnfcdrivers_la_SOURCES += pcsc.c pcsc.h
|
||||
endif
|
||||
|
||||
if DRIVER_ACR122_PCSC_ENABLED
|
||||
libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h
|
||||
endif
|
||||
@ -39,6 +43,11 @@ if DRIVER_PN532_I2C_ENABLED
|
||||
libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h
|
||||
endif
|
||||
|
||||
if DRIVER_PN71XX_ENABLED
|
||||
libnfcdrivers_la_LIBADD += @LIBNFC_NCI_LIBS@
|
||||
libnfcdrivers_la_SOURCES += pn71xx.c pn71xx.h
|
||||
endif
|
||||
|
||||
if PCSC_ENABLED
|
||||
libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@
|
||||
libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@
|
||||
|
||||
@ -93,7 +93,7 @@ const struct pn53x_io acr122_pcsc_io;
|
||||
// Prototypes
|
||||
char *acr122_pcsc_firmware(nfc_device *pnd);
|
||||
|
||||
const char *supported_devices[] = {
|
||||
static const char *supported_devices[] = {
|
||||
"ACS ACR122", // ACR122U & Touchatag, last version
|
||||
"ACS ACR 38U-CCID", // Touchatag, early version
|
||||
"ACS ACR38U-CCID", // Touchatag, early version, under MacOSX
|
||||
|
||||
@ -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"
|
||||
@ -331,7 +333,10 @@ acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const
|
||||
// acr122_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice));
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s Name %s", bus->dirname, dev->filename, acr122_usb_supported_devices[n].name);
|
||||
usb_close(udev);
|
||||
snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename);
|
||||
if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) {
|
||||
// truncation occurred, skipping that one
|
||||
continue;
|
||||
}
|
||||
device_found++;
|
||||
// Test if we reach the maximum "wanted" devices
|
||||
if (device_found == connstrings_len) {
|
||||
@ -427,12 +432,15 @@ acr122_usb_open(const nfc_context *context, const nfc_connstring connstring)
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
res = usb_set_altinterface(data.pudh, 0);
|
||||
if (res < 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set alternate setting on USB interface (%s)", _usb_strerror(res));
|
||||
usb_close(data.pudh);
|
||||
// we failed to use the specified device
|
||||
goto free_mem;
|
||||
// Check if there are more than 0 alternative interfaces and claim the first one
|
||||
if (dev->config->interface->altsetting->bAlternateSetting > 0) {
|
||||
res = usb_set_altinterface(data.pudh, 0);
|
||||
if (res < 0) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set alternate setting on USB interface (%s)", _usb_strerror(res));
|
||||
usb_close(data.pudh);
|
||||
// we failed to use the specified device
|
||||
goto free_mem;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for the device info and specification, fill it and return the info
|
||||
@ -590,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;
|
||||
@ -604,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) {
|
||||
@ -615,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);
|
||||
@ -630,6 +639,16 @@ 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");
|
||||
@ -658,7 +677,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;
|
||||
|
||||
@ -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);
|
||||
|
||||
1080
libnfc/drivers/pcsc.c
Normal file
1080
libnfc/drivers/pcsc.c
Normal file
File diff suppressed because it is too large
Load Diff
35
libnfc/drivers/pcsc.h
Normal file
35
libnfc/drivers/pcsc.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*-
|
||||
* Free/Libre Near Field Communication (NFC) library
|
||||
*
|
||||
* Libnfc historical contributors:
|
||||
* Copyright (C) 2019 Frank Morgner
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pcsc.h
|
||||
* @brief Driver for non-ACR122 devices (behind PC/SC daemon)
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_PCSC_H__
|
||||
#define __NFC_DRIVER_PCSC_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
extern const struct nfc_driver pcsc_driver;
|
||||
|
||||
#endif // ! __NFC_DRIVER_PCSC_H__
|
||||
@ -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"
|
||||
@ -132,13 +134,13 @@ struct pn53x_usb_supported_device {
|
||||
};
|
||||
|
||||
const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = {
|
||||
{ 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0, 0, 0 },
|
||||
{ 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x04, 0x84, 40 },
|
||||
{ 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x04, 0x84, 40 },
|
||||
{ 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 },
|
||||
{ 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0, 0, 0 },
|
||||
{ 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x04, 0x84, 40 },
|
||||
{ 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0, 0, 0 }
|
||||
{ 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40 },
|
||||
{ 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x84, 0x04, 0x40 },
|
||||
{ 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x84, 0x04, 0x40 },
|
||||
{ 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 }, // to check on real device
|
||||
{ 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40 },
|
||||
{ 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40 },
|
||||
{ 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0x84, 0x04, 0x40 }
|
||||
};
|
||||
|
||||
// PN533 USB descriptors backup buffers
|
||||
@ -337,7 +339,10 @@ pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const s
|
||||
// pn53x_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice));
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s", bus->dirname, dev->filename);
|
||||
usb_close(udev);
|
||||
snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename);
|
||||
if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) {
|
||||
// truncation occurred, skipping that one
|
||||
continue;
|
||||
}
|
||||
device_found++;
|
||||
// Test if we reach the maximum "wanted" devices
|
||||
if (device_found == connstrings_len) {
|
||||
@ -421,6 +426,11 @@ pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring)
|
||||
// Open the USB device
|
||||
if ((data.pudh = usb_open(dev)) == NULL)
|
||||
continue;
|
||||
|
||||
//To retrieve real USB endpoints configuration:
|
||||
//pn53x_usb_get_end_points(dev, &data);
|
||||
//printf("DEBUG ENDPOINTS In:0x%x Out:0x%x Size:0x%x\n", data.uiEndPointIn, data.uiEndPointOut, data.uiMaxPacketSize);
|
||||
|
||||
// Retrieve end points, using hardcoded defaults if available
|
||||
// or using the descriptors otherwise.
|
||||
if (pn53x_usb_get_end_points_default(dev, &data) == false) {
|
||||
@ -613,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;
|
||||
@ -809,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;
|
||||
|
||||
589
libnfc/drivers/pn71xx.c
Normal file
589
libnfc/drivers/pn71xx.c
Normal file
@ -0,0 +1,589 @@
|
||||
|
||||
/**
|
||||
* @file pn71xx.h
|
||||
* @brief Driver for PN71XX using libnfc-nci library
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include "pn71xx.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "drivers.h"
|
||||
#include "nfc-internal.h"
|
||||
|
||||
#include "linux_nfc_api.h"
|
||||
|
||||
#define PN71XX_DRIVER_NAME "pn71xx"
|
||||
|
||||
#define LOG_CATEGORY "libnfc.driver.pn71xx"
|
||||
#define LOG_GROUP NFC_LOG_GROUP_DRIVER
|
||||
|
||||
const nfc_modulation_type pn71xx_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0};
|
||||
const nfc_modulation_type pn71xx_supported_modulation_as_initiator[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0};
|
||||
|
||||
const nfc_baud_rate pn71xx_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
|
||||
const nfc_baud_rate pn71xx_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 };
|
||||
const nfc_baud_rate pn71xx_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 };
|
||||
const nfc_baud_rate pn71xx_jewel_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
|
||||
const nfc_baud_rate pn71xx_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
|
||||
|
||||
static nfcTagCallback_t TagCB;
|
||||
static nfc_tag_info_t *TagInfo = NULL;
|
||||
|
||||
static void onTagArrival(nfc_tag_info_t *pTagInfo);
|
||||
static void onTagDeparture(void);
|
||||
|
||||
/** ------------------------------------------------------------------------ */
|
||||
/** ------------------------------------------------------------------------ */
|
||||
/**
|
||||
* @brief Initialize libnfc_nci library to verify presence of PN71xx device.
|
||||
*
|
||||
* @param context NFC context.
|
||||
* @param connstrings array of 'nfc_connstring' buffer (allocated by caller). It is used to store the
|
||||
* connection info strings of devices found.
|
||||
* @param connstrings_len length of the connstrings array.
|
||||
* @return number of devices found.
|
||||
*/
|
||||
static size_t
|
||||
pn71xx_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
|
||||
{
|
||||
size_t device_found = 0;
|
||||
|
||||
if ((context == NULL) || (connstrings_len == 0)) return 0;
|
||||
|
||||
if (nfcManager_doInitialize() == 0) {
|
||||
nfc_connstring connstring = "pn71xx";
|
||||
memcpy(connstrings[device_found++], connstring, sizeof(nfc_connstring));
|
||||
}
|
||||
|
||||
return device_found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close connection to PN71xx by stopping the discovery loop and deinitializing the libnfc_nci library.
|
||||
*
|
||||
* @param pnd pointer on the device to close.
|
||||
*/
|
||||
static void
|
||||
pn71xx_close(nfc_device *pnd)
|
||||
{
|
||||
nfcManager_disableDiscovery();
|
||||
nfcManager_deregisterTagCallback();
|
||||
nfcManager_doDeinitialize();
|
||||
nfc_device_free(pnd);
|
||||
pnd = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open a connection to PN71xx, starting the discovery loop for tag detection.
|
||||
*
|
||||
* @param context NFC context.
|
||||
* @param connstring connection info to the device
|
||||
* @return pointer to the device, or NULL in case of error.
|
||||
*/
|
||||
static nfc_device *
|
||||
pn71xx_open(const nfc_context *context, const nfc_connstring connstring)
|
||||
{
|
||||
nfc_device *pnd;
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "open: %s", connstring);
|
||||
|
||||
pnd = nfc_device_new(context, connstring);
|
||||
if (!pnd) {
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pnd->driver = &pn71xx_driver;
|
||||
strcpy(pnd->name, "pn71xx-device");
|
||||
strcpy(pnd->connstring, connstring);
|
||||
|
||||
TagCB.onTagArrival = onTagArrival;
|
||||
TagCB.onTagDeparture = onTagDeparture;
|
||||
nfcManager_registerTagCallback(&TagCB);
|
||||
|
||||
nfcManager_enableDiscovery(DEFAULT_NFA_TECH_MASK, 1, 0, 0);
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "wait 1 seconds for polling");
|
||||
sleep(1);
|
||||
|
||||
return pnd;
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------ */
|
||||
/** ------------------------------------------------------------------------ */
|
||||
static bool IsTechnology(nfc_tag_info_t *TagInfo, nfc_modulation_type nmt)
|
||||
{
|
||||
switch (nmt) {
|
||||
case NMT_ISO14443A:
|
||||
if (TagInfo->technology == TARGET_TYPE_ISO14443_4
|
||||
|| TagInfo->technology == TARGET_TYPE_ISO14443_3A
|
||||
|| TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC
|
||||
|| TagInfo->technology == TARGET_TYPE_MIFARE_UL)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case NMT_ISO14443B:
|
||||
case NMT_ISO14443BI:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
if (TagInfo->technology == TARGET_TYPE_ISO14443_3B)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case NMT_FELICA:
|
||||
if (TagInfo->technology == TARGET_TYPE_FELICA)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case NMT_JEWEL:
|
||||
if (TagInfo->technology == TARGET_TYPE_ISO14443_3A
|
||||
&& TagInfo->protocol == NFA_PROTOCOL_T1T)
|
||||
return true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void BufferPrintBytes(char *buffer, unsigned int buflen, const uint8_t *data, unsigned int datalen)
|
||||
{
|
||||
int cx = 0;
|
||||
for (unsigned int i = 0x00; i < datalen; i++) {
|
||||
cx += snprintf(buffer + cx, buflen - cx, "%02X ", data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintTagInfo(nfc_tag_info_t *TagInfo)
|
||||
{
|
||||
switch (TagInfo->technology) {
|
||||
case TARGET_TYPE_UNKNOWN: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Unknown'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_ISO14443_3A: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3A'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_ISO14443_3B: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3B'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_ISO14443_4: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 4A'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_FELICA: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type F'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_ISO15693: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type V'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_NDEF: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type NDEF'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_NDEF_FORMATABLE: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Formatable'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_MIFARE_CLASSIC: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Classic'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_MIFARE_UL: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Ul'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_KOVIO_BARCODE: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Kovio Barcode'");
|
||||
}
|
||||
break;
|
||||
case TARGET_TYPE_ISO14443_3A_3B: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A/B'");
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type %d (Unknown or not supported)'\n", TagInfo->technology);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*32 is max UID len (Kovio tags)*/
|
||||
if ((0x00 != TagInfo->uid_length) && (32 >= TagInfo->uid_length)) {
|
||||
char buffer [100];
|
||||
int cx = 0;
|
||||
|
||||
if (4 == TagInfo->uid_length || 7 == TagInfo->uid_length || 10 == TagInfo->uid_length) {
|
||||
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID1 : \t'");
|
||||
} else if (8 == TagInfo->uid_length) {
|
||||
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID2 : \t'");
|
||||
} else {
|
||||
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "UID : \t'");
|
||||
}
|
||||
|
||||
BufferPrintBytes(buffer + cx, sizeof(buffer) - cx, (unsigned char *) TagInfo->uid, TagInfo->uid_length);
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s'", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------ */
|
||||
/** ------------------------------------------------------------------------ */
|
||||
|
||||
static void onTagArrival(nfc_tag_info_t *pTagInfo)
|
||||
{
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag found");
|
||||
|
||||
TagInfo = malloc(sizeof(nfc_tag_info_t));
|
||||
memcpy(TagInfo, pTagInfo, sizeof(nfc_tag_info_t));
|
||||
|
||||
PrintTagInfo(TagInfo);
|
||||
}
|
||||
|
||||
static void onTagDeparture(void)
|
||||
{
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag lost");
|
||||
|
||||
free(TagInfo);
|
||||
TagInfo = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_initiator_init(struct nfc_device *pnd)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_initiator_select_passive_target(struct nfc_device *pnd,
|
||||
const nfc_modulation nm,
|
||||
const uint8_t *pbtInitData, const size_t szInitData,
|
||||
nfc_target *pnt)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "select_passive_target");
|
||||
|
||||
if (TagInfo) {
|
||||
|
||||
nfc_target nttmp;
|
||||
memset(&nttmp, 0x00, sizeof(nfc_target));
|
||||
nttmp.nm = nm;
|
||||
|
||||
void *uidPtr = NULL;
|
||||
unsigned int maxLen = 0;
|
||||
|
||||
switch (nm.nmt) {
|
||||
case NMT_ISO14443A:
|
||||
if (IsTechnology(TagInfo, nm.nmt)) {
|
||||
maxLen = 10;
|
||||
uidPtr = nttmp.nti.nai.abtUid;
|
||||
|
||||
if (TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC) {
|
||||
nttmp.nti.nai.btSak = 0x08;
|
||||
} else {
|
||||
// make hardcoded desfire for freefare lib check
|
||||
nttmp.nti.nai.btSak = 0x20;
|
||||
nttmp.nti.nai.szAtsLen = 5;
|
||||
memcpy(nttmp.nti.nai.abtAts, "\x75\x77\x81\x02", 4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NMT_ISO14443B:
|
||||
if (IsTechnology(TagInfo, nm.nmt)) {
|
||||
maxLen = 4;
|
||||
uidPtr = nttmp.nti.nbi.abtPupi;
|
||||
}
|
||||
break;
|
||||
|
||||
case NMT_ISO14443BI:
|
||||
if (IsTechnology(TagInfo, nm.nmt)) {
|
||||
maxLen = 4;
|
||||
uidPtr = nttmp.nti.nii.abtDIV;
|
||||
}
|
||||
break;
|
||||
|
||||
case NMT_ISO14443B2SR:
|
||||
if (IsTechnology(TagInfo, nm.nmt)) {
|
||||
maxLen = 8;
|
||||
uidPtr = nttmp.nti.nsi.abtUID;
|
||||
}
|
||||
break;
|
||||
|
||||
case NMT_ISO14443B2CT:
|
||||
if (IsTechnology(TagInfo, nm.nmt)) {
|
||||
maxLen = 4;
|
||||
uidPtr = nttmp.nti.nci.abtUID;
|
||||
}
|
||||
break;
|
||||
|
||||
case NMT_FELICA:
|
||||
if (IsTechnology(TagInfo, nm.nmt)) {
|
||||
maxLen = 8;
|
||||
uidPtr = nttmp.nti.nfi.abtId;
|
||||
}
|
||||
break;
|
||||
|
||||
case NMT_JEWEL:
|
||||
if (IsTechnology(TagInfo, nm.nmt)) {
|
||||
maxLen = 4;
|
||||
uidPtr = nttmp.nti.nji.btId;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uidPtr && TagInfo->uid_length) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "target found");
|
||||
int len = TagInfo->uid_length > maxLen ? maxLen : TagInfo->uid_length;
|
||||
memcpy(uidPtr, TagInfo->uid, len);
|
||||
if (nm.nmt == NMT_ISO14443A)
|
||||
nttmp.nti.nai.szUidLen = len;
|
||||
|
||||
// Is a tag info struct available
|
||||
if (pnt) {
|
||||
memcpy(pnt, &nttmp, sizeof(nfc_target));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_initiator_deselect_target(struct nfc_device *pnd)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "deselect_passive_target");
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pn71xx_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx,
|
||||
const size_t szRx, int timeout)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "transceive_bytes timeout=%d", timeout);
|
||||
|
||||
if (!TagInfo) return NFC_EINVARG;
|
||||
|
||||
char buffer[500];
|
||||
BufferPrintBytes(buffer, sizeof(buffer), pbtTx, szTx);
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "===> %s", buffer);
|
||||
|
||||
int received = nfcTag_transceive(TagInfo->handle, (uint8_t *) pbtTx, szTx, pbtRx, szRx, 500);
|
||||
if (received <= 0)
|
||||
return NFC_EIO;
|
||||
|
||||
BufferPrintBytes(buffer, sizeof(buffer), pbtRx, received);
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "<=== %s", buffer);
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_initiator_poll_target(struct nfc_device *pnd,
|
||||
const nfc_modulation *pnmModulations, const size_t szModulations,
|
||||
const uint8_t uiPollNr, const uint8_t uiPeriod,
|
||||
nfc_target *pnt)
|
||||
{
|
||||
static int periodFactor = 150000;
|
||||
int period = uiPeriod * periodFactor;
|
||||
|
||||
if (pnd == NULL) return 0;
|
||||
|
||||
for (int j = 0; j < uiPollNr; j++) {
|
||||
for (unsigned int i = 0; i < szModulations; i++) {
|
||||
const nfc_modulation nm = pnmModulations[i];
|
||||
|
||||
nfc_target nt;
|
||||
int res = pn71xx_initiator_select_passive_target(pnd, nm, 0, 0, &nt);
|
||||
if (res > 0 && pnt) {
|
||||
memcpy(pnt, &nt, sizeof(nfc_target));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
usleep(period);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
|
||||
{
|
||||
if ((pnd == NULL) || (pnt == NULL)) return 1;
|
||||
return !TagInfo;
|
||||
}
|
||||
|
||||
|
||||
/** ------------------------------------------------------------------------ */
|
||||
/** ------------------------------------------------------------------------ */
|
||||
static int
|
||||
pn71xx_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
|
||||
switch (mode) {
|
||||
case N_TARGET:
|
||||
*supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_target;
|
||||
break;
|
||||
case N_INITIATOR:
|
||||
*supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_initiator;
|
||||
break;
|
||||
default:
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
if (mode) {}
|
||||
|
||||
switch (nmt) {
|
||||
case NMT_FELICA:
|
||||
*supported_br = (nfc_baud_rate *)pn71xx_felica_supported_baud_rates;
|
||||
break;
|
||||
case NMT_ISO14443A:
|
||||
*supported_br = (nfc_baud_rate *)pn71xx_iso14443a_supported_baud_rates;
|
||||
break;
|
||||
case NMT_ISO14443B:
|
||||
case NMT_ISO14443BI:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443B2CT:
|
||||
*supported_br = (nfc_baud_rate *)pn71xx_iso14443b_supported_baud_rates;
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
*supported_br = (nfc_baud_rate *)pn71xx_jewel_supported_baud_rates;
|
||||
break;
|
||||
case NMT_DEP:
|
||||
*supported_br = (nfc_baud_rate *)pn71xx_dep_supported_baud_rates;
|
||||
break;
|
||||
default:
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------ */
|
||||
/** ------------------------------------------------------------------------ */
|
||||
|
||||
static int
|
||||
pn71xx_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_get_information_about(nfc_device *pnd, char **pbuf)
|
||||
{
|
||||
static const char *info = "PN71XX nfc driver using libnfc-nci userspace library";
|
||||
size_t buflen = strlen(info) + 1;
|
||||
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
|
||||
*pbuf = malloc(buflen);
|
||||
memcpy(*pbuf, info, buflen);
|
||||
|
||||
return buflen;
|
||||
}
|
||||
/**
|
||||
* @brief Abort any pending operation
|
||||
*
|
||||
* @param pnd pointer on the NFC device.
|
||||
* @return NFC_SUCCESS
|
||||
*/
|
||||
static int
|
||||
pn71xx_abort_command(nfc_device *pnd)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "abort_command");
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_idle(struct nfc_device *pnd)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "idle");
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
pn71xx_PowerDown(struct nfc_device *pnd)
|
||||
{
|
||||
if (pnd == NULL) return NFC_EIO;
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "PowerDown");
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------ */
|
||||
/** ------------------------------------------------------------------------ */
|
||||
const struct nfc_driver pn71xx_driver = {
|
||||
.name = PN71XX_DRIVER_NAME,
|
||||
.scan_type = NOT_INTRUSIVE,
|
||||
.scan = pn71xx_scan,
|
||||
.open = pn71xx_open,
|
||||
.close = pn71xx_close,
|
||||
.strerror = NULL,
|
||||
|
||||
.initiator_init = pn71xx_initiator_init,
|
||||
.initiator_init_secure_element = NULL,
|
||||
.initiator_select_passive_target = pn71xx_initiator_select_passive_target,
|
||||
.initiator_poll_target = pn71xx_initiator_poll_target,
|
||||
.initiator_select_dep_target = NULL,
|
||||
.initiator_deselect_target = pn71xx_initiator_deselect_target,
|
||||
.initiator_transceive_bytes = pn71xx_initiator_transceive_bytes,
|
||||
.initiator_transceive_bits = NULL,
|
||||
.initiator_transceive_bytes_timed = NULL,
|
||||
.initiator_transceive_bits_timed = NULL,
|
||||
.initiator_target_is_present = pn71xx_initiator_target_is_present,
|
||||
|
||||
.target_init = NULL,
|
||||
.target_send_bytes = NULL,
|
||||
.target_receive_bytes = NULL,
|
||||
.target_send_bits = NULL,
|
||||
.target_receive_bits = NULL,
|
||||
|
||||
.device_set_property_bool = pn71xx_set_property_bool,
|
||||
.device_set_property_int = pn71xx_set_property_int,
|
||||
.get_supported_modulation = pn71xx_get_supported_modulation,
|
||||
.get_supported_baud_rate = pn71xx_get_supported_baud_rate,
|
||||
.device_get_information_about = pn71xx_get_information_about,
|
||||
|
||||
.abort_command = pn71xx_abort_command,
|
||||
.idle = pn71xx_idle,
|
||||
.powerdown = pn71xx_PowerDown,
|
||||
};
|
||||
|
||||
14
libnfc/drivers/pn71xx.h
Normal file
14
libnfc/drivers/pn71xx.h
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file pn71xx.h
|
||||
* @brief Driver for PN71XX using libnfc-nci library
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_PN71XX_H__
|
||||
#define __NFC_DRIVER_PN71XX_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
/* Reference to the driver structure */
|
||||
extern const struct nfc_driver pn71xx_driver;
|
||||
|
||||
#endif // ! __NFC_DRIVER_7120_H__
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* 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
|
||||
@ -169,37 +170,25 @@ void
|
||||
prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData)
|
||||
{
|
||||
switch (nm.nmt) {
|
||||
case NMT_ISO14443B: {
|
||||
case NMT_ISO14443B:
|
||||
// Application Family Identifier (AFI) must equals 0x00 in order to wakeup all ISO14443-B PICCs (see ISO/IEC 14443-3)
|
||||
*ppbtInitiatorData = (uint8_t *) "\x00";
|
||||
*pszInitiatorData = 1;
|
||||
}
|
||||
break;
|
||||
case NMT_ISO14443BI: {
|
||||
break;
|
||||
case NMT_ISO14443BI:
|
||||
// APGEN
|
||||
*ppbtInitiatorData = (uint8_t *) "\x01\x0b\x3f\x80";
|
||||
*pszInitiatorData = 4;
|
||||
}
|
||||
break;
|
||||
case NMT_ISO14443B2SR: {
|
||||
// Get_UID
|
||||
*ppbtInitiatorData = (uint8_t *) "\x0b";
|
||||
*pszInitiatorData = 1;
|
||||
}
|
||||
break;
|
||||
case NMT_ISO14443B2CT: {
|
||||
// SELECT-ALL
|
||||
*ppbtInitiatorData = (uint8_t *) "\x9F\xFF\xFF";
|
||||
*pszInitiatorData = 3;
|
||||
}
|
||||
break;
|
||||
case NMT_FELICA: {
|
||||
break;
|
||||
case NMT_FELICA:
|
||||
// polling payload must be present (see ISO/IEC 18092 11.2.2.5)
|
||||
*ppbtInitiatorData = (uint8_t *) "\x00\xff\xff\x01\x00";
|
||||
*pszInitiatorData = 5;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case NMT_ISO14443A:
|
||||
case NMT_ISO14443B2CT:
|
||||
case NMT_ISO14443B2SR:
|
||||
case NMT_ISO14443BICLASS:
|
||||
case NMT_JEWEL:
|
||||
case NMT_BARCODE:
|
||||
case NMT_DEP:
|
||||
|
||||
@ -34,7 +34,9 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <err.h>
|
||||
#if !defined(_MSC_VER)
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "nfc/nfc.h"
|
||||
|
||||
|
||||
56
libnfc/nfc.c
56
libnfc/nfc.c
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* 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
|
||||
@ -87,6 +88,10 @@
|
||||
#include "target-subr.h"
|
||||
#include "drivers.h"
|
||||
|
||||
#if defined (DRIVER_PCSC_ENABLED)
|
||||
# include "drivers/pcsc.h"
|
||||
#endif /* DRIVER_PCSC_ENABLED */
|
||||
|
||||
#if defined (DRIVER_ACR122_PCSC_ENABLED)
|
||||
# include "drivers/acr122_pcsc.h"
|
||||
#endif /* DRIVER_ACR122_PCSC_ENABLED */
|
||||
@ -119,6 +124,10 @@
|
||||
# include "drivers/pn532_i2c.h"
|
||||
#endif /* DRIVER_PN532_I2C_ENABLED */
|
||||
|
||||
#if defined (DRIVER_PN71XX_ENABLED)
|
||||
# include "drivers/pn71xx.h"
|
||||
#endif /* DRIVER_PN71XX_ENABLED */
|
||||
|
||||
|
||||
#define LOG_CATEGORY "libnfc.general"
|
||||
#define LOG_GROUP NFC_LOG_GROUP_GENERAL
|
||||
@ -130,12 +139,34 @@ struct nfc_driver_list {
|
||||
|
||||
const struct nfc_driver_list *nfc_drivers = NULL;
|
||||
|
||||
// descritions for debugging
|
||||
const char *nfc_property_name[] = {
|
||||
"NP_TIMEOUT_COMMAND",
|
||||
"NP_TIMEOUT_ATR",
|
||||
"NP_TIMEOUT_COM",
|
||||
"NP_HANDLE_CRC",
|
||||
"NP_HANDLE_PARITY",
|
||||
"NP_ACTIVATE_FIELD",
|
||||
"NP_ACTIVATE_CRYPTO1",
|
||||
"NP_INFINITE_SELECT",
|
||||
"NP_ACCEPT_INVALID_FRAMES",
|
||||
"NP_ACCEPT_MULTIPLE_FRAMES",
|
||||
"NP_AUTO_ISO14443_4",
|
||||
"NP_EASY_FRAMING",
|
||||
"NP_FORCE_ISO14443_A",
|
||||
"NP_FORCE_ISO14443_B",
|
||||
"NP_FORCE_SPEED_106"
|
||||
};
|
||||
|
||||
static void
|
||||
nfc_drivers_init(void)
|
||||
{
|
||||
#if defined (DRIVER_PN53X_USB_ENABLED)
|
||||
nfc_register_driver(&pn53x_usb_driver);
|
||||
#endif /* DRIVER_PN53X_USB_ENABLED */
|
||||
#if defined (DRIVER_PCSC_ENABLED)
|
||||
nfc_register_driver(&pcsc_driver);
|
||||
#endif /* DRIVER_ACR122_PCSC_ENABLED */
|
||||
#if defined (DRIVER_ACR122_PCSC_ENABLED)
|
||||
nfc_register_driver(&acr122_pcsc_driver);
|
||||
#endif /* DRIVER_ACR122_PCSC_ENABLED */
|
||||
@ -157,6 +188,9 @@ nfc_drivers_init(void)
|
||||
#if defined (DRIVER_ARYGON_ENABLED)
|
||||
nfc_register_driver(&arygon_driver);
|
||||
#endif /* DRIVER_ARYGON_ENABLED */
|
||||
#if defined (DRIVER_PN71XX_ENABLED)
|
||||
nfc_register_driver(&pn71xx_driver);
|
||||
#endif /* DRIVER_PN71XX_ENABLED */
|
||||
}
|
||||
|
||||
static int
|
||||
@ -172,8 +206,10 @@ nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_m
|
||||
int
|
||||
nfc_register_driver(const struct nfc_driver *ndr)
|
||||
{
|
||||
if (!ndr)
|
||||
if (!ndr) {
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_register_driver returning NFC_EINVARG");
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list));
|
||||
if (!pndl)
|
||||
@ -409,6 +445,7 @@ nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_
|
||||
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);
|
||||
}
|
||||
|
||||
@ -428,6 +465,7 @@ nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const
|
||||
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);
|
||||
}
|
||||
|
||||
@ -527,24 +565,30 @@ 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);
|
||||
uint8_t *abtTmpInit = malloc(sizeof(uint8_t) * maxAbt);
|
||||
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) {
|
||||
free(abtTmpInit);
|
||||
return res;
|
||||
}
|
||||
if (szInitData == 0) {
|
||||
// Provide default values, if any
|
||||
prepare_initiator_data(nm, &abtInit, &szInit);
|
||||
free(abtTmpInit);
|
||||
} else if (nm.nmt == NMT_ISO14443A) {
|
||||
abtInit = abtTmpInit;
|
||||
iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit);
|
||||
} else {
|
||||
abtInit = abtTmpInit;
|
||||
memcpy(abtInit, pbtInitData, szInitData);
|
||||
free(abtTmpInit);
|
||||
szInit = szInitData;
|
||||
}
|
||||
|
||||
HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
|
||||
|
||||
free(abtTmpInit);
|
||||
}
|
||||
|
||||
/** @ingroup initiator
|
||||
@ -1261,9 +1305,11 @@ nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_m
|
||||
if (nbr[j] == nm->nbr)
|
||||
return NFC_SUCCESS;
|
||||
}
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG");
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
}
|
||||
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG");
|
||||
return NFC_EINVARG;
|
||||
}
|
||||
|
||||
@ -1349,6 +1395,8 @@ str_nfc_modulation_type(const nfc_modulation_type nmt)
|
||||
return "ISO/IEC 14443-4B";
|
||||
case NMT_ISO14443BI:
|
||||
return "ISO/IEC 14443-4B'";
|
||||
case NMT_ISO14443BICLASS:
|
||||
return "ISO/IEC 14443-2B-3B iClass (Picopass)";
|
||||
case NMT_ISO14443B2CT:
|
||||
return "ISO/IEC 14443-2B ASK CTx";
|
||||
case NMT_ISO14443B2SR:
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* 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
|
||||
@ -503,7 +504,7 @@ snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, b
|
||||
{
|
||||
(void) verbose;
|
||||
int off = 0;
|
||||
off += snprintf(dst + off, size - off, " Size (bits): %lu\n", pnti->szDataLen * 8);
|
||||
off += snprintf(dst + off, size - off, " Size (bits): %lu\n", (unsigned long)(pnti->szDataLen * 8));
|
||||
off += snprintf(dst + off, size - off, " Content: ");
|
||||
for (uint8_t i = 0; i < pnti->szDataLen; i++) {
|
||||
off += snprintf(dst + off, size - off, "%02X", pnti->abtData[i]);
|
||||
@ -609,6 +610,15 @@ snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_inf
|
||||
snprint_hex(dst + off, size - off, pnsi->abtUID, 8);
|
||||
}
|
||||
|
||||
void
|
||||
snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
int off = 0;
|
||||
off += snprintf(dst + off, size - off, " UID: ");
|
||||
snprint_hex(dst + off, size - off, pnic->abtUID, 8);
|
||||
}
|
||||
|
||||
void
|
||||
snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose)
|
||||
{
|
||||
@ -668,6 +678,9 @@ snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose)
|
||||
case NMT_ISO14443B2SR:
|
||||
snprint_nfc_iso14443b2sr_info(dst + off, size - off, &pnt->nti.nsi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443BICLASS:
|
||||
snprint_nfc_iso14443biclass_info(dst + off, size - off, &pnt->nti.nhi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B2CT:
|
||||
snprint_nfc_iso14443b2ct_info(dst + off, size - off, &pnt->nti.nci, verbose);
|
||||
break;
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* 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
|
||||
@ -37,6 +38,7 @@ void snprint_nfc_iso14443a_info(char *dst, size_t size, const nfc_iso14443a_i
|
||||
void snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info *pnbi, bool verbose);
|
||||
void snprint_nfc_iso14443bi_info(char *dst, size_t size, const nfc_iso14443bi_info *pnii, bool verbose);
|
||||
void snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info *pnsi, bool verbose);
|
||||
void snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose);
|
||||
void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose);
|
||||
void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info *pnfi, bool verbose);
|
||||
void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose);
|
||||
|
||||
@ -4,7 +4,8 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
[
|
||||
AC_MSG_CHECKING(which drivers to build)
|
||||
AC_ARG_WITH(drivers,
|
||||
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_i2c', 'pn532_spi', 'pn532_uart' and 'pn53x_usb'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]),
|
||||
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pcsc', 'pn532_i2c', 'pn532_spi', 'pn532_uart', 'pn53x_usb' and 'pn71xx'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]),
|
||||
|
||||
[ case "${withval}" in
|
||||
yes | no)
|
||||
dnl ignore calls without any arguments
|
||||
@ -36,7 +37,8 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
fi
|
||||
;;
|
||||
all)
|
||||
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart"
|
||||
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart pcsc"
|
||||
|
||||
if test x"$spi_available" = x"yes"
|
||||
then
|
||||
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi"
|
||||
@ -45,11 +47,16 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
then
|
||||
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c"
|
||||
fi
|
||||
if test x"$nfc_nci_available" = x"yes"
|
||||
then
|
||||
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn71xx"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
DRIVERS_CFLAGS=""
|
||||
|
||||
driver_pcsc_enabled="no"
|
||||
driver_acr122_pcsc_enabled="no"
|
||||
driver_acr122_usb_enabled="no"
|
||||
driver_acr122s_enabled="no"
|
||||
@ -58,10 +65,16 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
driver_pn532_uart_enabled="no"
|
||||
driver_pn532_spi_enabled="no"
|
||||
driver_pn532_i2c_enabled="no"
|
||||
driver_pn71xx_enabled="no"
|
||||
|
||||
for driver in ${DRIVER_BUILD_LIST}
|
||||
do
|
||||
case "${driver}" in
|
||||
pcsc)
|
||||
pcsc_required="yes"
|
||||
driver_pcsc_enabled="yes"
|
||||
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PCSC_ENABLED"
|
||||
;;
|
||||
acr122_pcsc)
|
||||
pcsc_required="yes"
|
||||
driver_acr122_pcsc_enabled="yes"
|
||||
@ -102,6 +115,11 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
driver_pn532_i2c_enabled="yes"
|
||||
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED"
|
||||
;;
|
||||
pn71xx)
|
||||
nfc_nci_required="yes"
|
||||
driver_pn71xx_enabled="yes"
|
||||
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN71XX_ENABLED"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([Unknow driver: $driver])
|
||||
;;
|
||||
@ -109,6 +127,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
done
|
||||
AC_SUBST(DRIVERS_CFLAGS)
|
||||
AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_pcsc_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_PCSC_ENABLED, [test x"$driver_pcsc_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_ACR122_USB_ENABLED, [test x"$driver_acr122_usb_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_ACR122S_ENABLED, [test x"$driver_acr122s_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_PN53X_USB_ENABLED, [test x"$driver_pn53x_usb_enabled" = xyes])
|
||||
@ -116,11 +135,13 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
|
||||
AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_PN532_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes])
|
||||
AM_CONDITIONAL(DRIVER_PN71XX_ENABLED, [test x"$driver_pn71xx_enabled" = xyes])
|
||||
])
|
||||
|
||||
AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[
|
||||
echo
|
||||
echo "Selected drivers:"
|
||||
echo " pcsc............. $driver_pcsc_enabled"
|
||||
echo " acr122_pcsc...... $driver_acr122_pcsc_enabled"
|
||||
echo " acr122_usb....... $driver_acr122_usb_enabled"
|
||||
echo " acr122s.......... $driver_acr122s_enabled"
|
||||
@ -129,4 +150,5 @@ echo " pn53x_usb........ $driver_pn53x_usb_enabled"
|
||||
echo " pn532_uart....... $driver_pn532_uart_enabled"
|
||||
echo " pn532_spi....... $driver_pn532_spi_enabled"
|
||||
echo " pn532_i2c........ $driver_pn532_i2c_enabled"
|
||||
echo " pn71xx........... $driver_pn71xx_enabled"
|
||||
])
|
||||
|
||||
@ -23,7 +23,8 @@ 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)
|
||||
@ -41,6 +42,9 @@ FOREACH(source ${UTILS-SOURCES})
|
||||
LIST(APPEND TARGETS ../contrib/win32/stdlib)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32)
|
||||
ENDIF(${source} MATCHES "nfc-scan-device")
|
||||
IF(${source} MATCHES "nfc-read-forum-tag3")
|
||||
LIST(APPEND TARGETS ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/getopt.c)
|
||||
ENDIF()
|
||||
ENDIF(WIN32)
|
||||
|
||||
ADD_EXECUTABLE(${source} ${TARGETS})
|
||||
|
||||
@ -130,7 +130,9 @@ nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8
|
||||
|
||||
// When we have executed a read command, copy the received bytes into the param
|
||||
if (mc == MC_READ) {
|
||||
if (res == 16) {
|
||||
|
||||
//Check the length of response data, with PCSC reader, there have 2 bytes for SW value
|
||||
if (res == 16 || res == (16 + 2)) {
|
||||
memcpy(pmp->mpd.abtData, abtRx, 16);
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@ -27,6 +27,7 @@ This includes SAK decoding and fingerprinting is available.
|
||||
.TP
|
||||
\fB-t\fP \fIX\fP
|
||||
Polls only for types according to bitfield value of \fIX\fP:
|
||||
|
||||
1: ISO14443A
|
||||
2: Felica (212 kbps)
|
||||
4: Felica (424 kbps)
|
||||
@ -34,11 +35,12 @@ Polls only for types according to bitfield value of \fIX\fP:
|
||||
16: ISO14443B'
|
||||
32: ISO14443B-2 ST SRx
|
||||
64: ISO14443B-2 ASK CTx
|
||||
128: Jewel
|
||||
128: ISO14443B iClass
|
||||
256: ISO14443A-3 Jewel
|
||||
512: ISO14443A-2 NFC Barcode
|
||||
|
||||
So 255 (default) polls for all types.
|
||||
|
||||
Note that if 16, 32 or 64 then 8 is selected too.
|
||||
So 1023 (default) polls for all types.
|
||||
Note that if 16, 32, 64 or 128 then 8 is selected too.
|
||||
|
||||
.SH EXAMPLE
|
||||
For an ISO/IEC 14443-A tag (i.e.Mifare DESFire):
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2020 Adam Laurie
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@ -71,10 +72,11 @@ print_usage(const char *progname)
|
||||
printf("\t 16: ISO14443B'\n");
|
||||
printf("\t 32: ISO14443B-2 ST SRx\n");
|
||||
printf("\t 64: ISO14443B-2 ASK CTx\n");
|
||||
printf("\t 128: ISO14443A-3 Jewel\n");
|
||||
printf("\t 256: ISO14443A-2 NFC Barcode\n");
|
||||
printf("\tSo 511 (default) polls for all types.\n");
|
||||
printf("\tNote that if 16, 32 or 64 then 8 is selected too.\n");
|
||||
printf("\t 128: ISO14443B iClass\n");
|
||||
printf("\t 256: ISO14443A-3 Jewel\n");
|
||||
printf("\t 512: ISO14443A-2 NFC Barcode\n");
|
||||
printf("\tSo 1023 (default) polls for all types.\n");
|
||||
printf("\tNote that if 16, 32, 64 or 128 then 8 is selected too.\n");
|
||||
}
|
||||
|
||||
int
|
||||
@ -85,7 +87,7 @@ main(int argc, const char *argv[])
|
||||
size_t i;
|
||||
bool verbose = false;
|
||||
int res = 0;
|
||||
int mask = 0x1ff;
|
||||
int mask = 0x3ff;
|
||||
int arg;
|
||||
|
||||
nfc_context *context;
|
||||
@ -95,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")) {
|
||||
@ -109,13 +107,13 @@ main(int argc, const char *argv[])
|
||||
} else if ((0 == strcmp(argv[arg], "-t")) && (arg + 1 < argc)) {
|
||||
arg++;
|
||||
mask = atoi(argv[arg]);
|
||||
if ((mask < 1) || (mask > 0x1ff)) {
|
||||
if ((mask < 1) || (mask > 0x3ff)) {
|
||||
ERR("%i is invalid value for type bitfield.", mask);
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Force TypeB for all derivatives of B
|
||||
if (mask & 0x70)
|
||||
if (mask & 0xd0)
|
||||
mask |= 0x08;
|
||||
} else {
|
||||
ERR("%s is not supported option.", argv[arg]);
|
||||
@ -124,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);
|
||||
@ -272,6 +277,22 @@ main(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
if (mask & 0x80) {
|
||||
nm.nmt = NMT_ISO14443BICLASS;
|
||||
nm.nbr = NBR_106;
|
||||
// List ISO14443B iClass targets
|
||||
if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) {
|
||||
int n;
|
||||
if (verbose || (res > 0)) {
|
||||
printf("%d ISO14443B iClass passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_target(&ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & 0x100) {
|
||||
nm.nmt = NMT_JEWEL;
|
||||
nm.nbr = NBR_106;
|
||||
// List Jewel targets
|
||||
@ -287,7 +308,7 @@ main(int argc, const char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & 0x100) {
|
||||
if (mask & 0x200) {
|
||||
nm.nmt = NMT_BARCODE;
|
||||
nm.nbr = NBR_106;
|
||||
// List NFC Barcode targets
|
||||
@ -302,6 +323,7 @@ main(int argc, const char *argv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nfc_close(pnd);
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2011-2013 Adam Laurie
|
||||
* Copyright (C) 2018-2019 Danielle Bruneo
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@ -53,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"
|
||||
@ -69,7 +76,7 @@ static bool bUseKeyFile;
|
||||
static bool bForceKeyFile;
|
||||
static bool bTolerateFailures;
|
||||
static bool bFormatCard;
|
||||
static bool magic2 = false;
|
||||
static bool dWrite = false;
|
||||
static bool unlocked = false;
|
||||
static uint8_t uiBlocks;
|
||||
static uint8_t keys[] = {
|
||||
@ -208,10 +215,9 @@ authenticate(uint32_t uiBlock)
|
||||
// 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
|
||||
if (bFormatCard || !bUseKeyFile) {
|
||||
// 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++) {
|
||||
memcpy(mp.mpa.abtKey, keys + (key_index * 6), 6);
|
||||
if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) {
|
||||
@ -232,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) {
|
||||
@ -250,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");
|
||||
@ -260,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");
|
||||
@ -306,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,11 +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 {
|
||||
// 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;
|
||||
@ -386,31 +401,26 @@ 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;
|
||||
uint32_t uiWriteBlocks = 0;
|
||||
|
||||
//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);
|
||||
// Write the card from begin to end;
|
||||
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) {
|
||||
@ -423,60 +433,79 @@ write_card(int write_block_zero)
|
||||
fflush(stdout);
|
||||
|
||||
// Try to authenticate for the current sector
|
||||
if (!write_block_zero && !authenticate(uiBlock) && !bTolerateFailures) {
|
||||
printf("!\nError: authentication failed for block %02x\n", uiBlock);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_trailer_block(uiBlock)) {
|
||||
if (bFormatCard) {
|
||||
// Copy the default key and reset the access bits
|
||||
memcpy(mp.mpt.abtKeyA, default_key, sizeof(mp.mpt.abtKeyA));
|
||||
memcpy(mp.mpt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits));
|
||||
memcpy(mp.mpt.abtKeyB, default_key, sizeof(mp.mpt.abtKeyB));
|
||||
} else {
|
||||
// Copy the keys over from our key dump and store the retrieved access bits
|
||||
memcpy(mp.mpt.abtKeyA, mtDump.amb[uiBlock].mbt.abtKeyA, sizeof(mp.mpt.abtKeyA));
|
||||
memcpy(mp.mpt.abtAccessBits, mtDump.amb[uiBlock].mbt.abtAccessBits, sizeof(mp.mpt.abtAccessBits));
|
||||
memcpy(mp.mpt.abtKeyB, mtDump.amb[uiBlock].mbt.abtKeyB, sizeof(mp.mpt.abtKeyB));
|
||||
}
|
||||
|
||||
// Try to write the trailer
|
||||
if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) {
|
||||
printf("failed to write trailer block %d \n", uiBlock);
|
||||
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
|
||||
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 we are are writing to a chinese magic card, we've already unlocked
|
||||
// If we're writing to a direct write card, we need to authenticate
|
||||
// If we're writing something else, we'll need to authenticate
|
||||
if ((write_block_zero && dWrite) || !write_block_zero) {
|
||||
if (!authenticate(uiBlock) && !bTolerateFailures) {
|
||||
printf("!\nError: authentication failed for block %02x\n", uiBlock);
|
||||
return false;
|
||||
}
|
||||
if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp))
|
||||
bFailure = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_trailer_block(uiBlock)) {
|
||||
if (bFormatCard) {
|
||||
// Copy the default key and reset the access bits
|
||||
memcpy(mp.mpt.abtKeyA, default_key, sizeof(mp.mpt.abtKeyA));
|
||||
memcpy(mp.mpt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits));
|
||||
memcpy(mp.mpt.abtKeyB, default_key, sizeof(mp.mpt.abtKeyB));
|
||||
} else {
|
||||
// Copy the keys over from our key dump and store the retrieved access bits
|
||||
memcpy(mp.mpt.abtKeyA, mtDump.amb[uiBlock].mbt.abtKeyA, sizeof(mp.mpt.abtKeyA));
|
||||
memcpy(mp.mpt.abtAccessBits, mtDump.amb[uiBlock].mbt.abtAccessBits, sizeof(mp.mpt.abtAccessBits));
|
||||
memcpy(mp.mpt.abtKeyB, mtDump.amb[uiBlock].mbt.abtKeyB, sizeof(mp.mpt.abtKeyB));
|
||||
}
|
||||
|
||||
// Try to write the trailer
|
||||
if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) {
|
||||
printf("failed to write trailer block %d \n", uiBlock);
|
||||
bFailure = true;
|
||||
}
|
||||
} else {
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
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)
|
||||
if ((! bTolerateFailures) && bFailure)
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("|\n");
|
||||
printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
|
||||
fflush(stdout);
|
||||
@ -494,17 +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);
|
||||
@ -519,6 +555,7 @@ print_usage(const char *pcProgramName)
|
||||
printf(" %s r a U01ab23cd mycard.mfd\n\n", pcProgramName);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, const char *argv[])
|
||||
{
|
||||
@ -527,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]);
|
||||
@ -542,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') {
|
||||
@ -576,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);
|
||||
@ -615,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");
|
||||
@ -630,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");
|
||||
@ -643,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");
|
||||
}
|
||||
|
||||
@ -683,19 +757,16 @@ main(int argc, const char *argv[])
|
||||
// Testing RATS
|
||||
int res;
|
||||
if ((res = get_rats()) > 0) {
|
||||
printf("RATS support: yes\n");
|
||||
if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05)
|
||||
&& (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f)
|
||||
&& ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) {
|
||||
// MIFARE Plus 2K
|
||||
uiBlocks = 0x7f;
|
||||
}
|
||||
// Chinese magic emulation card, ATS=0978009102:dabc1910
|
||||
if ((res == 9) && (abtRx[5] == 0xda) && (abtRx[6] == 0xbc)
|
||||
&& (abtRx[7] == 0x19) && (abtRx[8] == 0x10)) {
|
||||
magic2 = true;
|
||||
}
|
||||
}
|
||||
printf("Guessing size: seems to be a %lu-byte card\n", (uiBlocks + 1) * sizeof(mifare_classic_block));
|
||||
} 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 (bUseKeyFile) {
|
||||
FILE *pfKeys = fopen(argv[5], "rb");
|
||||
@ -751,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);
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2013-2018 Adam Laurie
|
||||
* Copyright (C) 2018-2019 Daniele Bruneo
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@ -290,50 +291,46 @@ unlock_card(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_magic()
|
||||
static bool check_magic(void)
|
||||
{
|
||||
bool bFailure = false;
|
||||
int uid_data;
|
||||
|
||||
for (uint32_t page = 0; page <= 1; page++) {
|
||||
// Show if the readout went well
|
||||
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) {
|
||||
ERR("tag was removed");
|
||||
return false;
|
||||
}
|
||||
bFailure = false;
|
||||
}
|
||||
|
||||
uid_data = 0x00000000;
|
||||
|
||||
memcpy(mp.mpd.abtData, &uid_data, sizeof uid_data);
|
||||
memset(mp.mpd.abtData + 4, 0, 12);
|
||||
|
||||
//Force the write without checking for errors - otherwise the writes to the sector 0 seem to complain
|
||||
nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp);
|
||||
}
|
||||
|
||||
//Check that the ID is now set to 0x000000000000
|
||||
bool directWrite = true;
|
||||
// Try to read pages 0, 1, 2
|
||||
uint8_t original_b0[12];
|
||||
printf("Checking if UL badge is DirectWrite...\n");
|
||||
if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) {
|
||||
//printf("%u", mp.mpd.abtData);
|
||||
bool result = true;
|
||||
for (int i = 0; i <= 7; i++) {
|
||||
if (mp.mpd.abtData[i] != 0x00) result = false;
|
||||
memcpy(original_b0, mp.mpd.abtData, 12);
|
||||
printf(" Original Block 0 (Pages 0-2): ");
|
||||
for (int i = 0; i < 12; i++) {
|
||||
printf("%02x", original_b0[i]);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf(" Original UID: %02x%02x%02x%02x%02x%02x%02x\n",
|
||||
original_b0[0], original_b0[1], original_b0[2], original_b0[4], original_b0[5], original_b0[6], original_b0[7]);
|
||||
} else {
|
||||
printf("!\nError: unable to read block 0x%02x\n", 0);
|
||||
directWrite = false;
|
||||
}
|
||||
|
||||
//Initially check if we can unlock via the MF method
|
||||
if (unlock_card()) {
|
||||
printf(" Attempt to write Block 0 (pages 0-2) ...\n");
|
||||
for (uint32_t page = 0; page <= 2; page++) {
|
||||
printf(" Writing Page %i:", page);
|
||||
memcpy(mp.mpd.abtData, original_b0 + page * 4, 4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
printf(" %02x", mp.mpd.abtData[i]);
|
||||
}
|
||||
printf("\n");
|
||||
if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp)) {
|
||||
printf(" Failure writing Page %i\n", page);
|
||||
directWrite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (directWrite) {
|
||||
printf(" Block 0 written successfully\n");
|
||||
printf("Card is DirectWrite\n");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
printf("Card is not DirectWrite\n");
|
||||
return unlock_card();
|
||||
}
|
||||
|
||||
}
|
||||
@ -383,9 +380,9 @@ write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid)
|
||||
write_uid = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
|
||||
}
|
||||
|
||||
printf("Writing %d pages |", uiBlocks);
|
||||
/* We may need to skip 2 first pages. */
|
||||
if (!write_uid) {
|
||||
printf("Writing %d pages |", uiBlocks);
|
||||
printf("ss");
|
||||
uiSkippedPages = 2;
|
||||
} else {
|
||||
@ -393,6 +390,7 @@ write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid)
|
||||
printf("\nUnable to unlock card - are you sure the card is magic?\n");
|
||||
return false;
|
||||
}
|
||||
printf("Writing %d pages |", uiBlocks);
|
||||
}
|
||||
|
||||
for (uint32_t page = uiSkippedPages; page < uiBlocks; page++) {
|
||||
@ -409,9 +407,9 @@ write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid)
|
||||
}
|
||||
// NTAG and MF0UL21 have Dynamic Lock Bytes
|
||||
if (((iEV1Type == EV1_UL21 && page == 0x24) || \
|
||||
(iNTAGType == NTAG_213 && page == 0x28) || \
|
||||
(iNTAGType == NTAG_215 && page == 0x82) || \
|
||||
(iNTAGType == NTAG_216 && page == 0xe2)) && (!write_dyn_lock)) {
|
||||
(iNTAGType == NTAG_213 && page == 0x28) || \
|
||||
(iNTAGType == NTAG_215 && page == 0x82) || \
|
||||
(iNTAGType == NTAG_216 && page == 0xe2)) && (!write_dyn_lock)) {
|
||||
printf("s");
|
||||
uiSkippedPages++;
|
||||
continue;
|
||||
@ -527,7 +525,7 @@ main(int argc, const char *argv[])
|
||||
bool bFilename = false;
|
||||
FILE *pfDump;
|
||||
|
||||
if (argc < 3) {
|
||||
if (argc == 0) {
|
||||
print_usage(argv);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -580,7 +578,7 @@ main(int argc, const char *argv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! bFilename) {
|
||||
if (iAction != 3 && !bFilename) {
|
||||
ERR("Please supply a Mifare Dump filename");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -650,14 +648,14 @@ main(int argc, const char *argv[])
|
||||
if (get_ev1_version()) {
|
||||
if (!bPWD)
|
||||
printf("WARNING: Tag is EV1 or NTAG - PASSWORD may be required\n");
|
||||
if (abtRx[6] == 0x0b) {
|
||||
if (abtRx[6] == 0x0b || abtRx[6] == 0x00) {
|
||||
printf("EV1 type: MF0UL11 (48 bytes)\n");
|
||||
uiBlocks = 20; // total number of 4 byte 'pages'
|
||||
iDumpSize = uiBlocks * 4;
|
||||
iEV1Type = EV1_UL11;
|
||||
} else if (abtRx[6] == 0x0e) {
|
||||
printf("EV1 type: MF0UL21 (128 user bytes)\n");
|
||||
uiBlocks = 41;
|
||||
uiBlocks = 41;
|
||||
iDumpSize = uiBlocks * 4;
|
||||
iEV1Type = EV1_UL21;
|
||||
} else if (abtRx[6] == 0x0f) {
|
||||
@ -714,7 +712,7 @@ main(int argc, const char *argv[])
|
||||
|
||||
size_t szDump;
|
||||
if (((szDump = fread(&mtDump, 1, sizeof(mtDump), pfDump)) != iDumpSize && !bPart) || szDump <= 0) {
|
||||
ERR("Could not read from dump file or size mismatch: %s (read %lu, expected %lu)\n", argv[2], szDump, iDumpSize);
|
||||
ERR("Could not read from dump file or size mismatch: %s (read %lu, expected %lu)\n", argv[2], (unsigned long)szDump, (unsigned long)iDumpSize);
|
||||
fclose(pfDump);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -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