pax_global_header00006660000000000000000000000064123026567110014515gustar00rootroot0000000000000052 comment=2d4543673e9b76c02679ca8b89259659f1afd932 libnfc-1.7.1/000077500000000000000000000000001230265671100127605ustar00rootroot00000000000000libnfc-1.7.1/.gitignore000066400000000000000000000041001230265671100147430ustar00rootroot00000000000000*~ Doxyfile INSTALL Makefile Makefile.in aclocal.m4 ar-lib autom4te.cache/ build cmake/Makefile cmake/Makefile.in cmake/modules/Makefile cmake/modules/Makefile.in config.guess config.h config.h.in config.log config.status config.sub configure contrib/Makefile contrib/Makefile.in contrib/devd/Makefile contrib/devd/Makefile.in contrib/udev/Makefile contrib/udev/Makefile.in contrib/win32/Makefile contrib/win32/Makefile.in contrib/win32/sys/Makefile contrib/win32/sys/Makefile.in debian/ depcomp examples/*.o examples/.deps/ examples/.libs/ examples/Makefile examples/Makefile.in examples/doc/.deps/ examples/nfc-anticol examples/nfc-dep-initiator examples/nfc-dep-target examples/nfc-emulate-forum-tag2 examples/nfc-emulate-tag examples/nfc-emulate-uid examples/nfc-mfsetuid examples/nfc-poll examples/nfc-relay examples/pn53x-diagnose examples/pn53x-sam examples/pn53x-tamashell examples/pn53x-tamashell-scripts/Makefile examples/pn53x-tamashell-scripts/Makefile.in examples/quick_start_example1 examples/quick_start_example2 include/Makefile include/Makefile.in include/nfc/Makefile include/nfc/Makefile.in install-sh libnfc.pc libnfc/*.lo libnfc/*.o libnfc/.deps/ libnfc/.libs/ libnfc/Makefile libnfc/Makefile.in libnfc/buses/*.la libnfc/buses/*.lo libnfc/buses/*.o libnfc/buses/.deps/ libnfc/buses/.libs/ libnfc/buses/Makefile libnfc/buses/Makefile.in libnfc/chips/*.la libnfc/chips/*.lo libnfc/chips/*.o libnfc/chips/.deps/ libnfc/chips/.libs/ libnfc/chips/Makefile libnfc/chips/Makefile.in libnfc/drivers/*.la libnfc/drivers/*.lo libnfc/drivers/*.o libnfc/drivers/.deps/ libnfc/drivers/.libs/ libnfc/drivers/Makefile libnfc/drivers/Makefile.in libnfc/libnfc.la libtool ltmain.sh m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 missing stamp-h1 test/*.la test/*.lo test/*.o test/.deps/ test/.libs/ test/Makefile test/Makefile.in utils/*.la utils/*.lo utils/*.o utils/.deps/ utils/.libs/ utils/Makefile utils/Makefile.in utils/nfc-emulate-forum-tag4 utils/nfc-list utils/nfc-mfclassic utils/nfc-mfultralight utils/nfc-read-forum-tag3 utils/nfc-relay-picc utils/nfc-scan-device libnfc-1.7.1/AUTHORS000066400000000000000000000016041230265671100140310ustar00rootroot00000000000000# Alphabetical cleaned output of "git shortlog -s -e|cut -c 8-" : Adam Laurie Ahti Legonkov Alex Lian Anugrah Redja Kusuma Audrey Diacre Emanuele Bertoldi Eugeny Boger Francois Kooman Jiapeng Li Julien Schueller Laurent Latil Ludovic Rousseau Marcello Morena Mike Auty Nobuhiro Iwamatsu Peter Meerwald Philippe Teuwen Pim 't Hart Roel Verdult Romain Tartiere Romuald Conty lego libnfc-1.7.1/CMakeLists.txt000066400000000000000000000151161230265671100155240ustar00rootroot00000000000000PROJECT(libnfc C) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) SET(VERSION_MAJOR "1") SET(VERSION_MINOR "7") SET(VERSION_PATCH "1") SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") SET(PACKAGE_NAME "libnfc") SET(PACKAGE_VERSION ${VERSION}) 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") INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32) 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) ENDIF(WIN32) ADD_DEFINITIONS("-DHAVE_CONFIG_H") INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) # make it easy to locate CMake modules for finding libraries SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/") # Options SET(LIBNFC_LOG ON CACHE BOOL "Enable log facility (errors, warning, info and debug messages)") IF(LIBNFC_LOG) ADD_DEFINITIONS(-DLOG) ENDIF(LIBNFC_LOG) SET(LIBNFC_ENVVARS ON CACHE BOOL "Enable envvars facility") IF(LIBNFC_ENVVARS) ADD_DEFINITIONS(-DENVVARS) ENDIF(LIBNFC_ENVVARS) SET(LIBNFC_DEBUG_MODE OFF CACHE BOOL "Debug mode") IF(LIBNFC_DEBUG_MODE) ADD_DEFINITIONS(-DDEBUG) SET(CMAKE_C_FLAGS "-g3 ${CMAKE_C_FLAGS}") SET(WIN32_MODE "debug") SET(CMAKE_RC_FLAGS "-D_DEBUG ${CMAKE_RC_FLAGS}") ELSE(LIBNFC_DEBUG_MODE) SET(WIN32_MODE "release") ENDIF(LIBNFC_DEBUG_MODE) SET(LIBNFC_CONFFILES_MODE ON CACHE BOOL "Enable configuration files") IF(LIBNFC_CONFFILES_MODE) ADD_DEFINITIONS(-DCONFFILES) ENDIF(LIBNFC_CONFFILES_MODE) # Doxygen SET(builddir "${CMAKE_BINARY_DIR}") SET(top_srcdir "${CMAKE_SOURCE_DIR}") INCLUDE(UseDoxygen) IF(DEFINED CMAKE_INSTALL_LIBDIR) SET(libdir ${CMAKE_INSTALL_LIBDIR}) ELSE(DEFINED CMAKE_INSTALL_LIBDIR) SET(CMAKE_INSTALL_LIBDIR lib) SET(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) ENDIF(DEFINED CMAKE_INSTALL_LIBDIR) IF(DEFINED INCLUDE_INSTALL_DIR) SET(includedir ${INCLUDE_INSTALL_DIR}) ELSE(DEFINED INCLUDE_INSTALL_DIR) SET(INCLUDE_INSTALL_DIR include) SET(includedir ${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}) ENDIF(DEFINED INCLUDE_INSTALL_DIR) IF(NOT DEFINED SHARE_INSTALL_PREFIX) SET(SHARE_INSTALL_PREFIX share) ENDIF(NOT DEFINED SHARE_INSTALL_PREFIX) # Additonnal GCC flags IF(CMAKE_COMPILER_IS_GNUCC) # Make sure we will not miss some warnings ;) SET(CMAKE_C_FLAGS "-Wall -pedantic -std=c99 ${CMAKE_C_FLAGS}") ENDIF(CMAKE_COMPILER_IS_GNUCC) # Workarounds for libusb in C99 ADD_DEFINITIONS(-Du_int8_t=uint8_t -Du_int16_t=uint16_t) IF(MINGW) # force MinGW-w64 in 32bit mode SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}") SET(CMAKE_MODULE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") SET(CMAKE_SHARED_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") SET(CMAKE_EXE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}") SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}") ENDIF(MINGW) IF(NOT WIN32) # Set some pkg-config variables SET(prefix ${CMAKE_INSTALL_PREFIX}) SET(exec_prefix ${CMAKE_INSTALL_PREFIX}) SET(PACKAGE "libnfc") IF(LIBNFC_DRIVER_PN53X_USB) SET(PKG_REQ ${PKG_REQ} "libusb") ENDIF(LIBNFC_DRIVER_PN53X_USB) IF(LIBNFC_DRIVER_ACR122) SET(PKG_REQ ${PKG_REQ} "libpcsclite") ENDIF(LIBNFC_DRIVER_ACR122) # 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) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) ENDIF(NOT WIN32) # Require PCRE for Win32 IF (WIN32) FIND_PACKAGE(PCRE REQUIRED) IF(PCRE_INCLUDE_DIRS) INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIRS}) LINK_DIRECTORIES(${PCRE_LIBRARY_DIRS}) ENDIF(PCRE_INCLUDE_DIRS) ENDIF(WIN32) INCLUDE(LibnfcDrivers) IF(PCSC_INCLUDE_DIRS) INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS}) LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS}) ENDIF(PCSC_INCLUDE_DIRS) IF(LIBUSB_INCLUDE_DIRS) INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS}) LINK_DIRECTORIES(${LIBUSB_LIBRARY_DIRS}) SET(LIBUSB_FOUND TRUE) ENDIF(LIBUSB_INCLUDE_DIRS) # version.rc for Windows IF(WIN32) # Date for filling in rc file information MACRO (GET_CURRENT_YEAR RESULT) EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT}) STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}}) STRING(REGEX REPLACE ".*(..)/(..)/(....).*" "\\3" ${RESULT} ${${RESULT}}) ENDMACRO (GET_CURRENT_YEAR) GET_CURRENT_YEAR(CURRENT_YEAR) MESSAGE("Year for copyright is " ${CURRENT_YEAR}) 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) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY) ENDIF(WIN32) ADD_SUBDIRECTORY(libnfc) ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(utils) ADD_SUBDIRECTORY(examples) # Binary Package IF(WIN32) SET(CPACK_GENERATOR "ZIP") ELSE(WIN32) SET(CPACK_GENERATOR "TBZ2") ENDIF(WIN32) SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Near Field Communication (NFC) library") SET(CPACK_PACKAGE_VENDOR "Roel Verdult") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") SET(CPACK_PACKAGE_INSTALL_DIRECTORY "libnfc") SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH}) SET(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "NFC Library") SET(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example Applications") SET(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "Development Headers") IF(NOT WIN32) SET(CPACK_COMPONENT_MANUALS_DISPLAY_NAME "Example Applications Manuals") SET(CPACK_COMPONENT_MANUALS_DISABLED TRUE) SET(CPACK_COMPONENT_MANUALS_DEPENDS examples) ENDIF(NOT WIN32) SET(CPACK_COMPONENT_HEADERS_DISABLED TRUE) SET(CPACK_COMPONENT_HEADERS_DEPENDS libraries) SET(CPACK_COMPONENT_EXAMPLES_DEPENDS libraries) # Source Package IF(WIN32) SET(CPACK_SOURCE_GENERATOR "ZIP") ELSE(WIN32) SET(CPACK_SOURCE_GENERATOR "ZIP;TBZ2") ENDIF(WIN32) SET(CPACK_SOURCE_PACKAGE_FILE_NAME "libnfc-${VERSION}") SET(CPACK_SOURCE_IGNORE_FILES "~$" "/\\\\.git/" "bin/") INCLUDE(CPack) libnfc-1.7.1/COPYING000066400000000000000000000167251230265671100140260ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. libnfc-1.7.1/ChangeLog000066400000000000000000001052431230265671100145370ustar00rootroot00000000000000Feb 24, 2014 - 1.7.1 ------------------ Fixes: - Fix several issues reported by Coverity Scan (mem leaks, buff overflows, reuse after free, etc) - More robust when several conflicting uart drivers are in the config - Fix racing condition with uart_flush_input() - Silent pn53x_check_communication error messages when scanning - Fix nfc_target_init(), was returning success in case of timeout - Windows: fix several compilation issues - On tag selection, save current target info also for ISO14443B* - nfc-read-forum-tag3: fix incomplete NDEF retrieval and size of output file Improvements: - nfc-list: New option to choose which technologies to poll for - UART: drivers now supported under kFreeBSD - New LIBNFC_DEVICE env var to use one reader and exclude all other readers while LIBNFC_DEFAULT_DEVICE only prepends it to the configured devices list - New LIBNFC_AUTO_SCAN env var to enable(default)/disable auto scan - On tag selection, save current target info even if pnt=NULL - On tag selection, grant NP_INFINITE_SELECT also for ISO14443B* - Save & restore NP_INFINITE_SELECT status when changing it internally - nfc-mfclassic: add format/wipe command (thanks to Adam Laurie) - nfc-jewel: new utility to read/write Topaz/Jewel tags (thanks to Pim 't Hart) - nfc_initiator_select_passive_target() provides defaults if pbtInitData=NULL - nfc-read-forum-tag3: add -q option, add full parsing of NDEF Attribute Block Fixes & improvements specific to nfc_initiator_target_is_present(): - Supports fully PN532 & PN533, not tested on other chips - Fix usage after nfc_initiator_poll_target() - Set correctly last_error - Fix issue when there was no saved target - Allow NULL pointer to tag - Fix issues in case of tear off conditions - Now works with: * MFUL, MFC, MFC Mini, MFC 7-byte (re-selection: you'll need to auth again) * ISO14443-4A, ISO14443-4B * ISO14443-4B', ASK CTx, ST SRx * Jewel * FeliCa Sep 03, 2013 - 1.7.0 -------------------- Fixes: - pn53x: only create a current target when at least one have been found - pn532_uart: fix 'operation abort' feature with this driver - pn532_uart: let more time to PN532 to wake-up, this fix some specific cases where PN532 shown one of two runs (Thanks to Marcello Morena) - nfc-mfclassic: allow option f for read operation too - Avoid clash with system's htole32 if it exists - Include , required for getenv(3) - usb: fix USB enumeration issue (Thanks to Mike Auty) - acr122_pcsc: fix compilation on Mac OSX 10.8.4 - Fix pn53x_initiator_transceive_bytes_timed() measures for TypeB - Various minor fixes: warnings, style, etc. Improvements: - New PN532 over I2C driver, see contrib/libnfc/pn532_i2c_on_rpi.conf.sample - ACR122/Touchatag: misc improvements - ReadMobib/ReadNavigo: improve shell script portability - Add ISO14443-4 chaining support for RX (MI) - UART: add support for BeagleBone serial ports (Thanks to Johan Henselmans) - nfc-mfultralight: allow setting of UID for special 'chinese' ultralight cards Special thanks to: - Laurent Latil (new pn532_i2c driver for linux) - Nobuhiro Iwamatsu (warning fixes and debian package) Apr 05, 2013 - 1.7.0-rc7 (release candidate) -------------------------------------------- Fixes: - Fix bug when compiling without libusb - Fix several memory leaks in error handling conditions - Remove calls to exit() from the library - Create safer snprint_nfc_*() instead of sprint_nfc_*() functions - Fix warnings returned by cppcheck & clang/scan-build - Obsolete function 'usleep' => nanosleep() - Non reentrant function 'readdir' => readdir_r() - Non reentrant function 'strtok' => new connstring_decode() - Buffer may not be null-terminated after call to strncpy() - scanf without field width limits can crash with huge input data - Resource leaks: missing fclose() - Dead code, unused vars & vars scopes warnings - Unify copyright notices & update authors lists - Windows: Fix compilation due to new usbbus file - Windows: Clean up compiler/linker warnings - Fixed the suppression of the auto-fixup for linking against MS built libs - Fixed all the formatting warnings by shifting to inttypes.h specifiers - shifted to %lu for DWORD printf - nfc-anticol: fix ATS length - nfc-mfclassic: fix reporting of processed blocks total - nfc-mfclassic: detect MIFARE Plus 2K as 2K instead of 1K - pn53x_usb/acr122_usb: check usb_open() returns before using it Improvements: - New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample - Devels HACKING file: introduce clang/scan-build & cppcheck for better code - Better internal dependencies handling (bus <> drivers) - Cleaner handling of portability patches - Windows: logging via OutputDebugString(), ease debugging - nfc-mfclassic: use smaller files for cards < 4k - nfc-mfclassic: by defaut don't authorise wrong keyfile, use "f" to force - quick_start_example1.c: remove err.h dependency, easier for Windowsians - nfc-mfclassic: support some new magic cards with writeable sector #0 - nfc-anticol: add -t option to use timed functions Changes: - Upon malloc error, nfc_init() doesn't force exit() anymore so now you should test if context != NULL after nfc_init() call - API: nfc_initiator_target_is_present() & str_nfc_target() now take a pointer to nfc_target as argument instead of passing by value Special thanks to: - Eugeny Boger (new pn532_spi driver for linux) Mar 03, 2013 - 1.7.0-rc6 (release candidate) -------------------------------------------- Fixes: - Fix several memory leaks (nfc_drivers, libusb, config parser) - Fix stack smash while displaying long data transmission (LOG_HEX) - pn53x-tamashell: allow larger commands up to full extended frame - Add missing windows file in archive (version.rc.in) - Fix compilation warnings & potential bugs - Fix documentation - Fix missing malloc() calls checks - Fix missing free() calls in some error handlers Improvements: - Allow to disable conffils & envvar supports on embedded platforms - Add option to nfc-mfclassic to tolerate RW errors Changes: - Replace usb_set_debug() in applications by LIBNFC_LOG_LEVEL libusb group Feb 16, 2013 - 1.7.0-rc5 (release candidate) -------------------------------------------- Fixes: - Add missing sample configuration file in archive - Add missing windows files in archive - Preserve error code while using pn53x_set_property_bool() with NP_AUTO_ISO14443_4 flag Improvements: - New nfc_register_driver() function allowing to hook custom drivers - New nfc_free() function to free allocated buffers Special thanks to: - Ahti Legonkov (new nfc_register_driver()) Feb 04, 2013 - 1.7.0-rc4 (release candidate) -------------------------------------------- Fixes: - Fix tag selection for nfc-mfclassic, nfc-mfultralight, nfc-read-forum-tag3 and nfc-relay-picc - Fix crash in nfc-relay-picc -i/-t if fd3 or fd4 is missing Improvements: - Windows support build with CMake Changes: - Configuration directory (ie. libnfc.conf) can now be set a compile-time - Log can be enabled/disabled using CMake Special thanks to: - Alex Lian (Windows support improvements) - Nobuhiro Iwamatsu (Debian package improvements) Jan 31, 2013 - 1.7.0-rc3 (release candidate) -------------------------------------------- Fixes: - Fix pn53x_usb bulk write timeout - Fix BCC in nfc-emulate-uid example - Fix nfc-relay-picc example - Fix a miss returned value within some internal functions (user program could be affected) - Fix nfc-scan-device -i option - Remove wrong exit() calls in library - Fix issue in driver acr122_usb affecting Touchatag - Reenable some idle in all drivers, add selectively PowerDown when possible Changes: - nfc_emulate_target() now takes timeout parameter Special thanks to: - Alex Lian (Windows support refresh) Jan 20, 2013 - 1.7.0-rc2 (release candidate) -------------------------------------------- Fixes: - Fix API version in debian files - Fix wrong condition to display a warning when user disables autoscan - Fix unit tests - Fix ISO14443B' ATS Improvements: - Allow device.optional=true to tolerate missing device Changes: - pn532_uart driver is now enabled by default Dec 09, 2012 - 1.7.0-rc1 (release candidate) -------------------------------------------- Fixes: - nfc_initiator_deselect_target() now returns 0 on success (as expected by caller) - example/pn532-sam: Fix few bugs - Fix ACR122S device detection when no ACR122S device available (endless UART receive) - Suppress a lot of compiler warnings !.. which fixes many potential bugs - Display right driver name while detecting PCSC - Correctly handle PCSC header files on Mac OS X - Fix nfc-emulation (now works with utils/nfc-emulate-forum-tag4 and Nexus S) Improvements: - New nfc_initiator_init_secure_element() function to set SAM as wired card (only relevant with a PN532 SAM-equipped) - New str_nfc_target(), str_nfc_modulation_type(), str_nfc_baud_rate() function to convert some libnfc's types into allocated string - New nfc_device_target_is_present() to check if passed target is in the field - --enable-serial-autoprobe option at compile time to replace it with some run-time options - New -i option to nfc-scan-device to allow intrusive scan - New feature, libnfc now uses configuration files: * main configuration file can be used to set options (ie. intrusive, autoscan, log-level) * main configuration file can contains a device as default device, HIGHLY recommended for UART devices users * multiple devices files can be used to declare multiple devices and ordered them - UART port scan now includes ttyAMA* to detect UART-devices connected on Raspberry Pi (e.g. `nfc-scan-device -i`) - Support for OpenPCD2 (with a dedicated firmware) - Support for FTDI dongle under MacOS - Enhance messages display - Provides modprobe configuration file and instructions for Linux >3.1 with PN533 users. - Greatly improve log facility with log level filter, configurable using conf file (ie. /etc/nfc/libnfc.conf) or environment var LIBNFC_LOG_LEVEL - New man page for nfc-read-forum-tag3 utility (Thanks to UNFORGiVEN512) - New man page for nfc-scan-device utility - New man page for nfc-emulate-forum-tag2 example - README: Add few words about device permissions and udev/devd rules available in package - utils/nfc-emulate-forum-tag4: add support for v2.0 of the spec - New "make style" command to have a beautiful code - Code cleanup (indentation, white spaces, etc.) Changes: - New nfc_device_get_information_about() now allocates returned string - No more in/out paramaters in nfc_initiator_transceive_*() functions - Rename nfc-probe to nfc-scan-device - Rename abtUid from struct mifare_param_auth into abtAuthUid: this is not the UID while using 7-bytes UID MIFARE Classic tags. - utils/nfc-list: always display the card type when a card is found - nfc-utils: new fingerprinting method closer to AN10833, (Thanks to Balazs Bucsay) See NEWS file for major changes (ie. API changes) Special thanks to: - Ludovic Rousseau (Code cleanup, tests under MacOS, etc.) - Frank Morgner Feb 27, 2012 - 1.6.0-rc1 (release candidate) -------------------------------------------- Fixes: - utils/nfc-mfclassic: use MIFARE instead of Mifare typo - utils/nfc-list: continue to attempt to reach devices after a connection failure - libnfc: avoid readline auto-detection when cross-compiling - driver/pn53x_usb: fix path usage for FreeBSD - doc: quick_start_example1.c fixed - utils/*: verbose option back for nfc-list, and newly implemented in nfc-poll Improvements: - libnfc: enhanced documentation - libnfc: debug facility back without external depends - libnfc: add nfc_device_get_supported_modulation() and nfc_device_get_supported_baud_rate() functions - libnfc: enhanced code indent - drivers: implement driver for ACR122S device - utils/nfc-mfclassic: remove non-conscistent "extract payload" option in nfc-mfclassic - utils/nfc-emulate-forum-tag2: add missing manpage - utils/nfc-read-forum-tag3: add missing manpage - tests/*: fix some warnings in test - tests/test_dep*: add some DEP tests (Active/Passive in several baud rates) - doc: quick_start_example1 is now compiled when running make check or distcheck - libnfc: a printf-based logging replaces log4c - libnfc: various minor fixes/enhancements - utils/*: nfc-probe example added to show devices connection strings Changes: - PN53x specific errors are not public anymore; - Timeouts are now integers instead of timeval structure - Removes libusb types workaround (r200) as it seems to not be needed anymore but may disturb compiler - Removes parse_args() from nfc-utils.[hc] - Move nfc-emulate-forum-tag2 from utils to examples. - contrib: move udev and devd files into contrib/ - debian: udev rules file renamed See NEWS file for major changes (ie. API changes) Special thanks to: - Thomas Hood (Debian packages and various fixes/contributions) - Anugrah Redja (ACR122S driver) Oct 17, 2011 - 1.5.1 (unstable) ------------------------------- Fixes: - libnfc: fix invalid memory access when a new driver is probing for hardware and the number of requested devices was already reached - chips/pn53x: fix bug in _timed fcts - drivers/pn53x_usb: fix crash when usb_bulk_read() fails. - drivers/pn53x_usb: continue to search a available device on usb errors (ie. Device Busy) - drivers/pn53x_usb: make PN53x usb connection more stable - examples/nfc-relay: fix UID problem - windows: fix uart_receive() under Win32 platform Improvements: - libnfc: add logging facility using log4c. - libnfc: abort mecanism is now implemented in driver layer, so it can use pipe-based mecanism (as PN532_UART or ARYGON driver does under POSIX system) or flag-based mecanism. - libnfc: add ISO/IEC 14443 B' aka Type B' modulation partial support - libnfc: add partial support (list) for ISO14443B-3 ST SRx & ASK CTx cards - libnfc: compile unit tests only on demand unless using --enable-debug. - libnfc: error handling improvements - libnfc: new function nfc_idle() to set the NFC device in idle mode - libnfc: add partial support for Sony S360 reader - libnfc: some manual test reports have been added - libnfc: list_targets support for ASK CTS512B (no anticol support yet) - libnfc: nfc_disconnect() now switches NFC device into idle before disconnecting - libnfc: nfc_initiator_poll_target() is now available for all devices - libnfc: implement software polling for non-PN532 equipped device - chips/pn53x: add pn53x_data_new() function to alloc and init pn53x_data structure - chips/pn53x: add some SFR registers description - chips/pn53x: implement WriteBack cache - chips/pn53x: new pn53x_PowerDown wrapper for PowerDown (PN532) command - chips/pn53x: prints a debug trace when reading PN53x registers - chips/pn53x: set some parameters in ISO/IEC 14443A when using DEP mode (ie. SAK says ISO/IEC 18092 compliant) (Android NFC stack now detects the target as DEP) - chips/pn53x: some optimisations in registers initialisation - chips/pn53x: list_passive_targets() fixed for TypeB on LoGO - chips/pn53x: pn53x_data now have a operating_mode enum to know the current running mode (initiator, target or idle) - drivers/*: all commands are now abortable - drivers/pn532_uart,arygon: make valgrind happy with UART-based drivers - drivers/pn53x*: use shared pn53x_ack_frame[] and pn53x_nack_frame[] instead of local declaration - drivers/pn53x_usb: all USB errors are now reported in text format - drivers/pn53x_usb: enable progressive field on init to allow pn53x-tamashell to works (note: it does not distrib progressive field enabling when nfc_list_passive_target() is used) - drivers/pn53x_usb: implement PN53x extended information frames with USB devices - drivers/pn53x_usb: use progressive field on/off only for ISO14443 Type B target listing - buses/uart: now provides an abort mecanism for windows users - buses/uart: UART based drivers could now use uart_flush_input() to discard junk bytes on input. - examples/nfc-anticol: add -f option to force RATS - examples/nfc-mfclassic: handle 7-byte UID cards & MFC Mini - examples/nfc-anticol: now use nfc_abort_command() - examples/nfc-dep-*: disconnect from NFC device on error. - examples/nfc-emulate-forum-tag2: add new example to emulate a NFC Forum Tag Type 2 - examples/nfc-emulate-forum-tag4: add document references. - examples/nfc-emulate-forum-tag4: this example now fails with ENOTSUPP when used with a non-PN532 chip. - examples/nfc-mfclassic: write special Mifare 1K cards, including Block 0 / UID - examples/nfc-mfsetuid: add a new example to set UID of special Mifare 1K cards - examples/nfc-read-forum-tag3: add new example to read a NFC Forum Tag Type 3 - examples/pn53x-tamashell-scripts: minor enhancements - tests/test-dep: add a threaded DEP test to check DEP communication between two local devices - debian: enable all drivers at compile time - debian: improve debian packaging (Thanks to Thomas Hood) - debian: use a numbering that allow to have libnfc pre-version and debian package pre-version too. (Thanks to Thomas Hood) - freebsd: add FreeBSD devd(8) snippet configuration for Sony S330 readers. - windows: implement abort mecanism in pn532_uart driver (Based on provided patch: many thanks to Edwin Evans) - windows: USB drivers now relies on libusb-win32 with version >= 1.2.4.x (1.2.4.6 recommended) (Many thanks to Glenn) - windows: implement automatic uart port detection and input flush (Thanks to Edwin Evans) Changes: - libnfc: add 'struct timeval *timeout' parameter for pn53x_transceive(), pn53x_target_receive_bytes() and pn53x_target_send_bytes(). Apr 29, 2011 - 1.5.0 (unstable) ------------------------------- Fixes: - libnfc: silent warnings with more strict CFLAGS - libnfc: update devd(8) rules file for FreeBSD - libnfc: make libnfc compile under Windows - libnfc: fix nfc_pick_device() when called from nfc_connect with NULL nfc_device_desc_t parameter - chips/pn53x: fix a bug when value is larger than mask when using WriteRegister - chips/pn53x: adapt MaxRetries to avoid issue with 2 tags on PN531 - examples/nfc-mfclassic: UID was shown reverse-ordered Improvements: - libnfc: use a new way to handle drivers, introduce a real HAL - libnfc: use absolute include path instead of relative ones - libnfc: move some nfc_device_t members in a better place - libnfc: improve nfc_driver_t struct to embedded HAL API - libnfc: nfc_device_t now embeddeds driver data and chip data pointers (useful to be more generic) - libnfc: use more readable variables instead of strange coding convention - libnfc: move PRINT_HEX macro into nfc-internal.h - libnfc: introduce an abort mecanism - libnfc: suppress any PN53x references in nfc.c - libnfc: nfc-mfclassic and nfc-mfcultralight examples are now compiled under Windows - chips/pn53x: use the powerful C99 writing to construct PN53x commands - chips/pn53x: remove almost all memcpy() - chips/pn53x: WriteRegister, ReadRegister and SetParameters command wrappers are correctly named - chips/pn53x: introduce chip state (SLEEP, NORMAL or EXECUTE) - chips/pn53x: add SAMConfiguration command wrapper (need to be improved) - chips/pn53x: remove almost all const arrays - chips/pn53x: use human readable defines for commands instead of hex values - chips/pn53x: in debug mode, the PN53x command is shown in human-readable string, awesome isn't it? ;-) - chips/pn53x: try to determine IC version instead of hardcode it. - chips/pn53x: new fonction to build frames instead of build them in each driver - chips/pn53x: enable aborting blocking commands (e.g. TgInitAsTarget) and refactor *_check_communication() as pn53x_check_communication(). - chips/pn53x: add timed versions of transceive_bytes/bits, allow to detect emulated/non-emulated tags and more... - chips/pn53x: support CRC auto-handling in ...transceive_bytes_timed - drivers/pn53x_usb: ASK LoGO: enable progressive field feature. - drivers/pn532_uart: major improvement of UART handling - drivers/pn532_uart: check PN53x frames when received - drivers/pn53x_usb: enhance ASK LoGO dedicated code - drivers/pn53x_usb: add LEDs support for ASK LoGO and SCL3711 - drivers/pn532_uart: implement extended frame send/receive for PN532_UART driver. - drivers/arygon: use the new way to drive UART (its far more stable) - drivers/arygon: do not hard code PN532 chip type: pn53x_init() determine it and ARYGON device seems to not need to be waken up. - drivers/arygon: reject too heavy payload (ARYGON does not support PN53x extended frame even with PN532 equipped device) - drivers/pn532_uart & arygon: now runs almost twice faster than the previous stable release - buses/uart: receive() is now based on expected bytes instead of calculated timeouts.. - buses/uart: simplify uart_send() on POSIX systems. - examples/nfc-emulate-tag: minor comments improvements. - examples: remove nfc-message.h usage from examples. - examples/nfc-emulate-forum-tag4: fully reworked example: it now support all NFC-Forum device in read and write mode - examples/pn53x-tamashell: add an example for LoGO LEDs - examples/pn53x-tamashell: add a script to read Mobib card. - examples/pn53x-tamashell: add a script to read Navigo card. Changes: - libnfc: merge macros from nfc-messages.h into nfc-internal.h - libnfc: remove useless files: nfc-messages.h, buses.h and chips.h - API: new nfc_emulate_target() that ease target emulation for developer - macros: show PRINT_HEX result on stderr in debug mode (that helps to sync with debug msg which are printed on standard error output.) - drivers: split transceive() into send() and receive() to be able to handle more cases (differed replies, abort commands, etc) later - drivers: use a const structure of functions instead of -dirty- callbacks array - drivers/pn53x_usb: pn531_usb and pn533_usb drivers are now merged and use the pn53x IC version autodetection - buses/uart: use a smart way to determine available ports on POSIX systems (tested on Linux and FreeBSD) Feb 21, 2011 - 1.4.2 -------------------- Fixes: - libnfc: fgets instead of getline, bring MacOSX / BSD without glibc alive - libnfc: add missing CMake files to generated tarball needed by windows users (Thanks to Glenn) - drivers/pn532_uart: fix pn532 wakeup response handling - buses/uart: prevent from retrieving more than buffer length (potential buffer overflow) - buses/uart: intent to speed up interface - nfc-emulate-uid: use a correct UID - nfc-mfclassic: fixes a segfault when using only 1 argument Improvements: - libnfc: silent some compilation warnings - drivers/pn533_usb: support new device: ASK / LoGO. (Thanks to ASK for sending one sample) - chips/pn53x: set register directly if mask cover whole value. - pn53x-tamashell: accepts script as arg, this makes shebang possible - pn53x-tamashell: add pause command & doc - documentation: add a README-Windows.txt file - documentation: add more pcsc-lite related instruction in README Feb 1, 2011 - 1.4.1 ------------------- Fixes: - libnfc: fix missing pn53x-tamashell-scripts in generated tarball. (Thanks to usermeister) - buses/uart: improved UART communication on POSIX systems: slower devices can be detected and high speed devices works better - buses/uart: serial autoprobe now skips invalid devices but checks all ports in the list - drivers/pn53x_usb: prevent from stack corruption when using PN533-based device and add errors handling for ReadRegister and WriteRegister - drivers/arygon: fix polling on ARYGON devices - examples/nfc-emulate-tag: switch off easy framing when we are not emulating a ISO14443-4 target - examples/nfc-mfclassic: fix crash when file cannot be opened for writing - examples/nfc-mfultralight: fix 7 bytes UID display Improvements: - libnfc: add a "troubleshooting" section in README to document ACR122 problems with pcsclite. - libnfc: inform user if target UID can not be emulated - example/nfc-mfultralight: handle lock page writing - examples/nfc-emulate-tag: handle HALT & READ - tests: add register access test Experimental: Windows platform support (Thanks to Glenn Ergeerts) Nov 17, 2010 - 1.4.0 -------------------- Fixes: - libnfc: fix Felica listing - libnfc: fix storage of ISO14443B targets data - libnfc: fix MacOS build - libnfc: fix some errors string (ie. well-known "Invalid Parameter") - libnfc: fix memory leak while using *_pick() - drivers/pn53x_usb: fix ZLP USB issue - drivers/pn53x_usb: workaround for PN532 toggle bit USB bug - drivers/pn53x_usb: fix timeout problem in emulation mode - drivers/pn53x_usb,pn532_uart,arygon: more robust recovery from unstable states such as interrupted emulation modes - drivers/acr122: fix escape ioctl under Linux - buses/uart: fix UART default serial ports under Linux. - examples/nfc-anticol: fix bug preventing to run nfc-anticol after some other programs - examples/nfc-anticol: fix display of UID - ... and many other minor fixes Improvements: - libnfc: major emulation improvements: libnfc can now be used to emulate ISO/IEC 14443 type A tag (MIFARE, ISO14443-4), FeliCa and D.E.P. target - libnfc: documentation improvements - libnfc: decode select/initialization datas for almost all supported target types (ISO14443 A/B, Jewel/Topaz, FeliCa) - libnfc: add ISO/IEC 14443B baud rates: 212, 424 and 847 kbps - libnfc: cache some chip registers for faster communication - libnfc: greatly improved D.E.P. support - buses/uart: adjust UART's timeouts from baud rate: faster communication at high speed and more reliable at low speed (affect pn532_uart and arygon drivers) - drivers/arygon: retrieve ARYGON µC firmware version - examples/nfc-anticol: adds support for CL3 - examples/nfc-anticol: cascade based on SAK rather than CT, better for educational purpose - examples/nfc-anticol: Computes CRC rather than hardcoded one. - examples/nfc-utils: print_iso14443b_info() now displays many decoded information in verbose mode - examples/nfc-utils: print_iso14443a_info() now displays many decoded information and shows attempt to determine tag name in verbose mode - examples/nfc-list: new option -v for verbose mode - examples/nfc-list: now support for Jewel/Topaz too - examples/nfc-poll: now poll using all supported modulations - examples/nfc-dep-target: add hack to allow to use two devices on the same machine (for tests/debug purpose) - examples/pn53x-tamashell: New PN53x TAMA communication demonstration shell (support scripting) - examples/nfc-relay-picc: New tool to relay ISO14443-4 communications (even over network... Enjoy!) - examples/nfc-emulate-forum-tag4: New example to emulate a NFC Forum tag type 4 - examples/nfc-emulate-tag: New example to emulate tags - examples: add missing man pages - ... and many other minor improvements Changes: - API: Many changes, see NEWS file for more info how to migrate - buses/uart: split UART implementations: one file for POSIX and another one for Windows - examples: nfcip-* renamed to nfc-dep-* - examples: nfc-sam renamed to pn53x-sam - examples: nfc-emulate renamed to nfc-emulate-uid - examples: change examples license for the sake of consistency: LGPL covers library, re-usable examples code is now under BSD license. Aug 31, 2010 - 1.3.9 -------------------- Fixes: - libnfc: fix ATS - pn53x_usb: fix USB issues - nfc-mfultralight: fix read and write counters Improvments: - libnfc: rearrange source code - libnfc: enhance documentation - libnfc: add regression tests (not as much as expected but its here!) - build: configure script now supports --with-drivers option instead of --disable-pcsclite and --disable-libusb (see --help) - nfc-mfultralight: we now can write OTP bytes if user want to Changes: - API: nfc_initiator_select_tag() is now nfc_initiator_select_passive_target() - API: nfc_initiator_deselect_tag() is now nfc_initiator_deselect_target() - API: new function nfc_initiator_list_passive_targets() to list available targets in field - API: new nfc_perror(), nfc_strerror() and nfc_strerror_r() functions to handle errors - API: new types: nfc_target_type_t and nfc_target_t - API: new configuration option NDO_AUTO_ISO14443_4 to enable/disable auto iso14443-4 mode. - API: new configuration option NDO_EASY_FRAMING to enable/disable auto frames encapsulation and chaining - API: nfc_initiator_transceive_dep_bytes(), nfc_target_receive_dep_bytes() and nfc_target_send_dep_bytes() have been removed (unset NDO_EASY_FRAMING instead of these functions) - API: (experimental) new nfc_initiator_poll_targets() which allow to use hardware polling function - examples: add draft of a new example: nfc-sam. It tests the comunication with a connected SAM (Secure Access Module) - examples: add new example to show how to use new polling function - examples: add new example to diagnose basic elements (communication, rom and ram) of pn53x - nfc-mfultralight: on write failure, continue if authenticate works. - nfc-mfclassic: take care of 16-blocks-long sectors of Mifare Classic 4K in the nfc-mfclassic example's blocks counting routine. - nfc-mfclassic: now fails ealier when something goes wrong (this allow to prevent from false-success). - nfc-mfclassic: disable ISO14443-4 auto-switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance.(e.g. Nokia 6212 Classic) Note: This release will not install extra headers (like mifare.h), programs that depends on should copy theses files into their sources. Apr 6, 2010 - 1.3.4 -------------------- Fixes: - Fix CT (Cascade Tag) byte when using 10 bytes long UID. - Strip CT (Cascade Tag) from UIDs in nfc_initiator_select_tag(). - Fix CMake build (mainly on Windows related stuff) - Minors fixes in documentation. - Suppress almost all compilation warnings. Changes: - API: Provide ISO14443A CRC function. - Remove annoying info message when probing uart devices while serial autoprobing is disabled. - Rename README-Windows.txt (compilation using CMake) into CMake-Windows.txt - Add README for Windows compilation using win32/Makefile. Note: Windows users could now take main tarball using CMake to build or Windows specific archive using MinGW GNU/Make. Feb 17, 2010 - 1.3.3 -------------------- Fixes: - libnfc: Attempt to fix build on Windows using CMake; - libnfc: Fix build on NetBSD; - libnfc: Fix build on MacOS X; - nfc-relay: fix usage of two devices that use the same driver. Feb 01, 2010 - 1.3.2 -------------------- Fixes: - libnfc: Fix compilation issue under FreeBSD (should now compile on FreeBSD 6, 7 and 8). Note: Experimental CMake files are provided with this release, issues reports are welcome. Jan 20, 2010 - 1.3.1 -------------------- Fixes: - libnfc: Fix compilation issue under Windows; - uart bus: Fix possible invalid file descriptor in uart_close(); - uart bus: Serial autoprobing is now DISABLED to avoid UART disturbing. (Feature can be enabled using –enable-serial-autoprobe option while configure). Jan 14, 2010 - 1.3.0 -------------------- Fixes: - build: Add workarounds for libusb when compiling using C99; - build: Attempt to fix rpath issue on linux platform (it is already deprecated in main distributions. i.e. http://wiki.debian.org/RpathIssue); - build: wrong paths in pkg-config file; - libnfc: Remove warnings when compiling; - libnfc: Various code fixes and cleanup; - bus uart: Added support for recv/send of larger data chunks (>default_os_buffer); - bus uart: Fix some some buffer synchronization problems under POSIX system; - bus uart: Add configure option: --disable-serial-autoprobe to disable autoprobing; - libnfc: Fix nfc_target_init doesn't correctly reset the parity during initalization; - libnfc: added support for WUPA and 7,10 byte UID in nfc_initiator_select_tag(); - libnfc: Fix tag re-selection with UID length > 4 bytes (like DESFire or Ultralight); - nfc-mfclassic: Fix authenticated only with KEYA; Improvements: - build: Build on FreeBSD; - build: Add alternative build system (CMake); - build: Add new files usefull for desktop GNU/Linux users: some rules for udev to allow non-root access to PN53x USB devices; - build: Update msinttypes up to revision 26. (used when compiling under Windows); - build: Add "make doc" directive: it will build API documentation using Doxygen. (--enable-doc flag is required at configure time); - libnfc: Add C++ compatibility; - libnfc: Add driver agnostic nfc_pick_device(), nfc_list_devices(); - libnfc: It is now possible to specify a wanted device using new struct "nfc_device_desc_t"; - libnfc: Add device name to device descriptions (nfc_device_desc_t) to select a given PCSC device; - libnfc: Finally removed all dirty globals, it 'should' be thread-safe now; - libnfc: Less confusing message for bitstreams display; - libnfc: chips level introduction with pn53x.h/c; - drivers: Add PN532 UART driver; - drivers pn533_usb and pn531_usb: Lets search continuing to find other USB readers if any in PN531 and PN533 USB drivers; - drivers pn533_usb and pn531_usb: Support for the generic vendorid/productid of the NXP chip; - drivers pn533_usb and pn531_usb: Consolidate duplicated code; - examples: Add MIFARE Ultratag tool; - examples: Add man page for nfc-mfultool; - examples: MIFARE examples (mftool and mfultool) have now a better help message; - examples: Add NFCIP (NDEP) as experimental feature; - examples: add quiet mode to improve timing of emulate, relay and anticol commands; - nfc-list: List all devices in nfc-list(1); - nfc-list: Simply turns off the RF field upon exit; - nfc-emulate: allow UID to be specified; - nfc-relay: Initialize initiator device explicitly; - nfc-relay: Capture ctrl-c for quitting cleanly the relay attack application; - nfc-relay: exit properly if emulator initialization failed; - nfc-mfclassic: Add default keys tries; Changes: - API: Rename tag_info to nfc_target_info_t; - API: Rename init_modulation to nfc_modulation_t; - API: Rename dev_config_option to nfc_device_option_t; - API: Use NULL instead of INVALID_DEVICE_INFO to know if device is valid; - API: Rename chip_type to nfc_chip_t; - API: Rename dev_spec to nfc_device_spec_t; - API: Rename dev_info struct to nfc_device_t; - API: Variables have been renamed to match coding conventions; - API: Changed length parmeters from uint32_t to size_t; - Files: Remove defines.h public header; - Files: Prefix messages.h and types.h headers by "nfc-"; - Files: Revamp libnfc source tree; - Files: Move examples into src/examples subdirectory; - Examples: Rename nfc-mftool to nfc-mfclassic; - Examples: Rename nfc-mfultool to nfc-mfultralight; Jul 24, 2009 - 1.2.1 -------------------- - Fix ACR122 on 64 bits architecture under GNU/Linux. Jul 22, 2009 - 1.2.0 -------------------- - License changed from GPLv3 to LGPLv3 - ARYGON ADRA-USB/ADRB-USB reader support - PN533 support - C99 standard (all custom defined types have been renamed) - Autotoolized for GNU/Linux, *BSD and MacOSX - nfc examples (anticol, emulate, list, mftool, relay) are now prefixed by "nfc-" Mar 27, 2009 - 1.1.0 -------------------- - Next generation, support for ACR122v2 and PN531 USB devices Feb 12, 2009 - 1.0.0 -------------------- - Initial release libnfc-1.7.1/Doxyfile.in000066400000000000000000001756061230265671100151120ustar00rootroot00000000000000# Doxyfile 1.6.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = libnfc # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @builddir@/doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it parses. # With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this tag. # The format is ext=language, where ext is a file extension, and language is one of # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = YES # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # doxygen. The layout file controls the global structure of the generated output files # in an output format independent way. The create the layout file that represents # doxygen's defaults, run doxygen with the -l option. You can optionally specify a # file name after the option, if omitted DoxygenLayout.xml will be used as the name # of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = Doxygen.log #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @top_srcdir@/libnfc @top_srcdir@/examples @top_srcdir@/include/nfc @top_srcdir@/utils # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.c \ *.h \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = @top_srcdir@/libnfc/drivers.h \ @top_srcdir@/libnfc/iso14443-subr.c \ @top_srcdir@/libnfc/iso7816.h \ @top_srcdir@/libnfc/log-printf.c \ @top_srcdir@/libnfc/log.h \ @top_srcdir@/libnfc/mirror-subrc.c \ @top_srcdir@/libnfc/mirror-subrc.h \ # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = .git/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = @top_srcdir@/ \ @top_srcdir@/src/examples/doc # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = ChangeLog \ *.c # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # are set, an additional index file will be generated that can be used as input for # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated # HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. # For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's # filter section matches. # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NONE # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) # there is already a search function so this one should typically # be disabled. SEARCHENGINE = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = libnfc.tag # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 1000 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES libnfc-1.7.1/HACKING000066400000000000000000000040351230265671100137510ustar00rootroot00000000000000Hello hackers! General remarks about contributing ---------------------------------- Contributions to the libnfc are welcome! Here are some directions to get you started: 1. Follow style conventions The source code of the library trend to follow some conventions so that it is consistent in style and thus easier to read. Look around and respect the same style. Don't use tabs. Increment unit is two spaces. Don't leave dandling spaces or tabs at EOL. Helper script to get some uniformity in the style: $ make style If you use vim see the "Vim: How to prevent trailing whitespaces" http://www.carbon-project.org/Vim__How_to_prevent_trailing_whitespaces.html 2. Chase warnings: no warning should be introduced by your changes Depending what you touch, you can check with: 2.1 When using autotools $ autoreconf -Wall -vis 2.2 When compiling 2.2.1 Using extra flags: $ export CFLAGS="-Wall -g -O2 -Wextra -pipe -funsigned-char -fstrict-aliasing \ -Wchar-subscripts -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wunused \ -Wuninitialized -Wpointer-arith -Wredundant-decls -Winline -Wformat \ -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs \ -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition \ -Wbad-function-cast -Wnested-externs -Wmissing-declarations" $ ./configure $ make clean $ make 2.2.2 Using clang: $ scan-build ./configure $ make clean $ scan-build make 2.2.3 Using cppcheck (v1.58 or higher): $ make cppcheck 2.3 When Debianizing $ lintian --info --display-info --display-experimental *deb or (shorter version) $ lintian -iIE *deb 3. Preserve cross-platform compatility The source code should remain compilable across various platforms, including some you probably cannot test alone so keep it in mind. Supported platforms: - Linux - FreeBSD - Mac OS X - Windows with Mingw libnfc-1.7.1/Makefile.am000066400000000000000000000027461230265671100150250ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = $(LIBNFC_CFLAGS) SUBDIRS = libnfc utils examples include contrib cmake test pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libnfc.pc EXTRA_DIST = \ CMakeLists.txt \ Doxyfile \ README-Windows.txt \ libnfc.conf.sample CLEANFILES = Doxygen.log coverage.info libnfc.pc clean-local: clean-local-doc clean-local-coverage .PHONY: clean-local-coverage clean-local-doc doc style clean-local-coverage: -rm -rf coverage clean-local-doc: rm -rf doc doc : Doxyfile @DOXYGEN@ $(builddir)/Doxyfile DISTCHECK_CONFIGURE_FLAGS="--with-drivers=all" style: find . -name "*.[ch]" -exec perl -pi -e 's/[ \t]+$$//' {} \; find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ --indent=spaces=2 --indent-switches --indent-preprocessor \ --keep-one-line-blocks --max-instatement-indent=60 \ --brackets=linux --pad-oper --unpad-paren --pad-header \ --align-pointer=name {} \; cppcheck: cppcheck --quiet \ -I include -I libnfc -I libnfc/buses -I libnfc/chips -I libnfc/drivers \ --check-config . cppcheck --quiet --enable=all --std=posix --std=c99 \ -I include -I libnfc -I libnfc/buses -I libnfc/chips -I libnfc/drivers \ -DLOG -D__linux__ \ -DDRIVER_PN53X_USB_ENABLED -DDRIVER_ACR122_PCSC_ENABLED \ -DDRIVER_ACR122_USB_ENABLED -DDRIVER_ACR122S_ENABLED \ -DDRIVER_PN532_UART_ENABLED -DDRIVER_ARYGON_ENABLED \ -DDRIVER_PN532_SPI_ENABLED -DDRIVER_PN532_I2C_ENABLED \ --force --inconclusive . libnfc-1.7.1/NEWS000066400000000000000000000356571230265671100134770ustar00rootroot00000000000000New in 1.7.1: API Changes: * nfc_initiator_select_passive_target() provides defaults if pbtInitData=NULL * nfc_initiator_target_is_present() allow NULL pointer to tag New in 1.7.0: Drivers: * New PN532 over I2C driver, see contrib/libnfc/pn532_i2c_on_rpi.conf.sample API Changes: * New function iso14443b_crc_append() New in 1.7.0-rc7: Drivers: * New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample API Changes: * Functions - nfc_initiator_target_is_present() & str_nfc_target(): now take a pointer to nfc_target as argument - nfc_init(): upon malloc error, doesn't force exit() anymore so now you should test if context != NULL after nfc_init() call New in 1.7.0-rc5: API Changes: * Functions - New nfc_register_driver() function allowing to hook custom drivers. New in 1.7.0-rc3: API Changes: * Functions - Add timeout param to nfc_emulate_target() New in 1.7.0-rc2: Configuration: libnfc can now use a configuration file for special setups, or features activation. This file (/etc/nfc/libnfc.conf under GNU/Linux systems) supports already some keywords: - "allow_autoscan" to enable/disable device auto-detection feature; - "allow_intrusive_scan" to enable/disable intrusive auto-detection (ie. serial port probing); - "log_level" to select library verbosity; - "device.name" and "device.connstring" to define a user device, this is the recommended method if user has a not easily detectable device (ie. a serial one). It is also possible to define devices using dedicated configuration files and put them into device search directory (/etc/nfc/devices.d under GNU/Linux). Example for the OpenPCD2: create /etc/nfc/devices.d/openpcd2.conf with: name = "OpenPCD2" connstring = "pn532_uart:/dev/ttyACM0" optional = true The keyword "optional" does not mandate the device to be present always (it detects if the reader is indeed present before using it) API Changes: * Types - New NFC_ESOFT error to handle software errors (allocations, pipe creation, etc.) * Functions - Remove nfc_get_default_device() function: the default device is now the first in nfc_list_devices() or could be open using NULL connstring with nfc_open() function. - New enum-to-string converter functions str_nfc_modulation_type() and str_nfc_baud_rate() - New str_nfc_target() to convert nfc_target struct into allocated string - New nfc_device_get_information_about() function to retreive some device's information - No more in/out function parameter: nfc_initiator_transceive_*() now take a constant size for Rx buffer - New nfc_initiator_target_is_present() to test is the previously selected target is available in the field - nfc_initiator_transceive_bytes() returns NFC_EMFCAUTHFAIL when AUTH command failed on a Mifare Classic - New nfc_initiator_init_secure_element() to initiate a connection with secure element (Only supported with a PN532 with SAM equipped) New in 1.6.0-rc1: API Changes: * Types - '_t' suffix removed from all types (e.g. nfc_device_t is now nfc_device) - All errors removed in flavour of NFC_EIO, NFC_EINVARG, NFC_EDEVNOTSUPP, NFC_ENOTSUCHDEV, NFC_EOVFLOW, NFC_ETIMEOUT, NFC_EOPABORTED, NFC_ENOTIMPL, NFC_ETGRELEASED, NFC_ERFTRANS, NFC_ECHIP and NFC_SUCCESS - nfc_device_desc_t replaced by nfc_connstring: libnfc now uses connection strings to describe a device - byte_t typedef removed, libnfc now uses uint8_t from C99 - nfc_device is now an opaque type - nfc_properties replaces nfc_options * Functions - New nfc_get_default_device() function that allows to grab the connstring stored in LIBNFC_DEFAULT_DEVICE environnement variable or returns the first available device if not set - New nfc_device_get_connstring() accessor function to know the device connstring - New nfc_device_set_property_bool() function that replace nfc_configure() - New nfc_device_set_property_int() function to set integer property - nfc_device_name() renamed to nfc_device_get_name() for the sake of consistency - New nfc_device_get_last_error() function, an accessor to last error occured - Whole libnfc's functions now return 0 (NFC_SUCCESS) or positive value if appropriated on success and libnfc's error code on failure - nfc_connect(), nfc_disconnect() renamed to nfc_open(), nfc_close() respectively - Add 2 new functions: initialization and deinitialization functions: nfc_init() and nfc_exit() - New nfc_device_get_supported_modulation() and nfc_device_get_supported_baud_rate() functions * Dependencies - log4c is not anymore used for debugging facility. It was a bad choice, sorry for inconvenience. New in 1.5.1: API Changes * Types - Communication-level errors DEIO and DETIMEOUT are now know as ECOMIO, ECOMTIMEOUT respectively - Common device-level errors DEINVAL and DEABORT are now know as EINVALARG, EOPABORT respectively - New errors: EFRAACKMISMATCH, EFRAISERRFRAME, EDEVNOTSUP and ENOTIMPL * Functions - nfc_abort_command() returns a boolean - timeout (struct timeval) pointer added to nfc_initiator_transceive_bytes(), nfc_target_send_bytes() and nfc_target_receive_bytes() - timed functions nfc_initiator_transceive_bytes_timed() and nfc_initiator_transceive_bits_timed() now takes uint32_t as cycles pointer - nfc_initiator_poll_targets() renamed to nfc_initiator_poll_target() and only return one target New in 1.5.0: Installed files - nfc-message.h have been removed, internal macros are not part of API. - New nfc-emulation.h file offers a middle level API to handle emulation (see nfc-emulate-forum-tag4 example) API Changes * Types - New error: DEABORT raised when operation is aborted by user (using nfc_abort_command()) - nfc_chip_t type removed from public API (have been renamed to pn53x_type in chips/pn53x) - nfc_device_spec_t removed, each driver can use his own way to keep a connection pointer * Structures - nfc_device_t now have a nfc_driver_t struct pointer (named .driver) and void pointer (.driver_data) to handle device specific wrapping - nfc_device_t now have a void pointer (.chip_data) to keep some chip specific data - nfc_device_t now have an file descriptor array to manage to abort request - nfc_device_t does have .nc member (nfc_chip_t) anymore (different chips handling in now in chip level) - nfc_device_t does have .nds member (nfc_device_spec_t) anymore, each driver handle its communication using driver_data pointer - nfc_device_t does have .bActive member (bool) anymore, this variable was almost not used and was not efficient - nfc_device_t does have chip's register caches anymore, this is handle in chip level (using chip_data pointer) - driver_callbacks structure have been removed from public API - New nfc_emulator structure used by the new emulation API (see nfc_emulate_target()) - New nfc_emulation_state_machine structure used by the new emulation API, it handles an I/O function and data pointer to create a software based state-machine. * Functions - New nfc_abort_command() function to abort current running command. - New nfc_initiator_transceive_bits_timed() and nfc_initiator_transceive_bytes_timed() to transceive bits/bytes and measure the time to have a reply - New nfc_emulate_target() function to start a target emulation using an nfc_emulator structure (it contains a custom state-machine (nfc_emulation_state_machine struct) and a custom target (nfc_target_t) (see nfc-emulate-forum-tag4 to have a look on how-to use it) New in 1.4.1: API Changes * Types - New error: ETGUIDNOTSUP raised when UID is not 4 bytes long or does not start with 0x08 (Security restriction present in the NXP PN53x chips) New in 1.4.0: API Changes * Types - New nfc_device_option value (enum): NDO_FORCE_ISO14443_A to force the chip to switch in ISO14443-A - New nfc_dep_mode_t (enum) for DEP mode: NDM_UNDEFINED, NDM_PASSIVE, NDM_ACTIVE - New nfc_modulation_type_t (enum) that lists modulation types: NMT_ISO14443A, NMT_ISO14443B, NMT_FELICA, NMT_JEWEL, NMT_DEP - New nfc_baud_rate_t (enum): list of baud rates: NBR_UNDEFINED, NBR_106, NBR_212, NBR_424, NBR_847 - nfc_target_type_t have been removed from API (use nfc_modulation_t instead) * Structures - nfc_device_t now have a boolean bAutoIso14443_4 to keep the locally the state of NDO_AUTO_ISO14443_4 (should not be directly set, use nfc_configure() with NDO_AUTO_ISO14443_4) - nfc_device_t now have an uint8_t ui8Parameters to cache PN53x parameters - nfc_device_t now have a byte_t btSupportByte to cache supported modulations - nfc_dep_info_t have completely changed, please see API documentation - nfc_iso14443b_info_t have completely changed, please see API documentation - nfc_modulation_t have completely changed: it now contains a nfc_modulation_type_t and nfc_baud_rate_t couple. Initialization example: nfc_modulation_t nm = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; - nfc_target_t now contains new nfc_modulation_t instead of nfc_target_type_t. Initialization example: nfc_target_t nt = { .nm.nmt = NMT_ISO14443A, .nm.nbr = NBR_UNDEFINED, .nti.nai.abtAtqa = { 0x03, 0x44 }, .nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef }, .nti.nai.btSak = 0x20, .nti.nai.szUidLen = 4, .nti.nai.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, .nti.nai.szAtsLen = 5, }; * Functions - nfc_initiator_select_passive_target() now use new nfc_modulation_t and nfc_target_t instead of nfc_target_info_t - nfc_initiator_list_passive_targets() now use new nfc_modulation_t and nfc_target_t instead of nfc_target_info_t - nfc_initiator_poll_targets() use new nfc_modulation_t instead of nfc_target_type_t - nfc_initiator_select_dep_target() completely changed, use now nfc_dep_mode_t, nfc_baudrate_t, nfc_dep_info_t and nfc_target_t, please see API documentation - nfc_target_init() have an additional argument: nfc_target_t to describe the wanted target - append_iso14443a_crc() was renamed to iso14443a_crc_append() - New iso14443a_locate_historical_bytes() to locate historical bytes in ATS New in 1.3.9 (since 1.3.4): Installed files - mifaretag.h and mifareultag.h are removed, Mifare features are not a part of libnfc API anymore (these features are always available in examples/) API Changes * Types - New nfc_device_option_t value (enum): NDO_AUTO_14443_4, an option to enable/disable auto-switching to ISO/IEC 14443-4 if device is compliliant - New nfc_device_option_t value (enum): NDO_EASY_FRAMING, an option to enable/disable automatic frames encapsulation and chaining - New nfc_target_type_t (enum), with values like NTT_MIFARE, NTT_ISO14443B_106, NTT_DEP_ACTIVE_424, etc. - Mifare related types have been removed from API: mifare_cmd, mifare_param_auth, mifare_param_data, mifare_param_value, mifare_param * Structures - nfc_device_t now have boolean bEasyFraming to enable/disable "easy framing" feature (should not be directly set, use nfc_configure() with NDO_EASY_FRAMING) - nfc_device_t now have integer iLastError to handle last error - New chip_callbacks to handle error lookup per chip - driver_callbacks now have a pointer to chip_callbacks - New nfc_target_t that contains nfc_target_info_t and nfc_target_type_t * Functions - nfc_initiator_select_tag() became nfc_initiator_select_passive_target() - New nfc_initiator_list_passive_targets() returns a list of detected target on desired modulation - (experimental) New nfc_initiator_poll_targets() returns targets that are detected during hardware polling (available only with PN532) - nfc_initiator_transceive_dep_bytes(), nfc_target_receive_dep_bytes() and nfc_target_send_dep_bytes() have been removed from API, use NDO_EASY_FRAMING option to switch from raw mode to "easy framing" - nfc_initiator_mifare_cmd() have been removed: no more Mifare related stuff in libnfc's API - New nfc_strerror(), nfc_strerror_r() and nfc_perror() to report errors - New append_iso14443a_crc() to append iso14443a_crc() to a string New in 1.3.4 (since 1.2.1): Installed files - Headers are now installed in include/nfc instead of include/libnfc - libnfc.h have been renamed to nfc.h - defines.h and types.h have been merge into nfc-types.h - bitutils.h is not installed anymore, some functions are now in examples/nfc-utils.c - devices.h, dev_acr122.h, dev_arygon.h, dev_pn531.h, dev_pn533.h and rs232.h are not installed anymore - New header mifareultag.h, like mifaretag.h for Mifare UltraLight - New header nfc-messages.h with messages macros (DBG, ERR, INFO) API Changes * Types - uint32_t which was used as size now are size_t - chip_type became nfc_chip_t (enum) - init_modulation became nfc_modulation_t (enum), and now have NM_ACTIVE_DEP and NM_PASSIVE_DEP modulation values added * Structures - dev_info became nfc_device_t - dev_config_option became nfc_device_option_t - New nfc_device_desc_t to describe the way to access to a NFC device. Initialisation example: nfc_device_desc_t ndd = { ndd.pcDriver = "ARYGON"; ndd.pcPort = "/dev/ttyUSB0"; ndd.uiSpeed = 115200; }; - dev_callbacks became driver_callbacks and now have two function pointers more: pick_device() and list_devices() - New nfc_dep_info_t to handle DEP targets info - tag_info_iso14443a became nfc_iso14443a_info_t - tag_info_iso14443b became nfc_iso14443b_info_t - tag_info_felica became nfc_felica_info_t - tag_info_jewel became nfc_jewel_info_t - tag_info became nfc_target_info_t, and now have extended union to nfc_dep_info_t * Functions - nfc_connect() now takes 1 nfc_devive_desc_t argument (can be NULL) - New nfc_list_devices(), it find available NFC devices using all know drivers - (experimental) New nfc_initiator_select_dep(), it looks for DEP targets - (experimental) New nfc_initiator_transceive_dep_bytes(), like nfc_initiator_transceive_bytes() for DEP targets - (experimental) New nfc_target_receive_dep_bytes() and nfc_target_send_dep_bytes(), to receive/send bytes to DEP target (configured as initiator) while local NFC device is configured as target - New nfc_device_name() returns the device's name - New iso14443a_crc() computes CRC as described in ISO/IEC 14443 - New nfc_version() returns the actual version of libnfc (with SVN revision, if available) libnfc-1.7.1/README000066400000000000000000000117151230265671100136450ustar00rootroot00000000000000*- * Free/Libre Near Field Communication (NFC) library * * Libnfc historical contributors: * Copyright (C) 2009 Roel Verdult * Copyright (C) 2009-2013 Romuald Conty * Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2012-2013 Ludovic Rousseau * Additional contributors: * See AUTHORS file -* General Information =================== libnfc is a library which allows userspace application access to NFC devices. The official web site is: http://www.nfc-tools.org/ The official forum site is: http://www.libnfc.org/community/ The official development site is: http://libnfc.googlecode.com/ Important note: this file covers POSIX systems, for Windows please read README-Windows.txt Requirements ============ Some NFC drivers depend on third party software: * pn53x_usb & acr122_usb: - libusb-0.1 http://libusb.sf.net * acr122_pcsc: - pcsc-lite http://pcsclite.alioth.debian.org/ The regression test suite depends on the cutter framework: http://cutter.sf.net Installation ============ See the file 'INSTALL' for configure, build and install details. Additionnally, you may need to grant permissions to your user to drive your device. Under GNU/Linux systems, if you use udev, you could use the provided udev rules. e.g. under Debian, Ubuntu, etc. sudo cp contrib/udev/42-pn53x.rules /lib/udev/rules.d/ Under FreeBSD, if you use devd, there is also a rules file: contrib/devd/pn53x.conf. How to report bugs ================== To report a bug, visit http://code.google.com/p/libnfc/issues/list and fill out a bug report form. If you have questions, remarks, we encourage you to post this in the developers community: http://www.libnfc.org/community 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 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 ======= Patches can be posted to http://code.google.com/p/libnfc/issues/list or can be sent directly to libnfc's developers: http://nfc-tools.org/index.php?title=Contact 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. If your Touchatag or ACR122 device fails being detected by PCSC-lite daemon (pcsc_scan doesn't see anything) then try removing the bogus firmware detection of libccid: edit libccid_Info.plist configuration file (usually /etc/libccid_Info.plist) and locate "ifdDriverOptions", turn "0x0000" value into 0x0004 to allow bogus devices and restart 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 (usually /etc/libccid_Info.plist) and locate "ifdDriverOptions", turn "0x0000" value into 0x0001 to allow CCID exchange or 0x0005 to allow CCID exchange and bogus devices (cf previous remark) and restart pcscd daemon. Warning: if you use ACS CCID drivers (acsccid), configuration file is located 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, two kernel-modules must not be loaded in order to use libnfc : "nfc" and "pn533". To prevent kernel from loading automatically these modules, you can blacklist 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 Proprietary Notes ================= FeliCa is s registered trademark of the Sony Corporation. MIFARE is a trademark of NXP Semiconductors. Jewel Topaz is a trademark of Innovision Research & Technology. All other trademarks are the property of their respective owners. libnfc-1.7.1/README-Windows.txt000066400000000000000000000047721230265671100161200ustar00rootroot00000000000000*- * Free/Libre Near Field Communication (NFC) library * * Libnfc historical contributors: * Copyright (C) 2009 Roel Verdult * Copyright (C) 2009-2013 Romuald Conty * Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2012-2013 Ludovic Rousseau * Additional contributors of Windows-specific parts: * Copyright (C) 2010 Glenn Ergeerts * Copyright (C) 2013 Alex Lian -* Requirements ============ - MinGW-w64 compiler toolchain [1] - LibUsb-Win32 1.2.5.0 (or greater) [2] - CMake 2.8 [3] - PCRE for Windows [4] This was tested on Windows 7 64 bit, but should work on Windows Vista and Windows XP and 32 bit as well. Only the ACS ACR122 and the ASK Logo readers are tested at the moment, so any feedback about other devices is very welcome. Community forum: http://www.libnfc.org/community/ Building ======== To build the distribution the MinGW Makefiles generator of CMake was used. Here is an example of how to generate a distribution with the above mentioned requirements fulfilled (it is assumed the CMake binaries are in the system path, this is optional during installation of CMake): - Add the following directories to your PATH : c:\MinGW64\bin;c:\MinGW64\x86_64-w64-mingw32\lib32;c:\MinGW64\x86_64-w64-mingw32\include - Now it is possible to run CMake and mingw32-make: C:\dev\libnfc-read-only> mkdir ..\libnfc-build C:\dev\libnfc-read-only> cd ..\libnfc-build C:\dev\libnfc-build> cmake-gui . Now you can configure the build. Press "Configure", specify "MinGW32 Makefiles" and then you have the opportunity to set some configuration variables. If you don't want a Debug build change the variable CMAKE_BUILD_TYPE to "Release". If a non-GUI solution is preferred one can use: C:\dev\libnfc-build> cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release ..\libnfc-read-only Now run mingw32-make to build: C:\dev\libnfc-read-only\bin> mingw32-make The build will create a shared library for Windows (nfc.dll) to link your applications against. It will compile the tools against this shared library. References ========== [1] the easiest way is to use the TDM-GCC installer. Make sure to select MinGW-w64 in the installer, the regular MinGW does not contain headers for PCSC. http://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/tdm64-gcc-4.5.1.exe/download [2] http://sourceforge.net/projects/libusb-win32/files/ [3] http://www.cmake.org [4] http://gnuwin32.sourceforge.net/packages/pcre.htmlibnfc-1.7.1/cmake/000077500000000000000000000000001230265671100140405ustar00rootroot00000000000000libnfc-1.7.1/cmake/FixBundle.cmake.in000066400000000000000000000006241230265671100173310ustar00rootroot00000000000000INCLUDE(BundleUtilities) # set bundle to the full path of the executable already existing in the install tree SET(bundle "${CMAKE_INSTALL_PREFIX}/bin/nfc-list@CMAKE_EXECUTABLE_SUFFIX@") # set other_libs to a list of additional libs that cannot be reached by dependency analysis SET(other_libs "") SET(dirs "@LIBUSB_LIBRARY_DIR@" "@PCRE_BIN_DIRS@") fixup_bundle("${bundle}" "${other_libs}" "${dirs}") libnfc-1.7.1/cmake/Makefile.am000066400000000000000000000001671230265671100161000ustar00rootroot00000000000000SUBDIRS = modules EXTRA_DIST = \ FixBundle.cmake.in \ config_posix.h.cmake \ config_windows.h.cmake libnfc-1.7.1/cmake/config_posix.h.cmake000066400000000000000000000003351230265671100177600ustar00rootroot00000000000000#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" #cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" #cmakedefine _XOPEN_SOURCE @_XOPEN_SOURCE@ #cmakedefine SYSCONFDIR "@SYSCONFDIR@" libnfc-1.7.1/cmake/config_windows.h.cmake000066400000000000000000000003361230265671100203110ustar00rootroot00000000000000#include "contrib/windows.h" #cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" #cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" #cmakedefine LIBNFC_SYSCONFDIR "@LIBNFC_SYSCONFDIR@" libnfc-1.7.1/cmake/modules/000077500000000000000000000000001230265671100155105ustar00rootroot00000000000000libnfc-1.7.1/cmake/modules/COPYING-CMAKE-SCRIPTS000066400000000000000000000024571230265671100205160ustar00rootroot00000000000000Redistribution 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 copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. libnfc-1.7.1/cmake/modules/FindLIBUSB.cmake000066400000000000000000000040411230265671100202720ustar00rootroot00000000000000# This CMake script wants to use libusb functionality, therefore it looks # for libusb include files and libraries. # # Operating Systems Supported: # - Unix (requires pkg-config) # Tested with Ubuntu 9.04 and Fedora 11 # - Windows (requires MinGW) # Tested with Windows XP/Windows 7 # # This should work for both 32 bit and 64 bit systems. # # Author: F. Kooman # # FreeBSD has built-in libusb since 800069 IF(CMAKE_SYSTEM_NAME MATCHES FreeBSD) EXEC_PROGRAM(sysctl ARGS -n kern.osreldate OUTPUT_VARIABLE FREEBSD_VERSION) SET(MIN_FREEBSD_VERSION 800068) IF(FREEBSD_VERSION GREATER ${MIN_FREEBSD_VERSION}) SET(LIBUSB_FOUND TRUE) SET(LIBUSB_INCLUDE_DIRS "/usr/include") SET(LIBUSB_LIBRARIES "usb") SET(LIBUSB_LIBRARY_DIRS "/usr/lib/") ENDIF(FREEBSD_VERSION GREATER ${MIN_FREEBSD_VERSION}) 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/") # Must fix up variable to avoid backslashes during packaging STRING(REGEX REPLACE "\\\\" "/" LIBUSB_LIBRARY_DIR ${LIBUSB_LIBRARY_DIR}) ELSE(WIN32) # If not under Windows we use PkgConfig FIND_PACKAGE (PkgConfig) IF(PKG_CONFIG_FOUND) PKG_CHECK_MODULES(LIBUSB REQUIRED libusb) ELSE(PKG_CONFIG_FOUND) MESSAGE(FATAL_ERROR "Could not find PkgConfig") ENDIF(PKG_CONFIG_FOUND) ENDIF(WIN32) IF(LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES) SET(LIBUSB_FOUND TRUE) ENDIF(LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES) ENDIF(NOT LIBUSB_FOUND) IF(LIBUSB_FOUND) IF(NOT LIBUSB_FIND_QUIETLY) MESSAGE(STATUS "Found LIBUSB: ${LIBUSB_LIBRARIES} ${LIBUSB_INCLUDE_DIRS}") ENDIF (NOT LIBUSB_FIND_QUIETLY) ELSE(LIBUSB_FOUND) IF(LIBUSB_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find LIBUSB") ENDIF(LIBUSB_FIND_REQUIRED) ENDIF(LIBUSB_FOUND) libnfc-1.7.1/cmake/modules/FindPCRE.cmake000066400000000000000000000022771230265671100200540ustar00rootroot00000000000000# This CMake script wants to use pcre functionality needed for windows # compilation. However, since PCRE isn't really a default install location # there isn't much to search. # # Operating Systems Supported: # - Windows (requires MinGW) # Tested with Windows XP/Windows 7 # # This should work for both 32 bit and 64 bit systems. # # Author: A. Lian # IF(WIN32) IF(NOT PCRE_FOUND) FIND_PATH(PCRE_INCLUDE_DIRS regex.h) FIND_LIBRARY(PCRE_LIBRARIES NAMES PCRE pcre) FIND_PATH(PCRE_BIN_DIRS pcre3.dll) IF(PCRE_INCLUDE_DIRS AND PCRE_LIBRARIES AND PCRE_BIN_DIRS) SET(PCRE_FOUND TRUE) ENDIF(PCRE_INCLUDE_DIRS AND PCRE_LIBRARIES AND PCRE_BIN_DIRS) ENDIF(NOT PCRE_FOUND) IF(PCRE_FOUND) IF(NOT PCRE_FIND_QUIETLY) MESSAGE(STATUS "Found PCRE: ${PCRE_LIBRARIES} ${PCRE_INCLUDE_DIRS} ${PCRE_BIN_DIRS}") ENDIF (NOT PCRE_FIND_QUIETLY) ELSE(PCRE_FOUND) IF(PCRE_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find PCRE") ENDIF(PCRE_FIND_REQUIRED) ENDIF(PCRE_FOUND) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARIES PCRE_INCLUDE_DIRS PCRE_BIN_DIRS ) ENDIF(WIN32) libnfc-1.7.1/cmake/modules/FindPCSC.cmake000066400000000000000000000017071230265671100200500ustar00rootroot00000000000000# - Try to find the PC/SC smart card library # Once done this will define # # PCSC_FOUND - system has the PC/SC library # PCSC_INCLUDE_DIRS - the PC/SC include directory # PCSC_LIBRARIES - The libraries needed to use PC/SC # # Author: F. Kooman # Version: 20101019 # FIND_PACKAGE (PkgConfig) IF(PKG_CONFIG_FOUND) # Will find PC/SC library on Linux/BSDs using PkgConfig PKG_CHECK_MODULES(PCSC libpcsclite) # PKG_CHECK_MODULES(PCSC QUIET libpcsclite) # IF CMake >= 2.8.2? ENDIF(PKG_CONFIG_FOUND) IF(NOT PCSC_FOUND) # Will find PC/SC headers both on Mac and Windows FIND_PATH(PCSC_INCLUDE_DIRS WinSCard.h) # PCSC library is for Mac, WinSCard library is for Windows FIND_LIBRARY(PCSC_LIBRARIES NAMES PCSC libwinscard) ENDIF(NOT PCSC_FOUND) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSC DEFAULT_MSG PCSC_LIBRARIES PCSC_INCLUDE_DIRS ) MARK_AS_ADVANCED(PCSC_INCLUDE_DIRS PCSC_LIBRARIES) libnfc-1.7.1/cmake/modules/LibnfcDrivers.cmake000066400000000000000000000050231230265671100212460ustar00rootroot00000000000000SET(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) SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)") SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)") ENDIF(WIN32) SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)") SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)") IF(LIBNFC_DRIVER_ACR122_PCSC) FIND_PACKAGE(PCSC REQUIRED) ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_pcsc") ENDIF(LIBNFC_DRIVER_ACR122_PCSC) IF(LIBNFC_DRIVER_ACR122_USB) FIND_PACKAGE(LIBUSB REQUIRED) ADD_DEFINITIONS("-DDRIVER_ACR122_USB_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb") ENDIF(LIBNFC_DRIVER_ACR122_USB) IF(LIBNFC_DRIVER_ACR122S) ADD_DEFINITIONS("-DDRIVER_ACR122S_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122s") SET(UART_REQUIRED TRUE) ENDIF(LIBNFC_DRIVER_ACR122S) IF(LIBNFC_DRIVER_ARYGON) ADD_DEFINITIONS("-DDRIVER_ARYGON_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/arygon") SET(UART_REQUIRED TRUE) ENDIF(LIBNFC_DRIVER_ARYGON) IF(LIBNFC_DRIVER_PN532_I2C) ADD_DEFINITIONS("-DDRIVER_PN532_I2C_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_i2c") SET(I2C_REQUIRED TRUE) ENDIF(LIBNFC_DRIVER_PN532_I2C) IF(LIBNFC_DRIVER_PN532_SPI) ADD_DEFINITIONS("-DDRIVER_PN532_SPI_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_spi") SET(SPI_REQUIRED TRUE) ENDIF(LIBNFC_DRIVER_PN532_SPI) IF(LIBNFC_DRIVER_PN532_UART) ADD_DEFINITIONS("-DDRIVER_PN532_UART_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_uart") SET(UART_REQUIRED TRUE) ENDIF(LIBNFC_DRIVER_PN532_UART) IF(LIBNFC_DRIVER_PN53X_USB) FIND_PACKAGE(LIBUSB REQUIRED) ADD_DEFINITIONS("-DDRIVER_PN53X_USB_ENABLED") SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn53x_usb") SET(USB_REQUIRED TRUE) ENDIF(LIBNFC_DRIVER_PN53X_USB) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/drivers) libnfc-1.7.1/cmake/modules/Makefile.am000066400000000000000000000002111230265671100175360ustar00rootroot00000000000000EXTRA_DIST = \ COPYING-CMAKE-SCRIPTS \ FindLIBUSB.cmake \ FindPCSC.cmake \ FindPCRE.cmake \ UseDoxygen.cmake \ LibnfcDrivers.cmake libnfc-1.7.1/cmake/modules/UseDoxygen.cmake000066400000000000000000000054311230265671100206070ustar00rootroot00000000000000# - Run Doxygen # # Adds a doxygen target that runs doxygen to generate the html # and optionally the LaTeX API documentation. # The doxygen target is added to the doc target as dependency. # i.e.: the API documentation is built with: # make doc # # USAGE: GLOBAL INSTALL # # Install it with: # cmake ./ && sudo make install # Add the following to the CMakeLists.txt of your project: # include(UseDoxygen OPTIONAL) # Optionally copy Doxyfile.in in the directory of CMakeLists.txt and edit it. # # USAGE: INCLUDE IN PROJECT # # set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}) # include(UseDoxygen) # Add the Doxyfile.in and UseDoxygen.cmake files to the projects source directory. # # # Variables you may define are: # DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored. Defaults to "doc". # # DOXYFILE_LATEX_DIR - Directory where the Doxygen LaTeX output is stored. Defaults to "latex". # # DOXYFILE_HTML_DIR - Directory where the Doxygen html output is stored. Defaults to "html". # # # Copyright (c) 2009 Tobias Rautenkranz # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # macro(usedoxygen_set_default name value) if(NOT DEFINED "${name}") set("${name}" "${value}") endif() endmacro() find_package(Doxygen) if(DOXYGEN_FOUND) find_file(DOXYFILE_IN "Doxyfile.in" PATHS "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_ROOT}/Modules/") include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Doxyfile.in DEFAULT_MSG DOXYFILE_IN) endif() if(DOXYGEN_FOUND AND DOXYFILE_IN) add_custom_target(doxygen ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc") usedoxygen_set_default(DOXYFILE_HTML_DIR "html") set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR}") set(DOXYFILE_LATEX "NO") set(DOXYFILE_PDFLATEX "NO") set(DOXYFILE_DOT "NO") find_package(LATEX) if(LATEX_COMPILER AND MAKEINDEX_COMPILER) set(DOXYFILE_LATEX "YES") usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex") set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}") if(PDFLATEX_COMPILER) set(DOXYFILE_PDFLATEX "YES") endif() if(DOXYGEN_DOT_EXECUTABLE) set(DOXYFILE_DOT "YES") endif() add_custom_command(TARGET doxygen POST_BUILD COMMAND ${CMAKE_MAKE_PROGRAM} WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}") endif() configure_file(${DOXYFILE_IN} Doxyfile ESCAPE_QUOTES IMMEDIATE @ONLY) get_target_property(DOC_TARGET doc TYPE) if(NOT DOC_TARGET) add_custom_target(doc) endif() add_dependencies(doc doxygen) endif() libnfc-1.7.1/configure.ac000066400000000000000000000133341230265671100152520ustar00rootroot00000000000000# General init # /!\ Don't forget to update 'CMakeLists.txt' too /!\ AC_INIT([libnfc],[1.7.1],[nfc-tools@googlegroups.com]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADER(config.h) # GIT revison GIT_REVISION=`which git > /dev/null && git describe` if test x"$GIT_REVISION" != x""; then AC_DEFINE_UNQUOTED([GIT_REVISION], ["$GIT_REVISION"], [GIT revision]) fi AM_INIT_AUTOMAKE(subdir-objects dist-bzip2 no-dist-gzip) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) AC_LANG([C]) AC_PROG_CC AC_PROG_MAKE_SET WITH_POSIX_ONLY_EXAMPLES=1 # Libtool LT_INIT case "$host" in *-pc-linux-gnu) AC_MSG_RESULT([Fixing libtool for -rpath problems.]) sed -i -r 's/(hardcode_into_libs)=.*$/\1=no/' libtool ;; *-pc-mingw32msvc) WITH_POSIX_ONLY_EXAMPLES=0 AC_MSG_RESULT([Disable extended examples due to target Windows system.]) # Undefine __STRICT_ANSI__ to allow to use strdup, putenv, etc. without warnings CFLAGS="$CFLAGS -U__STRICT_ANSI__" ;; esac AM_CONDITIONAL(POSIX_ONLY_EXAMPLES_ENABLED, [test "$WITH_POSIX_ONLY_EXAMPLES" = "1"]) PKG_PROG_PKG_CONFIG # Checks for header files. AC_HEADER_STDC 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_FUNCS([memmove memset select strdup strerror strstr strtol usleep], [AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])]) AC_DEFINE(_NETBSD_SOURCE, 1, [Define on NetBSD to activate all library features]) AC_DEFINE(_DARWIN_C_SOURCE, 1, [Define on Darwin to activate all library features]) # Note: malloc function should be tested but it produces some error while cross-compiling with MinGW # AC_FUNC_MALLOC # Checks for types AC_TYPE_SIZE_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_OFF_T LIBNFC_CFLAGS='-I$(top_srcdir)/libnfc -I$(top_builddir)/include -I$(top_srcdir)/include' AC_SUBST(LIBNFC_CFLAGS) # Log support (default:yes) AC_ARG_ENABLE([log],AS_HELP_STRING([--disable-log],[Disable any logs]),[enable_log=$enableval],[enable_log="yes"]) AC_MSG_CHECKING(for log flag) AC_MSG_RESULT($enable_log) AM_CONDITIONAL([WITH_LOG], [test "$enable_log" != "no"]) if test x"$enable_log" = "xyes" then AC_DEFINE([LOG], [1], [Enable log]) fi # Conffiles support (default:yes) AC_ARG_ENABLE([conffiles],AS_HELP_STRING([--disable-conffiles],[Disable use of config files]),[enable_conffiles=$enableval],[enable_conffiles="yes"]) AC_MSG_CHECKING(for conffiles flag) AC_MSG_RESULT($enable_conffiles) AM_CONDITIONAL([WITH_CONFFILES], [test "$enable_conffiles" != "no"]) if test x"$enable_conffiles" = "xyes" then AC_DEFINE([CONFFILES], [1], [Enable conffiles]) fi # Envvars support (default:yes) AC_ARG_ENABLE([envvars],AS_HELP_STRING([--disable-envvars],[Disable use of environment variables]),[enable_envvars=$enableval],[enable_envvars="yes"]) AC_MSG_CHECKING(for envvars flag) AC_MSG_RESULT($enable_envvars) AM_CONDITIONAL([WITH_ENVVARS], [test "$enable_envvars" != "no"]) if test x"$enable_envvars" = "xyes" then AC_DEFINE([ENVVARS], [1], [Enable envvars]) fi # Debug support (default:no) AC_ARG_ENABLE([debug],AS_HELP_STRING([--enable-debug],[Enable debug mode]),[enable_debug=$enableval],[enable_debug="no"]) AC_MSG_CHECKING(for debug flag) AC_MSG_RESULT($enable_debug) AM_CONDITIONAL([WITH_DEBUG], [test "$enable_debug" != "no"]) if test x"$enable_debug" = "xyes" then AC_DEFINE([DEBUG], [1], [Enable debug flag]) CFLAGS="$CFLAGS -g -O0 -ggdb" fi # Handle --with-drivers option LIBNFC_ARG_WITH_DRIVERS # Enable UART if AM_CONDITIONAL(UART_ENABLED, [test x"$uart_required" = x"yes"]) # Enable SPI if AM_CONDITIONAL(SPI_ENABLED, [test x"$spi_required" = x"yes"]) # Enable I2C if AM_CONDITIONAL(I2C_ENABLED, [test x"$i2c_required" = x"yes"]) # Documentation (default: no) AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"]) AC_MSG_CHECKING(for documentation request) AC_MSG_RESULT($enable_doc) if test x"$enable_doc" = "xyes" then AC_PATH_PROG([DOXYGEN], [doxygen]) if test x$DOXYGEN = x then AC_MSG_ERROR([doxygen is mandatory.]) fi fi AM_CONDITIONAL(DOC_ENABLED, [test x"$enable_doc" = xyes]) # Dependencies PKG_CONFIG_REQUIRES="" LIBNFC_CHECK_LIBUSB LIBNFC_CHECK_PCSC AC_SUBST(PKG_CONFIG_REQUIRES) AM_CONDITIONAL(LIBUSB_ENABLED, [test "$HAVE_LIBUSB" = "1"]) AM_CONDITIONAL(PCSC_ENABLED, [test "$HAVE_PCSC" = "1"]) CUTTER_REQUIRED_VERSION=1.1.7 m4_ifdef([AC_CHECK_CUTTER], [AC_CHECK_CUTTER([>= $CUTTER_REQUIRED_VERSION])], [ac_cv_use_cutter="no"]) if test x$ac_cv_with_cutter = xyes -a x$ac_cv_use_cutter = xno; then AC_MSG_ERROR([cutter >= $CUTTER_REQUIRED_VERSION is mandatory.]) fi AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"]) AC_CHECK_READLINE # Help us to write great code ;-) CFLAGS="$CFLAGS -Wall -pedantic -Wextra" # Defines and C flags CFLAGS="$CFLAGS -std=c99" # Workarounds for libusb in c99 CFLAGS="$CFLAGS -Du_int8_t=uint8_t -Du_int16_t=uint16_t" AC_CONFIG_FILES([ Doxyfile Makefile cmake/Makefile cmake/modules/Makefile contrib/Makefile contrib/devd/Makefile contrib/libnfc/Makefile contrib/linux/Makefile contrib/udev/Makefile contrib/win32/Makefile contrib/win32/sys/Makefile contrib/win32/libnfc/Makefile contrib/win32/libnfc/buses/Makefile examples/Makefile examples/pn53x-tamashell-scripts/Makefile include/Makefile include/nfc/Makefile libnfc.pc libnfc/Makefile libnfc/buses/Makefile libnfc/chips/Makefile libnfc/drivers/Makefile test/Makefile utils/Makefile ]) AC_OUTPUT LIBNFC_DRIVERS_SUMMARY libnfc-1.7.1/contrib/000077500000000000000000000000001230265671100144205ustar00rootroot00000000000000libnfc-1.7.1/contrib/Makefile.am000066400000000000000000000001211230265671100164460ustar00rootroot00000000000000SUBDIRS = \ devd \ libnfc \ linux \ udev \ win32 EXTRA_DIST = \ windows.h libnfc-1.7.1/contrib/devd/000077500000000000000000000000001230265671100153425ustar00rootroot00000000000000libnfc-1.7.1/contrib/devd/Makefile.am000066400000000000000000000000331230265671100173720ustar00rootroot00000000000000EXTRA_DIST = \ pn53x.conf libnfc-1.7.1/contrib/devd/pn53x.conf000066400000000000000000000015531230265671100171720ustar00rootroot00000000000000# FreeBSD devd(8) rules for PN531 & PN533 devices. attach 110 { match "vendor" "0x04cc"; match "product" "(0x0531|0x2533)"; action "/usr/bin/chgrp nfc /dev/$device-name"; action "/bin/chmod g+rw /dev/$device-name"; }; attach 110 { match "vendor" "0x04e6"; match "product" "0x5591"; action "/usr/bin/chgrp nfc /dev/$device-name"; action "/bin/chmod g+rw /dev/$device-name"; }; attach 110 { match "vendor" "0x054c"; match "product" "0x0193"; action "/usr/bin/chgrp nfc /dev/$device-name"; action "/bin/chmod g+rw /dev/$device-name"; }; attach 110 { match "vendor" "0x1fd3"; match "product" "0x0608"; action "/usr/bin/chgrp nfc /dev/$device-name"; action "/bin/chmod g+rw /dev/$device-name"; }; attach 110 { match "vendor" "0x054c"; match "product" "0x02e1"; action "/usr/bin/chgrp nfc /dev/$device-name"; action "/bin/chmod g+rw /dev/$device-name"; }; libnfc-1.7.1/contrib/libnfc/000077500000000000000000000000001230265671100156555ustar00rootroot00000000000000libnfc-1.7.1/contrib/libnfc/Makefile.am000066400000000000000000000001641230265671100177120ustar00rootroot00000000000000EXTRA_DIST = \ pn532_via_uart2usb.conf.sample \ arygon.conf.sample \ pn532_uart_on_rpi.conf.sample libnfc-1.7.1/contrib/libnfc/arygon.conf.sample000066400000000000000000000002051230265671100213000ustar00rootroot00000000000000## Typical configuration file for Arygon/IDentive device (with Arygon-MCU on board) name = "IDentive" connstring = arygon:/dev/ttyS0 libnfc-1.7.1/contrib/libnfc/pn532_i2c_on_rpi.conf.sample000066400000000000000000000011511230265671100227540ustar00rootroot00000000000000## Typical configuration file for PN532 device on R-Pi connected using I2C ## Note: to use SPI port on R-Pi, you have to load kernel modules i2c-bcm2708 and i2c-dev: ## Edit /etc/modprobe.d/raspi-blacklist.conf and comment: #blacklist i2c-bcm2708 ## Edit /etc/modules and add a new line: i2c-dev name = "PN532 board via I2C" connstring = pn532_i2c:/dev/i2c-0 # Note: If you have an R-Pi revision 2.0, the I2C bus #1 is now routed to connector P1 # (instead of the I2C bus #0 routed on same connector on initial board revision), so # the configuration to use would probably be: # connstring = pn532_i2c:/dev/i2c-1 libnfc-1.7.1/contrib/libnfc/pn532_spi_on_rpi.conf.sample000066400000000000000000000004641230265671100231000ustar00rootroot00000000000000## Typical configuration file for PN532 device on R-Pi connected using SPI ## Note: to use SPI port on R-Pi, you have to load kernel module spi-bcm2708: ## Edit /etc/modprobe.d/raspi-blacklist.conf and comment: #blacklist spi-bcm2708 name = "PN532 board via SPI" connstring = pn532_spi:/dev/spidev0.0:500000 libnfc-1.7.1/contrib/libnfc/pn532_uart_on_rpi.conf.sample000066400000000000000000000004641230265671100232600ustar00rootroot00000000000000## Typical configuration file for PN532 device on R-Pi connected using UART ## Note: to use UART port on R-Pi, you have to disable linux serial console: ## http://learn.adafruit.com/adafruit-nfc-rfid-on-raspberry-pi/freeing-uart-on-the-pi name = "PN532 board via UART" connstring = pn532_uart:/dev/ttyAMA0 libnfc-1.7.1/contrib/libnfc/pn532_via_uart2usb.conf.sample000066400000000000000000000002421230265671100233370ustar00rootroot00000000000000## Typical configuration file for PN532 board (ie. microbuilder.eu / Adafruit) device name = "Adafruit PN532 board via UART" connstring = pn532_uart:/dev/ttyUSB0 libnfc-1.7.1/contrib/linux/000077500000000000000000000000001230265671100155575ustar00rootroot00000000000000libnfc-1.7.1/contrib/linux/Makefile.am000066400000000000000000000000461230265671100176130ustar00rootroot00000000000000EXTRA_DIST = \ blacklist-libnfc.conf libnfc-1.7.1/contrib/linux/blacklist-libnfc.conf000066400000000000000000000000361230265671100216300ustar00rootroot00000000000000blacklist nfc blacklist pn533 libnfc-1.7.1/contrib/udev/000077500000000000000000000000001230265671100153635ustar00rootroot00000000000000libnfc-1.7.1/contrib/udev/42-pn53x.rules000066400000000000000000000016111230265671100176360ustar00rootroot00000000000000# udev rules file for PN531 and PN533 devices (for udev 0.98 version) # to be installed in /etc/udev/rules.d SUBSYSTEM!="usb|usb_device", GOTO="pn53x_rules_end" ACTION!="add", GOTO="pn53x_rules_end" # PN531 ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="0531", MODE="0664", GROUP="plugdev" ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0193", MODE="0664", GROUP="plugdev" # PN533 ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="2533", MODE="0664", GROUP="plugdev" ATTRS{idVendor}=="04e6", ATTRS{idProduct}=="5591", MODE="0664", GROUP="plugdev" ATTRS{idVendor}=="1fd3", ATTRS{idProduct}=="0608", MODE="0664", GROUP="plugdev" ATTRS{idVendor}=="054c", ATTRS{idProduct}=="02e1", MODE="0664", GROUP="plugdev" # ACR122 / Touchatag ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2200", MODE="0664", GROUP="plugdev" ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90cc", MODE="0664", GROUP="plugdev" LABEL="pn53x_rules_end" libnfc-1.7.1/contrib/udev/Makefile.am000066400000000000000000000000371230265671100174170ustar00rootroot00000000000000EXTRA_DIST = \ 42-pn53x.rules libnfc-1.7.1/contrib/win32/000077500000000000000000000000001230265671100153625ustar00rootroot00000000000000libnfc-1.7.1/contrib/win32/Makefile.am000066400000000000000000000001441230265671100174150ustar00rootroot00000000000000SUBDIRS = libnfc sys . EXTRA_DIST = \ err.h \ nfc.def \ stdlib.c \ unistd.h \ version.rc.in libnfc-1.7.1/contrib/win32/err.h000066400000000000000000000005411230265671100163230ustar00rootroot00000000000000#ifndef _ERR_H_ #define _ERR_H_ #include #define warnx(...) do { \ fprintf (stderr, __VA_ARGS__); \ fprintf (stderr, "\n"); \ } while (0) #define errx(code, ...) do { \ fprintf (stderr, __VA_ARGS__); \ fprintf (stderr, "\n"); \ exit (code); \ } while (0) #define err errx #endif /* !_ERR_H_ */ libnfc-1.7.1/contrib/win32/libnfc/000077500000000000000000000000001230265671100166175ustar00rootroot00000000000000libnfc-1.7.1/contrib/win32/libnfc/Makefile.am000066400000000000000000000000621230265671100206510ustar00rootroot00000000000000SUBDIRS = buses . EXTRA_DIST = \ log-internal.c libnfc-1.7.1/contrib/win32/libnfc/buses/000077500000000000000000000000001230265671100177405ustar00rootroot00000000000000libnfc-1.7.1/contrib/win32/libnfc/buses/Makefile.am000066400000000000000000000000271230265671100217730ustar00rootroot00000000000000EXTRA_DIST = \ uart.c libnfc-1.7.1/contrib/win32/libnfc/buses/uart.c000066400000000000000000000202241230265671100210570ustar00rootroot00000000000000/*- * 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: * * 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 * */ /** * @file uart.c * @brief Windows UART driver */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "uart.h" #include #include "nfc-internal.h" #include #include "log.h" #define LOG_GROUP NFC_LOG_GROUP_COM #define LOG_CATEGORY "libnfc.bus.uart_win32" // Handle platform specific includes #include "contrib/windows.h" #define delay_ms( X ) Sleep( X ) struct serial_port_windows { HANDLE hPort; // Serial port handle DCB dcb; // Device control settings COMMTIMEOUTS ct; // Serial port time-out configuration }; serial_port uart_open(const char *pcPortName) { char acPortName[255]; struct serial_port_windows *sp = malloc(sizeof(struct serial_port_windows)); if (sp == 0) return INVALID_SERIAL_PORT; // Copy the input "com?" to "\\.\COM?" format sprintf(acPortName, "\\\\.\\%s", pcPortName); _strupr(acPortName); // Try to open the serial port sp->hPort = CreateFileA(acPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (sp->hPort == INVALID_HANDLE_VALUE) { uart_close(sp); return INVALID_SERIAL_PORT; } // Prepare the device control memset(&sp->dcb, 0, sizeof(DCB)); sp->dcb.DCBlength = sizeof(DCB); if (!BuildCommDCBA("baud=9600 data=8 parity=N stop=1", &sp->dcb)) { uart_close(sp); return INVALID_SERIAL_PORT; } // Update the active serial port if (!SetCommState(sp->hPort, &sp->dcb)) { uart_close(sp); return INVALID_SERIAL_PORT; } sp->ct.ReadIntervalTimeout = 30; sp->ct.ReadTotalTimeoutMultiplier = 0; sp->ct.ReadTotalTimeoutConstant = 30; sp->ct.WriteTotalTimeoutMultiplier = 30; sp->ct.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(sp->hPort, &sp->ct)) { uart_close(sp); return INVALID_SERIAL_PORT; } PurgeComm(sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR); return sp; } void uart_close(const serial_port sp) { if (((struct serial_port_windows *) sp)->hPort != INVALID_HANDLE_VALUE) { CloseHandle(((struct serial_port_windows *) sp)->hPort); } free(sp); } void uart_flush_input(const serial_port sp, bool wait) { PurgeComm(((struct serial_port_windows *) sp)->hPort, PURGE_RXABORT | PURGE_RXCLEAR); } void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { struct serial_port_windows *spw; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed); // Set port speed (Input and Output) switch (uiPortSpeed) { case 9600: case 19200: case 38400: case 57600: case 115200: case 230400: case 460800: break; default: log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d bauds. Speed value must be one of these constants: 9600 (default), 19200, 38400, 57600, 115200, 230400 or 460800.", uiPortSpeed); return; }; spw = (struct serial_port_windows *) sp; // Set baud rate spw->dcb.BaudRate = uiPortSpeed; if (!SetCommState(spw->hPort, &spw->dcb)) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to apply new speed settings."); return; } PurgeComm(spw->hPort, PURGE_RXABORT | PURGE_RXCLEAR); } uint32_t uart_get_speed(const serial_port sp) { const struct serial_port_windows *spw = (struct serial_port_windows *) sp; if (!GetCommState(spw->hPort, (serial_port) & spw->dcb)) return spw->dcb.BaudRate; return 0; } int uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout) { DWORD dwBytesToGet = (DWORD)szRx; DWORD dwBytesReceived = 0; DWORD dwTotalBytesReceived = 0; BOOL res; // XXX Put this part into uart_win32_timeouts () ? DWORD timeout_ms = timeout; COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = 0; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = timeout_ms; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = timeout_ms; if (!SetCommTimeouts(((struct serial_port_windows *) sp)->hPort, &timeouts)) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to apply new timeout settings."); return NFC_EIO; } 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() volatile bool *abort_flag_p = (volatile bool *)abort_p; do { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ReadFile"); res = ReadFile(((struct serial_port_windows *) sp)->hPort, pbtRx + dwTotalBytesReceived, dwBytesToGet, &dwBytesReceived, NULL); dwTotalBytesReceived += dwBytesReceived; if (!res) { DWORD err = GetLastError(); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "ReadFile error: %lu", err); return NFC_EIO; } else if (dwBytesReceived == 0) { return NFC_ETIMEOUT; } if (((DWORD)szRx) > dwTotalBytesReceived) { dwBytesToGet -= dwBytesReceived; } if (abort_flag_p != NULL && (*abort_flag_p) && dwTotalBytesReceived == 0) { return NFC_EOPABORTED; } } while (((DWORD)szRx) > dwTotalBytesReceived); LOG_HEX(LOG_GROUP, "RX", pbtRx, szRx); return (dwTotalBytesReceived == (DWORD) szRx) ? 0 : NFC_EIO; } int uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) { DWORD dwTxLen = 0; COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = 0; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = timeout; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = timeout; if (!SetCommTimeouts(((struct serial_port_windows *) sp)->hPort, &timeouts)) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to apply new timeout settings."); return NFC_EIO; } LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx); if (!WriteFile(((struct serial_port_windows *) sp)->hPort, pbtTx, szTx, &dwTxLen, NULL)) { return NFC_EIO; } if (!dwTxLen) return NFC_EIO; return 0; } BOOL is_port_available(int nPort) { TCHAR szPort[15]; COMMCONFIG cc; DWORD dwCCSize; sprintf(szPort, "COM%d", nPort); // Check if this port is available dwCCSize = sizeof(cc); return GetDefaultCommConfig(szPort, &cc, &dwCCSize); } // Path to the serial port is OS-dependant. // Try to guess what we should use. #define MAX_SERIAL_PORT_WIN 255 char ** uart_list_ports(void) { char **availablePorts = malloc((1 + MAX_SERIAL_PORT_WIN) * sizeof(char *)); if (!availablePorts) { perror("malloc"); return availablePorts; } int curIndex = 0; int i; for (i = 1; i <= MAX_SERIAL_PORT_WIN; i++) { if (is_port_available(i)) { availablePorts[curIndex] = (char *)malloc(10); if (!availablePorts[curIndex]) { perror("malloc"); break; } sprintf(availablePorts[curIndex], "COM%d", i); // printf("found candidate port: %s\n", availablePorts[curIndex]); curIndex++; } } availablePorts[curIndex] = NULL; return availablePorts; } libnfc-1.7.1/contrib/win32/libnfc/log-internal.c000066400000000000000000000036631230265671100213660ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Alex Lian * * 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 */ #include "log-internal.h" #include #include #include static void log_output_debug(const char *format, va_list args) { char buffer[1024]; HRESULT hr = StringCbVPrintf(buffer, sizeof(buffer), format, args); // Spew what we got, even if the buffer is not sized large enough if ((STRSAFE_E_INSUFFICIENT_BUFFER == hr) || (S_OK == hr)) OutputDebugString(buffer); } void log_vput_internal(const char *format, va_list args) { vfprintf(stderr, format, args); // Additional windows output to the debug window for debugging purposes log_output_debug(format, args); } void log_put_internal(const char *format, ...) { va_list va; va_start(va, format); vfprintf(stderr, format, va); // Additional windows output to the debug window for debugging purposes log_output_debug(format, va); va_end(va); } libnfc-1.7.1/contrib/win32/nfc.def000066400000000000000000000022071230265671100166110ustar00rootroot00000000000000LIBRARY libnfc VERSION 1.7 EXPORTS nfc_init nfc_exit nfc_open nfc_close nfc_abbort_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_poll_targets 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_set_property_int nfc_device_set_property_bool iso14443a_crc iso14443a_crc_append iso14443a_locate_historical_bytes nfc_version nfc_device_get_information_about str_nfc_modulation_type str_nfc_baud_rate str_nfc_target libnfc-1.7.1/contrib/win32/stdlib.c000066400000000000000000000032021230265671100170040ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Alex Lian * * 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 * */ /** * @file stdlib.c * @brief Windows System compatibility */ // Handle platform specific includes #include "contrib/windows.h" int setenv(const char *name, const char *value, int overwrite) { int exists = GetEnvironmentVariableA(name, NULL, 0); if ((exists && overwrite) || (!exists)) { if (!SetEnvironmentVariableA(name, value)) { // Set errno here correctly return -1; } return 0; } // Exists and overwrite is 0. return -1; } void unsetenv(const char *name) { SetEnvironmentVariableA(name, NULL); } libnfc-1.7.1/contrib/win32/sys/000077500000000000000000000000001230265671100162005ustar00rootroot00000000000000libnfc-1.7.1/contrib/win32/sys/Makefile.am000066400000000000000000000000311230265671100202260ustar00rootroot00000000000000EXTRA_DIST = \ select.h libnfc-1.7.1/contrib/win32/sys/select.h000066400000000000000000000020451230265671100176310ustar00rootroot00000000000000/*- * 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 * * 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 */ /** * @file select.h * @brief Dummy file to make the code compile under Windows */ libnfc-1.7.1/contrib/win32/unistd.h000066400000000000000000000027731230265671100170520ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file unistd.h * @brief This file intended to serve as a drop-in replacement for unistd.h on Windows */ #ifndef _UNISTD_H_ #define _UNISTD_H_ #include "contrib/windows.h" // Needed by Sleep() under Windows # include # define sleep(X) Sleep( X * 1000) // With MinGW, getopt(3) is provided as separate header #if defined(WIN32) && defined(__GNUC__) /* mingw compiler */ #include #endif #endif /* _UNISTD_H_ */ libnfc-1.7.1/contrib/win32/version.rc.in000066400000000000000000000021211230265671100177760ustar00rootroot00000000000000#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 FILETYPE @RC_FILE_TYPE@ FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "Comments", "@RC_COMMENT@\0" VALUE "CompanyName", "libnfc.org\0" VALUE "FileDescription", "\0" VALUE "FileVersion", "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@.0\0" VALUE "InternalName", "@RC_INTERNAL_NAME@ @WIN32_MODE@\0" VALUE "LegalCopyright", "Copyright (C) @CURRENT_YEAR@\0" VALUE "OriginalFilename", "@RC_ORIGINAL_NAME@\0" VALUE "ProductName", "@PACKAGE_NAME@ @WIN32_MODE@\0" VALUE "ProductVersion", "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@.0\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 1252 END END libnfc-1.7.1/contrib/windows.h000066400000000000000000000041151230265671100162640ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2011 Glenn Ergeerts * * 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 */ /** * @file windows.h * @brief Provide some windows related hacks due to lack of POSIX compat */ #ifndef __WINDOWS_H__ #define __WINDOWS_H__ # include # include # include "win32/err.h" # if defined (__MINGW32__) /* * Cheating here on the snprintf to incorporate the format argument * into the VA_ARGS. Else we get MinGW errors regarding number of arguments * if doing a fixed string with no arguments. */ # define snprintf(S, n, ...) sprintf(S, __VA_ARGS__) # define pipe(fds) _pipe(fds, 5000, _O_BINARY) # define ETIMEDOUT WSAETIMEDOUT # define ENOTSUP WSAEOPNOTSUPP # define ECONNABORTED WSAECONNABORTED # else # define snprintf sprintf_s # define strdup _strdup # endif /* * setenv and unsetenv are not Windows compliant nor implemented in MinGW. * These declarations get rid of the "implicit declaration warning." */ int setenv(const char *name, const char *value, int overwrite); void unsetenv(const char *name); #endif libnfc-1.7.1/examples/000077500000000000000000000000001230265671100145765ustar00rootroot00000000000000libnfc-1.7.1/examples/CMakeLists.txt000066400000000000000000000025611230265671100173420ustar00rootroot00000000000000SET(EXAMPLES-SOURCES nfc-anticol nfc-dep-initiator nfc-dep-target nfc-emulate-forum-tag2 nfc-emulate-tag nfc-emulate-uid nfc-mfsetuid nfc-poll nfc-relay ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libnfc) # Examples FOREACH(source ${EXAMPLES-SOURCES}) SET (TARGETS ${source}.c) IF(WIN32) SET(RC_COMMENT "${PACKAGE_NAME} example") SET(RC_INTERNAL_NAME ${source}) SET(RC_ORIGINAL_NAME ${source}.exe) SET(RC_FILE_TYPE VFT_APP) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY) LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc) ENDIF(WIN32) ADD_EXECUTABLE(${source} ${TARGETS}) TARGET_LINK_LIBRARIES(${source} nfc) TARGET_LINK_LIBRARIES(${source} nfcutils) INSTALL(TARGETS ${source} RUNTIME DESTINATION bin COMPONENT examples) ENDFOREACH(source) #install required libraries IF(WIN32) INCLUDE(InstallRequiredSystemLibraries) CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/cmake/FixBundle.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake @ONLY) INSTALL(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake) ENDIF(WIN32) IF(NOT WIN32) # Manuals for the examples FILE(GLOB manuals "${CMAKE_CURRENT_SOURCE_DIR}/*.1") INSTALL(FILES ${manuals} DESTINATION ${SHARE_INSTALL_PREFIX}/man/man1 COMPONENT manuals) ENDIF(NOT WIN32) libnfc-1.7.1/examples/Makefile.am000066400000000000000000000055311230265671100166360ustar00rootroot00000000000000SUBDIRS = pn53x-tamashell-scripts bin_PROGRAMS = \ nfc-anticol \ nfc-dep-initiator \ nfc-dep-target \ nfc-emulate-forum-tag2 \ nfc-emulate-tag \ nfc-emulate-uid \ nfc-mfsetuid \ nfc-poll \ nfc-relay \ pn53x-diagnose \ pn53x-sam if POSIX_ONLY_EXAMPLES_ENABLED bin_PROGRAMS += \ pn53x-tamashell endif check_PROGRAMS = \ quick_start_example1 \ quick_start_example2 # set the include path found by configure AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS) AM_CFLAGS = -I$(top_srcdir)/libnfc -I$(top_srcdir) nfc_poll_SOURCES = nfc-poll.c nfc_poll_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_anticol_SOURCES = nfc-anticol.c nfc_anticol_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_relay_SOURCES = nfc-relay.c nfc_relay_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_emulate_forum_tag2_SOURCES = nfc-emulate-forum-tag2.c nfc_emulate_forum_tag2_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_emulate_tag_SOURCES = nfc-emulate-tag.c nfc_emulate_tag_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_emulate_uid_SOURCES = nfc-emulate-uid.c nfc_emulate_uid_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_dep_target_SOURCES = nfc-dep-target.c nfc_dep_target_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_dep_initiator_SOURCES = nfc-dep-initiator.c nfc_dep_initiator_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la nfc_mfsetuid_SOURCES = nfc-mfsetuid.c nfc_mfsetuid_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la pn53x_diagnose_SOURCES = pn53x-diagnose.c pn53x_diagnose_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la pn53x_sam_SOURCES = pn53x-sam.c pn53x_sam_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la pn53x_tamashell_SOURCES = pn53x-tamashell.c pn53x_tamashell_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la pn53x_tamashell_LDFLAGS = @READLINE_LIBS@ quick_start_example1_SOURCES = doc/quick_start_example1.c quick_start_example1_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la quick_start_example2_SOURCES = doc/quick_start_example2.c quick_start_example2_LDADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la dist_man_MANS = \ nfc-anticol.1 \ nfc-dep-initiator.1 \ nfc-dep-target.1 \ nfc-emulate-tag.1 \ nfc-emulate-uid.1 \ nfc-poll.1 \ nfc-relay.1 \ nfc-mfsetuid.1 \ pn53x-diagnose.1 \ pn53x-sam.1 \ pn53x-tamashell.1 \ nfc-emulate-forum-tag2.1 EXTRA_DIST = CMakeLists.txt libnfc-1.7.1/examples/doc/000077500000000000000000000000001230265671100153435ustar00rootroot00000000000000libnfc-1.7.1/examples/doc/quick_start_example1.c000066400000000000000000000046111230265671100216360ustar00rootroot00000000000000/** * @file quick_start_example1.c * @brief Quick start example that presents how to use libnfc */ // To compile this simple example: // $ gcc -o quick_start_example1 quick_start_example1.c -lnfc #include #include static void print_hex(const uint8_t *pbtData, const size_t szBytes) { size_t szPos; for (szPos = 0; szPos < szBytes; szPos++) { printf("%02x ", pbtData[szPos]); } printf("\n"); } int main(int argc, const char *argv[]) { nfc_device *pnd; nfc_target nt; // Allocate only a pointer to nfc_context nfc_context *context; // Initialize libnfc and set the nfc_context nfc_init(&context); if (context == NULL) { printf("Unable to init libnfc (malloc)\n"); exit(EXIT_FAILURE); } // Display libnfc version const char *acLibnfcVersion = nfc_version(); (void)argc; printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); // Open, using the first available NFC device which can be in order of selection: // - default device specified using environment variable or // - first specified device in libnfc.conf (/etc/nfc) or // - first specified device in device-configuration directory (/etc/nfc/devices.d) or // - first auto-detected (if feature is not disabled in libnfc.conf) device pnd = nfc_open(context, NULL); if (pnd == NULL) { printf("ERROR: %s\n", "Unable to open NFC device."); exit(EXIT_FAILURE); } // Set opened NFC device to initiator mode if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); exit(EXIT_FAILURE); } printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); // Poll for a ISO14443A (MIFARE) tag const nfc_modulation nmMifare = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) > 0) { printf("The following (NFC) ISO14443A tag was found:\n"); printf(" ATQA (SENS_RES): "); print_hex(nt.nti.nai.abtAtqa, 2); printf(" UID (NFCID%c): ", (nt.nti.nai.abtUid[0] == 0x08 ? '3' : '1')); print_hex(nt.nti.nai.abtUid, nt.nti.nai.szUidLen); printf(" SAK (SEL_RES): "); print_hex(&nt.nti.nai.btSak, 1); if (nt.nti.nai.szAtsLen) { printf(" ATS (ATR): "); print_hex(nt.nti.nai.abtAts, nt.nti.nai.szAtsLen); } } // Close NFC device nfc_close(pnd); // Release the context nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/doc/quick_start_example2.c000066400000000000000000000047411230265671100216430ustar00rootroot00000000000000/** * @file quick_start_example2.c * @brief Quick start example that presents how to use libnfc */ // This is same example as quick_start_example1.c but using // some helper functions existing in libnfc. // Those functions are not available yet in a library // so binary object must be linked statically: // $ gcc -o quick_start_example2 -lnfc -I../.. quick_start_example2.c ../../utils/nfc-utils.o #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include "utils/nfc-utils.h" int main(int argc, const char *argv[]) { nfc_device *pnd; nfc_target nt; // Allocate only a pointer to nfc_context nfc_context *context; // Initialize libnfc and set the nfc_context nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Display libnfc version const char *acLibnfcVersion = nfc_version(); (void)argc; printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); // Open, using the first available NFC device which can be in order of selection: // - default device specified using environment variable or // - first specified device in libnfc.conf (/etc/nfc) or // - first specified device in device-configuration directory (/etc/nfc/devices.d) or // - first auto-detected (if feature is not disabled in libnfc.conf) device pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("%s", "Unable to open NFC device."); exit(EXIT_FAILURE); } // Set opened NFC device to initiator mode if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); exit(EXIT_FAILURE); } printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); // Poll for a ISO14443A (MIFARE) tag const nfc_modulation nmMifare = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) > 0) { printf("The following (NFC) ISO14443A tag was found:\n"); printf(" ATQA (SENS_RES): "); print_hex(nt.nti.nai.abtAtqa, 2); printf(" UID (NFCID%c): ", (nt.nti.nai.abtUid[0] == 0x08 ? '3' : '1')); print_hex(nt.nti.nai.abtUid, nt.nti.nai.szUidLen); printf(" SAK (SEL_RES): "); print_hex(&nt.nti.nai.btSak, 1); if (nt.nti.nai.szAtsLen) { printf(" ATS (ATR): "); print_hex(nt.nti.nai.abtAts, nt.nti.nai.szAtsLen); } } // Close NFC device nfc_close(pnd); // Release the context nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-anticol.1000066400000000000000000000030001230265671100170460ustar00rootroot00000000000000.TH nfc-anticol 1 "June 26, 2009" "libnfc" "libnfc's examples" .SH NAME nfc-anticol \- Demonstration of NFC anti-collision command line tool based on libnfc .SH SYNOPSIS .B nfc-anticol .SH DESCRIPTION .B nfc-anticol is an anti-collision demonstration tool for ISO/IEC 14443-A tags, performed by custom constructed frames. The first frame must be a short frame which is only 7 bits long. Commercial SDK's often don't support a feature to send frames that are not a multiple of 8 bits (1 byte) long. This makes it impossible to do the anti-collision yourself. The developer has to rely on closed proprietary software and should hope it does not contain vulnerabilities during the anti-collision phase. Performing the anti-collision using custom frames could protect against a malicious tag that, for example, violates the standard by sending frames with unsupported lengths. Note that this is only a demonstration tool, which can not handle multiple tags as real life anti-collisions with multiple tags generate "messy" bits which are neither 0 nor 1. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-anticol.c000066400000000000000000000245111230265671100171420ustar00rootroot00000000000000/*- * 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-anticol.c * @brief Generates one ISO14443-A anti-collision process "by-hand" */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include "utils/nfc-utils.h" #define SAK_FLAG_ATS_SUPPORTED 0x20 #define MAX_FRAME_LEN 264 static uint8_t abtRx[MAX_FRAME_LEN]; static int szRxBits; static size_t szRx = sizeof(abtRx); static uint8_t abtRawUid[12]; static uint8_t abtAtqa[2]; static uint8_t abtSak; static uint8_t abtAts[MAX_FRAME_LEN]; static uint8_t szAts = 0; static size_t szCL = 1;//Always start with Cascade Level 1 (CL1) static nfc_device *pnd; bool quiet_output = false; bool force_rats = false; bool timed = false; bool iso_ats_supported = false; // ISO14443A Anti-Collision Commands uint8_t abtReqa[1] = { 0x26 }; uint8_t abtSelectAll[2] = { 0x93, 0x20 }; uint8_t abtSelectTag[9] = { 0x93, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t abtRats[4] = { 0xe0, 0x50, 0x00, 0x00 }; uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 }; #define CASCADE_BIT 0x04 static bool transmit_bits(const uint8_t *pbtTx, const size_t szTxBits) { uint32_t cycles = 0; // Show transmitted command if (!quiet_output) { printf("Sent bits: "); print_hex_bits(pbtTx, szTxBits); } // Transmit the bit frame command, we don't use the arbitrary parity feature if (timed) { if ((szRxBits = nfc_initiator_transceive_bits_timed(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL, &cycles)) < 0) return false; if ((!quiet_output) && (szRxBits > 0)) { printf("Response after %u cycles\n", cycles); } } else { if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0) return false; } // Show received answer if (!quiet_output) { printf("Received bits: "); print_hex_bits(abtRx, szRxBits); } // Succesful transfer return true; } static bool transmit_bytes(const uint8_t *pbtTx, const size_t szTx) { uint32_t cycles = 0; // Show transmitted command if (!quiet_output) { printf("Sent bits: "); print_hex(pbtTx, szTx); } int res; // Transmit the command bytes if (timed) { if ((res = nfc_initiator_transceive_bytes_timed(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), &cycles)) < 0) return false; if ((!quiet_output) && (res > 0)) { printf("Response after %u cycles\n", cycles); } } else { if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0) return false; } szRx = res; // Show received answer if (!quiet_output) { printf("Received bits: "); print_hex(abtRx, szRx); } // Succesful transfer return true; } static void print_usage(char *argv[]) { printf("Usage: %s [OPTIONS]\n", argv[0]); printf("Options:\n"); printf("\t-h\tHelp. Print this message.\n"); printf("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n"); printf("\t-f\tForce RATS.\n"); printf("\t-t\tMeasure response time (in cycles).\n"); } int main(int argc, char *argv[]) { int arg; // Get commandline options for (arg = 1; arg < argc; arg++) { if (0 == strcmp(argv[arg], "-h")) { print_usage(argv); exit(EXIT_SUCCESS); } else if (0 == strcmp(argv[arg], "-q")) { quiet_output = true; } else if (0 == strcmp(argv[arg], "-f")) { force_rats = true; } else if (0 == strcmp(argv[arg], "-t")) { timed = true; } else { ERR("%s is not supported option.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); } } nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Try to open the NFC reader pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Error opening NFC reader"); nfc_exit(context); exit(EXIT_FAILURE); } // Initialise NFC device as "initiator" if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Configure the CRC if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Use raw send/receive methods if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Disable 14443-4 autoswitching if (nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, false) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC reader: %s opened\n\n", nfc_device_get_name(pnd)); // Send the 7 bits request command specified in ISO 14443A (0x26) if (!transmit_bits(abtReqa, 7)) { printf("Error: No tag available\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } memcpy(abtAtqa, abtRx, 2); // Anti-collision transmit_bytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { printf("WARNING: BCC check failed!\n"); } // Save the UID CL1 memcpy(abtRawUid, abtRx, 4); //Prepare and send CL1 Select-Command memcpy(abtSelectTag + 2, abtRx, 5); iso14443a_crc_append(abtSelectTag, 7); transmit_bytes(abtSelectTag, 9); abtSak = abtRx[0]; // Test if we are dealing with a CL2 if (abtSak & CASCADE_BIT) { szCL = 2;//or more // Check answer if (abtRawUid[0] != 0x88) { printf("WARNING: Cascade bit set but CT != 0x88!\n"); } } if (szCL == 2) { // We have to do the anti-collision for cascade level 2 // Prepare CL2 commands abtSelectAll[0] = 0x95; // Anti-collision transmit_bytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { printf("WARNING: BCC check failed!\n"); } // Save UID CL2 memcpy(abtRawUid + 4, abtRx, 4); // Selection abtSelectTag[0] = 0x95; memcpy(abtSelectTag + 2, abtRx, 5); iso14443a_crc_append(abtSelectTag, 7); transmit_bytes(abtSelectTag, 9); abtSak = abtRx[0]; // Test if we are dealing with a CL3 if (abtSak & CASCADE_BIT) { szCL = 3; // Check answer if (abtRawUid[0] != 0x88) { printf("WARNING: Cascade bit set but CT != 0x88!\n"); } } if (szCL == 3) { // We have to do the anti-collision for cascade level 3 // Prepare and send CL3 AC-Command abtSelectAll[0] = 0x97; transmit_bytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { printf("WARNING: BCC check failed!\n"); } // Save UID CL3 memcpy(abtRawUid + 8, abtRx, 4); // Prepare and send final Select-Command abtSelectTag[0] = 0x97; memcpy(abtSelectTag + 2, abtRx, 5); iso14443a_crc_append(abtSelectTag, 7); transmit_bytes(abtSelectTag, 9); abtSak = abtRx[0]; } } // Request ATS, this only applies to tags that support ISO 14443A-4 if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) { iso_ats_supported = true; } if ((abtRx[0] & SAK_FLAG_ATS_SUPPORTED) || force_rats) { iso14443a_crc_append(abtRats, 2); if (transmit_bytes(abtRats, 4)) { memcpy(abtAts, abtRx, szRx); szAts = szRx; } } // Done, halt the tag now iso14443a_crc_append(abtHalt, 2); transmit_bytes(abtHalt, 4); printf("\nFound tag with\n UID: "); switch (szCL) { case 1: printf("%02x%02x%02x%02x", abtRawUid[0], abtRawUid[1], abtRawUid[2], abtRawUid[3]); break; case 2: printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); printf("%02x%02x%02x%02x", abtRawUid[4], abtRawUid[5], abtRawUid[6], abtRawUid[7]); break; case 3: printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); printf("%02x%02x%02x", abtRawUid[5], abtRawUid[6], abtRawUid[7]); printf("%02x%02x%02x%02x", abtRawUid[8], abtRawUid[9], abtRawUid[10], abtRawUid[11]); break; } printf("\n"); printf("ATQA: %02x%02x\n SAK: %02x\n", abtAtqa[1], abtAtqa[0], abtSak); if (szAts > 1) { // if = 1, it's not actual ATS but error code if (force_rats && ! iso_ats_supported) { printf(" RATS forced\n"); } printf(" ATS: "); print_hex(abtAts, szAts); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-dep-initiator.1000066400000000000000000000020101230265671100201650ustar00rootroot00000000000000.TH nfc-dep-initiator 1 "October 8, 2010" "libnfc" "libnfc's examples" .SH NAME nfc-dep-initiator \- Demonstration tool to send/received data as D.E.P. initiator .SH SYNOPSIS .B nfc-dep-initiator .SH DESCRIPTION .B nfc-dep-initiator is a demonstration tool for putting NFC device in D.E.P. initiator mode. This example will attempt to select a passive D.E.P. target and exchange a simple "Hello" data with target. Note: this example is designed to work with a D.E.P. target driven by \fBnfc-dep-target\fP .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult , .br Romuald Conty . .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-dep-initiator.c000066400000000000000000000075251230265671100202670ustar00rootroot00000000000000/*- * 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-dep-initiator.c * @brief Turns the NFC device into a D.E.P. initiator (see NFCIP-1) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include "utils/nfc-utils.h" #define MAX_FRAME_LEN 264 static nfc_device *pnd; static nfc_context *context; static void stop_dep_communication(int sig) { (void) sig; if (pnd != NULL) { nfc_abort_command(pnd); } else { nfc_exit(context); exit(EXIT_FAILURE); } } int main(int argc, const char *argv[]) { nfc_target nt; uint8_t abtRx[MAX_FRAME_LEN]; uint8_t abtTx[] = "Hello World!"; if (argc > 1) { printf("Usage: %s\n", argv[0]); exit(EXIT_FAILURE); } nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Unable to open NFC device."); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s\n opened", nfc_device_get_name(pnd)); signal(SIGINT, stop_dep_communication); 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_dep_target(pnd, NDM_PASSIVE, NBR_212, NULL, &nt, 1000) < 0) { nfc_perror(pnd, "nfc_initiator_select_dep_target"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } print_nfc_target(&nt, false); printf("Sending: %s\n", abtTx); int res; if ((res = nfc_initiator_transceive_bytes(pnd, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 0)) < 0) { nfc_perror(pnd, "nfc_initiator_transceive_bytes"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } abtRx[res] = 0; printf("Received: %s\n", abtRx); if (nfc_initiator_deselect_target(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_deselect_target"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-dep-target.1000066400000000000000000000017641230265671100174700ustar00rootroot00000000000000.TH nfc-dep-target 1 "October 8, 2010" "libnfc" "libnfc's examples" .SH NAME nfc-dep-target \- Demonstration tool to send/received data as D.E.P. target .SH SYNOPSIS .B nfc-dep-target .SH DESCRIPTION .B nfc-dep-target is a demonstration tool for putting NFC device in D.E.P. target mode. This example will listen for a D.E.P. initiator and exchange a simple "Hello" data with initiator. Note: this example is designed to work with a D.E.P. initiator driven by \fBnfc-dep-initiator\fP. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult , .br Romuald Conty . .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-dep-target.c000066400000000000000000000116471230265671100175530ustar00rootroot00000000000000/*- * 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-dep-target.c * @brief Turns the NFC device into a D.E.P. target (see NFCIP-1) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "utils/nfc-utils.h" #define MAX_FRAME_LEN 264 static nfc_device *pnd; static nfc_context *context; static void stop_dep_communication(int sig) { (void) sig; if (pnd != NULL) { nfc_abort_command(pnd); } else { nfc_exit(context); exit(EXIT_FAILURE); } } int main(int argc, const char *argv[]) { uint8_t abtRx[MAX_FRAME_LEN]; int szRx; uint8_t abtTx[] = "Hello Mars!"; if (argc > 1) { printf("Usage: %s\n", argv[0]); exit(EXIT_FAILURE); } nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } #define MAX_DEVICE_COUNT 2 nfc_connstring connstrings[MAX_DEVICE_COUNT]; size_t szDeviceFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); // Little hack to allow using nfc-dep-initiator & nfc-dep-target from // the same machine: if there is more than one readers opened // nfc-dep-target will open the second reader // (we hope they're always detected in the same order) if (szDeviceFound == 1) { pnd = nfc_open(context, connstrings[0]); } else if (szDeviceFound > 1) { pnd = nfc_open(context, connstrings[1]); } else { printf("No device found.\n"); nfc_exit(context); exit(EXIT_FAILURE); } nfc_target nt = { .nm = { .nmt = NMT_DEP, .nbr = NBR_UNDEFINED }, .nti = { .ndi = { .abtNFCID3 = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0x00, 0x00 }, .szGB = 4, .abtGB = { 0x12, 0x34, 0x56, 0x78 }, .ndm = NDM_UNDEFINED, /* These bytes are not used by nfc_target_init: the chip will provide them automatically to the initiator */ .btDID = 0x00, .btBS = 0x00, .btBR = 0x00, .btTO = 0x00, .btPP = 0x01, }, }, }; if (pnd == NULL) { printf("Unable to open NFC device.\n"); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); signal(SIGINT, stop_dep_communication); printf("NFC device will now act as: "); print_nfc_target(&nt, false); printf("Waiting for initiator request...\n"); if ((szRx = nfc_target_init(pnd, &nt, abtRx, sizeof(abtRx), 0)) < 0) { nfc_perror(pnd, "nfc_target_init"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("Initiator request received. Waiting for data...\n"); if ((szRx = nfc_target_receive_bytes(pnd, abtRx, sizeof(abtRx), 0)) < 0) { nfc_perror(pnd, "nfc_target_receive_bytes"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } abtRx[(size_t) szRx] = '\0'; printf("Received: %s\n", abtRx); printf("Sending: %s\n", abtTx); if (nfc_target_send_bytes(pnd, abtTx, sizeof(abtTx), 0) < 0) { nfc_perror(pnd, "nfc_target_send_bytes"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("Data sent.\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-emulate-forum-tag2.1000066400000000000000000000035041230265671100210430ustar00rootroot00000000000000.Dd September 19, 2012 .Dt NFC-EMULATE-FORUM-TAG2 1 URM .Sh NAME .Nm nfc-emulate-forum-tag2 .Nd NFC Forum tag type 2 emulation command line demonstration tool .Sh SYNOPSIS .Nm .Sh DESCRIPTION .Nm is a demonstration tool that emulates a NFC-Forum Tag Type 2 with NDEF content. .Pp Some devices compliant with NFC-Forum Tag Type 2 can be used with this example, in read mode only. .Sh IMPORTANT This example has been developed using PN533 USB hardware as target and Google Nexus S phone as initiator. .Pp This is know to NOT work with Nokia 6212 Classic and could fail with several NFC Forum compliant devices due to the following reasons: .Pp - The emulated target has only a 4-byte UID while most devices assume a Tag Type 2 has always a 7-byte UID (as a real Mifare Ultralight tag); .Pp - The chip is emulating an ISO/IEC 14443-3 tag, without any hardware helper. If the initiator have too strict timeouts for software-based emulation (which is usually the case), this example will fail. This is not a bug and we can't do anything using this hardware (PN531/PN533). .Pp ACR122 devices (like touchatag, etc.) can be used by this example, but if something goes wrong, you will have to unplug/replug your device. This is not a .Em libnfc's bug, this problem is due to ACR122's internal MCU in front of NFC chip (PN532). .Sh BUGS Please report any bugs on the .Em libnfc issue tracker at: .Em http://code.google.com/p/libnfc/issues .Sh LICENCE .Em libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .Em libnfc-utils and .Em libnfc-examples are covered by the BSD 2-Clause license. .Sh AUTHORS .An Roel Verdult Aq roel@libnfc.org .An Romain Tartière Aq romain@libnfc.org .An Romuald Conty Aq romuald@libnfc.org .Pp This manual page was written by Romuald Conty. It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-emulate-forum-tag2.c000066400000000000000000000145171230265671100211330ustar00rootroot00000000000000/*- * 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-emulate-forum-tag2.c * @brief Emulates a NFC-Forum Tag Type 2 with a NDEF message * This example allow to emulate an NFC-Forum Tag Type 2 that contains * a read-only NDEF message. * * This example has been developed using PN533 USB hardware as target and * Google Nexus S phone as initiator. * * This is know to NOT work with Nokia 6212 Classic and could fail with * several NFC Forum compliant devices due to the following reasons: * - The emulated target has only a 4-byte UID while most devices assume a Tag * Type 2 has always a 7-byte UID (as a real Mifare Ultralight tag); * - The chip is emulating an ISO/IEC 14443-3 tag, without any hardware helper. * If the initiator has too strict timeouts for software-based emulation * (which is usually the case), this example will fail. This is not a bug * and we can't do anything using this hardware (PN531/PN533). */ /* * This implementation was written based on information provided by the * following documents: * * NFC Forum Type 2 Tag Operation * Technical Specification * NFCForum-TS-Type-2-Tag_1.0 - 2007-07-09 * * ISO/IEC 14443-3 * First edition - 2001-02-01 * Identification cards — Contactless integrated circuit(s) cards — Proximity cards * Part 3: Initialization and anticollision */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include "utils/nfc-utils.h" static nfc_device *pnd; static nfc_context *context; static void stop_emulation(int sig) { (void)sig; if (pnd != NULL) { nfc_abort_command(pnd); } else { nfc_exit(context); exit(EXIT_FAILURE); } } static uint8_t __nfcforum_tag2_memory_area[] = { 0x00, 0x00, 0x00, 0x00, // Block 0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // Block 2 (Static lock bytes: CC area and data area are read-only locked) 0xE1, 0x10, 0x06, 0x0F, // Block 3 (CC - NFC-Forum Tag Type 2 version 1.0, Data area (from block 4 to the end) is 48 bytes, Read-only mode) 0x03, 33, 0xd1, 0x02, // Block 4 (NDEF) 0x1c, 0x53, 0x70, 0x91, 0x01, 0x09, 0x54, 0x02, 0x65, 0x6e, 0x4c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x51, 0x01, 0x0b, 0x55, 0x03, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define READ 0x30 #define WRITE 0xA2 #define SECTOR_SELECT 0xC2 #define HALT 0x50 static int nfcforum_tag2_io(struct nfc_emulator *emulator, const uint8_t *data_in, const size_t data_in_len, uint8_t *data_out, const size_t data_out_len) { int res = 0; uint8_t *nfcforum_tag2_memory_area = (uint8_t *)(emulator->user_data); printf(" In: "); print_hex(data_in, data_in_len); switch (data_in[0]) { case READ: if (data_out_len >= 16) { memcpy(data_out, nfcforum_tag2_memory_area + (data_in[1] * 4), 16); res = 16; } else { res = -ENOSPC; } break; case HALT: printf("HALT sent\n"); res = -ECONNABORTED; break; default: printf("Unknown command: 0x%02x\n", data_in[0]); res = -ENOTSUP; } if (res < 0) { ERR("%s (%d)", strerror(-res), -res); } else { printf(" Out: "); print_hex(data_out, res); } return res; } int main(int argc, char *argv[]) { (void)argc; (void)argv; nfc_target nt = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_UNDEFINED, // Will be updated by nfc_target_init() }, .nti = { .nai = { .abtAtqa = { 0x00, 0x04 }, .abtUid = { 0x08, 0x00, 0xb0, 0x0b }, .szUidLen = 4, .btSak = 0x00, .szAtsLen = 0, }, } }; struct nfc_emulation_state_machine state_machine = { .io = nfcforum_tag2_io }; struct nfc_emulator emulator = { .target = &nt, .state_machine = &state_machine, .user_data = __nfcforum_tag2_memory_area, }; signal(SIGINT, stop_emulation); nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Unable to open NFC device"); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); printf("Emulating NDEF tag now, please touch it with a second NFC device\n"); if (nfc_emulate_target(pnd, &emulator, 0) < 0) { nfc_perror(pnd, argv[0]); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-emulate-tag.1000066400000000000000000000040461230265671100176350ustar00rootroot00000000000000.TH nfc-emulate-tag 1 "October 8, 2010" "libnfc" "libnfc's examples" .SH NAME nfc-emulate-tag \- Simple tag emulation command line demonstration tool .SH SYNOPSIS .B nfc-emulate-tag .SH DESCRIPTION .B nfc-emulate-tag is a simple tag emulation tool that demonstrates how emulation can be done using libnfc. Currently, this tool partially emulates a Mifare Mini: it is detected as Mifare Mini but internal MIFARE proprietary commands are not yet implemented. To be able to emulate a target, there are two main parts: - communication: handle modulation, anticollision, etc. - computation: process commands (input) and produce results (output). This demonstration tool proposes a logical structure to handle communication and a simple function to deal with computation. To improve the target capabilities, we can now implement more allowed commands in a single function: target_io() Please note that, due to timing issues, it is very difficult to implement an ISO14443-4 tag this way: RATS request expects a quick ATS answer. By the way, even if you implement another kind of tag, timing issues are often the source of problems like CRC or parity errors. The OmniKey CardMan 5321 is known to be very large on timings and is a good choice if you want to experiment with this emulator with a tolerant reader. .SH IMPORTANT ACR122 devices (like touchatag, etc.) can be used by this example (with probably timing issue), but if something goes wrong, you will have to unplug/replug your device. This is not a .B libnfc's bug, this problem is due to ACR122's internal MCU in front of NFC chip (PN532). .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Romuald Conty .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-emulate-tag.c000066400000000000000000000205631230265671100177210ustar00rootroot00000000000000/*- * 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-emulate-tag.c * @brief Emulates a simple tag */ // Note that depending on the device (initiator) you'll use against, this // emulator it might work or not. Some readers are very strict on responses // timings, e.g. a Nokia NFC and will drop communication too soon for us. #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include "utils/nfc-utils.h" #define MAX_FRAME_LEN (264) #define SAK_ISO14443_4_COMPLIANT 0x20 static uint8_t abtRx[MAX_FRAME_LEN]; static int szRx; static nfc_context *context; static nfc_device *pnd; static bool quiet_output = false; static bool init_mfc_auth = false; static void intr_hdlr(int sig) { (void) sig; printf("\nQuitting...\n"); if (pnd != NULL) { nfc_abort_command(pnd); } nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } static bool target_io(nfc_target *pnt, const uint8_t *pbtInput, const size_t szInput, uint8_t *pbtOutput, size_t *pszOutput) { bool loop = true; *pszOutput = 0; // Show transmitted command if (!quiet_output) { printf(" In: "); print_hex(pbtInput, szInput); } if (szInput) { switch (pbtInput[0]) { case 0x30: // Mifare read // block address is in pbtInput[1] *pszOutput = 15; strcpy((char *)pbtOutput, "You read block "); pbtOutput[15] = pbtInput[1]; break; case 0x50: // HLTA (ISO14443-3) if (!quiet_output) { printf("Initiator HLTA me. Bye!\n"); } loop = false; break; case 0x60: // Mifare authA case 0x61: // Mifare authB // Let's give back a very random nonce... *pszOutput = 2; pbtOutput[0] = 0x12; pbtOutput[1] = 0x34; // Next commands will be without CRC init_mfc_auth = true; break; case 0xe0: // RATS (ISO14443-4) // Send ATS *pszOutput = pnt->nti.nai.szAtsLen + 1; pbtOutput[0] = pnt->nti.nai.szAtsLen + 1; // ISO14443-4 says that ATS contains ATS_Length as first byte if (pnt->nti.nai.szAtsLen) { memcpy(pbtOutput + 1, pnt->nti.nai.abtAts, pnt->nti.nai.szAtsLen); } break; case 0xc2: // S-block DESELECT if (!quiet_output) { printf("Initiator DESELECT me. Bye!\n"); } loop = false; break; default: // Unknown if (!quiet_output) { printf("Unknown frame, emulated target abort.\n"); } loop = false; } } // Show transmitted command if ((!quiet_output) && *pszOutput) { printf(" Out: "); print_hex(pbtOutput, *pszOutput); } return loop; } static bool nfc_target_emulate_tag(nfc_device *dev, nfc_target *pnt) { size_t szTx; uint8_t abtTx[MAX_FRAME_LEN]; bool loop = true; if ((szRx = nfc_target_init(dev, pnt, abtRx, sizeof(abtRx), 0)) < 0) { nfc_perror(dev, "nfc_target_init"); return false; } while (loop) { loop = target_io(pnt, abtRx, (size_t) szRx, abtTx, &szTx); if (szTx) { if (nfc_target_send_bytes(dev, abtTx, szTx, 0) < 0) { nfc_perror(dev, "nfc_target_send_bytes"); return false; } } if (loop) { if (init_mfc_auth) { if (nfc_device_set_property_bool(dev, NP_HANDLE_CRC, false) < 0) { nfc_perror(pnd, "nfc_target_emulate_tag"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } init_mfc_auth = false; } if ((szRx = nfc_target_receive_bytes(dev, abtRx, sizeof(abtRx), 0)) < 0) { nfc_perror(dev, "nfc_target_receive_bytes"); return false; } } } return true; } int main(int argc, char *argv[]) { (void) argc; const char *acLibnfcVersion; #ifdef WIN32 signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr); #else signal(SIGINT, intr_hdlr); #endif nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Display libnfc version acLibnfcVersion = nfc_version(); printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); // Try to open the NFC reader pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Unable to open NFC device"); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); // Notes for ISO14443-A emulated tags: // * Only short UIDs are supported // If your UID is longer it will be truncated // Therefore e.g. an UltraLight can only have short UID, which is // typically badly handled by readers who still try to send their "0x95" // * First byte of UID will be masked by 0x08 by the PN53x firmware // as security countermeasure against real UID emulation // Example of a Mifare Classic Mini // Note that crypto1 is not implemented in this example nfc_target nt = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_UNDEFINED, }, .nti = { .nai = { .abtAtqa = { 0x00, 0x04 }, .abtUid = { 0x08, 0xab, 0xcd, 0xef }, .btSak = 0x09, .szUidLen = 4, .szAtsLen = 0, }, }, }; /* // Example of a FeliCa nfc_target nt = { .nm = { .nmt = NMT_FELICA, .nbr = NBR_UNDEFINED, }, .nti = { .nfi = { .abtId = { 0x01, 0xFE, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF }, .abtPad = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF }, .abtSysCode = { 0xFF, 0xFF }, }, }, }; */ /* // Example of a ISO14443-4 (DESfire) nfc_target nt = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_UNDEFINED, }, .nti = { .nai = { abtAtqa = { 0x03, 0x44 }, abtUid = { 0x08, 0xab, 0xcd, 0xef }, btSak = 0x20, .szUidLen = 4, .abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, .szAtsLen = 5, }, }, }; */ printf("%s will emulate this ISO14443-A tag:\n", argv[0]); print_nfc_target(&nt, true); // Switch off NP_EASY_FRAMING if target is not ISO14443-4 if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, (nt.nti.nai.btSak & SAK_ISO14443_4_COMPLIANT)) < 0) { nfc_perror(pnd, "nfc_target_emulate_tag"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device (configured as target) is now emulating the tag, please touch it with a second NFC device (initiator)\n"); if (!nfc_target_emulate_tag(pnd, &nt)) { nfc_perror(pnd, "nfc_target_emulate_tag"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-emulate-uid.1000066400000000000000000000054141230265671100176430ustar00rootroot00000000000000.TH nfc-emulate-uid 1 "June 26, 2009" "libnfc" "libnfc's examples" .SH NAME nfc-emulate-uid \- NFC target emulation command line tool based on libnfc .SH SYNOPSIS .B nfc-emulate-uid .RI [ OPTIONS ] .RI [ UID ] .SH DESCRIPTION .B nfc-emulate-uid is a tag emulation tool that allows one to choose any tag UID. Tag emulation is one of the main added features in NFC. But to avoid abuse of existing systems, manufacturers of the NFC controller intentionally did not support emulation of 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 uniqueness of the UID. Unfortunately, this example can't directly start in fully customisable target mode. Just after launching this example, you will have to go through the hardcoded initial anti-collision with the 0x08-prefixed UID. To achieve it, you can e.g. send a RATS (Request for Answer To Select) command by using a second NFC device (placed in target's field) and launching nfc-list or nfc-anticol. After this first step, you now have a NFC device (configured as target) that really emulates a custom UID. You could view it using the second NFC device with nfc-list. Timing control is very important for a successful anti-collision sequence: - The emulator must be very fast to react: Using the ACR122 device gives many timing issues, "PN53x only" USB devices also give some timing issues but an embedded microprocessor would probably improve greatly the situation. - The reader should not be too strict on timing (the standard is very strict). The OmniKey CardMan 5321 is known to be very large on timings and is a good choice if you want to experiment with this emulator with a tolerant reader. Nokia NFC 6212 and Pegoda readers are much too strict and won't be fooled. .SH OPTIONS .IR UID 8 hex digits format that represents desired UID (default is DEADBEEF). .SH IMPORTANT ACR122 devices (like touchatag, etc.) can be used by this example (with timing issues), but if something goes wrong, you will have to unplug/replug your device. This is not a .B libnfc's bug, this problem is due to ACR122's internal MCU in front of NFC chip (PN532). .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-emulate-uid.c000066400000000000000000000171751230265671100177340ustar00rootroot00000000000000/*- * 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-emulate-uid.c * @brief Emulates a tag which which have a "really" custom UID * * NFC devices are able to emulate passive tags but manufacturers restrict the * customization of UID. With PN53x, UID is only 4-byte long and the first * byte of emulated UID is hard-wired to 0x08 which is the standard way to say * this is a random UID. This example shows how to emulate a fully customized * UID by "manually" replying to anti-collision process sent by the initiator. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include "utils/nfc-utils.h" #define MAX_FRAME_LEN 264 static uint8_t abtRecv[MAX_FRAME_LEN]; static int szRecvBits; static nfc_device *pnd; static nfc_context *context; // ISO14443A Anti-Collision response uint8_t abtAtqa[2] = { 0x04, 0x00 }; uint8_t abtUidBcc[5] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x22 }; uint8_t abtSak[9] = { 0x08, 0xb6, 0xdd }; static void intr_hdlr(int sig) { (void) sig; if (pnd != NULL) { printf("\nAborting current command...\n"); nfc_abort_command(pnd); } } static void print_usage(char *argv[]) { printf("Usage: %s [OPTIONS] [UID]\n", argv[0]); printf("Options:\n"); printf("\t-h\tHelp. Print this message.\n"); printf("\t-q\tQuiet mode. Silent output: received and sent frames will not be shown (improves timing).\n"); printf("\n"); printf("\t[UID]\tUID to emulate, specified as 8 HEX digits (default is DEADBEEF).\n"); } int main(int argc, char *argv[]) { uint8_t *pbtTx = NULL; size_t szTxBits; bool quiet_output = false; int arg, i; // Get commandline options for (arg = 1; arg < argc; arg++) { if (0 == strcmp(argv[arg], "-h")) { print_usage(argv); exit(EXIT_SUCCESS); } else if (0 == strcmp(argv[arg], "-q")) { printf("Quiet mode.\n"); quiet_output = true; } else if ((arg == argc - 1) && (strlen(argv[arg]) == 8)) { // See if UID was specified as HEX string uint8_t abtTmp[3] = { 0x00, 0x00, 0x00 }; printf("[+] Using UID: %s\n", argv[arg]); abtUidBcc[4] = 0x00; for (i = 0; i < 4; ++i) { memcpy(abtTmp, argv[arg] + i * 2, 2); abtUidBcc[i] = (uint8_t) strtol((char *) abtTmp, NULL, 16); abtUidBcc[4] ^= abtUidBcc[i]; } } else { ERR("%s is not supported option.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); } } #ifdef WIN32 signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr); #else signal(SIGINT, intr_hdlr); #endif nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Try to open the NFC device pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Unable to open NFC device"); nfc_exit(context); exit(EXIT_FAILURE); } printf("\n"); printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); printf("[+] Try to break out the auto-emulation, this requires a second NFC device!\n"); printf("[+] To do this, please send any command after the anti-collision\n"); printf("[+] For example, send a RATS command or use the \"nfc-anticol\" or \"nfc-list\" tool.\n"); // Note: We have to build a "fake" nfc_target in order to do exactly the same that was done before the new nfc_target_init() was introduced. nfc_target nt = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_UNDEFINED, }, .nti = { .nai = { .abtAtqa = { 0x04, 0x00 }, .abtUid = { 0x08, 0xad, 0xbe, 0xef }, .btSak = 0x20, .szUidLen = 4, .szAtsLen = 0, }, }, }; if ((szRecvBits = nfc_target_init(pnd, &nt, abtRecv, sizeof(abtRecv), 0)) < 0) { nfc_perror(pnd, "nfc_target_init"); ERR("Could not come out of auto-emulation, no command was received"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("[+] Received initiator command: "); print_hex_bits(abtRecv, (size_t) szRecvBits); printf("[+] Configuring communication\n"); if ((nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) || (nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true) < 0)) { nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("[+] Done, the emulated tag is initialized with UID: %02X%02X%02X%02X\n\n", abtUidBcc[0], abtUidBcc[1], abtUidBcc[2], abtUidBcc[3]); while (true) { // Test if we received a frame if ((szRecvBits = nfc_target_receive_bits(pnd, abtRecv, sizeof(abtRecv), 0)) > 0) { // Prepare the command to send back for the anti-collision request switch (szRecvBits) { case 7: // Request or Wakeup pbtTx = abtAtqa; szTxBits = 16; // New anti-collsion session started if (!quiet_output) printf("\n"); break; case 16: // Select All pbtTx = abtUidBcc; szTxBits = 40; break; case 72: // Select Tag pbtTx = abtSak; szTxBits = 24; break; default: // unknown length? szTxBits = 0; break; } if (!quiet_output) { printf("R: "); print_hex_bits(abtRecv, (size_t) szRecvBits); } // Test if we know how to respond if (szTxBits) { // Send and print the command to the screen if (nfc_target_send_bits(pnd, pbtTx, szTxBits, NULL) < 0) { nfc_perror(pnd, "nfc_target_send_bits"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (!quiet_output) { printf("T: "); print_hex_bits(pbtTx, szTxBits); } } } } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-mfsetuid.1000066400000000000000000000021761230265671100172520ustar00rootroot00000000000000.TH nfc-mfsetuid 1 "Sep 05, 2011" "libnfc" "NFC Utilities" .SH NAME nfc-mfsetuid \- MIFARE 1K special card UID setting and recovery tool .SH SYNOPSIS .B nfc-mfsetuid [ .I UID ] .SH DESCRIPTION .B nfc-mfsetuid is a MIFARE tool that allows setting of UID on special versions (Chinese clones) of Mifare 1K cards. It will also recover damaged cards that have had invalid data written to block 0 (e.g. wrong BCC). Currently only 4 Byte UID is supported. Specify an eight hex character UID or leave blank for the default '01234567'. .SH OPTIONS .B -f Format. Wipe all data (set to 0xFF) and reset ACLs to defaults. .B -q Quiet. Suppress output of commands and responses. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Adam Laurie .PP This manual page was written by Adam Laurie . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-mfsetuid.c000066400000000000000000000260201230265671100173260ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2011 Adam Laurie * * 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-mfsetuid.c * @brief Set UID of special Mifare cards */ /** * based on nfc-anticol.c */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include "utils/nfc-utils.h" #define SAK_FLAG_ATS_SUPPORTED 0x20 #define MAX_FRAME_LEN 264 static uint8_t abtRx[MAX_FRAME_LEN]; static int szRxBits; static uint8_t abtRawUid[12]; static uint8_t abtAtqa[2]; static uint8_t abtSak; static uint8_t abtAts[MAX_FRAME_LEN]; static uint8_t szAts = 0; static size_t szCL = 1;//Always start with Cascade Level 1 (CL1) static nfc_device *pnd; bool quiet_output = false; bool iso_ats_supported = false; // ISO14443A Anti-Collision Commands uint8_t abtReqa[1] = { 0x26 }; uint8_t abtSelectAll[2] = { 0x93, 0x20 }; uint8_t abtSelectTag[9] = { 0x93, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t abtRats[4] = { 0xe0, 0x50, 0x00, 0x00 }; uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 }; #define CASCADE_BIT 0x04 // special unlock command uint8_t abtUnlock1[1] = { 0x40 }; uint8_t abtUnlock2[1] = { 0x43 }; uint8_t abtWipe[1] = { 0x41 }; uint8_t abtWrite[4] = { 0xa0, 0x00, 0x5f, 0xb1 }; uint8_t abtData[18] = { 0x01, 0x23, 0x45, 0x67, 0x00, 0x08, 0x04, 0x00, 0x46, 0x59, 0x25, 0x58, 0x49, 0x10, 0x23, 0x02, 0x23, 0xeb }; uint8_t abtBlank[18] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x36, 0xCC }; static bool transmit_bits(const uint8_t *pbtTx, const size_t szTxBits) { // Show transmitted command if (!quiet_output) { printf("Sent bits: "); print_hex_bits(pbtTx, szTxBits); } // Transmit the bit frame command, we don't use the arbitrary parity feature if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0) return false; // Show received answer if (!quiet_output) { printf("Received bits: "); print_hex_bits(abtRx, szRxBits); } // Succesful transfer return true; } static bool transmit_bytes(const uint8_t *pbtTx, const size_t szTx) { // Show transmitted command if (!quiet_output) { printf("Sent bits: "); print_hex(pbtTx, szTx); } int res; // Transmit the command bytes if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0) return false; // Show received answer if (!quiet_output) { printf("Received bits: "); print_hex(abtRx, res); } // Succesful transfer return true; } static void print_usage(char *argv[]) { printf("Usage: %s [OPTIONS] [UID]\n", argv[0]); printf("Options:\n"); printf("\t-h\tHelp. Print this message.\n"); printf("\t-f\tFormat. Delete all data (set to 0xFF) and reset ACLs to default.\n"); printf("\t-q\tQuiet mode. Suppress output of READER and CARD data (improves timing).\n"); printf("\n\tSpecify UID (4 HEX bytes) to set UID, or leave blank for default '01234567'.\n"); printf("\tThis utility can be used to recover cards that have been damaged by writing bad\n"); printf("\tdata (e.g. wrong BCC), thus making them non-selectable by most tools/readers.\n"); printf("\n\t*** Note: this utility only works with special Mifare 1K cards (Chinese clones).\n\n"); } int main(int argc, char *argv[]) { int arg, i; bool format = false; unsigned int c; char tmp[3] = { 0x00, 0x00, 0x00 }; // Get commandline options for (arg = 1; arg < argc; arg++) { if (0 == strcmp(argv[arg], "-h")) { print_usage(argv); exit(EXIT_SUCCESS); } else if (0 == strcmp(argv[arg], "-f")) { format = true; } else if (0 == strcmp(argv[arg], "-q")) { quiet_output = true; } else if (strlen(argv[arg]) == 8) { for (i = 0 ; i < 4 ; ++i) { memcpy(tmp, argv[arg] + i * 2, 2); sscanf(tmp, "%02x", &c); abtData[i] = (char) c; } abtData[4] = abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3]; iso14443a_crc_append(abtData, 16); } else { ERR("%s is not supported option.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); } } nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Try to open the NFC reader pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Error opening NFC reader"); nfc_exit(context); exit(EXIT_FAILURE); } // Initialise NFC device as "initiator" if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Configure the CRC if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Use raw send/receive methods if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Disable 14443-4 autoswitching if (nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, false) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); // Send the 7 bits request command specified in ISO 14443A (0x26) if (!transmit_bits(abtReqa, 7)) { printf("Error: No tag available\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } memcpy(abtAtqa, abtRx, 2); // Anti-collision transmit_bytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { printf("WARNING: BCC check failed!\n"); } // Save the UID CL1 memcpy(abtRawUid, abtRx, 4); //Prepare and send CL1 Select-Command memcpy(abtSelectTag + 2, abtRx, 5); iso14443a_crc_append(abtSelectTag, 7); transmit_bytes(abtSelectTag, 9); abtSak = abtRx[0]; // Test if we are dealing with a CL2 if (abtSak & CASCADE_BIT) { szCL = 2;//or more // Check answer if (abtRawUid[0] != 0x88) { printf("WARNING: Cascade bit set but CT != 0x88!\n"); } } if (szCL == 2) { // We have to do the anti-collision for cascade level 2 // Prepare CL2 commands abtSelectAll[0] = 0x95; // Anti-collision transmit_bytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { printf("WARNING: BCC check failed!\n"); } // Save UID CL2 memcpy(abtRawUid + 4, abtRx, 4); // Selection abtSelectTag[0] = 0x95; memcpy(abtSelectTag + 2, abtRx, 5); iso14443a_crc_append(abtSelectTag, 7); transmit_bytes(abtSelectTag, 9); abtSak = abtRx[0]; // Test if we are dealing with a CL3 if (abtSak & CASCADE_BIT) { szCL = 3; // Check answer if (abtRawUid[0] != 0x88) { printf("WARNING: Cascade bit set but CT != 0x88!\n"); } } if (szCL == 3) { // We have to do the anti-collision for cascade level 3 // Prepare and send CL3 AC-Command abtSelectAll[0] = 0x97; transmit_bytes(abtSelectAll, 2); // Check answer if ((abtRx[0] ^ abtRx[1] ^ abtRx[2] ^ abtRx[3] ^ abtRx[4]) != 0) { printf("WARNING: BCC check failed!\n"); } // Save UID CL3 memcpy(abtRawUid + 8, abtRx, 4); // Prepare and send final Select-Command abtSelectTag[0] = 0x97; memcpy(abtSelectTag + 2, abtRx, 5); iso14443a_crc_append(abtSelectTag, 7); transmit_bytes(abtSelectTag, 9); abtSak = abtRx[0]; } } // Request ATS, this only applies to tags that support ISO 14443A-4 if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) { iso_ats_supported = true; } printf("\nFound tag with\n UID: "); switch (szCL) { case 1: printf("%02x%02x%02x%02x", abtRawUid[0], abtRawUid[1], abtRawUid[2], abtRawUid[3]); break; case 2: printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); printf("%02x%02x%02x%02x", abtRawUid[4], abtRawUid[5], abtRawUid[6], abtRawUid[7]); break; case 3: printf("%02x%02x%02x", abtRawUid[1], abtRawUid[2], abtRawUid[3]); printf("%02x%02x%02x", abtRawUid[5], abtRawUid[6], abtRawUid[7]); printf("%02x%02x%02x%02x", abtRawUid[8], abtRawUid[9], abtRawUid[10], abtRawUid[11]); break; } printf("\n"); printf("ATQA: %02x%02x\n SAK: %02x\n", abtAtqa[1], abtAtqa[0], abtSak); if (szAts > 1) { // if = 1, it's not actual ATS but error code printf(" ATS: "); print_hex(abtAts, szAts); } printf("\n"); // now reset UID iso14443a_crc_append(abtHalt, 2); transmit_bytes(abtHalt, 4); transmit_bits(abtUnlock1, 7); if (format) { transmit_bytes(abtWipe, 1); transmit_bytes(abtHalt, 4); transmit_bits(abtUnlock1, 7); } transmit_bytes(abtUnlock2, 1); transmit_bytes(abtWrite, 4); transmit_bytes(abtData, 18); if (format) { for (i = 3 ; i < 64 ; i += 4) { abtWrite[1] = (char) i; iso14443a_crc_append(abtWrite, 2); transmit_bytes(abtWrite, 4); transmit_bytes(abtBlank, 18); } } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-poll.1000066400000000000000000000036071230265671100164000ustar00rootroot00000000000000.TH nfc-poll 1 "June 26, 2009" "libnfc" "libnfc's examples" .SH NAME nfc-poll \- poll first available NFC target .SH SYNOPSIS .B nfc-poll .SH DESCRIPTION .B nfc-poll is a utility for polling any available target (tags but also NFCIP targets) using ISO14443-A, FeliCa, Jewel and ISO14443-B modulations. This tool uses hardware polling feature if available (ie. PN532) or switch back to software polling, it will display available information retrieved from the tag. .SH OPTIONS .TP .B \-v Tells .I nfc-poll to be verbose and display detailed information about the targets shown. This includes SAK decoding and fingerprinting is available. .SH IMPORTANT There are some well-know limits with this example: - Even with NDO_AUTO_14443_4A enabled (default), .B nfc-poll can miss ATS. That due to the way the PN532 use to poll for ISO14443 type A, it will attempt to find ISO14443-4-only targets, then ISO14443-3. If your ISO14443-4 target is present when PN532 looks for ISO14443-4-only, ATS will be retrieved. But if your target enter the field during ISO14443-3, RATS will not be sent and ATS not retrieved. - .B nfc-poll can show up only one card while two are in field. That's due, again, to the way the PN532 poll for targets. It will stop polling when one modulation got a result, so if you have, for example, one ISO14443-3 (eg. Mifare Ultralight) and one ISO14443-4 (eg. Mifare DESFire), it will probably return only the ISO14443-4. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Romuald Conty .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-poll.c000066400000000000000000000110131230265671100164500ustar00rootroot00000000000000/*- * 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-poll.c * @brief Polling example */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include "utils/nfc-utils.h" #define MAX_DEVICE_COUNT 16 static nfc_device *pnd = NULL; static nfc_context *context; static void stop_polling(int sig) { (void) sig; if (pnd != NULL) nfc_abort_command(pnd); else { nfc_exit(context); exit(EXIT_FAILURE); } } static void print_usage(const char *progname) { printf("usage: %s [-v]\n", progname); printf(" -v\t verbose display\n"); } int main(int argc, const char *argv[]) { bool verbose = false; signal(SIGINT, stop_polling); // Display libnfc version const char *acLibnfcVersion = nfc_version(); printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); if (argc != 1) { if ((argc == 2) && (0 == strcmp("-v", argv[1]))) { verbose = true; } else { print_usage(argv[0]); exit(EXIT_FAILURE); } } const uint8_t uiPollNr = 20; const uint8_t uiPeriod = 2; const nfc_modulation nmModulations[5] = { { .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 }, }; const size_t szModulations = 5; nfc_target nt; int res = 0; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("%s", "Unable to open NFC device."); nfc_exit(context); exit(EXIT_FAILURE); } if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); printf("NFC device will poll during %ld ms (%u pollings of %lu ms for %" PRIdPTR " modulations)\n", (unsigned long) uiPollNr * szModulations * uiPeriod * 150, uiPollNr, (unsigned long) uiPeriod * 150, szModulations); if ((res = nfc_initiator_poll_target(pnd, nmModulations, szModulations, uiPollNr, uiPeriod, &nt)) < 0) { nfc_perror(pnd, "nfc_initiator_poll_target"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (res > 0) { print_nfc_target(&nt, verbose); } else { printf("No target found.\n"); } printf("Waiting for card removing..."); while (0 == nfc_initiator_target_is_present(pnd, NULL)) {} nfc_perror(pnd, "nfc_initiator_target_is_present"); printf("done.\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/nfc-relay.1000066400000000000000000000023571230265671100165470ustar00rootroot00000000000000.TH nfc-relay 1 "June 26, 2009" "libnfc" "libnfc'examples" .SH NAME nfc-relay \- Relay attack command line tool based on libnfc .SH SYNOPSIS .B nfc-relay .SH DESCRIPTION .B nfc-relay is a utility that demonstrates a relay attack. This tool requires two NFC devices. One device (configured as target) will emulate an ISO/IEC 14443 type A tag, while the second device (configured as initiator) will act as a reader. The genuine tag can be placed on the second device (initiator) and the tag emulator (target) can be placed close to the original reader. All communication is now relayed and shown in the screen on real-time. This tool has the same issues regarding timing as \fBnfc-emulate-uid\fP has, therefore we advise you to try it against e.g. an OmniKey CardMan 5321 reader. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/nfc-relay.c000066400000000000000000000207431230265671100166300ustar00rootroot00000000000000/*- * 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-relay.c * @brief Relay example using two devices. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include "utils/nfc-utils.h" #define MAX_FRAME_LEN 264 #define MAX_DEVICE_COUNT 2 static uint8_t abtReaderRx[MAX_FRAME_LEN]; static uint8_t abtReaderRxPar[MAX_FRAME_LEN]; static int szReaderRxBits; static uint8_t abtTagRx[MAX_FRAME_LEN]; static uint8_t abtTagRxPar[MAX_FRAME_LEN]; static int szTagRxBits; static nfc_device *pndReader; static nfc_device *pndTag; static bool quitting = false; static void intr_hdlr(int sig) { (void) sig; printf("\nQuitting...\n"); quitting = true; return; } static void print_usage(char *argv[]) { printf("Usage: %s [OPTIONS]\n", argv[0]); printf("Options:\n"); printf("\t-h\tHelp. Print this message.\n"); printf("\t-q\tQuiet mode. Suppress output of READER and EMULATOR data (improves timing).\n"); } int main(int argc, char *argv[]) { int arg; bool quiet_output = false; const char *acLibnfcVersion = nfc_version(); // Get commandline options for (arg = 1; arg < argc; arg++) { if (0 == strcmp(argv[arg], "-h")) { print_usage(argv); exit(EXIT_SUCCESS); } else if (0 == strcmp(argv[arg], "-q")) { quiet_output = true; } else { ERR("%s is not supported option.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); } } // Display libnfc version printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); #ifdef WIN32 signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr); #else signal(SIGINT, intr_hdlr); #endif nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } nfc_connstring connstrings[MAX_DEVICE_COUNT]; // List available devices size_t szFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (szFound < 2) { ERR("%" PRIdPTR " device found but two opened devices are needed to relay NFC.", szFound); nfc_exit(context); exit(EXIT_FAILURE); } // Try to open the NFC emulator device pndTag = nfc_open(context, connstrings[0]); if (pndTag == NULL) { ERR("Error opening NFC emulator device"); nfc_exit(context); exit(EXIT_FAILURE); } printf("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n"); printf("NFC emulator device: %s opened\n", nfc_device_get_name(pndTag)); printf("[+] Try to break out the auto-emulation, this requires a second reader!\n"); printf("[+] To do this, please send any command after the anti-collision\n"); printf("[+] For example, send a RATS command or use the \"nfc-anticol\" tool\n"); nfc_target nt = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_UNDEFINED, }, .nti = { .nai = { .abtAtqa = { 0x04, 0x00 }, .abtUid = { 0x08, 0xad, 0xbe, 0xef }, .btSak = 0x20, .szUidLen = 4, .szAtsLen = 0, }, }, }; if ((szReaderRxBits = nfc_target_init(pndTag, &nt, abtReaderRx, sizeof(abtReaderRx), 0)) < 0) { ERR("%s", "Initialization of NFC emulator failed"); nfc_close(pndTag); nfc_exit(context); exit(EXIT_FAILURE); } printf("%s", "Configuring emulator settings..."); if ((nfc_device_set_property_bool(pndTag, NP_HANDLE_CRC, false) < 0) || (nfc_device_set_property_bool(pndTag, NP_HANDLE_PARITY, false) < 0) || (nfc_device_set_property_bool(pndTag, NP_ACCEPT_INVALID_FRAMES, true)) < 0) { nfc_perror(pndTag, "nfc_device_set_property_bool"); nfc_close(pndTag); nfc_exit(context); exit(EXIT_FAILURE); } printf("%s", "Done, emulated tag is initialized"); // Try to open the NFC reader pndReader = nfc_open(context, connstrings[1]); if (pndReader == NULL) { printf("Error opening NFC reader device\n"); nfc_close(pndTag); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC reader device: %s opened", nfc_device_get_name(pndReader)); printf("%s", "Configuring NFC reader settings..."); if (nfc_initiator_init(pndReader) < 0) { nfc_perror(pndReader, "nfc_initiator_init"); nfc_close(pndTag); nfc_close(pndReader); nfc_exit(context); exit(EXIT_FAILURE); } if ((nfc_device_set_property_bool(pndReader, NP_HANDLE_CRC, false) < 0) || (nfc_device_set_property_bool(pndReader, NP_HANDLE_PARITY, false) < 0) || (nfc_device_set_property_bool(pndReader, NP_ACCEPT_INVALID_FRAMES, true)) < 0) { nfc_perror(pndReader, "nfc_device_set_property_bool"); nfc_close(pndTag); nfc_close(pndReader); nfc_exit(context); exit(EXIT_FAILURE); } printf("%s", "Done, relaying frames now!"); while (!quitting) { // Test if we received a frame from the reader if ((szReaderRxBits = nfc_target_receive_bits(pndTag, abtReaderRx, sizeof(abtReaderRx), abtReaderRxPar)) > 0) { // Drop down the field before sending a REQA command and start a new session if (szReaderRxBits == 7 && abtReaderRx[0] == 0x26) { // Drop down field for a very short time (original tag will reboot) if (nfc_device_set_property_bool(pndReader, NP_ACTIVATE_FIELD, false) < 0) { nfc_perror(pndReader, "nfc_device_set_property_bool"); nfc_close(pndTag); nfc_close(pndReader); nfc_exit(context); exit(EXIT_FAILURE); } if (!quiet_output) printf("\n"); if (nfc_device_set_property_bool(pndReader, NP_ACTIVATE_FIELD, true) < 0) { nfc_perror(pndReader, "nfc_device_set_property_bool"); nfc_close(pndTag); nfc_close(pndReader); nfc_exit(context); exit(EXIT_FAILURE); } } // Print the reader frame to the screen if (!quiet_output) { printf("R: "); print_hex_par(abtReaderRx, (size_t) szReaderRxBits, abtReaderRxPar); } // Forward the frame to the original tag if ((szTagRxBits = nfc_initiator_transceive_bits (pndReader, abtReaderRx, (size_t) szReaderRxBits, abtReaderRxPar, abtTagRx, sizeof(abtTagRx), abtTagRxPar)) > 0) { // Redirect the answer back to the reader if (nfc_target_send_bits(pndTag, abtTagRx, szTagRxBits, abtTagRxPar) < 0) { nfc_perror(pndTag, "nfc_target_send_bits"); nfc_close(pndTag); nfc_close(pndReader); nfc_exit(context); exit(EXIT_FAILURE); } // Print the tag frame to the screen if (!quiet_output) { printf("T: "); print_hex_par(abtTagRx, szTagRxBits, abtTagRxPar); } } } } nfc_close(pndTag); nfc_close(pndReader); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/pn53x-diagnose.1000066400000000000000000000013721230265671100174270ustar00rootroot00000000000000.TH pn53x-diagnose 1 "June 15, 2010" "libnfc" "libnfc's examples" .SH NAME pn53x-diagnose \- PN53x diagnose tool .SH SYNOPSIS .B pn53x-diagnose .SH DESCRIPTION .B pn53x-diagnose is a utility to diagnose PN531, PN532 and PN533 chips. It runs communication, RAM and ROM tests. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Romuald Conty .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/pn53x-diagnose.c000066400000000000000000000115121230265671100175060ustar00rootroot00000000000000/*- * 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 pn53x-diagnose.c * @brief Small application to diagnose PN53x using dedicated commands */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "utils/nfc-utils.h" #include "libnfc/chips/pn53x.h" #define MAX_DEVICE_COUNT 16 int main(int argc, const char *argv[]) { size_t i; nfc_device *pnd = NULL; const char *acLibnfcVersion; bool result; uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); const uint8_t pncmd_diagnose_communication_line_test[] = { Diagnose, 0x00, 0x06, 'l', 'i', 'b', 'n', 'f', 'c' }; const uint8_t pncmd_diagnose_rom_test[] = { Diagnose, 0x01 }; const uint8_t pncmd_diagnose_ram_test[] = { Diagnose, 0x02 }; if (argc > 1) { printf("Usage: %s", argv[0]); exit(EXIT_FAILURE); } nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Display libnfc version acLibnfcVersion = nfc_version(); printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); nfc_connstring connstrings[MAX_DEVICE_COUNT]; size_t szFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (szFound == 0) { printf("No NFC device found.\n"); } for (i = 0; i < szFound; i++) { int res = 0; pnd = nfc_open(context, connstrings[i]); if (pnd == NULL) { ERR("%s", "Unable to open NFC device."); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device [%s] opened.\n", nfc_device_get_name(pnd)); res = pn53x_transceive(pnd, pncmd_diagnose_communication_line_test, sizeof(pncmd_diagnose_communication_line_test), abtRx, szRx, 0); if (res > 0) { szRx = (size_t) res; // Result of Diagnose ping for RC-S360 doesn't contain status byte so we've to handle both cases result = (memcmp(pncmd_diagnose_communication_line_test + 1, abtRx, sizeof(pncmd_diagnose_communication_line_test) - 1) == 0) || (memcmp(pncmd_diagnose_communication_line_test + 2, abtRx, sizeof(pncmd_diagnose_communication_line_test) - 2) == 0); printf(" Communication line test: %s\n", result ? "OK" : "Failed"); } else { nfc_perror(pnd, "pn53x_transceive: cannot diagnose communication line"); } res = pn53x_transceive(pnd, pncmd_diagnose_rom_test, sizeof(pncmd_diagnose_rom_test), abtRx, szRx, 0); if (res > 0) { szRx = (size_t) res; result = ((szRx == 1) && (abtRx[0] == 0x00)); printf(" ROM test: %s\n", result ? "OK" : "Failed"); } else { nfc_perror(pnd, "pn53x_transceive: cannot diagnose ROM"); } res = pn53x_transceive(pnd, pncmd_diagnose_ram_test, sizeof(pncmd_diagnose_ram_test), abtRx, szRx, 0); if (res > 0) { szRx = (size_t) res; result = ((szRx == 1) && (abtRx[0] == 0x00)); printf(" RAM test: %s\n", result ? "OK" : "Failed"); } else { nfc_perror(pnd, "pn53x_transceive: cannot diagnose RAM"); } } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/pn53x-sam.1000066400000000000000000000020671230265671100164200ustar00rootroot00000000000000.TH pn53x-sam 1 "June 15, 2010" "libnfc" "libnfc's examples" .SH NAME pn53x-sam \- PN53x SAM communication demonstration tool .SH SYNOPSIS .B pn53x-sam .SH DESCRIPTION .B pn53x-sam is a utility attempt to test a simple connection with a SAM (Secure Access Module) in several modes. To run this utility you must have a SAM (like the NXP's P5CN072 chip) successfully connected to your PN53x chip. Warning: the SAM inside a Touchatag/ACR122U is \fInot\fP hooked to the PN532 but to the intermediate controller so \fBpn53x-sam\fP won't work with a Touchatag/ACR122U. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Emanuele Bertoldi .PP This manual page was written by Emanuele Bertoldi . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/pn53x-sam.c000066400000000000000000000156231230265671100165040ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2010 Emanuele Bertoldi * * 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 pn53x-sam.c * @brief Configures the NFC device to communicate with a SAM (Secure Access Module). * @note This example requiers a PN532 with SAM connected using S2C interface * @see PN532 User manual */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include "utils/nfc-utils.h" #include "libnfc/chips/pn53x.h" #define MAX_FRAME_LEN 264 #define TIMEOUT 60 // secs. static void wait_one_minute(void) { int secs = 0; printf("|"); fflush(stdout); while (secs < TIMEOUT) { sleep(1); secs++; printf("."); fflush(stdout); } printf("|\n"); } int main(int argc, const char *argv[]) { (void) argc; (void) argv; nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Display libnfc version const char *acLibnfcVersion = nfc_version(); printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); // Open using the first available NFC device nfc_device *pnd; pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("%s", "Unable to open NFC device."); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); // Print the example's menu printf("\nSelect the communication mode:\n"); printf("[1] Virtual card mode.\n"); printf("[2] Wired card mode.\n"); printf("[3] Dual card mode.\n"); printf(">> "); // Take user's choice int input = getchar(); printf("\n"); if ((input < '1') || (input > '3')) { ERR("%s", "Invalid selection."); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } /* * '1' -> "Virtual mode" (0x02) * '2' -> "Wired card" (0x03) * '3' -> "Dual card" (0x04) */ int iMode = input - '0' + 0x01; pn532_sam_mode mode = iMode; // Connect with the SAM switch (mode) { case PSM_VIRTUAL_CARD: { // FIXME Its a private pn53x function if (pn532_SAMConfiguration(pnd, mode, 0) < 0) { nfc_perror(pnd, "pn53x_SAMConfiguration"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("Now the SAM is readable for 1 minute from an external reader.\n"); wait_one_minute(); } break; case PSM_WIRED_CARD: { // Set opened NFC device to initiator mode if (nfc_initiator_init_secure_element(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init_secure_element"); 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"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Read the SAM's info const nfc_modulation nmSAM = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; nfc_target nt; int res; if ((res = nfc_initiator_select_passive_target(pnd, nmSAM, NULL, 0, &nt)) < 0) { nfc_perror(pnd, "nfc_initiator_select_passive_target"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } else if (res == 0) { ERR("No SAM found."); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } else if (res == 1) { printf("The following ISO14443A tag (SAM) was found:\n"); print_nfc_target(&nt, true); } else { ERR("%s", "More than one ISO14442 tag found as SAM."); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } } break; case PSM_DUAL_CARD: { // FIXME Its a private pn53x function if (pn532_SAMConfiguration(pnd, mode, 0) < 0) { nfc_perror(pnd, "pn53x_SAMConfiguration"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } uint8_t abtRx[MAX_FRAME_LEN]; nfc_target nt = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_UNDEFINED, }, .nti = { .nai = { .abtAtqa = { 0x04, 0x00 }, .abtUid = { 0x08, 0xad, 0xbe, 0xef }, .btSak = 0x20, .szUidLen = 4, .szAtsLen = 0, }, }, }; printf("Now both, NFC device (configured as target) and SAM are readables from an external NFC initiator.\n"); printf("Please note that NFC device (configured as target) stay in target mode until it receive RATS, ATR_REQ or proprietary command.\n"); if (nfc_target_init(pnd, &nt, abtRx, sizeof(abtRx), 0) < 0) { nfc_perror(pnd, "nfc_target_init"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // wait_one_minute (); } break; case PSM_NORMAL: // This should not happend... nothing to do. break; } // Disconnect from the SAM pn532_SAMConfiguration(pnd, PSM_NORMAL, -1); // Close NFC device nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/examples/pn53x-tamashell-scripts/000077500000000000000000000000001230265671100212105ustar00rootroot00000000000000libnfc-1.7.1/examples/pn53x-tamashell-scripts/ASK_LoGO_LEDs.cmd000066400000000000000000000013361230265671100240450ustar00rootroot00000000000000# To be used only on ASK LoGO readers!!! # As we don't know how GPIO can be wired, it may hurt your hardware!!! # P32=0 LED1 # P34=0 progressive field off # SFR_P3: 0x..101011 08 ff b0 2b p 100 # P32=0 LED1 # P31=0 LED2 # SFR_P3: 0x..101001 08 ff b0 29 p 100 # P32=0 LED1 # P31=0 LED2 # P30=0 P33=0 LED3 # SFR_P3: 0x..100000 08 ff b0 20 p 100 # P32=0 LED1 # P31=0 LED2 # P30=0 P33=0 LED3 # P35=0 LED4 # SFR_P3: 0x..000000 08 ff b0 00 p 100 # P32=0 LED1 # P31=0 LED2 # P30=0 P33=0 LED3 # SFR_P3: 0x..100000 08 ff b0 20 p 100 # P32=0 LED1 # P31=0 LED2 # SFR_P3: 0x..101001 08 ff b0 29 p 100 # P32=0 LED1 # SFR_P3: 0x..101011 08 ff b0 2b p 100 # P32=0 LED1 # SFR_P3: 0x..101011 08 ff b0 2b libnfc-1.7.1/examples/pn53x-tamashell-scripts/Makefile.am000066400000000000000000000001371230265671100232450ustar00rootroot00000000000000EXTRA_DIST = \ ReadMobib.sh \ ReadNavigo.sh \ UltraLightRead.cmd \ UltraLightReadWrite.cmd libnfc-1.7.1/examples/pn53x-tamashell-scripts/ReadMobib.sh000077500000000000000000000033671230265671100234040ustar00rootroot00000000000000#!/bin/sh cat << EOF | \ pn53x-tamashell |\ awk '\ /^> #.*:/{ sub(/^> #/,"") n=$0 for (i=0;i<8-length();i++) { n= n " " } getline getline getline sub(/Rx: 00/,"") gsub(/ +/," ") sub(/ 90 00 $/,"") print n toupper($0)}' |\ grep -v ": 6A 83" # Select one typeB target 4A010300 # Select ICC file 4001 80a4 0800 04 3f00 0002 #ICC: 4001 80b2 0104 1d # Select Holder file 4001 80a4 0800 04 3f00 3f1c #Holder1: 4001 80b2 0104 1d #Holder2: 4001 80b2 0204 1d # Select EnvHol file 4001 00a4 0800 04 2000 2001 #EnvHol1: 4001 00b2 0104 1d #EnvHol2: 4001 00b2 0204 1d # Select EvLog file 4001 00a4 0800 04 2000 2010 #EvLog1: 4001 00b2 0104 1d #EvLog2: 4001 00b2 0204 1d #EvLog3: 4001 00b2 0304 1d # Select ConList file 4001 00a4 0800 04 2000 2050 #ConList: 4001 00b2 0104 1d # Select Contra file 4001 00a4 0800 04 2000 2020 #Contra1: 4001 00b2 0104 1d #Contra2: 4001 00b2 0204 1d #Contra3: 4001 00b2 0304 1d #Contra4: 4001 00b2 0404 1d #Contra5: 4001 00b2 0504 1d #Contra6: 4001 00b2 0604 1d #Contra7: 4001 00b2 0704 1d #Contra8: 4001 00b2 0804 1d #Contra9: 4001 00b2 0904 1d #ContraA: 4001 00b2 0a04 1d #ContraB: 4001 00b2 0b04 1d #ContraC: 4001 00b2 0c04 1d # Select Counter file 4001 00a4 0800 04 2000 2069 #Counter: 4001 00b2 0104 1d # Select LoadLog file 4001 00a4 0800 04 1000 1014 #LoadLog: 4001 00b2 0104 1d # Select Purcha file 4001 00a4 08 0004 1000 1015 #Purcha1: 4001 00b2 0104 1d #Purcha2: 4001 00b2 0204 1d #Purcha3: 4001 00b2 0304 1d # Select SpecEv file 4001 00a4 08 0004 2000 2040 #SpecEv1: 4001 00b2 0104 1d #SpecEv2: 4001 00b2 0204 1d #SpecEv3: 4001 00b2 0304 1d #SpecEv4: 4001 00b2 0404 1d EOF libnfc-1.7.1/examples/pn53x-tamashell-scripts/ReadNavigo.sh000077500000000000000000000032321230265671100235660ustar00rootroot00000000000000#!/bin/sh ID=$(cat << EOF | \ pn53x-tamashell |\ grep -A1 "^Tx: 42 01 0b 3f 80" |\ sed -e '1d' -e "s/^Rx: 00 .. .. \(.. .. .. ..\).*/\1/" -e 's/ //g' # Timeouts 3205000002 # ListTarget ModeB 4a010300 # TypeB' APGEN 42010b3f80 EOF ) if [ -z "$ID" ]; then echo "Error: I was not abble to read Navigo ID" >&2 exit 1 fi cat << EOF | \ pn53x-tamashell |\ awk '\ /^> #.*:/{ sub(/^> #/,"") n=$0 for (i=0;i<8-length();i++) { n= n " " } getline getline getline sub(/Rx: 00/,"") gsub(/ +/," ") sub(/ 90 00 $/,"") print n toupper($0)}' # Timeouts 3205000002 # ListTarget ModeB 4a010300 # TypeB' 42010b3f80 # timings... 3202010b0c # TypeB' ATTRIB 42 01 0f $ID # Select ICC file 42 01 04 0a 00a4 0800 04 3f00 0002 #ICC: 42 01 06 06 00b2 0104 1d # Select EnvHol file 42 01 08 0a 00a4 0800 04 2000 2001 #EnvHol1: 42 01 0a 06 00b2 0104 1d # Select EvLog file 42 01 0c 0a 00a4 0800 04 2000 2010 #EvLog1: 42 01 0e 06 00b2 0104 1d #EvLog2: 42 01 00 06 00b2 0204 1d #EvLog3: 42 01 02 06 00b2 0304 1d # Select ConList file 42 01 04 0a 00a4 0800 04 2000 2050 #ConList: 42 01 06 06 00b2 0104 1d # Select Contra file 42 01 08 0a 00a4 0800 04 2000 2020 #Contra1: 42 01 0a 06 00b2 0104 1d #Contra2: 42 01 0c 06 00b2 0204 1d #Contra3: 42 01 0e 06 00b2 0304 1d #Contra4: 42 01 00 06 00b2 0404 1d # Select Counter file 42 01 02 0a 00a4 0800 04 2000 2069 #Counter: 42 01 04 06 00b2 0104 1d # Select SpecEv file 42 01 06 0a 00a4 08 0004 2000 2040 #SpecEv1: 42 01 08 06 00b2 0104 1d # TypeB' Disconnect 42 01 03 EOF libnfc-1.7.1/examples/pn53x-tamashell-scripts/UltraLightRead.cmd000066400000000000000000000007541230265671100245560ustar00rootroot0000000000000002; // Get firmware version // Reads content of a Mifare UltraLight // PLEASE PUT ULTRALIGHT TAG NOW 4A 01 00; // 1 target requested // Read memory content from address 4 40 01 30 00; Read 16 bytes from address 0x00 40 01 30 04; Read 16 bytes from address 0x04 40 01 30 08; Read 16 bytes from address 0x08 40 01 30 0C; Read 16 bytes from address 0x0C libnfc-1.7.1/examples/pn53x-tamashell-scripts/UltraLightReadWrite.cmd000066400000000000000000000042651230265671100255720ustar00rootroot0000000000000002; Get firmware version // Create NFC-Forum tag type2 with URL // WARNING It burns the OTP bits of sector 3!! // PLEASE PUT ULTRALIGHT TAG NOW 4A 01 00; 1 target requested // Clear memory from address 0x04 40 01 A2 04 00 00 00 00; Write 4 bytes from address 0x04 40 01 A2 05 00 00 00 00; Write 4 bytes from address 0x05 40 01 A2 06 00 00 00 00; Write 4 bytes from address 0x06 40 01 A2 07 00 00 00 00; Write 4 bytes from address 0x07 40 01 A2 08 00 00 00 00; Write 4 bytes from address 0x08 40 01 A2 09 00 00 00 00; Write 4 bytes from address 0x09 40 01 A2 0A 00 00 00 00; Write 4 bytes from address 0x0A 40 01 A2 0B 00 00 00 00; Write 4 bytes from address 0x0B 40 01 A2 0C 00 00 00 00; Write 4 bytes from address 0x0C // Read memory content from address 4 40 01 30 04; Read 16 bytes from address 0x04 40 01 30 08; Read 16 bytes from address 0x08 40 01 30 0C; Read 16 bytes from address 0x0C // cf NFC-Forum Type 1 Tag Operation Specification TS // Write @ address 0x03 (OTP): NDEF, v1.0, 48 bytes, RW 40 01 A2 03 E1 10 06 00; // Write @ address 0x04: NDEF TLV, 15 bytes,... // cf NFC-Forum NFC Data Exchange Format (NDEF) TS // ...,MB,ME,SR,TNF=1 (wkt), typeL=1 byte 40 01 A2 04 03 0F D1 01; // Write @ address 0x05: payloadL=11 bytes,... // cf NFC-Forum NFC Record Type Definition (RTD) TS // ...,type=urn:nfc:wkt:U = URI // cf NFC-Forum URI Record Type Definition TS // ...,01=>URI id code=http://www. // ...,"l" 40 01 A2 05 0B 55 01 6C; // Write @ address 0x06: "ibnf" 40 01 A2 06 69 62 6E 66; // Write @ address 0x07: "c.or" 40 01 A2 07 63 2E 6F 72; // Write @ address 0x08: "g",TLV:FE 40 01 A2 08 67 FE 00 00; // Read memory content from address 4 40 01 30 04; Read 16 bytes from address 0x04 40 01 30 08; Read 16 bytes from address 0x08 40 01 30 0C; Read 16 bytes from address 0x0C libnfc-1.7.1/examples/pn53x-tamashell.1000066400000000000000000000037451230265671100176160ustar00rootroot00000000000000.TH pn53x-tamashell 1 "September 15, 2010" .SH NAME pn53x-tamashell \- PN53x TAMA communication demonstration shell .SH SYNOPSIS .B pn53x-tamashell .IR [script] .SH DESCRIPTION .B pn53x-tamashell is a simple interactive tool to send so called TAMA commands and receive the answers. TAMA refers to the command set supported by the PN53x family. Messages are binary and the shell expects hexadecimal notation. TAMA commands and responses prefixes (0xD4/0xD5), CRC and any framing above are handled transparently. You can use the shell interactively (with readline support) or you can write your own script file consisting in commands and comments (anything that starts with ";", "#" or "//"). Spaces are ignored and can be used for readability. Shebang is supported, simply start your script with: #!/usr/bin/env \fBpn53x-tamashell\fP .SH COMMANDS \fIp N\fP to introduce a pause of N milliseconds. \fIq\fP or \fICtrl-d\fP to quit. .SH EXAMPLES GetFirmware command is D4 02, so one has just to send the command "02": $ \fBpn53x-tamashell\fP Connected to NFC reader: SCM Micro/SCL3711-NFC&RW - PN533 v2.7 (0x07) > 02 Tx: 02 Rx: 33 02 07 07 > 40 Tx: 40 Rx: Command Not Acceptable > q Bye! Same thing, with a script: $ \fBpn53x-tamashell\fP << EOF // This is a comment 02 // GetFirmware 40 // Command with missing arguments EOF Connected to NFC reader: SCM Micro/SCL3711-NFC&RW - PN533 v2.7 (0x07) > // This is a comment > 02 // GetFirmware Tx: 02 Rx: 33 02 07 07 > 40 // Command with missing arguments Tx: 40 Rx: Command Not Acceptable > Bye! .SH OPTIONS .IR script Script file with tama commands .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .PP This manual page is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/examples/pn53x-tamashell.c000066400000000000000000000131501230265671100176670ustar00rootroot00000000000000/*- * 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 pn53x-tamashell.c * @brief Configures the NFC device to communicate with a SAM (Secure Access Module). */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H # include #if defined(HAVE_READLINE) # include # include #endif //HAVE_READLINE #include #include #include #include #ifndef _WIN32 # include # define msleep(x) do { \ struct timespec xsleep; \ xsleep.tv_sec = x / 1000; \ xsleep.tv_nsec = (x - xsleep.tv_sec * 1000) * 1000 * 1000; \ nanosleep(&xsleep, NULL); \ } while (0) #else # include # define msleep Sleep #endif #include #include "utils/nfc-utils.h" #include "libnfc/chips/pn53x.h" #define MAX_FRAME_LEN 264 int main(int argc, const char *argv[]) { nfc_device *pnd; uint8_t abtRx[MAX_FRAME_LEN]; uint8_t abtTx[MAX_FRAME_LEN]; size_t szRx = sizeof(abtRx); size_t szTx; FILE *input = NULL; if (argc >= 2) { if ((input = fopen(argv[1], "r")) == NULL) { ERR("%s", "Cannot open file."); exit(EXIT_FAILURE); } } nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Try to open the NFC reader pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("%s", "Unable to open NFC device."); if (input != NULL) { fclose(input); } nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); if (input != NULL) { fclose(input); } nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } const char *prompt = "> "; while (1) { int offset = 0; char *cmd; #if defined(HAVE_READLINE) if (input == NULL) { // means we use stdin cmd = readline(prompt); // NULL if ctrl-d if (cmd == NULL) { printf("Bye!\n"); break; } add_history(cmd); } else { #endif //HAVE_READLINE size_t n = 512; char *ret = NULL; cmd = malloc(n); printf("%s", prompt); fflush(0); if (input != NULL) { ret = fgets(cmd, n, input); } else { ret = fgets(cmd, n, stdin); } if (ret == NULL || strlen(cmd) <= 0) { printf("Bye!\n"); free(cmd); break; } // FIXME print only if read from redirected stdin (i.e. script) printf("%s", cmd); #if defined(HAVE_READLINE) } #endif //HAVE_READLINE if (cmd[0] == 'q') { printf("Bye!\n"); free(cmd); break; } if (cmd[0] == 'p') { int ms = 0; offset++; while (isspace(cmd[offset])) { offset++; } sscanf(cmd + offset, "%10d", &ms); printf("Pause for %i msecs\n", ms); if (ms > 0) { msleep(ms); } free(cmd); continue; } szTx = 0; for (int i = 0; i < MAX_FRAME_LEN; i++) { int size; unsigned int byte; while (isspace(cmd[offset])) { offset++; } size = sscanf(cmd + offset, "%2x", &byte); if (size < 1) { break; } abtTx[i] = byte; szTx++; if (cmd[offset + 1] == 0) { // if last hex was only 1 symbol break; } offset += 2; } if ((int)szTx < 1) { free(cmd); continue; } printf("Tx: "); print_hex(abtTx, szTx); szRx = sizeof(abtRx); int res = 0; if ((res = pn53x_transceive(pnd, abtTx, szTx, abtRx, szRx, 0)) < 0) { free(cmd); nfc_perror(pnd, "Rx"); continue; } szRx = (size_t) res; printf("Rx: "); print_hex(abtRx, szRx); free(cmd); } if (input != NULL) { fclose(input); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/include/000077500000000000000000000000001230265671100144035ustar00rootroot00000000000000libnfc-1.7.1/include/CMakeLists.txt000066400000000000000000000000271230265671100171420ustar00rootroot00000000000000ADD_SUBDIRECTORY(nfc) libnfc-1.7.1/include/Makefile.am000066400000000000000000000000531230265671100164350ustar00rootroot00000000000000SUBDIRS = nfc EXTRA_DIST = CMakeLists.txt libnfc-1.7.1/include/nfc/000077500000000000000000000000001230265671100151515ustar00rootroot00000000000000libnfc-1.7.1/include/nfc/CMakeLists.txt000066400000000000000000000002231230265671100177060ustar00rootroot00000000000000# Headers FILE(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h") INSTALL(FILES ${headers} DESTINATION ${INCLUDE_INSTALL_DIR}/nfc COMPONENT headers) libnfc-1.7.1/include/nfc/Makefile.am000066400000000000000000000002221230265671100172010ustar00rootroot00000000000000 nfcinclude_HEADERS = \ nfc.h \ nfc-emulation.h \ nfc-types.h nfcincludedir = $(includedir)/nfc EXTRA_DIST = CMakeLists.txt libnfc-1.7.1/include/nfc/nfc-emulation.h000066400000000000000000000040101230265671100200560ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc-emulation.h * @brief Provide a small API to ease emulation in libnfc */ #ifndef __NFC_EMULATION_H__ #define __NFC_EMULATION_H__ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct nfc_emulator; struct nfc_emulation_state_machine; /** * @struct nfc_emulator * @brief NFC emulator structure */ struct nfc_emulator { nfc_target *target; struct nfc_emulation_state_machine *state_machine; void *user_data; }; /** * @struct nfc_emulation_state_machine * @brief NFC emulation state machine structure */ struct nfc_emulation_state_machine { int (*io)(struct nfc_emulator *emulator, const uint8_t *data_in, const size_t data_in_len, uint8_t *data_out, const size_t data_out_len); void *data; }; NFC_EXPORT int nfc_emulate_target(nfc_device *pnd, struct nfc_emulator *emulator, const int timeout); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __NFC_EMULATION_H__ */ libnfc-1.7.1/include/nfc/nfc-types.h000066400000000000000000000227131230265671100172370ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc-types.h * @brief Define NFC types */ #ifndef __NFC_TYPES_H__ #define __NFC_TYPES_H__ #include #include #include #include #ifndef NFC_BUFSIZE_CONNSTRING #define NFC_BUFSIZE_CONNSTRING 1024 #endif /** * NFC context */ typedef struct nfc_context nfc_context; /** * NFC device */ typedef struct nfc_device nfc_device; /** * NFC device driver */ typedef struct nfc_driver nfc_driver; /** * Connection string */ typedef char nfc_connstring[NFC_BUFSIZE_CONNSTRING]; /** * Properties */ typedef enum { /** * Default command processing timeout * Property value's (duration) unit is ms and 0 means no timeout (infinite). * Default value is set by driver layer */ NP_TIMEOUT_COMMAND, /** * Timeout between ATR_REQ and ATR_RES * When the device is in initiator mode, a target is considered as mute if no * valid ATR_RES is received within this timeout value. * Default value for this property is 103 ms on PN53x based devices. */ NP_TIMEOUT_ATR, /** * Timeout value to give up reception from the target in case of no answer. * Default value for this property is 52 ms). */ NP_TIMEOUT_COM, /** Let the PN53X chip handle the CRC bytes. This means that the chip appends * the CRC bytes to the frames that are transmitted. It will parse the last * bytes from received frames as incoming CRC bytes. They will be verified * against the used modulation and protocol. If an frame is expected with * incorrect CRC bytes this option should be disabled. Example frames where * this is useful are the ATQA and UID+BCC that are transmitted without CRC * bytes during the anti-collision phase of the ISO14443-A protocol. */ NP_HANDLE_CRC, /** Parity bits in the network layer of ISO14443-A are by default generated and * validated in the PN53X chip. This is a very convenient feature. On certain * times though it is useful to get full control of the transmitted data. The * proprietary MIFARE Classic protocol uses for example custom (encrypted) * parity bits. For interoperability it is required to be completely * compatible, including the arbitrary parity bits. When this option is * disabled, the functions to communicating bits should be used. */ NP_HANDLE_PARITY, /** This option can be used to enable or disable the electronic field of the * NFC device. */ NP_ACTIVATE_FIELD, /** The internal CRYPTO1 co-processor can be used to transmit messages * encrypted. This option is automatically activated after a successful MIFARE * Classic authentication. */ NP_ACTIVATE_CRYPTO1, /** The default configuration defines that the PN53X chip will try indefinitely * to invite a tag in the field to respond. This could be desired when it is * certain a tag will enter the field. On the other hand, when this is * uncertain, it will block the application. This option could best be compared * to the (NON)BLOCKING option used by (socket)network programming. */ NP_INFINITE_SELECT, /** If this option is enabled, frames that carry less than 4 bits are allowed. * According to the standards these frames should normally be handles as * invalid frames. */ NP_ACCEPT_INVALID_FRAMES, /** If the NFC device should only listen to frames, it could be useful to let * it gather multiple frames in a sequence. They will be stored in the internal * FIFO of the PN53X chip. This could be retrieved by using the receive data * functions. Note that if the chip runs out of bytes (FIFO = 64 bytes long), * it will overwrite the first received frames, so quick retrieving of the * received data is desirable. */ NP_ACCEPT_MULTIPLE_FRAMES, /** This option can be used to enable or disable the auto-switching mode to * ISO14443-4 is device is compliant. * In initiator mode, it means that NFC chip will send RATS automatically when * select and it will automatically poll for ISO14443-4 card when ISO14443A is * requested. * In target mode, with a NFC chip compliant (ie. PN532), the chip will * emulate a 14443-4 PICC using hardware capability */ NP_AUTO_ISO14443_4, /** Use automatic frames encapsulation and chaining. */ NP_EASY_FRAMING, /** Force the chip to switch in ISO14443-A */ NP_FORCE_ISO14443_A, /** Force the chip to switch in ISO14443-B */ NP_FORCE_ISO14443_B, /** Force the chip to run at 106 kbps */ NP_FORCE_SPEED_106, } nfc_property; // Compiler directive, set struct alignment to 1 uint8_t for compatibility # pragma pack(1) /** * @enum nfc_dep_mode * @brief NFC D.E.P. (Data Exchange Protocol) active/passive mode */ typedef enum { NDM_UNDEFINED = 0, NDM_PASSIVE, NDM_ACTIVE, } nfc_dep_mode; /** * @struct nfc_dep_info * @brief NFC target information in D.E.P. (Data Exchange Protocol) see ISO/IEC 18092 (NFCIP-1) */ typedef struct { /** NFCID3 */ uint8_t abtNFCID3[10]; /** DID */ uint8_t btDID; /** Supported send-bit rate */ uint8_t btBS; /** Supported receive-bit rate */ uint8_t btBR; /** Timeout value */ uint8_t btTO; /** PP Parameters */ uint8_t btPP; /** General Bytes */ uint8_t abtGB[48]; size_t szGB; /** DEP mode */ nfc_dep_mode ndm; } nfc_dep_info; /** * @struct nfc_iso14443a_info * @brief NFC ISO14443A tag (MIFARE) information */ typedef struct { uint8_t abtAtqa[2]; uint8_t btSak; size_t szUidLen; uint8_t abtUid[10]; size_t szAtsLen; uint8_t abtAts[254]; // Maximal theoretical ATS is FSD-2, FSD=256 for FSDI=8 in RATS } nfc_iso14443a_info; /** * @struct nfc_felica_info * @brief NFC FeLiCa tag information */ typedef struct { size_t szLen; uint8_t btResCode; uint8_t abtId[8]; uint8_t abtPad[8]; uint8_t abtSysCode[2]; } nfc_felica_info; /** * @struct nfc_iso14443b_info * @brief NFC ISO14443B tag information */ typedef struct { /** abtPupi store PUPI contained in ATQB (Answer To reQuest of type B) (see ISO14443-3) */ uint8_t abtPupi[4]; /** abtApplicationData store Application Data contained in ATQB (see ISO14443-3) */ uint8_t abtApplicationData[4]; /** abtProtocolInfo store Protocol Info contained in ATQB (see ISO14443-3) */ uint8_t abtProtocolInfo[3]; /** ui8CardIdentifier store CID (Card Identifier) attributted by PCD to the PICC */ uint8_t ui8CardIdentifier; } nfc_iso14443b_info; /** * @struct nfc_iso14443bi_info * @brief NFC ISO14443B' tag information */ typedef struct { /** DIV: 4 LSBytes of tag serial number */ uint8_t abtDIV[4]; /** Software version & type of REPGEN */ uint8_t btVerLog; /** Config Byte, present if long REPGEN */ uint8_t btConfig; /** ATR, if any */ size_t szAtrLen; uint8_t abtAtr[33]; } nfc_iso14443bi_info; /** * @struct nfc_iso14443b2sr_info * @brief NFC ISO14443-2B ST SRx tag information */ typedef struct { uint8_t abtUID[8]; } nfc_iso14443b2sr_info; /** * @struct nfc_iso14443b2ct_info * @brief NFC ISO14443-2B ASK CTx tag information */ typedef struct { uint8_t abtUID[4]; uint8_t btProdCode; uint8_t btFabCode; } nfc_iso14443b2ct_info; /** * @struct nfc_jewel_info * @brief NFC Jewel tag information */ typedef struct { uint8_t btSensRes[2]; uint8_t btId[4]; } nfc_jewel_info; /** * @union nfc_target_info * @brief Union between all kind of tags information structures. */ typedef union { nfc_iso14443a_info nai; nfc_felica_info nfi; nfc_iso14443b_info nbi; nfc_iso14443bi_info nii; nfc_iso14443b2sr_info nsi; nfc_iso14443b2ct_info nci; nfc_jewel_info nji; nfc_dep_info ndi; } nfc_target_info; /** * @enum nfc_baud_rate * @brief NFC baud rate enumeration */ typedef enum { NBR_UNDEFINED = 0, NBR_106, NBR_212, NBR_424, NBR_847, } nfc_baud_rate; /** * @enum nfc_modulation_type * @brief NFC modulation type enumeration */ typedef enum { NMT_ISO14443A = 1, NMT_JEWEL, 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, } nfc_modulation_type; /** * @enum nfc_mode * @brief NFC mode type enumeration */ typedef enum { N_TARGET, N_INITIATOR, } nfc_mode; /** * @struct nfc_modulation * @brief NFC modulation structure */ typedef struct { nfc_modulation_type nmt; nfc_baud_rate nbr; } nfc_modulation; /** * @struct nfc_target * @brief NFC target structure */ typedef struct { nfc_target_info nti; nfc_modulation nm; } nfc_target; // Reset struct alignment to default # pragma pack() #endif // _LIBNFC_TYPES_H_ libnfc-1.7.1/include/nfc/nfc.h000066400000000000000000000210541230265671100160720ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc.h * @brief libnfc interface * * Provide all usefull functions (API) to handle NFC devices. */ #ifndef _LIBNFC_H_ # define _LIBNFC_H_ # include # include # include # ifdef _WIN32 /* Windows platform */ # ifndef _WINDLL /* CMake compilation */ # ifdef nfc_EXPORTS # define NFC_EXPORT __declspec(dllexport) # else /* nfc_EXPORTS */ # define NFC_EXPORT __declspec(dllimport) # endif /* nfc_EXPORTS */ # else /* _WINDLL */ /* Manual makefile */ # define NFC_EXPORT # endif /* _WINDLL */ # else /* _WIN32 */ # define NFC_EXPORT # endif /* _WIN32 */ # include # ifndef __has_attribute # define __has_attribute(x) 0 # endif # if __has_attribute(nonnull) || defined(__GNUC__) # define __has_attribute_nonnull 1 # endif # if __has_attribute_nonnull # define ATTRIBUTE_NONNULL( param ) __attribute__((nonnull (param))) # else # define ATTRIBUTE_NONNULL( param ) # endif # ifdef __cplusplus extern "C" { # endif // __cplusplus /* Library initialization/deinitialization */ NFC_EXPORT void nfc_init(nfc_context **context) ATTRIBUTE_NONNULL(1); NFC_EXPORT void nfc_exit(nfc_context *context) ATTRIBUTE_NONNULL(1); NFC_EXPORT int nfc_register_driver(const nfc_driver *driver); /* NFC Device/Hardware manipulation */ NFC_EXPORT nfc_device *nfc_open(nfc_context *context, const nfc_connstring connstring) ATTRIBUTE_NONNULL(1); NFC_EXPORT void nfc_close(nfc_device *pnd); NFC_EXPORT int nfc_abort_command(nfc_device *pnd); NFC_EXPORT size_t nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], size_t connstrings_len) ATTRIBUTE_NONNULL(1); NFC_EXPORT int nfc_idle(nfc_device *pnd); /* NFC initiator: act as "reader" */ NFC_EXPORT int nfc_initiator_init(nfc_device *pnd); NFC_EXPORT int nfc_initiator_init_secure_element(nfc_device *pnd); NFC_EXPORT int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt); NFC_EXPORT int nfc_initiator_list_passive_targets(nfc_device *pnd, const nfc_modulation nm, nfc_target ant[], const size_t szTargets); NFC_EXPORT int nfc_initiator_poll_target(nfc_device *pnd, const nfc_modulation *pnmTargetTypes, const size_t szTargetTypes, const uint8_t uiPollNr, const uint8_t uiPeriod, nfc_target *pnt); NFC_EXPORT int nfc_initiator_select_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout); NFC_EXPORT int nfc_initiator_poll_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout); NFC_EXPORT int nfc_initiator_deselect_target(nfc_device *pnd); NFC_EXPORT int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout); NFC_EXPORT int nfc_initiator_transceive_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar); NFC_EXPORT int nfc_initiator_transceive_bytes_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles); NFC_EXPORT int nfc_initiator_transceive_bits_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar, uint32_t *cycles); NFC_EXPORT int nfc_initiator_target_is_present(nfc_device *pnd, const nfc_target *pnt); /* NFC target: act as tag (i.e. MIFARE Classic) or NFC target device. */ NFC_EXPORT int nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout); NFC_EXPORT int nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout); NFC_EXPORT int nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout); NFC_EXPORT int nfc_target_send_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar); NFC_EXPORT int nfc_target_receive_bits(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar); /* Error reporting */ NFC_EXPORT const char *nfc_strerror(const nfc_device *pnd); NFC_EXPORT int nfc_strerror_r(const nfc_device *pnd, char *buf, size_t buflen); NFC_EXPORT void nfc_perror(const nfc_device *pnd, const char *s); NFC_EXPORT int nfc_device_get_last_error(const nfc_device *pnd); /* Special data accessors */ NFC_EXPORT const char *nfc_device_get_name(nfc_device *pnd); NFC_EXPORT const char *nfc_device_get_connstring(nfc_device *pnd); NFC_EXPORT int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); NFC_EXPORT int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); /* Properties accessors */ NFC_EXPORT int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value); NFC_EXPORT int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable); /* Misc. functions */ NFC_EXPORT void iso14443a_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc); NFC_EXPORT void iso14443a_crc_append(uint8_t *pbtData, size_t szLen); NFC_EXPORT void iso14443b_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc); NFC_EXPORT void iso14443b_crc_append(uint8_t *pbtData, size_t szLen); NFC_EXPORT uint8_t *iso14443a_locate_historical_bytes(uint8_t *pbtAts, size_t szAts, size_t *pszTk); NFC_EXPORT void nfc_free(void *p); NFC_EXPORT const char *nfc_version(void); NFC_EXPORT int nfc_device_get_information_about(nfc_device *pnd, char **buf); /* String converter functions */ NFC_EXPORT const char *str_nfc_modulation_type(const nfc_modulation_type nmt); NFC_EXPORT const char *str_nfc_baud_rate(const nfc_baud_rate nbr); NFC_EXPORT int str_nfc_target(char **buf, const nfc_target *pnt, bool verbose); /* Error codes */ /** @ingroup error * @hideinitializer * Success (no error) */ #define NFC_SUCCESS 0 /** @ingroup error * @hideinitializer * Input / output error, device may not be usable anymore without re-open it */ #define NFC_EIO -1 /** @ingroup error * @hideinitializer * Invalid argument(s) */ #define NFC_EINVARG -2 /** @ingroup error * @hideinitializer * Operation not supported by device */ #define NFC_EDEVNOTSUPP -3 /** @ingroup error * @hideinitializer * No such device */ #define NFC_ENOTSUCHDEV -4 /** @ingroup error * @hideinitializer * Buffer overflow */ #define NFC_EOVFLOW -5 /** @ingroup error * @hideinitializer * Operation timed out */ #define NFC_ETIMEOUT -6 /** @ingroup error * @hideinitializer * Operation aborted (by user) */ #define NFC_EOPABORTED -7 /** @ingroup error * @hideinitializer * Not (yet) implemented */ #define NFC_ENOTIMPL -8 /** @ingroup error * @hideinitializer * Target released */ #define NFC_ETGRELEASED -10 /** @ingroup error * @hideinitializer * Error while RF transmission */ #define NFC_ERFTRANS -20 /** @ingroup error * @hideinitializer * MIFARE Classic: authentication failed */ #define NFC_EMFCAUTHFAIL -30 /** @ingroup error * @hideinitializer * Software error (allocation, file/pipe creation, etc.) */ #define NFC_ESOFT -80 /** @ingroup error * @hideinitializer * Device's internal chip error */ #define NFC_ECHIP -90 # ifdef __cplusplus } # endif // __cplusplus #endif // _LIBNFC_H_ libnfc-1.7.1/libnfc.conf.sample000066400000000000000000000016761230265671100163560ustar00rootroot00000000000000# Allow device auto-detection (default: true) # Note: if this auto-detection is disabled, user has to set manually a device # configuration using file or environment variable #allow_autoscan = true # Allow intrusive auto-detection (default: false) # Warning: intrusive auto-detection can seriously disturb other devices # This option is not recommended, user should prefer to add manually his device. #allow_intrusive_scan = false # Set log level (default: error) # Valid log levels are (in order of verbosity): 0 (none), 1 (error), 2 (info), 3 (debug) # Note: if you compiled with --enable-debug option, the default log level is "debug" #log_level = 1 # Manually set default device (no default) # To set a default device, you must set both name and connstring for your device # Note: if autoscan is enabled, default device will be the first device available in device list. #device.name = "microBuilder.eu" #device.connstring = "pn532_uart:/dev/ttyUSB0" libnfc-1.7.1/libnfc.pc.in000066400000000000000000000003671230265671100151540ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libnfc Description: Near Field Communication (NFC) library Version: @VERSION@ Requires: @PKG_CONFIG_REQUIRES@ Libs: -L${libdir} -lnfc Cflags: -I${includedir} libnfc-1.7.1/libnfc/000077500000000000000000000000001230265671100142155ustar00rootroot00000000000000libnfc-1.7.1/libnfc/CMakeLists.txt000066400000000000000000000072061230265671100167620ustar00rootroot00000000000000# Windows MinGW workarounds IF(WIN32) SET(WINDOWS_SOURCES ../contrib/win32/stdlib) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32) # Add in the rc for version information in the dll LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../windows/libnfc.rc) ENDIF(WIN32) # Library's chips SET(CHIPS_SOURCES chips/pn53x) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/chips) # Library's buses IF(USB_REQUIRED) LIST(APPEND BUSES_SOURCES buses/usbbus) ENDIF(USB_REQUIRED) IF(UART_REQUIRED) IF(WIN32) # Windows have a special implementation for UART LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/uart) ELSE(WIN32) LIST(APPEND BUSES_SOURCES buses/uart) ENDIF(WIN32) ENDIF(UART_REQUIRED) IF(I2C_REQUIRED) IF(WIN32) # Windows is not supported at the moment #LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c) MESSAGE( FATAL_ERROR "I2C not (yet) supported under Windows!" ) ELSE(WIN32) LIST(APPEND BUSES_SOURCES buses/i2c) ENDIF(WIN32) ENDIF(I2C_REQUIRED) IF(SPI_REQUIRED) IF(WIN32) # Windows is not supported at the moment #LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi) MESSAGE( FATAL_ERROR "SPI not (yet) supported under Windows!" ) ELSE(WIN32) LIST(APPEND BUSES_SOURCES buses/spi) ENDIF(WIN32) ENDIF(SPI_REQUIRED) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses) IF(WIN32) # Windows now requires regex, so we utilize PCRE # since Windows doesn't get the benefit of finding in CMake # it has to be added manually IF(PCRE_FOUND) INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIRS}) LINK_DIRECTORIES(${PCRE_LIBRARY_DIRS}) ENDIF(PCRE_FOUND) ENDIF(WIN32) IF(PCSC_FOUND) INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS}) LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS}) ENDIF(PCSC_FOUND) IF(LIBUSB_FOUND) INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS}) LINK_DIRECTORIES(${LIBUSB_LIBRARY_DIRS}) ENDIF(LIBUSB_FOUND) # Library SET(LIBRARY_SOURCES nfc nfc-device nfc-emulation nfc-internal conf iso14443-subr mirror-subr target-subr ${DRIVERS_SOURCES} ${BUSES_SOURCES} ${CHIPS_SOURCES} ${WINDOWS_SOURCES}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) IF(LIBNFC_LOG) IF(WIN32) SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}") LIST(APPEND LIBRARY_SOURCES log ../contrib/win32/libnfc/log-internal) ELSE(WIN32) LIST(APPEND LIBRARY_SOURCES log log-internal) ENDIF(WIN32) ENDIF(LIBNFC_LOG) ADD_LIBRARY(nfc SHARED ${LIBRARY_SOURCES}) IF(PCSC_FOUND) TARGET_LINK_LIBRARIES(nfc ${PCSC_LIBRARIES}) ENDIF(PCSC_FOUND) IF(LIBUSB_FOUND) TARGET_LINK_LIBRARIES(nfc ${LIBUSB_LIBRARIES}) ENDIF(LIBUSB_FOUND) SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 0) IF(WIN32) # Libraries that are windows specific TARGET_LINK_LIBRARIES(nfc wsock32) IF(PCRE_FOUND) TARGET_LINK_LIBRARIES(nfc ${PCRE_LIBRARIES}) ENDIF(PCRE_FOUND) ADD_CUSTOM_COMMAND( OUTPUT libnfc.lib COMMAND dlltool -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def ) ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib) # On Windows the shared (runtime) library should be either in the same # directory as the excutables or in the path, we add it to same directory INSTALL(TARGETS nfc RUNTIME DESTINATION bin COMPONENT libraries) # At compile time we need the .LIB file, we place it in the lib directory INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) ELSE(WIN32) INSTALL(TARGETS nfc LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) ENDIF(WIN32) libnfc-1.7.1/libnfc/Makefile.am000066400000000000000000000023261230265671100162540ustar00rootroot00000000000000SUBDIRS = chips buses drivers . # set the include path found by configure AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS) -DSYSCONFDIR='"$(sysconfdir)"' lib_LTLIBRARIES = libnfc.la libnfc_la_SOURCES = \ conf.c \ iso14443-subr.c \ mirror-subr.c \ nfc.c \ nfc-device.c \ nfc-emulation.c \ nfc-internal.c \ target-subr.c \ conf.h \ drivers.h \ iso7816.h \ log.h \ log-internal.h \ mirror-subr.h \ nfc-internal.h \ target-subr.h libnfc_la_LDFLAGS = -no-undefined -version-info 5:1:0 -export-symbols-regex '^nfc_|^iso14443a_|^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 \ $(top_builddir)/libnfc/buses/libnfcbuses.la \ $(top_builddir)/libnfc/drivers/libnfcdrivers.la if PCSC_ENABLED libnfc_la_CFLAGS += @libpcsclite_CFLAGS@ -DHAVE_PCSC libnfc_la_LIBADD += @libpcsclite_LIBS@ endif if LIBUSB_ENABLED libnfc_la_CFLAGS += @libusb_CFLAGS@ -DHAVE_LIBUSB libnfc_la_LIBADD += @libusb_LIBS@ endif if WITH_LOG libnfc_la_SOURCES += log.c log-internal.c endif EXTRA_DIST = \ CMakeLists.txt libnfc-1.7.1/libnfc/additional-pages.dox000066400000000000000000000035661230265671100201500ustar00rootroot00000000000000/** * @mainpage libnfc reference manual * * @section intro_sec Introduction * This is the developer manual for \b libnfc. * libnfc is an open source library that allows you to communicate with NFC devices. For more info, see the * libnfc homepage. * * @section quick_start_sec Quick start * If you are looking for libnfc's public API, you should start with the Modules page which links to the different categories of libnfc's functionality. * Some commented examples that present how to use \b libnfc can be found here: * @subpage examples_page * * Others example programs can be found in the libnfc source distribution under the "examples" subdirectory \ref examples. * * You can also find utils in the libnfc source distribution under the "utils" subdirectory \ref utils. * * \section errorhandling Error handling * * \b libnfc functions typically return 0 or more on success or a negative error code * on failure. These negative error codes relate to LIBNFC_ERROR constants * which are listed on the \ref error "Error reporting" documentation page. * * @section upgrading_sec Upgrading from previous version * If you are upgrading from a previous \b libnfc version, please take care about changes, specially API changes. * All important changes should be listed in @subpage changelog_page. */ /** * @page examples_page Examples * @section intro_sec Introduction * This page presents some examples to help developers which use \b libnfc. * * @section example_1_sec Simple tag UID reader. * This short commented code example should be helpful to quick start development with \b libnfc, it grab the first available NFC device and print the first found ISO14443-A tag (e.g. MIFARE Classic, MIFARE Ultralight). * @include examples/doc/quick_start_example1.c */ /** * @page changelog_page ChangeLog * @verbinclude ChangeLog */ libnfc-1.7.1/libnfc/buses/000077500000000000000000000000001230265671100153365ustar00rootroot00000000000000libnfc-1.7.1/libnfc/buses/Makefile.am000066400000000000000000000015321230265671100173730ustar00rootroot00000000000000# set the include path found by configure AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS) noinst_LTLIBRARIES = libnfcbuses.la libnfcbuses_la_SOURCES = empty.c libnfcbuses_la_CFLAGS = -I$(top_srcdir)/libnfc libnfcbuses_la_LIBADD = EXTRA_DIST = if SPI_ENABLED libnfcbuses_la_SOURCES += spi.c spi.h libnfcbuses_la_CFLAGS += libnfcbuses_la_LIBADD += endif EXTRA_DIST += spi.c spi.h if UART_ENABLED libnfcbuses_la_SOURCES += uart.c uart.h libnfcbuses_la_CFLAGS += libnfcbuses_la_LIBADD += endif EXTRA_DIST += uart.c uart.h if LIBUSB_ENABLED libnfcbuses_la_SOURCES += usbbus.c usbbus.h libnfcbuses_la_CFLAGS += @libusb_CFLAGS@ libnfcbuses_la_LIBADD += @libusb_LIBS@ endif EXTRA_DIST += usbbus.c usbbus.h if I2C_ENABLED libnfcbuses_la_SOURCES += i2c.c i2c.h libnfcbuses_la_CFLAGS += libnfcbuses_la_LIBADD += endif EXTRA_DIST += i2c.c i2c.h libnfc-1.7.1/libnfc/buses/empty.c000066400000000000000000000000601230265671100166340ustar00rootroot00000000000000/* empty source code file */ #include libnfc-1.7.1/libnfc/buses/i2c.c000066400000000000000000000127701230265671100161660ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Laurent Latil * * 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 * */ /** * @file i2c.c * @brief I2C driver (implemented / tested for Linux only currently) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "i2c.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nfc-internal.h" #define LOG_GROUP NFC_LOG_GROUP_COM #define LOG_CATEGORY "libnfc.bus.i2c" # if defined (__linux__) const char *i2c_ports_device_radix[] = { "i2c-", NULL }; # else # error "Can't determine I2C devices standard names for your system" # endif struct i2c_device_unix { int fd; // I2C device file descriptor }; #define I2C_DATA( X ) ((struct i2c_device_unix *) X) /** * @brief Open an I2C device * * @param pcI2C_busName I2C bus device name * @param devAddr address of the I2C device on the bus * @return pointer to the I2C device structure, or INVALID_I2C_BUS, INVALID_I2C_ADDRESS error codes. */ i2c_device i2c_open(const char *pcI2C_busName, uint32_t devAddr) { struct i2c_device_unix *id = malloc(sizeof(struct i2c_device_unix)); if (id == 0) return INVALID_I2C_BUS ; id->fd = open(pcI2C_busName, O_RDWR | O_NOCTTY | O_NONBLOCK); if (id->fd == -1) { perror("Cannot open I2C bus"); i2c_close(id); return INVALID_I2C_BUS ; } if (ioctl(id->fd, I2C_SLAVE, devAddr) < 0) { perror("Cannot select I2C device"); i2c_close(id); return INVALID_I2C_ADDRESS ; } return id; } /** * @brief Close the I2C device * * @param id I2C device to close. */ void i2c_close(const i2c_device id) { if (I2C_DATA(id) ->fd >= 0) { close(I2C_DATA(id) ->fd); } free(id); } /** * @brief Read a frame from the I2C device and copy data to \a pbtRx * * @param id I2C device. * @param pbtRx pointer on buffer used to store data * @param szRx length of the buffer * @return length (in bytes) of read data, or driver error code (negative value) */ ssize_t i2c_read(i2c_device id, uint8_t *pbtRx, const size_t szRx) { ssize_t res; ssize_t recCount; recCount = read(I2C_DATA(id) ->fd, pbtRx, szRx); if (recCount < 0) { res = NFC_EIO; } else { if (recCount < (ssize_t)szRx) { res = NFC_EINVARG; } else { res = recCount; } } return res; } /** * @brief Write a frame to I2C device containing \a pbtTx content * * @param id I2C device. * @param pbtTx pointer on buffer containing data * @param szTx length of the buffer * @return NFC_SUCCESS on success, otherwise driver error code */ int i2c_write(i2c_device id, const uint8_t *pbtTx, const size_t szTx) { LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx); ssize_t writeCount; writeCount = write(I2C_DATA(id) ->fd, pbtTx, szTx); if ((const ssize_t) szTx == writeCount) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "wrote %d bytes successfully.", (int)szTx); return NFC_SUCCESS; } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Error: wrote only %d bytes (%d expected).", (int)writeCount, (int) szTx); return NFC_EIO; } } /** * @brief Get the path of all I2C bus devices. * * @return array of strings defining the names of all I2C buses available. This array, and each string, are allocated * by this function and must be freed by caller. */ char ** i2c_list_ports(void) { char **res = malloc(sizeof(char *)); if (!res) { perror("malloc"); return res; } size_t szRes = 1; res[0] = NULL; DIR *dir; if ((dir = opendir("/dev")) == NULL) { perror("opendir error: /dev"); return res; } struct dirent entry; struct dirent *result; while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) { const char **p = i2c_ports_device_radix; while (*p) { if (!strncmp(entry.d_name, *p, strlen(*p))) { char **res2 = realloc(res, (szRes + 1) * sizeof(char *)); if (!res2) { perror("malloc"); goto oom; } res = res2; if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) { perror("malloc"); goto oom; } sprintf(res[szRes - 1], "/dev/%s", entry.d_name); szRes++; res[szRes - 1] = NULL; } p++; } } oom: closedir(dir); return res; } libnfc-1.7.1/libnfc/buses/i2c.h000066400000000000000000000034251230265671100161700ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Laurent Latil * * 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 * */ /** * @file i2c.h * @brief I2C driver header */ #ifndef __NFC_BUS_I2C_H__ # define __NFC_BUS_I2C_H__ # include # include # include # include # include # include typedef void *i2c_device; # define INVALID_I2C_BUS (void*)(~1) # define INVALID_I2C_ADDRESS (void*)(~2) i2c_device i2c_open(const char *pcI2C_busName, uint32_t devAddr); void i2c_close(const i2c_device id); ssize_t i2c_read(i2c_device id, uint8_t *pbtRx, const size_t szRx); int i2c_write(i2c_device id, const uint8_t *pbtTx, const size_t szTx); char **i2c_list_ports(void); #endif // __NFC_BUS_I2C_H__ libnfc-1.7.1/libnfc/buses/spi.c000066400000000000000000000163341230265671100163040ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Evgeny Boger * * 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 * */ /** * @file spi.c * @brief SPI driver */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "spi.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nfc-internal.h" #define LOG_GROUP NFC_LOG_GROUP_COM #define LOG_CATEGORY "libnfc.bus.spi" # if defined(__APPLE__) const char *spi_ports_device_radix[] = { "spidev", NULL }; # elif defined (__FreeBSD__) || defined (__OpenBSD__) const char *spi_ports_device_radix[] = { "spidev", NULL }; # elif defined (__linux__) const char *spi_ports_device_radix[] = { "spidev", NULL }; # else # error "Can't determine spi port string for your system" # endif struct spi_port_unix { int fd; // Serial port file descriptor //~ struct termios termios_backup; // Terminal info before using the port //~ struct termios termios_new; // Terminal info during the transaction }; #define SPI_DATA( X ) ((struct spi_port_unix *) X) spi_port spi_open(const char *pcPortName) { struct spi_port_unix *sp = malloc(sizeof(struct spi_port_unix)); if (sp == 0) return INVALID_SPI_PORT; sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK); if (sp->fd == -1) { spi_close(sp); return INVALID_SPI_PORT; } return sp; } void spi_set_speed(spi_port sp, const uint32_t uiPortSpeed) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "SPI port speed requested to be set to %d Hz.", uiPortSpeed); int ret; ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_WR_MAX_SPEED_HZ, &uiPortSpeed); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ret %d", ret); if (ret == -1) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error setting SPI speed."); } void spi_set_mode(spi_port sp, const uint32_t uiPortMode) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "SPI port mode requested to be set to %d.", uiPortMode); int ret; ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_WR_MODE, &uiPortMode); if (ret == -1) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error setting SPI mode."); } uint32_t spi_get_speed(spi_port sp) { uint32_t uiPortSpeed = 0; int ret; ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_RD_MAX_SPEED_HZ, &uiPortSpeed); if (ret == -1) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error reading SPI speed."); return uiPortSpeed; } void spi_close(const spi_port sp) { close(SPI_DATA(sp)->fd); free(sp); } /** * @brief Perform bit reversal on one byte \a x * * @return reversed byte */ static uint8_t bit_reversal(const uint8_t x) { uint8_t ret = x; ret = (((ret & 0xaa) >> 1) | ((ret & 0x55) << 1)); ret = (((ret & 0xcc) >> 2) | ((ret & 0x33) << 2)); ret = (((ret & 0xf0) >> 4) | ((ret & 0x0f) << 4)); return ret; } /** * @brief Send \a pbtTx content to SPI then receive data from SPI and copy data to \a pbtRx. CS line stays active between transfers as well as during transfers. * * @return 0 on success, otherwise a driver error is returned */ int spi_send_receive(spi_port sp, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, bool lsb_first) { size_t transfers = 0; struct spi_ioc_transfer tr[2]; uint8_t *pbtTxLSB = 0; if (szTx) { LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx); if (lsb_first) { pbtTxLSB = malloc(szTx * sizeof(uint8_t)); if (!pbtTxLSB) { return NFC_ESOFT; } size_t i; for (i = 0; i < szTx; ++i) { pbtTxLSB[i] = bit_reversal(pbtTx[i]); } pbtTx = pbtTxLSB; } struct spi_ioc_transfer tr_send = { .tx_buf = (unsigned long) pbtTx, .rx_buf = 0, .len = szTx , .delay_usecs = 0, .speed_hz = 0, .bits_per_word = 0, }; tr[transfers] = tr_send; ++transfers; } if (szRx) { struct spi_ioc_transfer tr_receive = { .tx_buf = 0, .rx_buf = (unsigned long) pbtRx, .len = szRx, .delay_usecs = 0, .speed_hz = 0, .bits_per_word = 0, }; tr[transfers] = tr_receive; ++transfers; } if (transfers) { int ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_MESSAGE(transfers), tr); if (szTx && lsb_first) { free(pbtTxLSB); } if (ret != (int)(szRx + szTx)) { return NFC_EIO; } // Reverse received bytes if needed if (szRx) { if (lsb_first) { size_t i; for (i = 0; i < szRx; ++i) { pbtRx[i] = bit_reversal(pbtRx[i]); } } LOG_HEX(LOG_GROUP, "RX", pbtRx, szRx); } } return NFC_SUCCESS; } /** * @brief Receive data from SPI and copy data to \a pbtRx * * @return 0 on success, otherwise driver error code */ int spi_receive(spi_port sp, uint8_t *pbtRx, const size_t szRx, bool lsb_first) { return spi_send_receive(sp, 0, 0, pbtRx, szRx, lsb_first); } /** * @brief Send \a pbtTx content to SPI * * @return 0 on success, otherwise a driver error is returned */ int spi_send(spi_port sp, const uint8_t *pbtTx, const size_t szTx, bool lsb_first) { return spi_send_receive(sp, pbtTx, szTx, 0, 0, lsb_first); } char ** spi_list_ports(void) { char **res = malloc(sizeof(char *)); size_t szRes = 1; res[0] = NULL; DIR *pdDir = opendir("/dev"); struct dirent *pdDirEnt; struct dirent entry; struct dirent *result; while ((readdir_r(pdDir, &entry, &result) == 0) && (result != NULL)) { pdDirEnt = &entry; #if !defined(__APPLE__) if (!isdigit(pdDirEnt->d_name[strlen(pdDirEnt->d_name) - 1])) continue; #endif const char **p = spi_ports_device_radix; while (*p) { if (!strncmp(pdDirEnt->d_name, *p, strlen(*p))) { char **res2 = realloc(res, (szRes + 1) * sizeof(char *)); if (!res2) goto oom; res = res2; if (!(res[szRes - 1] = malloc(6 + strlen(pdDirEnt->d_name)))) goto oom; sprintf(res[szRes - 1], "/dev/%s", pdDirEnt->d_name); szRes++; res[szRes - 1] = NULL; } p++; } } oom: closedir(pdDir); return res; } libnfc-1.7.1/libnfc/buses/spi.h000066400000000000000000000041601230265671100163030ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Evgeny Boger * * 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 * */ /** * @file spi.h * @brief SPI driver header */ #ifndef __NFC_BUS_SPI_H__ # define __NFC_BUS_SPI_H__ # include # include # include # include # include # include // Define shortcut to types to make code more readable typedef void *spi_port; # define INVALID_SPI_PORT (void*)(~1) # define CLAIMED_SPI_PORT (void*)(~2) spi_port spi_open(const char *pcPortName); void spi_close(const spi_port sp); void spi_set_speed(spi_port sp, const uint32_t uiPortSpeed); void spi_set_mode(spi_port sp, const uint32_t uiPortMode); uint32_t spi_get_speed(const spi_port sp); int spi_receive(spi_port sp, uint8_t *pbtRx, const size_t szRx, bool lsb_first); int spi_send(spi_port sp, const uint8_t *pbtTx, const size_t szTx, bool lsb_first); int spi_send_receive(spi_port sp, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, bool lsb_first); char **spi_list_ports(void); #endif // __NFC_BUS_SPI_H__ libnfc-1.7.1/libnfc/buses/uart.c000066400000000000000000000261101230265671100164550ustar00rootroot00000000000000/*- * 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: * * 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 * */ /** * @file uart.c * @brief UART driver */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "uart.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nfc-internal.h" #define LOG_GROUP NFC_LOG_GROUP_COM #define LOG_CATEGORY "libnfc.bus.uart" #ifndef _WIN32 // Needed by sleep() under Unix # include # include # define msleep(x) do { \ struct timespec xsleep; \ xsleep.tv_sec = x / 1000; \ xsleep.tv_nsec = (x - xsleep.tv_sec * 1000) * 1000 * 1000; \ nanosleep(&xsleep, NULL); \ } while (0) #else // Needed by Sleep() under Windows # include # define msleep Sleep #endif # if defined(__APPLE__) const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial-", NULL }; # elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__FreeBSD_kernel__) const char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL }; # elif defined (__linux__) const char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", "ttyACM", "ttyAMA", "ttyO", NULL }; # else # error "Can't determine serial string for your system" # endif // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct # define CCLAIMED 0x80000000 struct serial_port_unix { int fd; // Serial port file descriptor struct termios termios_backup; // Terminal info before using the port struct termios termios_new; // Terminal info during the transaction }; #define UART_DATA( X ) ((struct serial_port_unix *) X) void uart_close_ext(const serial_port sp, const bool restore_termios); serial_port uart_open(const char *pcPortName) { struct serial_port_unix *sp = malloc(sizeof(struct serial_port_unix)); if (sp == 0) return INVALID_SERIAL_PORT; sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK); if (sp->fd == -1) { uart_close_ext(sp, false); return INVALID_SERIAL_PORT; } if (tcgetattr(sp->fd, &sp->termios_backup) == -1) { uart_close_ext(sp, false); return INVALID_SERIAL_PORT; } // Make sure the port is not claimed already if (sp->termios_backup.c_iflag & CCLAIMED) { uart_close_ext(sp, false); return CLAIMED_SERIAL_PORT; } // Copy the old terminal info struct sp->termios_new = sp->termios_backup; sp->termios_new.c_cflag = CS8 | CLOCAL | CREAD; sp->termios_new.c_iflag = CCLAIMED | IGNPAR; sp->termios_new.c_oflag = 0; sp->termios_new.c_lflag = 0; sp->termios_new.c_cc[VMIN] = 0; // block until n bytes are received sp->termios_new.c_cc[VTIME] = 0; // block until a timer expires (n * 100 mSec.) if (tcsetattr(sp->fd, TCSANOW, &sp->termios_new) == -1) { uart_close_ext(sp, true); return INVALID_SERIAL_PORT; } return sp; } void uart_flush_input(serial_port sp, bool wait) { // flush commands may seem to be without effect // if asked too quickly after previous event, cf comments below // therefore a "wait" argument allows now to wait before flushing // I believe that now the byte-eater part is not required anymore --Phil if (wait) { msleep(50); // 50 ms } // This line seems to produce absolutely no effect on my system (GNU/Linux 2.6.35) tcflush(UART_DATA(sp)->fd, TCIFLUSH); // So, I wrote this byte-eater // Retrieve the count of the incoming bytes int available_bytes_count = 0; int res; res = ioctl(UART_DATA(sp)->fd, FIONREAD, &available_bytes_count); if (res != 0) { return; } if (available_bytes_count == 0) { return; } char *rx = malloc(available_bytes_count); if (!rx) { perror("malloc"); return; } // There is something available, read the data if (read(UART_DATA(sp)->fd, rx, available_bytes_count) < 0) { perror("uart read"); free(rx); return; } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d bytes have eaten.", available_bytes_count); free(rx); } void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed); // Portability note: on some systems, B9600 != 9600 so we have to do // uint32_t <=> speed_t associations by hand. speed_t stPortSpeed = B9600; switch (uiPortSpeed) { case 9600: stPortSpeed = B9600; break; case 19200: stPortSpeed = B19200; break; case 38400: stPortSpeed = B38400; break; # ifdef B57600 case 57600: stPortSpeed = B57600; break; # endif # ifdef B115200 case 115200: stPortSpeed = B115200; break; # endif # ifdef B230400 case 230400: stPortSpeed = B230400; break; # endif # ifdef B460800 case 460800: stPortSpeed = B460800; break; # endif default: log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).", uiPortSpeed); return; }; // Set port speed (Input and Output) cfsetispeed(&(UART_DATA(sp)->termios_new), stPortSpeed); cfsetospeed(&(UART_DATA(sp)->termios_new), stPortSpeed); if (tcsetattr(UART_DATA(sp)->fd, TCSADRAIN, &(UART_DATA(sp)->termios_new)) == -1) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to apply new speed settings."); } } uint32_t uart_get_speed(serial_port sp) { uint32_t uiPortSpeed = 0; switch (cfgetispeed(&UART_DATA(sp)->termios_new)) { case B9600: uiPortSpeed = 9600; break; case B19200: uiPortSpeed = 19200; break; case B38400: uiPortSpeed = 38400; break; # ifdef B57600 case B57600: uiPortSpeed = 57600; break; # endif # ifdef B115200 case B115200: uiPortSpeed = 115200; break; # endif # ifdef B230400 case B230400: uiPortSpeed = 230400; break; # endif # ifdef B460800 case B460800: uiPortSpeed = 460800; break; # endif } return uiPortSpeed; } void uart_close_ext(const serial_port sp, const bool restore_termios) { if (UART_DATA(sp)->fd >= 0) { if (restore_termios) tcsetattr(UART_DATA(sp)->fd, TCSANOW, &UART_DATA(sp)->termios_backup); close(UART_DATA(sp)->fd); } free(sp); } void uart_close(const serial_port sp) { uart_close_ext(sp, true); } /** * @brief Receive data from UART and copy data to \a pbtRx * * @return 0 on success, otherwise driver error code */ int uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout) { int iAbortFd = abort_p ? *((int *)abort_p) : 0; int received_bytes_count = 0; int available_bytes_count = 0; const int expected_bytes_count = (int)szRx; int res; fd_set rfds; do { select: // Reset file descriptor FD_ZERO(&rfds); FD_SET(UART_DATA(sp)->fd, &rfds); if (iAbortFd) { FD_SET(iAbortFd, &rfds); } struct timeval timeout_tv; if (timeout > 0) { timeout_tv.tv_sec = (timeout / 1000); timeout_tv.tv_usec = ((timeout % 1000) * 1000); } res = select(MAX(UART_DATA(sp)->fd, iAbortFd) + 1, &rfds, NULL, NULL, timeout ? &timeout_tv : NULL); if ((res < 0) && (EINTR == errno)) { // The system call was interupted by a signal and a signal handler was // run. Restart the interupted system call. goto select; } // Read error if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error: %s", strerror(errno)); return NFC_EIO; } // Read time-out if (res == 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Timeout!"); return NFC_ETIMEOUT; } if (FD_ISSET(iAbortFd, &rfds)) { // Abort requested log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Abort!"); close(iAbortFd); return NFC_EOPABORTED; } // Retrieve the count of the incoming bytes res = ioctl(UART_DATA(sp)->fd, FIONREAD, &available_bytes_count); if (res != 0) { return NFC_EIO; } // There is something available, read the data res = read(UART_DATA(sp)->fd, pbtRx + received_bytes_count, MIN(available_bytes_count, (expected_bytes_count - received_bytes_count))); // Stop if the OS has some troubles reading the data if (res <= 0) { return NFC_EIO; } received_bytes_count += res; } while (expected_bytes_count > received_bytes_count); LOG_HEX(LOG_GROUP, "RX", pbtRx, szRx); return NFC_SUCCESS; } /** * @brief Send \a pbtTx content to UART * * @return 0 on success, otherwise a driver error is returned */ int uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) { (void) timeout; LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx); if ((int) szTx == write(UART_DATA(sp)->fd, pbtTx, szTx)) return NFC_SUCCESS; else return NFC_EIO; } char ** uart_list_ports(void) { char **res = malloc(sizeof(char *)); if (!res) { perror("malloc"); return res; } size_t szRes = 1; res[0] = NULL; DIR *dir; if ((dir = opendir("/dev")) == NULL) { perror("opendir error: /dev"); return res; } struct dirent entry; struct dirent *result; while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) { #if !defined(__APPLE__) if (!isdigit(entry.d_name[strlen(entry.d_name) - 1])) continue; #endif const char **p = serial_ports_device_radix; while (*p) { if (!strncmp(entry.d_name, *p, strlen(*p))) { char **res2 = realloc(res, (szRes + 1) * sizeof(char *)); if (!res2) { perror("malloc"); goto oom; } res = res2; if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) { perror("malloc"); goto oom; } sprintf(res[szRes - 1], "/dev/%s", entry.d_name); szRes++; res[szRes - 1] = NULL; } p++; } } oom: closedir(dir); return res; } libnfc-1.7.1/libnfc/buses/uart.h000066400000000000000000000037221230265671100164660ustar00rootroot00000000000000/*- * 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: * * 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 * */ /** * @file uart.h * @brief UART driver header */ #ifndef __NFC_BUS_UART_H__ # define __NFC_BUS_UART_H__ # include # include # include # include # include // Define shortcut to types to make code more readable typedef void *serial_port; # define INVALID_SERIAL_PORT (void*)(~1) # define CLAIMED_SERIAL_PORT (void*)(~2) serial_port uart_open(const char *pcPortName); void uart_close(const serial_port sp); void uart_flush_input(const serial_port sp, bool wait); void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed); uint32_t uart_get_speed(const serial_port sp); int uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout); int uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout); char **uart_list_ports(void); #endif // __NFC_BUS_UART_H__ libnfc-1.7.1/libnfc/buses/usbbus.c000066400000000000000000000051551230265671100170130ustar00rootroot00000000000000/*- * 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: * * 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 * */ /** * @file usbbus.c * @brief libusb 0.1 driver wrapper */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include "usbbus.h" #include "log.h" #define LOG_CATEGORY "libnfc.buses.usbbus" #define LOG_GROUP NFC_LOG_GROUP_DRIVER int usb_prepare(void) { static bool usb_initialized = false; if (!usb_initialized) { #ifdef ENVVARS char *env_log_level = getenv("LIBNFC_LOG_LEVEL"); // Set libusb debug only if asked explicitely: // LIBUSB_LOG_LEVEL=12288 (= NFC_LOG_PRIORITY_DEBUG * 2 ^ NFC_LOG_GROUP_LIBUSB) if (env_log_level && (((atoi(env_log_level) >> (NFC_LOG_GROUP_LIBUSB * 2)) & 0x00000003) >= NFC_LOG_PRIORITY_DEBUG)) { setenv("USB_DEBUG", "255", 1); } #endif usb_init(); usb_initialized = true; } int res; // usb_find_busses will find all of the busses on the system. Returns the // number of changes since previous call to this function (total of new // busses and busses removed). if ((res = usb_find_busses()) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to find USB busses (%s)", _usb_strerror(res)); return -1; } // usb_find_devices will find all of the devices on each bus. This should be // called after usb_find_busses. Returns the number of changes since the // previous call to this function (total of new device and devices removed). if ((res = usb_find_devices()) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to find USB devices (%s)", _usb_strerror(res)); return -1; } return 0; } libnfc-1.7.1/libnfc/buses/usbbus.h000066400000000000000000000031001230265671100170040ustar00rootroot00000000000000/*- * 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: * * 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 * */ /** * @file usbbus.h * @brief libusb 0.1 driver header */ #ifndef __NFC_BUS_USB_H__ # define __NFC_BUS_USB_H__ #ifndef _WIN32 // Under POSIX system, we use libusb (>= 0.1.12) #include #define USB_TIMEDOUT ETIMEDOUT #define _usb_strerror( X ) strerror(-X) #else // Under Windows we use libusb-win32 (>= 1.2.5) #include #define USB_TIMEDOUT 116 #define _usb_strerror( X ) usb_strerror() #endif #include #include int usb_prepare(void); #endif // __NFC_BUS_USB_H__ libnfc-1.7.1/libnfc/chips/000077500000000000000000000000001230265671100153235ustar00rootroot00000000000000libnfc-1.7.1/libnfc/chips/Makefile.am000066400000000000000000000003511230265671100173560ustar00rootroot00000000000000 # set the include path found by configure AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS) noinst_LTLIBRARIES = libnfcchips.la libnfcchips_la_SOURCES = pn53x.c pn53x.h pn53x-internal.h libnfcchips_la_CFLAGS = -I$(top_srcdir)/libnfc libnfc-1.7.1/libnfc/chips/pn53x-internal.h000066400000000000000000000372141230265671100202720ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file pn53x-internal.h * @brief PN531, PN532 and PN533 defines and compatibility */ #ifndef __PN53X_INTERNAL_H__ #define __PN53X_INTERNAL_H__ #include "log.h" // Miscellaneous #define Diagnose 0x00 #define GetFirmwareVersion 0x02 #define GetGeneralStatus 0x04 #define ReadRegister 0x06 #define WriteRegister 0x08 #define ReadGPIO 0x0C #define WriteGPIO 0x0E #define SetSerialBaudRate 0x10 #define SetParameters 0x12 #define SAMConfiguration 0x14 #define PowerDown 0x16 #define AlparCommandForTDA 0x18 // RC-S360 has another command 0x18 for reset &..? // RF communication #define RFConfiguration 0x32 #define RFRegulationTest 0x58 // Initiator #define InJumpForDEP 0x56 #define InJumpForPSL 0x46 #define InListPassiveTarget 0x4A #define InATR 0x50 #define InPSL 0x4E #define InDataExchange 0x40 #define InCommunicateThru 0x42 #define InQuartetByteExchange 0x38 #define InDeselect 0x44 #define InRelease 0x52 #define InSelect 0x54 #define InActivateDeactivatePaypass 0x48 #define InAutoPoll 0x60 // Target #define TgInitAsTarget 0x8C #define TgSetGeneralBytes 0x92 #define TgGetData 0x86 #define TgSetData 0x8E #define TgSetDataSecure 0x96 #define TgSetMetaData 0x94 #define TgSetMetaDataSecure 0x98 #define TgGetInitiatorCommand 0x88 #define TgResponseToInitiator 0x90 #define TgGetTargetStatus 0x8A /** @note PN53x's normal frame: * * .-- Start * | .-- Packet length * | | .-- Length checksum * | | | .-- Direction (D4 Host to PN, D5 PN to Host) * | | | | .-- Code * | | | | | .-- Packet checksum * | | | | | | .-- Postamble * V | | | | | | * ----- V V V V V V * 00 FF 02 FE D4 02 2A 00 */ /** @note PN53x's extended frame: * * .-- Start * | .-- Fixed to FF to enable extended frame * | | .-- Packet length * | | | .-- Length checksum * | | | | .-- Direction (D4 Host to PN, D5 PN to Host) * | | | | | .-- Code * | | | | | | .-- Packet checksum * | | | | | | | .-- Postamble * V V V | | | | | * ----- ----- ----- V V V V V * 00 FF FF FF 00 02 FE D4 02 2A 00 */ /** * Start bytes, packet length, length checksum, direction, packet checksum and postamble are overhead */ // The TFI is considered part of the overhead # define PN53x_NORMAL_FRAME__DATA_MAX_LEN 254 # define PN53x_NORMAL_FRAME__OVERHEAD 8 # define PN53x_EXTENDED_FRAME__DATA_MAX_LEN 264 # define PN53x_EXTENDED_FRAME__OVERHEAD 11 # define PN53x_ACK_FRAME__LEN 6 typedef struct { uint8_t ui8Code; uint8_t ui8CompatFlags; #ifdef LOG const char *abtCommandText; #endif } pn53x_command; typedef enum { PN53X = 0x00, // Unknown PN53x chip type PN531 = 0x01, PN532 = 0x02, PN533 = 0x04, RCS360 = 0x08 } pn53x_type; #ifndef LOG # define PNCMD( X, Y ) { X , Y } # define PNCMD_TRACE( X ) do {} while(0) #else # define PNCMD( X, Y ) { X , Y, #X } # define PNCMD_TRACE( X ) do { \ for (size_t i=0; i<(sizeof(pn53x_commands)/sizeof(pn53x_command)); i++) { \ if ( X == pn53x_commands[i].ui8Code ) { \ log_put( LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", pn53x_commands[i].abtCommandText ); \ break; \ } \ } \ } while(0) #endif static const pn53x_command pn53x_commands[] = { // Miscellaneous PNCMD(Diagnose, PN531 | PN532 | PN533 | RCS360), PNCMD(GetFirmwareVersion, PN531 | PN532 | PN533 | RCS360), PNCMD(GetGeneralStatus, PN531 | PN532 | PN533 | RCS360), PNCMD(ReadRegister, PN531 | PN532 | PN533 | RCS360), PNCMD(WriteRegister, PN531 | PN532 | PN533 | RCS360), PNCMD(ReadGPIO, PN531 | PN532 | PN533), PNCMD(WriteGPIO, PN531 | PN532 | PN533), PNCMD(SetSerialBaudRate, PN531 | PN532 | PN533), PNCMD(SetParameters, PN531 | PN532 | PN533 | RCS360), PNCMD(SAMConfiguration, PN531 | PN532), PNCMD(PowerDown, PN531 | PN532), PNCMD(AlparCommandForTDA, PN533 | RCS360), // Has another usage on RC-S360... // RF communication PNCMD(RFConfiguration, PN531 | PN532 | PN533 | RCS360), PNCMD(RFRegulationTest, PN531 | PN532 | PN533), // Initiator PNCMD(InJumpForDEP, PN531 | PN532 | PN533 | RCS360), PNCMD(InJumpForPSL, PN531 | PN532 | PN533), PNCMD(InListPassiveTarget, PN531 | PN532 | PN533 | RCS360), PNCMD(InATR, PN531 | PN532 | PN533), PNCMD(InPSL, PN531 | PN532 | PN533), PNCMD(InDataExchange, PN531 | PN532 | PN533), PNCMD(InCommunicateThru, PN531 | PN532 | PN533 | RCS360), PNCMD(InQuartetByteExchange, PN533), PNCMD(InDeselect, PN531 | PN532 | PN533 | RCS360), PNCMD(InRelease, PN531 | PN532 | PN533 | RCS360), PNCMD(InSelect, PN531 | PN532 | PN533), PNCMD(InAutoPoll, PN532), PNCMD(InActivateDeactivatePaypass, PN533), // Target PNCMD(TgInitAsTarget, PN531 | PN532 | PN533), PNCMD(TgSetGeneralBytes, PN531 | PN532 | PN533), PNCMD(TgGetData, PN531 | PN532 | PN533), PNCMD(TgSetData, PN531 | PN532 | PN533), PNCMD(TgSetDataSecure, PN533), PNCMD(TgSetMetaData, PN531 | PN532 | PN533), PNCMD(TgSetMetaDataSecure, PN533), PNCMD(TgGetInitiatorCommand, PN531 | PN532 | PN533), PNCMD(TgResponseToInitiator, PN531 | PN532 | PN533), PNCMD(TgGetTargetStatus, PN531 | PN532 | PN533), }; // SFR part #define _BV( X ) (1 << X) #define P30 0 #define P31 1 #define P32 2 #define P33 3 #define P34 4 #define P35 5 // Registers part #ifdef LOG typedef struct { uint16_t ui16Address; const char *abtRegisterText; const char *abtRegisterDescription; } pn53x_register; # define PNREG( X, Y ) { X , #X, Y } #endif /* LOG */ #ifndef LOG # define PNREG_TRACE( X ) do { \ } while(0) #else # define PNREG_TRACE( X ) do { \ for (size_t i=0; i<(sizeof(pn53x_registers)/sizeof(pn53x_register)); i++) { \ if ( X == pn53x_registers[i].ui16Address ) { \ log_put( LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s (%s)", pn53x_registers[i].abtRegisterText, pn53x_registers[i].abtRegisterDescription ); \ break; \ } \ } \ } while(0) #endif // Register addresses #define PN53X_REG_Control_switch_rng 0x6106 #define PN53X_REG_CIU_Mode 0x6301 #define PN53X_REG_CIU_TxMode 0x6302 #define PN53X_REG_CIU_RxMode 0x6303 #define PN53X_REG_CIU_TxControl 0x6304 #define PN53X_REG_CIU_TxAuto 0x6305 #define PN53X_REG_CIU_TxSel 0x6306 #define PN53X_REG_CIU_RxSel 0x6307 #define PN53X_REG_CIU_RxThreshold 0x6308 #define PN53X_REG_CIU_Demod 0x6309 #define PN53X_REG_CIU_FelNFC1 0x630A #define PN53X_REG_CIU_FelNFC2 0x630B #define PN53X_REG_CIU_MifNFC 0x630C #define PN53X_REG_CIU_ManualRCV 0x630D #define PN53X_REG_CIU_TypeB 0x630E // #define PN53X_REG_- 0x630F // #define PN53X_REG_- 0x6310 #define PN53X_REG_CIU_CRCResultMSB 0x6311 #define PN53X_REG_CIU_CRCResultLSB 0x6312 #define PN53X_REG_CIU_GsNOFF 0x6313 #define PN53X_REG_CIU_ModWidth 0x6314 #define PN53X_REG_CIU_TxBitPhase 0x6315 #define PN53X_REG_CIU_RFCfg 0x6316 #define PN53X_REG_CIU_GsNOn 0x6317 #define PN53X_REG_CIU_CWGsP 0x6318 #define PN53X_REG_CIU_ModGsP 0x6319 #define PN53X_REG_CIU_TMode 0x631A #define PN53X_REG_CIU_TPrescaler 0x631B #define PN53X_REG_CIU_TReloadVal_hi 0x631C #define PN53X_REG_CIU_TReloadVal_lo 0x631D #define PN53X_REG_CIU_TCounterVal_hi 0x631E #define PN53X_REG_CIU_TCounterVal_lo 0x631F // #define PN53X_REG_- 0x6320 #define PN53X_REG_CIU_TestSel1 0x6321 #define PN53X_REG_CIU_TestSel2 0x6322 #define PN53X_REG_CIU_TestPinEn 0x6323 #define PN53X_REG_CIU_TestPinValue 0x6324 #define PN53X_REG_CIU_TestBus 0x6325 #define PN53X_REG_CIU_AutoTest 0x6326 #define PN53X_REG_CIU_Version 0x6327 #define PN53X_REG_CIU_AnalogTest 0x6328 #define PN53X_REG_CIU_TestDAC1 0x6329 #define PN53X_REG_CIU_TestDAC2 0x632A #define PN53X_REG_CIU_TestADC 0x632B // #define PN53X_REG_- 0x632C // #define PN53X_REG_- 0x632D // #define PN53X_REG_- 0x632E #define PN53X_REG_CIU_RFlevelDet 0x632F #define PN53X_REG_CIU_SIC_CLK_en 0x6330 #define PN53X_REG_CIU_Command 0x6331 #define PN53X_REG_CIU_CommIEn 0x6332 #define PN53X_REG_CIU_DivIEn 0x6333 #define PN53X_REG_CIU_CommIrq 0x6334 #define PN53X_REG_CIU_DivIrq 0x6335 #define PN53X_REG_CIU_Error 0x6336 #define PN53X_REG_CIU_Status1 0x6337 #define PN53X_REG_CIU_Status2 0x6338 #define PN53X_REG_CIU_FIFOData 0x6339 #define PN53X_REG_CIU_FIFOLevel 0x633A #define PN53X_REG_CIU_WaterLevel 0x633B #define PN53X_REG_CIU_Control 0x633C #define PN53X_REG_CIU_BitFraming 0x633D #define PN53X_REG_CIU_Coll 0x633E #define PN53X_SFR_P3 0xFFB0 #define PN53X_SFR_P3CFGA 0xFFFC #define PN53X_SFR_P3CFGB 0xFFFD #define PN53X_SFR_P7CFGA 0xFFF4 #define PN53X_SFR_P7CFGB 0xFFF5 #define PN53X_SFR_P7 0xFFF7 /* PN53x specific errors */ #define ETIMEOUT 0x01 #define ECRC 0x02 #define EPARITY 0x03 #define EBITCOUNT 0x04 #define EFRAMING 0x05 #define EBITCOLL 0x06 #define ESMALLBUF 0x07 #define EBUFOVF 0x09 #define ERFTIMEOUT 0x0a #define ERFPROTO 0x0b #define EOVHEAT 0x0d #define EINBUFOVF 0x0e #define EINVPARAM 0x10 #define EDEPUNKCMD 0x12 #define EINVRXFRAM 0x13 #define EMFAUTH 0x14 #define ENSECNOTSUPP 0x18 // PN533 only #define EBCC 0x23 #define EDEPINVSTATE 0x25 #define EOPNOTALL 0x26 #define ECMD 0x27 #define ETGREL 0x29 #define ECID 0x2a #define ECDISCARDED 0x2b #define ENFCID3 0x2c #define EOVCURRENT 0x2d #define ENAD 0x2e #ifdef LOG static const pn53x_register pn53x_registers[] = { PNREG(PN53X_REG_CIU_Mode, "Defines general modes for transmitting and receiving"), PNREG(PN53X_REG_CIU_TxMode, "Defines the transmission data rate and framing during transmission"), PNREG(PN53X_REG_CIU_RxMode, "Defines the transmission data rate and framing during receiving"), PNREG(PN53X_REG_CIU_TxControl, "Controls the logical behaviour of the antenna driver pins TX1 and TX2"), PNREG(PN53X_REG_CIU_TxAuto, "Controls the settings of the antenna driver"), PNREG(PN53X_REG_CIU_TxSel, "Selects the internal sources for the antenna driver"), PNREG(PN53X_REG_CIU_RxSel, "Selects internal receiver settings"), PNREG(PN53X_REG_CIU_RxThreshold, "Selects thresholds for the bit decoder"), PNREG(PN53X_REG_CIU_Demod, "Defines demodulator settings"), PNREG(PN53X_REG_CIU_FelNFC1, "Defines the length of the valid range for the received frame"), PNREG(PN53X_REG_CIU_FelNFC2, "Defines the length of the valid range for the received frame"), PNREG(PN53X_REG_CIU_MifNFC, "Controls the communication in ISO/IEC 14443/MIFARE and NFC target mode at 106 kbit/s"), PNREG(PN53X_REG_CIU_ManualRCV, "Allows manual fine tuning of the internal receiver"), PNREG(PN53X_REG_CIU_TypeB, "Configure the ISO/IEC 14443 type B"), // PNREG (PN53X_REG_-, "Reserved"), // PNREG (PN53X_REG_-, "Reserved"), PNREG(PN53X_REG_CIU_CRCResultMSB, "Shows the actual MSB values of the CRC calculation"), PNREG(PN53X_REG_CIU_CRCResultLSB, "Shows the actual LSB values of the CRC calculation"), PNREG(PN53X_REG_CIU_GsNOFF, "Selects the conductance of the antenna driver pins TX1 and TX2 for load modulation when own RF field is switched OFF"), PNREG(PN53X_REG_CIU_ModWidth, "Controls the setting of the width of the Miller pause"), PNREG(PN53X_REG_CIU_TxBitPhase, "Bit synchronization at 106 kbit/s"), PNREG(PN53X_REG_CIU_RFCfg, "Configures the receiver gain and RF level"), PNREG(PN53X_REG_CIU_GsNOn, "Selects the conductance of the antenna driver pins TX1 and TX2 for modulation, when own RF field is switched ON"), PNREG(PN53X_REG_CIU_CWGsP, "Selects the conductance of the antenna driver pins TX1 and TX2 when not in modulation phase"), PNREG(PN53X_REG_CIU_ModGsP, "Selects the conductance of the antenna driver pins TX1 and TX2 when in modulation phase"), PNREG(PN53X_REG_CIU_TMode, "Defines settings for the internal timer"), PNREG(PN53X_REG_CIU_TPrescaler, "Defines settings for the internal timer"), PNREG(PN53X_REG_CIU_TReloadVal_hi, "Describes the 16-bit long timer reload value (Higher 8 bits)"), PNREG(PN53X_REG_CIU_TReloadVal_lo, "Describes the 16-bit long timer reload value (Lower 8 bits)"), PNREG(PN53X_REG_CIU_TCounterVal_hi, "Describes the 16-bit long timer actual value (Higher 8 bits)"), PNREG(PN53X_REG_CIU_TCounterVal_lo, "Describes the 16-bit long timer actual value (Lower 8 bits)"), // PNREG (PN53X_REG_-, "Reserved"), PNREG(PN53X_REG_CIU_TestSel1, "General test signals configuration"), PNREG(PN53X_REG_CIU_TestSel2, "General test signals configuration and PRBS control"), PNREG(PN53X_REG_CIU_TestPinEn, "Enables test signals output on pins."), PNREG(PN53X_REG_CIU_TestPinValue, "Defines the values for the 8-bit parallel bus when it is used as I/O bus"), PNREG(PN53X_REG_CIU_TestBus, "Shows the status of the internal test bus"), PNREG(PN53X_REG_CIU_AutoTest, "Controls the digital self-test"), PNREG(PN53X_REG_CIU_Version, "Shows the CIU version"), PNREG(PN53X_REG_CIU_AnalogTest, "Controls the pins AUX1 and AUX2"), PNREG(PN53X_REG_CIU_TestDAC1, "Defines the test value for the TestDAC1"), PNREG(PN53X_REG_CIU_TestDAC2, "Defines the test value for the TestDAC2"), PNREG(PN53X_REG_CIU_TestADC, "Show the actual value of ADC I and Q"), // PNREG (PN53X_REG_-, "Reserved for tests"), // PNREG (PN53X_REG_-, "Reserved for tests"), // PNREG (PN53X_REG_-, "Reserved for tests"), PNREG(PN53X_REG_CIU_RFlevelDet, "Power down of the RF level detector"), PNREG(PN53X_REG_CIU_SIC_CLK_en, "Enables the use of secure IC clock on P34 / SIC_CLK"), PNREG(PN53X_REG_CIU_Command, "Starts and stops the command execution"), PNREG(PN53X_REG_CIU_CommIEn, "Control bits to enable and disable the passing of interrupt requests"), PNREG(PN53X_REG_CIU_DivIEn, "Controls bits to enable and disable the passing of interrupt requests"), PNREG(PN53X_REG_CIU_CommIrq, "Contains common CIU interrupt request flags"), PNREG(PN53X_REG_CIU_DivIrq, "Contains miscellaneous interrupt request flags"), PNREG(PN53X_REG_CIU_Error, "Error flags showing the error status of the last command executed"), PNREG(PN53X_REG_CIU_Status1, "Contains status flags of the CRC, Interrupt Request System and FIFO buffer"), PNREG(PN53X_REG_CIU_Status2, "Contain status flags of the receiver, transmitter and Data Mode Detector"), PNREG(PN53X_REG_CIU_FIFOData, "In- and output of 64 byte FIFO buffer"), PNREG(PN53X_REG_CIU_FIFOLevel, "Indicates the number of bytes stored in the FIFO"), PNREG(PN53X_REG_CIU_WaterLevel, "Defines the thresholds for FIFO under- and overflow warning"), PNREG(PN53X_REG_CIU_Control, "Contains miscellaneous control bits"), PNREG(PN53X_REG_CIU_BitFraming, "Adjustments for bit oriented frames"), PNREG(PN53X_REG_CIU_Coll, "Defines the first bit collision detected on the RF interface"), // SFR PNREG(PN53X_SFR_P3CFGA, "Port 3 configuration"), PNREG(PN53X_SFR_P3CFGB, "Port 3 configuration"), PNREG(PN53X_SFR_P3, "Port 3 value"), PNREG(PN53X_SFR_P7CFGA, "Port 7 configuration"), PNREG(PN53X_SFR_P7CFGB, "Port 7 configuration"), PNREG(PN53X_SFR_P7, "Port 7 value"), }; #endif #endif /* __PN53X_INTERNAL_H__ */ libnfc-1.7.1/libnfc/chips/pn53x.c000066400000000000000000003545721230265671100164640ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file pn53x.c * @brief PN531, PN532 and PN533 common functions */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include "nfc/nfc.h" #include "nfc-internal.h" #include "pn53x.h" #include "pn53x-internal.h" #include "mirror-subr.h" #define LOG_CATEGORY "libnfc.chip.pn53x" #define LOG_GROUP NFC_LOG_GROUP_CHIP const uint8_t pn53x_ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 }; const uint8_t pn53x_nack_frame[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 }; static const uint8_t pn53x_error_frame[] = { 0x00, 0x00, 0xff, 0x01, 0xff, 0x7f, 0x81, 0x00 }; const nfc_baud_rate pn53x_iso14443a_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn53x_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 }; const nfc_baud_rate pn53x_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; const nfc_baud_rate pn53x_jewel_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn532_iso14443b_supported_baud_rates[] = { NBR_106, 0 }; const nfc_baud_rate pn533_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; const nfc_modulation_type pn53x_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_DEP, 0}; /* prototypes */ int pn53x_reset_settings(struct nfc_device *pnd); int pn53x_writeback_register(struct nfc_device *pnd); nfc_modulation pn53x_ptt_to_nm(const pn53x_target_type ptt); pn53x_modulation pn53x_nm_to_pm(const nfc_modulation nm); pn53x_target_type pn53x_nm_to_ptt(const nfc_modulation nm); void *pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt); void pn53x_current_target_free(const struct nfc_device *pnd); bool pn53x_current_target_is(const struct nfc_device *pnd, const nfc_target *pnt); /* implementations */ int pn53x_init(struct nfc_device *pnd) { int res = 0; // GetFirmwareVersion command is used to set PN53x chips type (PN531, PN532 or PN533) if ((res = pn53x_decode_firmware_version(pnd)) < 0) { return res; } if (!CHIP_DATA(pnd)->supported_modulation_as_initiator) { CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * 9); if (! CHIP_DATA(pnd)->supported_modulation_as_initiator) return NFC_ESOFT; int nbSupportedModulation = 0; if ((pnd->btSupportByte & SUPPORT_ISO14443A)) { CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443A; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_FELICA; nbSupportedModulation++; } if (pnd->btSupportByte & SUPPORT_ISO14443B) { CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B; nbSupportedModulation++; } if (CHIP_DATA(pnd)->type != PN531) { CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL; nbSupportedModulation++; } CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_DEP; nbSupportedModulation++; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = 0; } if (!CHIP_DATA(pnd)->supported_modulation_as_target) { CHIP_DATA(pnd)->supported_modulation_as_target = (nfc_modulation_type *) pn53x_supported_modulation_as_target; } // CRC handling should be enabled by default as declared in nfc_device_new // which is the case by default for pn53x, so nothing to do here // Parity handling should be enabled by default as declared in nfc_device_new // which is the case by default for pn53x, so nothing to do here // We can't read these parameters, so we set a default config by using the SetParameters wrapper // Note: pn53x_SetParameters() will save the sent value in pnd->ui8Parameters cache if ((res = pn53x_SetParameters(pnd, PARAM_AUTO_ATR_RES | PARAM_AUTO_RATS)) < 0) { return res; } if ((res = pn53x_reset_settings(pnd)) < 0) { return res; } return NFC_SUCCESS; } int pn53x_reset_settings(struct nfc_device *pnd) { int res = 0; // Reset the ending transmission bits register, it is unknown what the last tranmission used there CHIP_DATA(pnd)->ui8TxBits = 0; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_BitFraming, SYMBOL_TX_LAST_BITS, 0x00)) < 0) { return res; } // Make sure we reset the CRC and parity to chip handling. if ((res = pn53x_set_property_bool(pnd, NP_HANDLE_CRC, true)) < 0) return res; if ((res = pn53x_set_property_bool(pnd, NP_HANDLE_PARITY, true)) < 0) return res; // Activate "easy framing" feature by default if ((res = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) return res; // Deactivate the CRYPTO1 cipher, it may could cause problems when still active if ((res = pn53x_set_property_bool(pnd, NP_ACTIVATE_CRYPTO1, false)) < 0) return res; return NFC_SUCCESS; } int pn53x_transceive(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRxLen, int timeout) { bool mi = false; int res = 0; if (CHIP_DATA(pnd)->wb_trigged) { if ((res = pn53x_writeback_register(pnd)) < 0) { return res; } } PNCMD_TRACE(pbtTx[0]); if (timeout > 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Timeout value: %d", timeout); } else if (timeout == 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "No timeout"); } else if (timeout == -1) { timeout = CHIP_DATA(pnd)->timeout_command; } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid timeout value: %d", timeout); } uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); // Check if receiving buffers are available, if not, replace them if (szRxLen == 0 || !pbtRx) { pbtRx = abtRx; } else { szRx = szRxLen; } // Call the send/receice callback functions of the current driver if ((res = CHIP_DATA(pnd)->io->send(pnd, pbtTx, szTx, timeout)) < 0) { return res; } // Command is sent, we store the command CHIP_DATA(pnd)->last_command = pbtTx[0]; // Handle power mode for PN532 if ((CHIP_DATA(pnd)->type == PN532) && (TgInitAsTarget == pbtTx[0])) { // PN532 automatically goes into PowerDown mode when TgInitAsTarget command will be sent CHIP_DATA(pnd)->power_mode = POWERDOWN; } if ((res = CHIP_DATA(pnd)->io->receive(pnd, pbtRx, szRx, timeout)) < 0) { return res; } if ((CHIP_DATA(pnd)->type == PN532) && (TgInitAsTarget == pbtTx[0])) { // PN532 automatically wakeup on external RF field CHIP_DATA(pnd)->power_mode = NORMAL; // When TgInitAsTarget reply that means an external RF have waken up the chip } switch (pbtTx[0]) { case PowerDown: case InDataExchange: case InCommunicateThru: case InJumpForPSL: case InPSL: case InATR: case InSelect: case InJumpForDEP: case TgGetData: case TgGetInitiatorCommand: case TgSetData: case TgResponseToInitiator: case TgSetGeneralBytes: case TgSetMetaData: if (pbtRx[0] & 0x80) { abort(); } // NAD detected // if (pbtRx[0] & 0x40) { abort(); } // MI detected mi = pbtRx[0] & 0x40; CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; break; case Diagnose: if (pbtTx[1] == 0x06) { // Diagnose: Card presence detection CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; } else { CHIP_DATA(pnd)->last_status_byte = 0; }; break; case InDeselect: case InRelease: if (CHIP_DATA(pnd)->type == RCS360) { // Error code is in pbtRx[1] but we ignore error code anyway // because other PN53x chips always return 0 on those commands CHIP_DATA(pnd)->last_status_byte = 0; break; } CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; break; case ReadRegister: case WriteRegister: if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by the status byte CHIP_DATA(pnd)->last_status_byte = pbtRx[0] & 0x3f; } else { CHIP_DATA(pnd)->last_status_byte = 0; } break; default: CHIP_DATA(pnd)->last_status_byte = 0; } while (mi) { int res2; uint8_t abtRx2[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; // Send empty command to card if ((res2 = CHIP_DATA(pnd)->io->send(pnd, pbtTx, 2, timeout)) < 0) { return res2; } if ((res2 = CHIP_DATA(pnd)->io->receive(pnd, abtRx2, sizeof(abtRx2), timeout)) < 0) { return res2; } mi = abtRx2[0] & 0x40; if ((size_t)(res + res2 - 1) > szRx) { CHIP_DATA(pnd)->last_status_byte = ESMALLBUF; break; } memcpy(pbtRx + res, abtRx2 + 1, res2 - 1); // Copy last status byte pbtRx[0] = abtRx2[0]; res += res2 - 1; } szRx = (size_t) res; switch (CHIP_DATA(pnd)->last_status_byte) { case 0: res = (int)szRx; break; case ETIMEOUT: case ECRC: case EPARITY: case EBITCOUNT: case EFRAMING: case EBITCOLL: case ERFPROTO: case ERFTIMEOUT: case EDEPUNKCMD: case EDEPINVSTATE: case ENAD: case ENFCID3: case EINVRXFRAM: case EBCC: case ECID: res = NFC_ERFTRANS; break; case ESMALLBUF: case EOVCURRENT: case EBUFOVF: case EOVHEAT: case EINBUFOVF: res = NFC_ECHIP; break; case EINVPARAM: case EOPNOTALL: case ECMD: case ENSECNOTSUPP: res = NFC_EINVARG; break; case ETGREL: case ECDISCARDED: res = NFC_ETGRELEASED; pn53x_current_target_free(pnd); break; case EMFAUTH: // When a MIFARE Classic AUTH fails, the tag is automatically in HALT state res = NFC_EMFCAUTHFAIL; break; default: res = NFC_ECHIP; break; }; if (res < 0) { pnd->last_error = res; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Chip error: \"%s\" (%02x), returned error: \"%s\" (%d))", pn53x_strerror(pnd), CHIP_DATA(pnd)->last_status_byte, nfc_strerror(pnd), res); } else { pnd->last_error = 0; } return res; } int pn53x_set_parameters(struct nfc_device *pnd, const uint8_t ui8Parameter, const bool bEnable) { uint8_t ui8Value = (bEnable) ? (CHIP_DATA(pnd)->ui8Parameters | ui8Parameter) : (CHIP_DATA(pnd)->ui8Parameters & ~(ui8Parameter)); if (ui8Value != CHIP_DATA(pnd)->ui8Parameters) { return pn53x_SetParameters(pnd, ui8Value); } return NFC_SUCCESS; } int pn53x_set_tx_bits(struct nfc_device *pnd, const uint8_t ui8Bits) { // Test if we need to update the transmission bits register setting if (CHIP_DATA(pnd)->ui8TxBits != ui8Bits) { int res = 0; // Set the amount of transmission bits in the PN53X chip register if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_BitFraming, SYMBOL_TX_LAST_BITS, ui8Bits)) < 0) return res; // Store the new setting CHIP_DATA(pnd)->ui8TxBits = ui8Bits; } return NFC_SUCCESS; } int pn53x_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtFrame) { uint8_t btFrame; uint8_t btData; uint32_t uiBitPos; uint32_t uiDataPos = 0; size_t szBitsLeft = szTxBits; size_t szFrameBits = 0; // Make sure we should frame at least something if (szBitsLeft == 0) return NFC_ECHIP; // Handle a short response (1byte) as a special case if (szBitsLeft < 9) { *pbtFrame = *pbtTx; szFrameBits = szTxBits; return szFrameBits; } // We start by calculating the frame length in bits szFrameBits = szTxBits + (szTxBits / 8); // Parse the data bytes and add the parity bits // This is really a sensitive process, mirror the frame bytes and append parity bits // buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ... // split "buffer" up in segments of 8 bits again and mirror them // air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + .. while (true) { // Reset the temporary frame byte; btFrame = 0; for (uiBitPos = 0; uiBitPos < 8; uiBitPos++) { // Copy as much data that fits in the frame byte btData = mirror(pbtTx[uiDataPos]); btFrame |= (btData >> uiBitPos); // Save this frame byte *pbtFrame = mirror(btFrame); // Set the remaining bits of the date in the new frame byte and append the parity bit btFrame = (btData << (8 - uiBitPos)); btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7 - uiBitPos)); // Backup the frame bits we have so far pbtFrame++; *pbtFrame = mirror(btFrame); // Increase the data (without parity bit) position uiDataPos++; // Test if we are done if (szBitsLeft < 9) return szFrameBits; szBitsLeft -= 8; } // Every 8 data bytes we lose one frame byte to the parities pbtFrame++; } } int pn53x_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBits, uint8_t *pbtRx, uint8_t *pbtRxPar) { uint8_t btFrame; uint8_t btData; uint8_t uiBitPos; uint32_t uiDataPos = 0; uint8_t *pbtFramePos = (uint8_t *) pbtFrame; size_t szBitsLeft = szFrameBits; size_t szRxBits = 0; // Make sure we should frame at least something if (szBitsLeft == 0) return NFC_ECHIP; // Handle a short response (1byte) as a special case if (szBitsLeft < 9) { *pbtRx = *pbtFrame; szRxBits = szFrameBits; return szRxBits; } // Calculate the data length in bits szRxBits = szFrameBits - (szFrameBits / 9); // Parse the frame bytes, remove the parity bits and store them in the parity array // This process is the reverse of WrapFrame(), look there for more info while (true) { for (uiBitPos = 0; uiBitPos < 8; uiBitPos++) { btFrame = mirror(pbtFramePos[uiDataPos]); btData = (btFrame << uiBitPos); btFrame = mirror(pbtFramePos[uiDataPos + 1]); btData |= (btFrame >> (8 - uiBitPos)); pbtRx[uiDataPos] = mirror(btData); if (pbtRxPar != NULL) pbtRxPar[uiDataPos] = ((btFrame >> (7 - uiBitPos)) & 0x01); // Increase the data (without parity bit) position uiDataPos++; // Test if we are done if (szBitsLeft < 9) return szRxBits; szBitsLeft -= 9; } // Every 8 data bytes we lose one frame byte to the parities pbtFramePos++; } } int pn53x_decode_target_data(const uint8_t *pbtRawData, size_t szRawData, pn53x_type type, nfc_modulation_type nmt, nfc_target_info *pnti) { uint8_t szAttribRes; const uint8_t *pbtUid; switch (nmt) { case NMT_ISO14443A: // We skip the first byte: its the target number (Tg) pbtRawData++; // Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset if (type == PN531) { pnti->nai.abtAtqa[1] = *(pbtRawData++); pnti->nai.abtAtqa[0] = *(pbtRawData++); } else { pnti->nai.abtAtqa[0] = *(pbtRawData++); pnti->nai.abtAtqa[1] = *(pbtRawData++); } pnti->nai.btSak = *(pbtRawData++); // Copy the NFCID1 pnti->nai.szUidLen = *(pbtRawData++); pbtUid = pbtRawData; pbtRawData += pnti->nai.szUidLen; // Did we received an optional ATS (Smardcard ATR) if (szRawData > (pnti->nai.szUidLen + 5)) { pnti->nai.szAtsLen = ((*(pbtRawData++)) - 1); // In pbtRawData, ATS Length byte is counted in ATS Frame. memcpy(pnti->nai.abtAts, pbtRawData, pnti->nai.szAtsLen); } else { pnti->nai.szAtsLen = 0; } // For PN531, strip CT (Cascade Tag) to retrieve and store the _real_ UID // (e.g. 0x8801020304050607 is in fact 0x01020304050607) if ((pnti->nai.szUidLen == 8) && (pbtUid[0] == 0x88)) { pnti->nai.szUidLen = 7; memcpy(pnti->nai.abtUid, pbtUid + 1, 7); // } else if ((pnti->nai.szUidLen == 12) && (pbtUid[0] == 0x88) && (pbtUid[4] == 0x88)) { } else if (pnti->nai.szUidLen > 10) { pnti->nai.szUidLen = 10; memcpy(pnti->nai.abtUid, pbtUid + 1, 3); memcpy(pnti->nai.abtUid + 3, pbtUid + 5, 3); memcpy(pnti->nai.abtUid + 6, pbtUid + 8, 4); } else { // For PN532, PN533 memcpy(pnti->nai.abtUid, pbtUid, pnti->nai.szUidLen); } break; case NMT_ISO14443B: // We skip the first byte: its the target number (Tg) pbtRawData++; // Now we are in ATQB, we skip the first ATQB byte always equal to 0x50 pbtRawData++; // Store the PUPI (Pseudo-Unique PICC Identifier) memcpy(pnti->nbi.abtPupi, pbtRawData, 4); pbtRawData += 4; // Store the Application Data memcpy(pnti->nbi.abtApplicationData, pbtRawData, 4); pbtRawData += 4; // Store the Protocol Info memcpy(pnti->nbi.abtProtocolInfo, pbtRawData, 3); pbtRawData += 3; // We leave the ATQB field, we now enter in Card IDentifier szAttribRes = *(pbtRawData++); if (szAttribRes) { pnti->nbi.ui8CardIdentifier = *(pbtRawData++); } break; case NMT_ISO14443BI: // Skip V & T Addresses pbtRawData++; if (*pbtRawData != 0x07) { // 0x07 = REPGEN return NFC_ECHIP; } pbtRawData++; // Store the UID memcpy(pnti->nii.abtDIV, pbtRawData, 4); pbtRawData += 4; pnti->nii.btVerLog = *(pbtRawData++); if (pnti->nii.btVerLog & 0x80) { // Type = long? pnti->nii.btConfig = *(pbtRawData++); if (pnti->nii.btConfig & 0x40) { memcpy(pnti->nii.abtAtr, pbtRawData, szRawData - 8); pnti->nii.szAtrLen = szRawData - 8; } } break; case NMT_ISO14443B2SR: // Store the UID memcpy(pnti->nsi.abtUID, pbtRawData, 8); break; case NMT_ISO14443B2CT: // Store UID LSB memcpy(pnti->nci.abtUID, pbtRawData, 2); pbtRawData += 2; // Store Prod Code & Fab Code pnti->nci.btProdCode = *(pbtRawData++); pnti->nci.btFabCode = *(pbtRawData++); // Store UID MSB memcpy(pnti->nci.abtUID + 2, pbtRawData, 2); break; case NMT_FELICA: // We skip the first byte: its the target number (Tg) pbtRawData++; // Store the mandatory info pnti->nfi.szLen = *(pbtRawData++); pnti->nfi.btResCode = *(pbtRawData++); // Copy the NFCID2t memcpy(pnti->nfi.abtId, pbtRawData, 8); pbtRawData += 8; // Copy the felica padding memcpy(pnti->nfi.abtPad, pbtRawData, 8); pbtRawData += 8; // Test if the System code (SYST_CODE) is available if (pnti->nfi.szLen > 18) { memcpy(pnti->nfi.abtSysCode, pbtRawData, 2); } break; case NMT_JEWEL: // We skip the first byte: its the target number (Tg) pbtRawData++; // Store the mandatory info memcpy(pnti->nji.btSensRes, pbtRawData, 2); pbtRawData += 2; memcpy(pnti->nji.btId, pbtRawData, 4); break; // Should not happend... case NMT_DEP: return NFC_ECHIP; break; } return NFC_SUCCESS; } static int pn53x_ReadRegister(struct nfc_device *pnd, uint16_t ui16RegisterAddress, uint8_t *ui8Value) { uint8_t abtCmd[] = { ReadRegister, ui16RegisterAddress >> 8, ui16RegisterAddress & 0xff }; uint8_t abtRegValue[2]; size_t szRegValue = sizeof(abtRegValue); int res = 0; PNREG_TRACE(ui16RegisterAddress); if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRegValue, szRegValue, -1)) < 0) { return res; } if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte *ui8Value = abtRegValue[1]; } else { *ui8Value = abtRegValue[0]; } return NFC_SUCCESS; } int pn53x_read_register(struct nfc_device *pnd, uint16_t ui16RegisterAddress, uint8_t *ui8Value) { return pn53x_ReadRegister(pnd, ui16RegisterAddress, ui8Value); } static int pn53x_WriteRegister(struct nfc_device *pnd, const uint16_t ui16RegisterAddress, const uint8_t ui8Value) { uint8_t abtCmd[] = { WriteRegister, ui16RegisterAddress >> 8, ui16RegisterAddress & 0xff, ui8Value }; PNREG_TRACE(ui16RegisterAddress); return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_write_register(struct nfc_device *pnd, const uint16_t ui16RegisterAddress, const uint8_t ui8SymbolMask, const uint8_t ui8Value) { if ((ui16RegisterAddress < PN53X_CACHE_REGISTER_MIN_ADDRESS) || (ui16RegisterAddress > PN53X_CACHE_REGISTER_MAX_ADDRESS)) { // Direct write if (ui8SymbolMask != 0xff) { int res = 0; uint8_t ui8CurrentValue; if ((res = pn53x_read_register(pnd, ui16RegisterAddress, &ui8CurrentValue)) < 0) return res; uint8_t ui8NewValue = ((ui8Value & ui8SymbolMask) | (ui8CurrentValue & (~ui8SymbolMask))); if (ui8NewValue != ui8CurrentValue) { return pn53x_WriteRegister(pnd, ui16RegisterAddress, ui8NewValue); } } else { return pn53x_WriteRegister(pnd, ui16RegisterAddress, ui8Value); } } else { // Write-back cache area const int internal_address = ui16RegisterAddress - PN53X_CACHE_REGISTER_MIN_ADDRESS; CHIP_DATA(pnd)->wb_data[internal_address] = (CHIP_DATA(pnd)->wb_data[internal_address] & CHIP_DATA(pnd)->wb_mask[internal_address] & (~ui8SymbolMask)) | (ui8Value & ui8SymbolMask); CHIP_DATA(pnd)->wb_mask[internal_address] = CHIP_DATA(pnd)->wb_mask[internal_address] | ui8SymbolMask; CHIP_DATA(pnd)->wb_trigged = true; } return NFC_SUCCESS; } int pn53x_writeback_register(struct nfc_device *pnd) { int res = 0; // TODO Check at each step (ReadRegister, WriteRegister) if we didn't exceed max supported frame length BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); // First step, it looks for registers to be read before applying the requested mask CHIP_DATA(pnd)->wb_trigged = false; for (size_t n = 0; n < PN53X_CACHE_REGISTER_SIZE; n++) { if ((CHIP_DATA(pnd)->wb_mask[n]) && (CHIP_DATA(pnd)->wb_mask[n] != 0xff)) { // This register needs to be read: mask is present but does not cover full data width (ie. mask != 0xff) const uint16_t pn53x_register_address = PN53X_CACHE_REGISTER_MIN_ADDRESS + n; BUFFER_APPEND(abtReadRegisterCmd, pn53x_register_address >> 8); BUFFER_APPEND(abtReadRegisterCmd, pn53x_register_address & 0xff); } } if (BUFFER_SIZE(abtReadRegisterCmd) > 1) { // It needs to read some registers uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // It transceives the previously constructed ReadRegister command if ((res = pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1)) < 0) { return res; } size_t i = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte i = 1; } for (size_t n = 0; n < PN53X_CACHE_REGISTER_SIZE; n++) { if ((CHIP_DATA(pnd)->wb_mask[n]) && (CHIP_DATA(pnd)->wb_mask[n] != 0xff)) { CHIP_DATA(pnd)->wb_data[n] = ((CHIP_DATA(pnd)->wb_data[n] & CHIP_DATA(pnd)->wb_mask[n]) | (abtRes[i] & (~CHIP_DATA(pnd)->wb_mask[n]))); if (CHIP_DATA(pnd)->wb_data[n] != abtRes[i]) { // Requested value is different from read one CHIP_DATA(pnd)->wb_mask[n] = 0xff; // We can now apply whole data bits } else { CHIP_DATA(pnd)->wb_mask[n] = 0x00; // We already have the right value } i++; } } } // Now, the writeback-cache only has masks with 0xff, we can start to WriteRegister BUFFER_INIT(abtWriteRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtWriteRegisterCmd, WriteRegister); for (size_t n = 0; n < PN53X_CACHE_REGISTER_SIZE; n++) { if (CHIP_DATA(pnd)->wb_mask[n] == 0xff) { const uint16_t pn53x_register_address = PN53X_CACHE_REGISTER_MIN_ADDRESS + n; PNREG_TRACE(pn53x_register_address); BUFFER_APPEND(abtWriteRegisterCmd, pn53x_register_address >> 8); BUFFER_APPEND(abtWriteRegisterCmd, pn53x_register_address & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, CHIP_DATA(pnd)->wb_data[n]); // This register is handled, we reset the mask to prevent CHIP_DATA(pnd)->wb_mask[n] = 0x00; } } if (BUFFER_SIZE(abtWriteRegisterCmd) > 1) { // We need to write some registers if ((res = pn53x_transceive(pnd, abtWriteRegisterCmd, BUFFER_SIZE(abtWriteRegisterCmd), NULL, 0, -1)) < 0) { return res; } } return NFC_SUCCESS; } int pn53x_decode_firmware_version(struct nfc_device *pnd) { const uint8_t abtCmd[] = { GetFirmwareVersion }; uint8_t abtFw[4]; size_t szFwLen = sizeof(abtFw); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtFw, szFwLen, -1)) < 0) { return res; } szFwLen = (size_t) res; // Determine which version of chip it is: PN531 will return only 2 bytes, while others return 4 bytes and have the first to tell the version IC if (szFwLen == 2) { CHIP_DATA(pnd)->type = PN531; } else if (szFwLen == 4) { if (abtFw[0] == 0x32) { // PN532 version IC CHIP_DATA(pnd)->type = PN532; } else if (abtFw[0] == 0x33) { // PN533 version IC if (abtFw[1] == 0x01) { // Sony ROM code CHIP_DATA(pnd)->type = RCS360; } else { CHIP_DATA(pnd)->type = PN533; } } else { // Unknown version IC return NFC_ENOTIMPL; } } else { // Unknown chip return NFC_ENOTIMPL; } // Convert firmware info in text, PN531 gives 2 bytes info, but PN532 and PN533 gives 4 switch (CHIP_DATA(pnd)->type) { case PN531: snprintf(CHIP_DATA(pnd)->firmware_text, sizeof(CHIP_DATA(pnd)->firmware_text), "PN531 v%d.%d", abtFw[0], abtFw[1]); pnd->btSupportByte = SUPPORT_ISO14443A | SUPPORT_ISO18092; break; case PN532: snprintf(CHIP_DATA(pnd)->firmware_text, sizeof(CHIP_DATA(pnd)->firmware_text), "PN532 v%d.%d", abtFw[1], abtFw[2]); pnd->btSupportByte = abtFw[3]; break; case PN533: case RCS360: snprintf(CHIP_DATA(pnd)->firmware_text, sizeof(CHIP_DATA(pnd)->firmware_text), "PN533 v%d.%d", abtFw[1], abtFw[2]); pnd->btSupportByte = abtFw[3]; break; case PN53X: // Could not happend break; } return NFC_SUCCESS; } static uint8_t pn53x_int_to_timeout(const int ms) { uint8_t res = 0; if (ms) { res = 0x10; for (int i = 3280; i > 1; i /= 2) { if (ms > i) break; res--; } } return res; } int pn53x_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value) { switch (property) { case NP_TIMEOUT_COMMAND: CHIP_DATA(pnd)->timeout_command = value; break; case NP_TIMEOUT_ATR: CHIP_DATA(pnd)->timeout_atr = value; return pn53x_RFConfiguration__Various_timings(pnd, pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_atr), pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_communication)); break; case NP_TIMEOUT_COM: CHIP_DATA(pnd)->timeout_communication = value; return pn53x_RFConfiguration__Various_timings(pnd, pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_atr), pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_communication)); break; // Following properties are invalid (not integer) case NP_HANDLE_CRC: case NP_HANDLE_PARITY: case NP_ACTIVATE_FIELD: case NP_ACTIVATE_CRYPTO1: case NP_INFINITE_SELECT: case NP_ACCEPT_INVALID_FRAMES: case NP_ACCEPT_MULTIPLE_FRAMES: case NP_AUTO_ISO14443_4: case NP_EASY_FRAMING: case NP_FORCE_ISO14443_A: case NP_FORCE_ISO14443_B: case NP_FORCE_SPEED_106: return NFC_EINVARG; } return NFC_SUCCESS; } int pn53x_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable) { uint8_t btValue; int res = 0; switch (property) { case NP_HANDLE_CRC: // Enable or disable automatic receiving/sending of CRC bytes if (bEnable == pnd->bCrc) { // Nothing to do return NFC_SUCCESS; } // TX and RX are both represented by the symbol 0x80 btValue = (bEnable) ? 0x80 : 0x00; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_CRC_ENABLE, btValue)) < 0) return res; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_CRC_ENABLE, btValue)) < 0) return res; pnd->bCrc = bEnable; return NFC_SUCCESS; break; case NP_HANDLE_PARITY: // Handle parity bit by PN53X chip or parse it as data bit if (bEnable == pnd->bPar) // Nothing to do return NFC_SUCCESS; btValue = (bEnable) ? 0x00 : SYMBOL_PARITY_DISABLE; if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_ManualRCV, SYMBOL_PARITY_DISABLE, btValue)) < 0) return res; pnd->bPar = bEnable; return NFC_SUCCESS; break; case NP_EASY_FRAMING: pnd->bEasyFraming = bEnable; return NFC_SUCCESS; break; case NP_ACTIVATE_FIELD: return pn53x_RFConfiguration__RF_field(pnd, bEnable); break; case NP_ACTIVATE_CRYPTO1: btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00; return pn53x_write_register(pnd, PN53X_REG_CIU_Status2, SYMBOL_MF_CRYPTO1_ON, btValue); break; case NP_INFINITE_SELECT: // TODO Made some research around this point: // timings could be tweak better than this, and maybe we can tweak timings // to "gain" a sort-of hardware polling (ie. like PN532 does) pnd->bInfiniteSelect = bEnable; return pn53x_RFConfiguration__MaxRetries(pnd, (bEnable) ? 0xff : 0x00, // MxRtyATR, default: active = 0xff, passive = 0x02 (bEnable) ? 0xff : 0x01, // MxRtyPSL, default: 0x01 (bEnable) ? 0xff : 0x02 // MxRtyPassiveActivation, default: 0xff (0x00 leads to problems with PN531) ); break; case NP_ACCEPT_INVALID_FRAMES: btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00; return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_NO_ERROR, btValue); break; case NP_ACCEPT_MULTIPLE_FRAMES: btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00; return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_MULTIPLE, btValue); break; case NP_AUTO_ISO14443_4: if (bEnable == pnd->bAutoIso14443_4) // Nothing to do return NFC_SUCCESS; pnd->bAutoIso14443_4 = bEnable; return pn53x_set_parameters(pnd, PARAM_AUTO_RATS, bEnable); break; case NP_FORCE_ISO14443_A: if (!bEnable) { // Nothing to do return NFC_SUCCESS; } // Force pn53x to be in ISO14443-A mode if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_FRAMING, 0x00)) < 0) { return res; } if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_FRAMING, 0x00)) < 0) { return res; } // Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards) return pn53x_write_register(pnd, PN53X_REG_CIU_TxAuto, SYMBOL_FORCE_100_ASK, 0x40); break; case NP_FORCE_ISO14443_B: if (!bEnable) { // Nothing to do return NFC_SUCCESS; } // Force pn53x to be in ISO14443-B mode if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_FRAMING, 0x03)) < 0) { return res; } return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_FRAMING, 0x03); break; case NP_FORCE_SPEED_106: if (!bEnable) { // Nothing to do return NFC_SUCCESS; } // Force pn53x to be at 106 kbps if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxMode, SYMBOL_TX_SPEED, 0x00)) < 0) { return res; } return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_SPEED, 0x00); break; // Following properties are invalid (not boolean) case NP_TIMEOUT_COMMAND: case NP_TIMEOUT_ATR: case NP_TIMEOUT_COM: return NFC_EINVARG; break; } return NFC_EINVARG; } int pn53x_idle(struct nfc_device *pnd) { int res = 0; switch (CHIP_DATA(pnd)->operating_mode) { case TARGET: // InRelease used in target mode stops the target emulation and no more // tag are seen from external initiator if ((res = pn53x_InRelease(pnd, 0)) < 0) { return res; } if ((CHIP_DATA(pnd)->type == PN532) && (pnd->driver->powerdown)) { // Use PowerDown to go in "Low VBat" power mode if ((res = pnd->driver->powerdown(pnd)) < 0) { return res; } } break; case INITIATOR: // Use InRelease to go in "Standby mode" if ((res = pn53x_InRelease(pnd, 0)) < 0) { return res; } // Disable RF field to avoid heating if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { return res; } if ((CHIP_DATA(pnd)->type == PN532) && (pnd->driver->powerdown)) { // Use PowerDown to go in "Low VBat" power mode if ((res = pnd->driver->powerdown(pnd)) < 0) { return res; } } break; case IDLE: // Nothing to do. break; }; // Clear the current nfc_target pn53x_current_target_free(pnd); CHIP_DATA(pnd)->operating_mode = IDLE; return NFC_SUCCESS; } int pn53x_check_communication(struct nfc_device *pnd) { const uint8_t abtCmd[] = { Diagnose, 0x00, 'l', 'i', 'b', 'n', 'f', 'c' }; const uint8_t abtExpectedRx[] = { 0x00, 'l', 'i', 'b', 'n', 'f', 'c' }; uint8_t abtRx[sizeof(abtExpectedRx)]; size_t szRx = sizeof(abtRx); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, szRx, 500)) < 0) return res; szRx = (size_t) res; if ((sizeof(abtExpectedRx) == szRx) && (0 == memcmp(abtRx, abtExpectedRx, sizeof(abtExpectedRx)))) return NFC_SUCCESS; return NFC_EIO; } int pn53x_initiator_init(struct nfc_device *pnd) { pn53x_reset_settings(pnd); int res; if (CHIP_DATA(pnd)->sam_mode != PSM_NORMAL) { if ((res = pn532_SAMConfiguration(pnd, PSM_NORMAL, -1)) < 0) { return res; } } // Configure the PN53X to be an Initiator or Reader/Writer if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_Control, SYMBOL_INITIATOR, 0x10)) < 0) return res; CHIP_DATA(pnd)->operating_mode = INITIATOR; return NFC_SUCCESS; } int pn532_initiator_init_secure_element(struct nfc_device *pnd) { return pn532_SAMConfiguration(pnd, PSM_WIRED_CARD, -1); } static int pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt, int timeout) { uint8_t abtTargetsData[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szTargetsData = sizeof(abtTargetsData); int res = 0; nfc_target nttmp; if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT) { 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; return pnd->last_error; } // No native support in InListPassiveTarget so we do discovery by hand if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_ISO14443_B, true)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_SPEED_106, true)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true)) < 0) { return res; } if ((res = nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) { return res; } bool found = false; do { if (nm.nmt == NMT_ISO14443B2SR) { // Some work to do before getting the UID... uint8_t abtInitiate[] = "\x06\x00"; size_t szInitiateLen = 2; uint8_t abtSelect[] = { 0x0e, 0x00 }; uint8_t abtRx[1]; // 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 continue; } else return res; } abtSelect[1] = abtRx[0]; if ((res = pn53x_initiator_transceive_bytes(pnd, abtSelect, sizeof(abtSelect), abtRx, sizeof(abtRx), timeout)) < 0) { 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 }; // 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 continue; } else 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 (szTargetsData != 2) return 0; // Target is not ISO14443B2CT uint8_t abtRead[] = { 0xC4 }; // Reading UID_MSB (Read address 4) if ((res = pn53x_initiator_transceive_bytes(pnd, abtRead, sizeof(abtRead), abtTargetsData + 4, sizeof(abtTargetsData) - 4, timeout)) < 0) { return res; } szTargetsData = 6; // u16 UID_LSB, u8 prod code, u8 fab code, u16 UID_MSB } nttmp.nm = nm; if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { return res; } if (nm.nmt == NMT_ISO14443BI) { // Select tag uint8_t abtAttrib[6]; memcpy(abtAttrib, abtTargetsData, sizeof(abtAttrib)); abtAttrib[1] = 0x0f; // ATTRIB if ((res = pn53x_initiator_transceive_bytes(pnd, abtAttrib, sizeof(abtAttrib), NULL, 0, timeout)) < 0) { return res; } szTargetsData = (size_t)res; } found = true; break; } while (pnd->bInfiniteSelect); if (! found) return 0; } else { const pn53x_modulation pm = pn53x_nm_to_pm(nm); if (PM_UNDEFINED == pm) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } if ((res = pn53x_InListPassiveTarget(pnd, pm, 1, pbtInitData, szInitData, abtTargetsData, &szTargetsData, timeout)) <= 0) return res; if (szTargetsData <= 1) // For Coverity to know szTargetsData is always > 1 if res > 0 return 0; nttmp.nm = nm; if ((res = pn53x_decode_target_data(abtTargetsData + 1, szTargetsData - 1, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { return res; } } if (pn53x_current_target_new(pnd, &nttmp) == NULL) { pnd->last_error = NFC_ESOFT; return pnd->last_error; } // Is a tag info struct available if (pnt) { memcpy(pnt, &nttmp, sizeof(nfc_target)); } return abtTargetsData[0]; } int pn53x_initiator_select_passive_target(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt) { return pn53x_initiator_select_passive_target_ext(pnd, nm, pbtInitData, szInitData, pnt, 0); } int pn53x_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) { int res = 0; if (CHIP_DATA(pnd)->type == PN532) { size_t szTargetTypes = 0; pn53x_target_type apttTargetTypes[32]; memset(apttTargetTypes, PTT_UNDEFINED, 32 * sizeof(pn53x_target_type)); for (size_t n = 0; n < szModulations; n++) { const pn53x_target_type ptt = pn53x_nm_to_ptt(pnmModulations[n]); if (PTT_UNDEFINED == ptt) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } apttTargetTypes[szTargetTypes] = ptt; if ((pnd->bAutoIso14443_4) && (ptt == PTT_MIFARE)) { // Hack to have ATS apttTargetTypes[szTargetTypes] = PTT_ISO14443_4A_106; szTargetTypes++; apttTargetTypes[szTargetTypes] = PTT_MIFARE; } szTargetTypes++; } nfc_target ntTargets[2]; if ((res = pn53x_InAutoPoll(pnd, apttTargetTypes, szTargetTypes, uiPollNr, uiPeriod, ntTargets, 0)) < 0) return res; switch (res) { case 1: *pnt = ntTargets[0]; if (pn53x_current_target_new(pnd, pnt) == NULL) { return pnd->last_error = NFC_ESOFT; } return res; break; case 2: *pnt = ntTargets[1]; // We keep the selected one if (pn53x_current_target_new(pnd, pnt) == NULL) { return pnd->last_error = NFC_ESOFT; } return res; break; default: return NFC_ECHIP; break; } } else { bool bInfiniteSelect = pnd->bInfiniteSelect; int result = 0; if ((res = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return res; // FIXME It does not support DEP targets do { for (size_t p = 0; p < uiPollNr; p++) { for (size_t n = 0; n < szModulations; n++) { uint8_t *pbtInitiatorData; size_t szInitiatorData; prepare_initiator_data(pnmModulations[n], &pbtInitiatorData, &szInitiatorData); const int timeout_ms = uiPeriod * 150; if ((res = pn53x_initiator_select_passive_target_ext(pnd, pnmModulations[n], pbtInitiatorData, szInitiatorData, pnt, timeout_ms)) < 0) { if (pnd->last_error != NFC_ETIMEOUT) { result = pnd->last_error; goto end; } } else { result = res; goto end; } } } } while (uiPollNr == 0xff); // uiPollNr==0xff means infinite polling // We reach this point when each listing give no result, we simply have to return 0 end: if (! bInfiniteSelect) { if ((res = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) return res; } return result; } return NFC_ECHIP; } int pn53x_initiator_select_dep_target(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout) { const uint8_t abtPassiveInitiatorData[] = { 0x00, 0xff, 0xff, 0x00, 0x0f }; // Only for 212/424 kpbs: First 4 bytes shall be set like this according to NFCIP-1, last byte is TSN (Time Slot Number) const uint8_t *pbtPassiveInitiatorData = NULL; switch (nbr) { case NBR_212: case NBR_424: // Only use this predefined bytes array when we are at 212/424kbps pbtPassiveInitiatorData = abtPassiveInitiatorData; break; case NBR_106: // Nothing to do break; case NBR_847: case NBR_UNDEFINED: return NFC_EINVARG; break; } pn53x_current_target_free(pnd); int res; if (pndiInitiator) { res = pn53x_InJumpForDEP(pnd, ndm, nbr, pbtPassiveInitiatorData, pndiInitiator->abtNFCID3, pndiInitiator->abtGB, pndiInitiator->szGB, pnt, timeout); } else { res = pn53x_InJumpForDEP(pnd, ndm, nbr, pbtPassiveInitiatorData, NULL, NULL, 0, pnt, timeout); } if (res > 0) { if (pn53x_current_target_new(pnd, pnt) == NULL) { return NFC_ESOFT; } } return res; } int pn53x_initiator_transceive_bits(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar) { int res = 0; size_t szFrameBits = 0; size_t szFrameBytes = 0; size_t szRxBits = 0; uint8_t ui8rcc; uint8_t ui8Bits = 0; uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { InCommunicateThru }; // Check if we should prepare the parity bits ourself if (!pnd->bPar) { // Convert data with parity to a frame if ((res = pn53x_wrap_frame(pbtTx, szTxBits, pbtTxPar, abtCmd + 1)) < 0) return res; szFrameBits = res; } else { szFrameBits = szTxBits; } // Retrieve the leading bits ui8Bits = szFrameBits % 8; // Get the amount of frame bytes + optional (1 byte if there are leading bits) szFrameBytes = (szFrameBits / 8) + ((ui8Bits == 0) ? 0 : 1); // When the parity is handled before us, we just copy the data if (pnd->bPar) memcpy(abtCmd + 1, pbtTx, szFrameBytes); // Set the amount of transmission bits in the PN53X chip register if ((res = pn53x_set_tx_bits(pnd, ui8Bits)) < 0) return res; // Send the frame to the PN53X chip and get the answer // We have to give the amount of bytes + (the command byte 0x42) uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); if ((res = pn53x_transceive(pnd, abtCmd, szFrameBytes + 1, abtRx, szRx, -1)) < 0) return res; szRx = (size_t) res; // Get the last bit-count that is stored in the received byte if ((res = pn53x_read_register(pnd, PN53X_REG_CIU_Control, &ui8rcc)) < 0) return res; ui8Bits = ui8rcc & SYMBOL_RX_LAST_BITS; // Recover the real frame length in bits szFrameBits = ((szRx - 1 - ((ui8Bits == 0) ? 0 : 1)) * 8) + ui8Bits; if (pbtRx != NULL) { // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive() // Check if we should recover the parity bits ourself if (!pnd->bPar) { // Unwrap the response frame if ((res = pn53x_unwrap_frame(abtRx + 1, szFrameBits, pbtRx, pbtRxPar)) < 0) return res; szRxBits = res; } else { // Save the received bits szRxBits = szFrameBits; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx - 1); } } // Everything went successful return szRxBits; } int pn53x_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout) { size_t szExtraTxLen; uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; int res = 0; // We can not just send bytes without parity if while the PN53X expects we handled them if (!pnd->bPar) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } // Copy the data into the command frame if (pnd->bEasyFraming) { abtCmd[0] = InDataExchange; abtCmd[1] = 1; /* target number */ memcpy(abtCmd + 2, pbtTx, szTx); szExtraTxLen = 2; } else { abtCmd[0] = InCommunicateThru; memcpy(abtCmd + 1, pbtTx, szTx); szExtraTxLen = 1; } // To transfer command frames bytes we can not have any leading bits, reset this to zero if ((res = pn53x_set_tx_bits(pnd, 0)) < 0) { pnd->last_error = res; return pnd->last_error; } // Send the frame to the PN53X chip and get the answer // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42) uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; if ((res = pn53x_transceive(pnd, abtCmd, szTx + szExtraTxLen, abtRx, sizeof(abtRx), timeout)) < 0) { pnd->last_error = res; return pnd->last_error; } const size_t szRxLen = (size_t)res - 1; if (pbtRx != NULL) { if (szRxLen > szRx) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Buffer size is too short: %" PRIuPTR " available(s), %" PRIuPTR " needed", szRx, szRxLen); return NFC_EOVFLOW; } // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRxLen); } // Everything went successful, we return received bytes count return szRxLen; } static void __pn53x_init_timer(struct nfc_device *pnd, const uint32_t max_cycles) { // The prescaler will dictate what will be the precision and // the largest delay to measure before saturation. Some examples: // prescaler = 0 => precision: ~73ns timer saturates at ~5ms // prescaler = 1 => precision: ~221ns timer saturates at ~15ms // prescaler = 2 => precision: ~369ns timer saturates at ~25ms // prescaler = 10 => precision: ~1.5us timer saturates at ~100ms if (max_cycles > 0xFFFF) { CHIP_DATA(pnd)->timer_prescaler = ((max_cycles / 0xFFFF) - 1) / 2; } else { CHIP_DATA(pnd)->timer_prescaler = 0; } uint16_t reloadval = 0xFFFF; // Initialize timer pn53x_write_register(pnd, PN53X_REG_CIU_TMode, 0xFF, SYMBOL_TAUTO | ((CHIP_DATA(pnd)->timer_prescaler >> 8) & SYMBOL_TPRESCALERHI)); pn53x_write_register(pnd, PN53X_REG_CIU_TPrescaler, 0xFF, (CHIP_DATA(pnd)->timer_prescaler & SYMBOL_TPRESCALERLO)); pn53x_write_register(pnd, PN53X_REG_CIU_TReloadVal_hi, 0xFF, (reloadval >> 8) & 0xFF); pn53x_write_register(pnd, PN53X_REG_CIU_TReloadVal_lo, 0xFF, reloadval & 0xFF); } static uint32_t __pn53x_get_timer(struct nfc_device *pnd, const uint8_t last_cmd_byte) { uint8_t parity; uint8_t counter_hi, counter_lo; uint16_t counter, u16cycles; uint32_t u32cycles; size_t off = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte off = 1; } // Read timer BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_hi >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_hi & 0xff); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_lo >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_TCounterVal_lo & 0xff); uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // Let's send the previously constructed ReadRegister command if (pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1) < 0) { return false; } counter_hi = abtRes[off]; counter_lo = abtRes[off + 1]; counter = counter_hi; counter = (counter << 8) + counter_lo; if (counter == 0) { // counter saturated u32cycles = 0xFFFFFFFF; } else { u16cycles = 0xFFFF - counter; u32cycles = u16cycles; u32cycles *= (CHIP_DATA(pnd)->timer_prescaler * 2 + 1); u32cycles++; // Correction depending on PN53x Rx detection handling: // timer stops after 5 (or 2 for PN531) bits are received if (CHIP_DATA(pnd)->type == PN531) { u32cycles -= (2 * 128); } else { u32cycles -= (5 * 128); } // Correction depending on last parity bit sent parity = (last_cmd_byte >> 7) ^ ((last_cmd_byte >> 6) & 1) ^ ((last_cmd_byte >> 5) & 1) ^ ((last_cmd_byte >> 4) & 1) ^ ((last_cmd_byte >> 3) & 1) ^ ((last_cmd_byte >> 2) & 1) ^ ((last_cmd_byte >> 1) & 1) ^ (last_cmd_byte & 1); parity = parity ? 0 : 1; // When sent ...YY (cmd ends with logical 1, so when last parity bit is 1): if (parity) { // it finishes 64us sooner than a ...ZY signal u32cycles += 64; } // Correction depending on device design u32cycles += CHIP_DATA(pnd)->timer_correction; } return u32cycles; } int pn53x_initiator_transceive_bits_timed(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar, uint32_t *cycles) { // TODO Do something with these bytes... (void) pbtTxPar; (void) pbtRxPar; uint16_t i; uint8_t sz = 0; int res = 0; size_t szRxBits = 0; // Sorry, no arbitrary parity bits support for now if (!pnd->bPar) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } // Sorry, no easy framing support if (pnd->bEasyFraming) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } // TODO CRC support but it probably doesn't make sense for (szTxBits % 8 != 0) ... if (pnd->bCrc) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } __pn53x_init_timer(pnd, *cycles); // Once timer is started, we cannot use Tama commands anymore. // E.g. on SCL3711 timer settings are reset by 0x42 InCommunicateThru command to: // 631a=82 631b=a5 631c=02 631d=00 // Prepare FIFO BUFFER_INIT(abtWriteRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtWriteRegisterCmd, WriteRegister); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_COMMAND & SYMBOL_COMMAND_TRANSCEIVE); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_FLUSH_BUFFER); for (i = 0; i < ((szTxBits / 8) + 1); i++) { BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, pbtTx[i]); } // Send data BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_START_SEND | ((szTxBits % 8) & SYMBOL_TX_LAST_BITS)); // Let's send the previously constructed WriteRegister command if ((res = pn53x_transceive(pnd, abtWriteRegisterCmd, BUFFER_SIZE(abtWriteRegisterCmd), NULL, 0, -1)) < 0) { return res; } // Recv data // we've to watch for coming data until we decide to timeout. // our PN53x timer saturates after 4.8ms so this function shouldn't be used for // responses coming very late anyway. // Ideally we should implement a real timer here too but looping a few times is good enough. for (i = 0; i < (3 * (CHIP_DATA(pnd)->timer_prescaler * 2 + 1)); i++) { pn53x_read_register(pnd, PN53X_REG_CIU_FIFOLevel, &sz); if (sz > 0) break; } size_t off = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte off = 1; } while (1) { BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); for (i = 0; i < sz; i++) { BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); } BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // Let's send the previously constructed ReadRegister command if ((res = pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1)) < 0) { return res; } for (i = 0; i < sz; i++) { pbtRx[i + szRxBits] = abtRes[i + off]; } szRxBits += (size_t)(sz & SYMBOL_FIFO_LEVEL); sz = abtRes[sz + off]; if (sz == 0) break; } szRxBits *= 8; // in bits, not bytes // Recv corrected timer value *cycles = __pn53x_get_timer(pnd, pbtTx[szTxBits / 8]); return szRxBits; } int pn53x_initiator_transceive_bytes_timed(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles) { uint16_t i; uint8_t sz = 0; int res = 0; // We can not just send bytes without parity while the PN53X expects we handled them if (!pnd->bPar) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } // Sorry, no easy framing support // TODO to be changed once we'll provide easy framing support from libnfc itself... if (pnd->bEasyFraming) { pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } uint8_t txmode = 0; if (pnd->bCrc) { // check if we're in TypeA or TypeB mode to compute right CRC later if ((res = pn53x_read_register(pnd, PN53X_REG_CIU_TxMode, &txmode)) < 0) { return res; } } __pn53x_init_timer(pnd, *cycles); // Once timer is started, we cannot use Tama commands anymore. // E.g. on SCL3711 timer settings are reset by 0x42 InCommunicateThru command to: // 631a=82 631b=a5 631c=02 631d=00 // Prepare FIFO BUFFER_INIT(abtWriteRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtWriteRegisterCmd, WriteRegister); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_Command & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_COMMAND & SYMBOL_COMMAND_TRANSCEIVE); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_FLUSH_BUFFER); for (i = 0; i < szTx; i++) { BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, pbtTx[i]); } // Send data BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming >> 8); BUFFER_APPEND(abtWriteRegisterCmd, PN53X_REG_CIU_BitFraming & 0xff); BUFFER_APPEND(abtWriteRegisterCmd, SYMBOL_START_SEND); // Let's send the previously constructed WriteRegister command if ((res = pn53x_transceive(pnd, abtWriteRegisterCmd, BUFFER_SIZE(abtWriteRegisterCmd), NULL, 0, -1)) < 0) { return res; } // Recv data size_t szRxLen = 0; // we've to watch for coming data until we decide to timeout. // our PN53x timer saturates after 4.8ms so this function shouldn't be used for // responses coming very late anyway. // Ideally we should implement a real timer here too but looping a few times is good enough. for (i = 0; i < (3 * (CHIP_DATA(pnd)->timer_prescaler * 2 + 1)); i++) { pn53x_read_register(pnd, PN53X_REG_CIU_FIFOLevel, &sz); if (sz > 0) break; } size_t off = 0; if (CHIP_DATA(pnd)->type == PN533) { // PN533 prepends its answer by a status byte off = 1; } while (1) { BUFFER_INIT(abtReadRegisterCmd, PN53x_EXTENDED_FRAME__DATA_MAX_LEN); BUFFER_APPEND(abtReadRegisterCmd, ReadRegister); for (i = 0; i < sz; i++) { BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOData & 0xff); } BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel >> 8); BUFFER_APPEND(abtReadRegisterCmd, PN53X_REG_CIU_FIFOLevel & 0xff); uint8_t abtRes[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRes = sizeof(abtRes); // Let's send the previously constructed ReadRegister command if ((res = pn53x_transceive(pnd, abtReadRegisterCmd, BUFFER_SIZE(abtReadRegisterCmd), abtRes, szRes, -1)) < 0) { return res; } if (pbtRx != NULL) { if ((szRxLen + sz) > szRx) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Buffer size is too short: %" PRIuPTR " available(s), %" PRIuPTR " needed", szRx, szRxLen + sz); return NFC_EOVFLOW; } // Copy the received bytes for (i = 0; i < sz; i++) { pbtRx[i + szRxLen] = abtRes[i + off]; } } szRxLen += (size_t)(sz & SYMBOL_FIFO_LEVEL); sz = abtRes[sz + off]; if (sz == 0) break; } // Recv corrected timer value if (pnd->bCrc) { // We've to compute CRC ourselves to know last byte actually sent uint8_t *pbtTxRaw; pbtTxRaw = (uint8_t *) malloc(szTx + 2); if (!pbtTxRaw) return NFC_ESOFT; memcpy(pbtTxRaw, pbtTx, szTx); if ((txmode & SYMBOL_TX_FRAMING) == 0x00) iso14443a_crc_append(pbtTxRaw, szTx); else if ((txmode & SYMBOL_TX_FRAMING) == 0x03) iso14443b_crc_append(pbtTxRaw, szTx); else log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unsupported framing type %02X, cannot adjust CRC cycles", txmode & SYMBOL_TX_FRAMING); *cycles = __pn53x_get_timer(pnd, pbtTxRaw[szTx + 1]); free(pbtTxRaw); } else { *cycles = __pn53x_get_timer(pnd, pbtTx[szTx - 1]); } return szRxLen; } int pn53x_initiator_deselect_target(struct nfc_device *pnd) { pn53x_current_target_free(pnd); return pn53x_InDeselect(pnd, 0); // 0 mean deselect all selected targets } static int pn53x_Diagnose06(struct nfc_device *pnd) { // Send Card Presence command const uint8_t abtCmd[] = { Diagnose, 0x06 }; uint8_t abtRx[1]; int ret = 0; int failures = 0; // Card Presence command can take more time than default one: when a card is // removed from the field, the PN53x took few hundred ms more to reply // correctly. Longest delay observed was with a JCOP31 on a PN532. // 1000 ms should be enough to detect all tested cases while (failures < 2) { if ((ret = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, sizeof(abtRx), 1000)) != 1) { // When it fails with a timeout (0x01) chip error, it means the target is not reacheable anymore if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { return NFC_ETGRELEASED; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { return NFC_SUCCESS; } } return ret; } static int pn53x_ISO14443A_4_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping -4A"); if (CHIP_DATA(pnd)->type == PN533) { ret = pn53x_Diagnose06(pnd); if ((ret == NFC_ETIMEOUT) || (ret == NFC_ETGRELEASED)) { // This happens e.g. when a JCOP31 is removed from PN533 // InRelease takes an abnormal time to reply so let's take care of it now with large timeout: const uint8_t abtCmd[] = { InRelease, 0x00 }; pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 2000); ret = NFC_ETGRELEASED; } } else if (CHIP_DATA(pnd)->type == PN532) { // Diagnose06 failed completely with a JCOP31 on a PN532 so let's do it manually if ((ret = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) return ret; uint8_t abtCmd[1] = {0xb2}; // CID=0 int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) ret = ret2; } else { ret = NFC_EDEVNOTSUPP; } return ret; } static int pn53x_ISO14443A_Jewel_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Jewel"); uint8_t abtCmd[1] = {0x78}; int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout return NFC_ETGRELEASED; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { return NFC_SUCCESS; } } return ret; } static int pn53x_ISO14443A_MFUL_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping MFUL"); // Limitation: test on MFULC non-authenticated with read of first sector forbidden will fail if (CHIP_DATA(pnd)->type == PN533) { ret = pn53x_Diagnose06(pnd); } else { uint8_t abtCmd[2] = {0x30, 0x00}; int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout return NFC_ETGRELEASED; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { return NFC_SUCCESS; } } } return ret; } static int pn53x_ISO14443A_MFC_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping MFC"); if ((CHIP_DATA(pnd)->type == PN533) && (CHIP_DATA(pnd)->current_target->nti.nai.btSak != 0x09)) { // MFC Mini (atqa0004/sak09) fails on PN533, so we exclude it ret = pn53x_Diagnose06(pnd); } else { // Limitation: re-select will lose authentication of already authenticated sector bool bInfiniteSelect = pnd->bInfiniteSelect; uint8_t pbtInitiatorData[12]; size_t szInitiatorData = 0; iso14443_cascade_uid(CHIP_DATA(pnd)->current_target->nti.nai.abtUid, CHIP_DATA(pnd)->current_target->nti.nai.szUidLen, pbtInitiatorData, &szInitiatorData); if ((ret = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) return ret; if ((ret = pn53x_initiator_select_passive_target_ext(pnd, CHIP_DATA(pnd)->current_target->nm, pbtInitiatorData, szInitiatorData, NULL, 300)) == 1) { ret = NFC_SUCCESS; } else if ((ret == 0) || (ret == NFC_ETIMEOUT)) { ret = NFC_ETGRELEASED; } if (bInfiniteSelect) { int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return ret2; } } return ret; } static int pn53x_DEP_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping DEP"); if ((CHIP_DATA(pnd)->type == PN531) || (CHIP_DATA(pnd)->type == PN532) || (CHIP_DATA(pnd)->type == PN533)) ret = pn53x_Diagnose06(pnd); else ret = NFC_EDEVNOTSUPP; return ret; } static int pn53x_Felica_is_present(struct nfc_device *pnd) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Felica"); // if (CHIP_DATA(pnd)->type == PN533) { ret = pn53x_Diagnose06(pnd); } else... // Because ping fails now & then, better not to use Diagnose at all // Limitation: does not work on Felica Lite cards (neither Diagnose nor our method) uint8_t abtCmd[10] = {0x0A, 0x04}; memcpy(abtCmd + 2, CHIP_DATA(pnd)->current_target->nti.nfi.abtId, 8); int failures = 0; // Sometimes ping fails so we want to give the card some more chances... while (failures < 3) { if (nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300) == 11) { return NFC_SUCCESS; } else { failures++; } } return NFC_ETGRELEASED; } static int pn53x_ISO14443B_4_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping -4B"); if (CHIP_DATA(pnd)->type == PN533) { // Not supported on PN532 even if the doc is same as for PN533 ret = pn53x_Diagnose06(pnd); } else { // Sending R(NACK) in raw: if ((ret = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) return ret; // uint8_t abtCmd[1] = {0xb2}; // if on PN533, CID=0 uint8_t abtCmd[2] = {0xba, 0x01}; // if on PN532, CID=1 int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) ret = ret2; } return ret; } static int pn53x_ISO14443B_I_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B'"); // Sending ATTRIB in raw: if ((ret = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, false)) < 0) return ret; uint8_t abtCmd[6] = {0x01, 0x0f}; memcpy(abtCmd + 2, CHIP_DATA(pnd)->current_target->nti.nii.abtDIV, 4); int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } int ret2; if ((ret2 = pn53x_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) ret = ret2; return ret; } static int pn53x_ISO14443B_SR_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B2 ST SRx"); // Sending Get_UID in raw: (EASY_FRAMING is already supposed to be false) uint8_t abtCmd[1] = {0x0b}; int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } return ret; } static int pn53x_ISO14443B_CT_is_present(struct nfc_device *pnd) { int ret; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B2 ASK CTx"); // Sending SELECT in raw: (EASY_FRAMING is already supposed to be false) uint8_t abtCmd[3] = {0x9f}; memcpy(abtCmd + 1, CHIP_DATA(pnd)->current_target->nti.nci.abtUID, 2); int failures = 0; while (failures < 2) { if ((ret = nfc_initiator_transceive_bytes(pnd, abtCmd, sizeof(abtCmd), NULL, 0, 300)) < 1) { if ((ret == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Timeout ret = NFC_ETGRELEASED; break; } else { // Other errors can appear when card is tired-off, let's try again failures++; } } else { ret = NFC_SUCCESS; break; } } return ret; } int pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) { // Check if there is a saved target if (CHIP_DATA(pnd)->current_target == NULL) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): no saved target"); return pnd->last_error = NFC_EINVARG; } // Check if the argument target nt is equals to current saved target if ((pnt != NULL) && (!pn53x_current_target_is(pnd, pnt))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): another target"); return pnd->last_error = NFC_ETGRELEASED; } // Ping target int ret; switch (CHIP_DATA(pnd)->current_target->nm.nmt) { case NMT_ISO14443A: if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & 0x20) { ret = pn53x_ISO14443A_4_is_present(pnd); } else if ((CHIP_DATA(pnd)->current_target->nti.nai.abtAtqa[0] == 0x00) && (CHIP_DATA(pnd)->current_target->nti.nai.abtAtqa[1] == 0x44) && (CHIP_DATA(pnd)->current_target->nti.nai.btSak == 0x00)) { ret = pn53x_ISO14443A_MFUL_is_present(pnd); } else if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & 0x08) { ret = pn53x_ISO14443A_MFC_is_present(pnd); } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): card type A not supported"); ret = NFC_EDEVNOTSUPP; } break; case NMT_DEP: ret = pn53x_DEP_is_present(pnd); break; case NMT_FELICA: ret = pn53x_Felica_is_present(pnd); break; case NMT_JEWEL: ret = pn53x_ISO14443A_Jewel_is_present(pnd); break; case NMT_ISO14443B: ret = pn53x_ISO14443B_4_is_present(pnd); break; case NMT_ISO14443BI: ret = pn53x_ISO14443B_I_is_present(pnd); break; case NMT_ISO14443B2SR: ret = pn53x_ISO14443B_SR_is_present(pnd); break; case NMT_ISO14443B2CT: ret = pn53x_ISO14443B_CT_is_present(pnd); break; default: log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): card type not supported"); ret = NFC_EDEVNOTSUPP; break; } if (ret == NFC_ETGRELEASED) pn53x_current_target_free(pnd); return pnd->last_error = ret; } #define SAK_ISO14443_4_COMPLIANT 0x20 #define SAK_ISO18092_COMPLIANT 0x40 int pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRxLen, int timeout) { pn53x_reset_settings(pnd); CHIP_DATA(pnd)->operating_mode = TARGET; pn53x_target_mode ptm = PTM_NORMAL; int res = 0; switch (pnt->nm.nmt) { case NMT_ISO14443A: ptm = PTM_PASSIVE_ONLY; if ((pnt->nti.nai.abtUid[0] != 0x08) || (pnt->nti.nai.szUidLen != 4)) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } pn53x_set_parameters(pnd, PARAM_AUTO_ATR_RES, false); if (CHIP_DATA(pnd)->type == PN532) { // We have a PN532 if ((pnt->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) && (pnd->bAutoIso14443_4)) { // We have a ISO14443-4 tag to emulate and NP_AUTO_14443_4A option is enabled ptm |= PTM_ISO14443_4_PICC_ONLY; // We add ISO14443-4 restriction pn53x_set_parameters(pnd, PARAM_14443_4_PICC, true); } else { pn53x_set_parameters(pnd, PARAM_14443_4_PICC, false); } } break; case NMT_FELICA: ptm = PTM_PASSIVE_ONLY; break; case NMT_DEP: pn53x_set_parameters(pnd, PARAM_AUTO_ATR_RES, true); ptm = PTM_DEP_ONLY; if (pnt->nti.ndi.ndm == NDM_PASSIVE) { ptm |= PTM_PASSIVE_ONLY; // We add passive mode restriction } break; case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_JEWEL: pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; break; } // Let the PN53X be activated by the RF level detector from power down mode if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxAuto, SYMBOL_INITIAL_RF_ON, 0x04)) < 0) return res; uint8_t abtMifareParams[6]; uint8_t *pbtMifareParams = NULL; uint8_t *pbtTkt = NULL; size_t szTkt = 0; uint8_t abtFeliCaParams[18]; uint8_t *pbtFeliCaParams = NULL; const uint8_t *pbtNFCID3t = NULL; const uint8_t *pbtGBt = NULL; size_t szGBt = 0; switch (pnt->nm.nmt) { case NMT_ISO14443A: { // Set ATQA (SENS_RES) abtMifareParams[0] = pnt->nti.nai.abtAtqa[1]; abtMifareParams[1] = pnt->nti.nai.abtAtqa[0]; // Set UID // Note: in this mode we can only emulate a single size (4 bytes) UID where the first is hard-wired by PN53x as 0x08 abtMifareParams[2] = pnt->nti.nai.abtUid[1]; abtMifareParams[3] = pnt->nti.nai.abtUid[2]; abtMifareParams[4] = pnt->nti.nai.abtUid[3]; // Set SAK (SEL_RES) abtMifareParams[5] = pnt->nti.nai.btSak; pbtMifareParams = abtMifareParams; // Historical Bytes pbtTkt = iso14443a_locate_historical_bytes(pnt->nti.nai.abtAts, pnt->nti.nai.szAtsLen, &szTkt); } break; case NMT_FELICA: // Set NFCID2t memcpy(abtFeliCaParams, pnt->nti.nfi.abtId, 8); // Set PAD memcpy(abtFeliCaParams + 8, pnt->nti.nfi.abtPad, 8); // Set SystemCode memcpy(abtFeliCaParams + 16, pnt->nti.nfi.abtSysCode, 2); pbtFeliCaParams = abtFeliCaParams; break; case NMT_DEP: // Set NFCID3 pbtNFCID3t = pnt->nti.ndi.abtNFCID3; // Set General Bytes, if relevant szGBt = pnt->nti.ndi.szGB; if (szGBt) pbtGBt = pnt->nti.ndi.abtGB; // Set ISO/IEC 14443 part // Set ATQA (SENS_RES) abtMifareParams[0] = 0x08; abtMifareParams[1] = 0x00; // Set UID // Note: in this mode we can only emulate a single size (4 bytes) UID where the first is hard-wired by PN53x as 0x08 abtMifareParams[2] = 0x12; abtMifareParams[3] = 0x34; abtMifareParams[4] = 0x56; // Set SAK (SEL_RES) abtMifareParams[5] = SAK_ISO18092_COMPLIANT; // Allow ISO/IEC 18092 in DEP mode pbtMifareParams = abtMifareParams; // Set FeliCa part // Set NFCID2t abtFeliCaParams[0] = 0x01; abtFeliCaParams[1] = 0xfe; abtFeliCaParams[2] = 0x12; abtFeliCaParams[3] = 0x34; abtFeliCaParams[4] = 0x56; abtFeliCaParams[5] = 0x78; abtFeliCaParams[6] = 0x90; abtFeliCaParams[7] = 0x12; // Set PAD abtFeliCaParams[8] = 0xc0; abtFeliCaParams[9] = 0xc1; abtFeliCaParams[10] = 0xc2; abtFeliCaParams[11] = 0xc3; abtFeliCaParams[12] = 0xc4; abtFeliCaParams[13] = 0xc5; abtFeliCaParams[14] = 0xc6; abtFeliCaParams[15] = 0xc7; // Set System Code abtFeliCaParams[16] = 0x0f; abtFeliCaParams[17] = 0xab; pbtFeliCaParams = abtFeliCaParams; break; case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_JEWEL: pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; break; } bool targetActivated = false; size_t szRx; while (!targetActivated) { uint8_t btActivatedMode; if ((res = pn53x_TgInitAsTarget(pnd, ptm, pbtMifareParams, pbtTkt, szTkt, pbtFeliCaParams, pbtNFCID3t, pbtGBt, szGBt, pbtRx, szRxLen, &btActivatedMode, timeout)) < 0) { if (res == NFC_ETIMEOUT) { pn53x_idle(pnd); } return res; } szRx = (size_t) res; nfc_modulation nm = { .nmt = NMT_DEP, // Silent compilation warnings .nbr = NBR_UNDEFINED }; nfc_dep_mode ndm = NDM_UNDEFINED; // Decode activated "mode" switch (btActivatedMode & 0x70) { // Baud rate case 0x00: // 106kbps nm.nbr = NBR_106; break; case 0x10: // 212kbps nm.nbr = NBR_212; break; case 0x20: // 424kbps nm.nbr = NBR_424; break; }; if (btActivatedMode & 0x04) { // D.E.P. nm.nmt = NMT_DEP; if ((btActivatedMode & 0x03) == 0x01) { // Active mode ndm = NDM_ACTIVE; } else { // Passive mode ndm = NDM_PASSIVE; } } else { // Not D.E.P. if ((btActivatedMode & 0x03) == 0x00) { // MIFARE nm.nmt = NMT_ISO14443A; } else if ((btActivatedMode & 0x03) == 0x02) { // FeliCa nm.nmt = NMT_FELICA; } } if (pnt->nm.nmt == nm.nmt) { // Actual activation have the right modulation type if ((pnt->nm.nbr == NBR_UNDEFINED) || (pnt->nm.nbr == nm.nbr)) { // Have the right baud rate (or undefined) if ((pnt->nm.nmt != NMT_DEP) || (pnt->nti.ndi.ndm == NDM_UNDEFINED) || (pnt->nti.ndi.ndm == ndm)) { // Have the right DEP mode (or is not a DEP) targetActivated = true; } } } if (targetActivated) { pnt->nm.nbr = nm.nbr; // Update baud rate if (pnt->nm.nmt == NMT_DEP) { pnt->nti.ndi.ndm = ndm; // Update DEP mode } if (pn53x_current_target_new(pnd, pnt) == NULL) { pnd->last_error = NFC_ESOFT; return pnd->last_error; } if (ptm & PTM_ISO14443_4_PICC_ONLY) { // When PN532 is in PICC target mode, it automatically reply to RATS so // we don't need to forward this command szRx = 0; } } } return szRx; } int pn53x_target_receive_bits(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, uint8_t *pbtRxPar) { size_t szRxBits = 0; uint8_t abtCmd[] = { TgGetInitiatorCommand }; uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = 0; // Try to gather a received frame from the reader if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, szRx, -1)) < 0) return res; szRx = (size_t) res; // Get the last bit-count that is stored in the received byte uint8_t ui8rcc; if ((res = pn53x_read_register(pnd, PN53X_REG_CIU_Control, &ui8rcc)) < 0) return res; uint8_t ui8Bits = ui8rcc & SYMBOL_RX_LAST_BITS; // Recover the real frame length in bits size_t szFrameBits = ((szRx - 1 - ((ui8Bits == 0) ? 0 : 1)) * 8) + ui8Bits; // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive() // Check if we should recover the parity bits ourself if (!pnd->bPar) { // Unwrap the response frame if ((res = pn53x_unwrap_frame(abtRx + 1, szFrameBits, pbtRx, pbtRxPar)) < 0) return res; szRxBits = res; } else { // Save the received bits szRxBits = szFrameBits; if ((szRx - 1) > szRxLen) return NFC_EOVFLOW; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx - 1); } // Everyting seems ok, return received bits count return szRxBits; } int pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, int timeout) { uint8_t abtCmd[1]; // XXX I think this is not a clean way to provide some kind of "EasyFraming" // but at the moment I have no more better than this if (pnd->bEasyFraming) { switch (CHIP_DATA(pnd)->current_target->nm.nmt) { case NMT_DEP: abtCmd[0] = TgGetData; break; case NMT_ISO14443A: if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) { // We are dealing with a ISO/IEC 14443-4 compliant target if ((CHIP_DATA(pnd)->type == PN532) && (pnd->bAutoIso14443_4)) { // We are using ISO/IEC 14443-4 PICC emulation capability from the PN532 abtCmd[0] = TgGetData; break; } else { // TODO Support EasyFraming for other cases by software pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } } // NO BREAK case NMT_JEWEL: case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_FELICA: abtCmd[0] = TgGetInitiatorCommand; break; } } else { abtCmd[0] = TgGetInitiatorCommand; } // Try to gather a received frame from the reader uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), abtRx, szRx, timeout)) < 0) return pnd->last_error; szRx = (size_t) res; // Save the received bytes count szRx -= 1; if (szRx > szRxLen) return NFC_EOVFLOW; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx); // Everyting seems ok, return received bytes count return szRx; } int pn53x_target_send_bits(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar) { size_t szFrameBits = 0; size_t szFrameBytes = 0; uint8_t ui8Bits = 0; uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { TgResponseToInitiator }; int res = 0; // Check if we should prepare the parity bits ourself if (!pnd->bPar) { // Convert data with parity to a frame if ((res = pn53x_wrap_frame(pbtTx, szTxBits, pbtTxPar, abtCmd + 1)) < 0) return res; szFrameBits = res; } else { szFrameBits = szTxBits; } // Retrieve the leading bits ui8Bits = szFrameBits % 8; // Get the amount of frame bytes + optional (1 byte if there are leading bits) szFrameBytes = (szFrameBits / 8) + ((ui8Bits == 0) ? 0 : 1); // When the parity is handled before us, we just copy the data if (pnd->bPar) memcpy(abtCmd + 1, pbtTx, szFrameBytes); // Set the amount of transmission bits in the PN53X chip register if ((res = pn53x_set_tx_bits(pnd, ui8Bits)) < 0) return res; // Try to send the bits to the reader if ((res = pn53x_transceive(pnd, abtCmd, szFrameBytes + 1, NULL, 0, -1)) < 0) return res; // Everyting seems ok, return return sent bits count return szTxBits; } int pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout) { uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; int res = 0; // We can not just send bytes without parity if while the PN53X expects we handled them if (!pnd->bPar) return NFC_ECHIP; // XXX I think this is not a clean way to provide some kind of "EasyFraming" // but at the moment I have no more better than this if (pnd->bEasyFraming) { switch (CHIP_DATA(pnd)->current_target->nm.nmt) { case NMT_DEP: abtCmd[0] = TgSetData; break; case NMT_ISO14443A: if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) { // We are dealing with a ISO/IEC 14443-4 compliant target if ((CHIP_DATA(pnd)->type == PN532) && (pnd->bAutoIso14443_4)) { // We are using ISO/IEC 14443-4 PICC emulation capability from the PN532 abtCmd[0] = TgSetData; break; } else { // TODO Support EasyFraming for other cases by software pnd->last_error = NFC_ENOTIMPL; return pnd->last_error; } } // NO BREAK case NMT_JEWEL: case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_FELICA: abtCmd[0] = TgResponseToInitiator; break; } } else { abtCmd[0] = TgResponseToInitiator; } // Copy the data into the command frame memcpy(abtCmd + 1, pbtTx, szTx); // Try to send the bits to the reader if ((res = pn53x_transceive(pnd, abtCmd, szTx + 1, NULL, 0, timeout)) < 0) return res; // Everyting seems ok, return sent byte count return szTx; } static struct sErrorMessage { int iErrorCode; const char *pcErrorMsg; } sErrorMessages[] = { /* Chip-level errors (internal errors, RF errors, etc.) */ { 0x00, "Success" }, { ETIMEOUT, "Timeout" }, // Time Out, the target has not answered { ECRC, "CRC Error" }, // A CRC error has been detected by the CIU { EPARITY, "Parity Error" }, // A Parity error has been detected by the CIU { EBITCOUNT, "Erroneous Bit Count" }, // During an anti-collision/select operation (ISO/IEC14443-3 Type A and ISO/IEC18092 106 kbps passive mode), an erroneous Bit Count has been detected { EFRAMING, "Framing Error" }, // Framing error during MIFARE operation { EBITCOLL, "Bit-collision" }, // An abnormal bit-collision has been detected during bit wise anti-collision at 106 kbps { ESMALLBUF, "Communication Buffer Too Small" }, // Communication buffer size insufficient { EBUFOVF, "Buffer Overflow" }, // RF Buffer overflow has been detected by the CIU (bit BufferOvfl of the register CIU_Error) { ERFPROTO, "RF Protocol Error" }, // RF Protocol error (see PN53x manual) { EOVHEAT, "Chip Overheating" }, // Temperature error: the internal temperature sensor has detected overheating, and therefore has automatically switched off the antenna drivers { EINBUFOVF, "Internal Buffer overflow."}, // Internal buffer overflow { EINVPARAM, "Invalid Parameter"}, // Invalid parameter (range, format, …) { EOPNOTALL, "Operation Not Allowed" }, // Operation not allowed in this configuration (host controller interface) { ECMD, "Command Not Acceptable" }, // Command is not acceptable due to the current context { EOVCURRENT, "Over Current" }, /* DEP errors */ { ERFTIMEOUT, "RF Timeout" }, // In active communication mode, the RF field has not been switched on in time by the counterpart (as defined in NFCIP-1 standard) { EDEPUNKCMD, "Unknown DEP Command" }, { EDEPINVSTATE, "Invalid DEP State" }, // DEP Protocol: Invalid device state, the system is in a state which does not allow the operation { ENAD, "NAD Missing in DEP Frame" }, /* MIFARE */ { EMFAUTH, "Mifare Authentication Error" }, /* Misc */ { EINVRXFRAM, "Invalid Received Frame" }, // DEP Protocol, Mifare or ISO/IEC14443-4: The data format does not match to the specification. { ENSECNOTSUPP, "NFC Secure not supported" }, // Target or Initiator does not support NFC Secure { EBCC, "Wrong UID Check Byte (BCC)" }, // ISO/IEC14443-3: UID Check byte is wrong { ETGREL, "Target Released" }, // Target have been released by initiator { ECID, "Card ID Mismatch" }, // ISO14443 type B: Card ID mismatch, meaning that the expected card has been exchanged with another one. { ECDISCARDED, "Card Discarded" }, // ISO/IEC14443 type B: the card previously activated has disappeared. { ENFCID3, "NFCID3 Mismatch" }, }; const char * pn53x_strerror(const struct nfc_device *pnd) { const char *pcRes = "Unknown error"; size_t i; for (i = 0; i < (sizeof(sErrorMessages) / sizeof(struct sErrorMessage)); i++) { if (sErrorMessages[i].iErrorCode == CHIP_DATA(pnd)->last_status_byte) { pcRes = sErrorMessages[i].pcErrorMsg; break; } } return pcRes; } int pn53x_RFConfiguration__RF_field(struct nfc_device *pnd, bool bEnable) { uint8_t abtCmd[] = { RFConfiguration, RFCI_FIELD, (bEnable) ? 0x01 : 0x00 }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_RFConfiguration__Various_timings(struct nfc_device *pnd, const uint8_t fATR_RES_Timeout, const uint8_t fRetryTimeout) { uint8_t abtCmd[] = { RFConfiguration, RFCI_TIMING, 0x00, // RFU fATR_RES_Timeout, // ATR_RES timeout (default: 0x0B 102.4 ms) fRetryTimeout // TimeOut during non-DEP communications (default: 0x0A 51.2 ms) }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_RFConfiguration__MaxRtyCOM(struct nfc_device *pnd, const uint8_t MaxRtyCOM) { uint8_t abtCmd[] = { RFConfiguration, RFCI_RETRY_DATA, MaxRtyCOM // MaxRtyCOM, default: 0x00 (no retry, only one try), inifite: 0xff }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_RFConfiguration__MaxRetries(struct nfc_device *pnd, const uint8_t MxRtyATR, const uint8_t MxRtyPSL, const uint8_t MxRtyPassiveActivation) { // Retry format: 0x00 means only 1 try, 0xff means infinite uint8_t abtCmd[] = { RFConfiguration, RFCI_RETRY_SELECT, MxRtyATR, // MxRtyATR, default: active = 0xff, passive = 0x02 MxRtyPSL, // MxRtyPSL, default: 0x01 MxRtyPassiveActivation // MxRtyPassiveActivation, default: 0xff (0x00 leads to problems with PN531) }; return pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); } int pn53x_SetParameters(struct nfc_device *pnd, const uint8_t ui8Value) { uint8_t abtCmd[] = { SetParameters, ui8Value }; int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 0) { return res; } // We save last parameters in register cache CHIP_DATA(pnd)->ui8Parameters = ui8Value; return NFC_SUCCESS; } int pn532_SAMConfiguration(struct nfc_device *pnd, const pn532_sam_mode sam_mode, int timeout) { uint8_t abtCmd[] = { SAMConfiguration, sam_mode, 0x00, 0x00 }; size_t szCmd = sizeof(abtCmd); if (CHIP_DATA(pnd)->type != PN532) { // This function is not supported by pn531 neither pn533 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } switch (sam_mode) { case PSM_NORMAL: // Normal mode case PSM_WIRED_CARD: // Wired card mode szCmd = 2; break; case PSM_VIRTUAL_CARD: // Virtual card mode case PSM_DUAL_CARD: // Dual card mode // TODO Implement timeout handling szCmd = 3; break; default: pnd->last_error = NFC_EINVARG; return pnd->last_error; } CHIP_DATA(pnd)->sam_mode = sam_mode; return (pn53x_transceive(pnd, abtCmd, szCmd, NULL, 0, timeout)); } int pn53x_PowerDown(struct nfc_device *pnd) { uint8_t abtCmd[] = { PowerDown, 0xf0 }; int res; if ((res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)) < 0) return res; CHIP_DATA(pnd)->power_mode = LOWVBAT; return res; } /** * @brief C wrapper to InListPassiveTarget command * @return Returns selected targets count on success, otherwise returns libnfc's error code (negative value) * * @param pnd struct nfc_device struct pointer that represent currently used device * @param pmInitModulation Desired modulation * @param pbtInitiatorData Optional initiator data used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID * @param szInitiatorData Length of initiator data \a pbtInitiatorData * @param pbtTargetsData pointer on a pre-allocated byte array to receive TargetData[n] as described in pn53x user manual * @param pszTargetsData size_t pointer where size of \a pbtTargetsData will be written * * @note Selected targets count can be found in \a pbtTargetsData[0] if available (i.e. \a pszTargetsData content is more than 0) * @note To decode theses TargetData[n], there is @fn pn53x_decode_target_data */ int pn53x_InListPassiveTarget(struct nfc_device *pnd, const pn53x_modulation pmInitModulation, const uint8_t szMaxTargets, const uint8_t *pbtInitiatorData, const size_t szInitiatorData, uint8_t *pbtTargetsData, size_t *pszTargetsData, int timeout) { uint8_t abtCmd[15] = { InListPassiveTarget }; abtCmd[1] = szMaxTargets; // MaxTg switch (pmInitModulation) { case PM_ISO14443A_106: case PM_FELICA_212: case PM_FELICA_424: // all gone fine. break; case PM_ISO14443B_106: if (!(pnd->btSupportByte & SUPPORT_ISO14443B)) { // Eg. Some PN532 doesn't support type B! pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } break; case PM_JEWEL_106: if (CHIP_DATA(pnd)->type == PN531) { // These modulations are not supported by pn531 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } break; case PM_ISO14443B_212: case PM_ISO14443B_424: case PM_ISO14443B_847: if ((CHIP_DATA(pnd)->type != PN533) || (!(pnd->btSupportByte & SUPPORT_ISO14443B))) { // These modulations are not supported by pn531 neither pn532 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } break; case PM_UNDEFINED: pnd->last_error = NFC_EINVARG; return pnd->last_error; } abtCmd[2] = pmInitModulation; // BrTy, the type of init modulation used for polling a passive tag // Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID). if (pbtInitiatorData) memcpy(abtCmd + 3, pbtInitiatorData, szInitiatorData); int res = 0; if ((res = pn53x_transceive(pnd, abtCmd, 3 + szInitiatorData, pbtTargetsData, *pszTargetsData, timeout)) < 0) { return res; } *pszTargetsData = (size_t) res; return pbtTargetsData[0]; } int pn53x_InDeselect(struct nfc_device *pnd, const uint8_t ui8Target) { if (CHIP_DATA(pnd)->type == RCS360) { // We should do act here *only* if a target was previously selected uint8_t abtStatus[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szStatus = sizeof(abtStatus); uint8_t abtCmdGetStatus[] = { GetGeneralStatus }; int res = 0; if ((res = pn53x_transceive(pnd, abtCmdGetStatus, sizeof(abtCmdGetStatus), abtStatus, szStatus, -1)) < 0) { return res; } szStatus = (size_t) res; if ((szStatus < 3) || (abtStatus[2] == 0)) { return NFC_SUCCESS; } // No much choice what to deselect actually... uint8_t abtCmdRcs360[] = { InDeselect, 0x01, 0x01 }; return (pn53x_transceive(pnd, abtCmdRcs360, sizeof(abtCmdRcs360), NULL, 0, -1)); } uint8_t abtCmd[] = { InDeselect, ui8Target }; return (pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1)); } int pn53x_InRelease(struct nfc_device *pnd, const uint8_t ui8Target) { int res = 0; if (CHIP_DATA(pnd)->type == RCS360) { // We should do act here *only* if a target was previously selected uint8_t abtStatus[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szStatus = sizeof(abtStatus); uint8_t abtCmdGetStatus[] = { GetGeneralStatus }; if ((res = pn53x_transceive(pnd, abtCmdGetStatus, sizeof(abtCmdGetStatus), abtStatus, szStatus, -1)) < 0) { return res; } szStatus = (size_t) res; if ((szStatus < 3) || (abtStatus[2] == 0)) { return NFC_SUCCESS; } // No much choice what to release actually... uint8_t abtCmdRcs360[] = { InRelease, 0x01, 0x01 }; res = pn53x_transceive(pnd, abtCmdRcs360, sizeof(abtCmdRcs360), NULL, 0, -1); return (res >= 0) ? NFC_SUCCESS : res; } uint8_t abtCmd[] = { InRelease, ui8Target }; res = pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); return (res >= 0) ? NFC_SUCCESS : res; } int pn53x_InAutoPoll(struct nfc_device *pnd, const pn53x_target_type *ppttTargetTypes, const size_t szTargetTypes, const uint8_t btPollNr, const uint8_t btPeriod, nfc_target *pntTargets, const int timeout) { size_t szTargetFound = 0; if (CHIP_DATA(pnd)->type != PN532) { // This function is not supported by pn531 neither pn533 pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } // InAutoPoll frame looks like this { 0xd4, 0x60, 0x0f, 0x01, 0x00 } => { direction, command, pollnr, period, types... } size_t szTxInAutoPoll = 3 + szTargetTypes; uint8_t abtCmd[3 + 15] = { InAutoPoll, btPollNr, btPeriod }; for (size_t n = 0; n < szTargetTypes; n++) { abtCmd[3 + n] = ppttTargetTypes[n]; } uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = pn53x_transceive(pnd, abtCmd, szTxInAutoPoll, abtRx, szRx, timeout); szRx = (size_t) res; if (res < 0) { return res; } else if (szRx > 0) { szTargetFound = abtRx[0]; if (szTargetFound > 0) { uint8_t ln; uint8_t *pbt = abtRx + 1; /* 1st target */ // Target type pn53x_target_type ptt = *(pbt++); pntTargets[0].nm = pn53x_ptt_to_nm(ptt); // AutoPollTargetData length ln = *(pbt++); if ((res = pn53x_decode_target_data(pbt, ln, CHIP_DATA(pnd)->type, pntTargets[0].nm.nmt, &(pntTargets[0].nti))) < 0) { return res; } pbt += ln; if (abtRx[0] > 1) { /* 2nd target */ // Target type ptt = *(pbt++); pntTargets[1].nm = pn53x_ptt_to_nm(ptt); // AutoPollTargetData length ln = *(pbt++); pn53x_decode_target_data(pbt, ln, CHIP_DATA(pnd)->type, pntTargets[1].nm.nmt, &(pntTargets[1].nti)); } } } return szTargetFound; } /** * @brief Wrapper for InJumpForDEP command * @param pmInitModulation desired initial modulation * @param pbtPassiveInitiatorData NFCID1 (4 bytes) at 106kbps (optionnal, see NFCIP-1: 11.2.1.26) or Polling Request Frame's payload (5 bytes) at 212/424kbps (mandatory, see NFCIP-1: 11.2.2.5) * @param szPassiveInitiatorData size of pbtPassiveInitiatorData content * @param pbtNFCID3i NFCID3 of the initiator * @param pbtGBi General Bytes of the initiator * @param szGBi count of General Bytes * @param[out] pnt \a nfc_target which will be filled by this function */ int pn53x_InJumpForDEP(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const uint8_t *pbtPassiveInitiatorData, const uint8_t *pbtNFCID3i, const uint8_t *pbtGBi, const size_t szGBi, nfc_target *pnt, const int timeout) { // Max frame size = 1 (Command) + 1 (ActPass) + 1 (Baud rate) + 1 (Next) + 5 (PassiveInitiatorData) + 10 (NFCID3) + 48 (General bytes) = 67 bytes uint8_t abtCmd[67] = { InJumpForDEP, (ndm == NDM_ACTIVE) ? 0x01 : 0x00 }; size_t offset = 4; // 1 byte for command, 1 byte for DEP mode (Active/Passive), 1 byte for baud rate, 1 byte for following parameters flag switch (nbr) { case NBR_106: abtCmd[2] = 0x00; // baud rate is 106 kbps if (pbtPassiveInitiatorData && (ndm == NDM_PASSIVE)) { /* can't have passive initiator data when using active mode */ abtCmd[3] |= 0x01; memcpy(abtCmd + offset, pbtPassiveInitiatorData, 4); offset += 4; } break; case NBR_212: abtCmd[2] = 0x01; // baud rate is 212 kbps if (pbtPassiveInitiatorData && (ndm == NDM_PASSIVE)) { abtCmd[3] |= 0x01; memcpy(abtCmd + offset, pbtPassiveInitiatorData, 5); offset += 5; } break; case NBR_424: abtCmd[2] = 0x02; // baud rate is 424 kbps if (pbtPassiveInitiatorData && (ndm == NDM_PASSIVE)) { abtCmd[3] |= 0x01; memcpy(abtCmd + offset, pbtPassiveInitiatorData, 5); offset += 5; } break; case NBR_847: case NBR_UNDEFINED: pnd->last_error = NFC_EINVARG; return pnd->last_error; break; } if (pbtNFCID3i) { abtCmd[3] |= 0x02; memcpy(abtCmd + offset, pbtNFCID3i, 10); offset += 10; } if (szGBi && pbtGBi) { abtCmd[3] |= 0x04; memcpy(abtCmd + offset, pbtGBi, szGBi); offset += szGBi; } uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); int res = 0; // Try to find a target, call the transceive callback function of the current device if ((res = pn53x_transceive(pnd, abtCmd, offset, abtRx, szRx, timeout)) < 0) return res; szRx = (size_t) res; // Make sure one target has been found, the PN53X returns 0x00 if none was available if (abtRx[1] >= 1) { // Is a target struct available if (pnt) { pnt->nm.nmt = NMT_DEP; pnt->nm.nbr = nbr; pnt->nti.ndi.ndm = ndm; memcpy(pnt->nti.ndi.abtNFCID3, abtRx + 2, 10); pnt->nti.ndi.btDID = abtRx[12]; pnt->nti.ndi.btBS = abtRx[13]; pnt->nti.ndi.btBR = abtRx[14]; pnt->nti.ndi.btTO = abtRx[15]; pnt->nti.ndi.btPP = abtRx[16]; if (szRx > 17) { pnt->nti.ndi.szGB = szRx - 17; memcpy(pnt->nti.ndi.abtGB, abtRx + 17, pnt->nti.ndi.szGB); } else { pnt->nti.ndi.szGB = 0; } } } return abtRx[1]; } int pn53x_TgInitAsTarget(struct nfc_device *pnd, pn53x_target_mode ptm, const uint8_t *pbtMifareParams, const uint8_t *pbtTkt, size_t szTkt, const uint8_t *pbtFeliCaParams, const uint8_t *pbtNFCID3t, const uint8_t *pbtGBt, const size_t szGBt, uint8_t *pbtRx, const size_t szRxLen, uint8_t *pbtModeByte, int timeout) { uint8_t abtCmd[39 + 47 + 48] = { TgInitAsTarget }; // Worst case: 39-byte base, 47 bytes max. for General Bytes, 48 bytes max. for Historical Bytes size_t szOptionalBytes = 0; int res = 0; // Clear the target init struct, reset to all zeros memset(abtCmd + 1, 0x00, sizeof(abtCmd) - 1); // Store the target mode in the initialization params abtCmd[1] = ptm; // MIFARE part if (pbtMifareParams) { memcpy(abtCmd + 2, pbtMifareParams, 6); } // FeliCa part if (pbtFeliCaParams) { memcpy(abtCmd + 8, pbtFeliCaParams, 18); } // DEP part if (pbtNFCID3t) { memcpy(abtCmd + 26, pbtNFCID3t, 10); } // General Bytes (ISO/IEC 18092) if ((CHIP_DATA(pnd)->type == PN531) || (CHIP_DATA(pnd)->type == RCS360)) { if (szGBt) { memcpy(abtCmd + 36, pbtGBt, szGBt); szOptionalBytes = szGBt; } } else { abtCmd[36] = (uint8_t)(szGBt); if (szGBt) { memcpy(abtCmd + 37, pbtGBt, szGBt); } szOptionalBytes = szGBt + 1; } // Historical bytes (ISO/IEC 14443-4) if ((CHIP_DATA(pnd)->type != PN531) && (CHIP_DATA(pnd)->type != RCS360)) { // PN531 does not handle Historical Bytes abtCmd[36 + szOptionalBytes] = (uint8_t)(szTkt); if (szTkt) { memcpy(abtCmd + 37 + szOptionalBytes, pbtTkt, szTkt); } szOptionalBytes += szTkt + 1; } // Request the initialization as a target uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; size_t szRx = sizeof(abtRx); if ((res = pn53x_transceive(pnd, abtCmd, 36 + szOptionalBytes, abtRx, szRx, timeout)) < 0) return res; szRx = (size_t) res; // Note: the first byte is skip: // its the "mode" byte which contains baudrate, DEP and Framing type (Mifare, active or FeliCa) datas. if (pbtModeByte) { *pbtModeByte = abtRx[0]; } // Save the received byte count szRx -= 1; if ((szRx - 1) > szRxLen) return NFC_EOVFLOW; // Copy the received bytes memcpy(pbtRx, abtRx + 1, szRx); return szRx; } int pn53x_check_ack_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen) { if (szRxFrameLen >= sizeof(pn53x_ack_frame)) { if (0 == memcmp(pbtRxFrame, pn53x_ack_frame, sizeof(pn53x_ack_frame))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PN53x ACKed"); return NFC_SUCCESS; } } pnd->last_error = NFC_EIO; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unexpected PN53x reply!"); return pnd->last_error; } int pn53x_check_error_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen) { if (szRxFrameLen >= sizeof(pn53x_error_frame)) { if (0 == memcmp(pbtRxFrame, pn53x_error_frame, sizeof(pn53x_error_frame))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PN53x sent an error frame"); pnd->last_error = NFC_EIO; return pnd->last_error; } } return NFC_SUCCESS; } /** * @brief Build a PN53x frame * * @param pbtData payload (bytes array) of the frame, will become PD0, ..., PDn in PN53x frame * @note The first byte of pbtData is the Command Code (CC) */ int pn53x_build_frame(uint8_t *pbtFrame, size_t *pszFrame, const uint8_t *pbtData, const size_t szData) { if (szData <= PN53x_NORMAL_FRAME__DATA_MAX_LEN) { // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1) pbtFrame[3] = szData + 1; // LCS - Packet length checksum pbtFrame[4] = 256 - (szData + 1); // TFI pbtFrame[5] = 0xD4; // DATA - Copy the PN53X command into the packet buffer memcpy(pbtFrame + 6, pbtData, szData); // DCS - Calculate data payload checksum uint8_t btDCS = (256 - 0xD4); for (size_t szPos = 0; szPos < szData; szPos++) { btDCS -= pbtData[szPos]; } pbtFrame[6 + szData] = btDCS; // 0x00 - End of stream marker pbtFrame[szData + 7] = 0x00; (*pszFrame) = szData + PN53x_NORMAL_FRAME__OVERHEAD; } else if (szData <= PN53x_EXTENDED_FRAME__DATA_MAX_LEN) { // Extended frame marker pbtFrame[3] = 0xff; pbtFrame[4] = 0xff; // LENm pbtFrame[5] = (szData + 1) >> 8; // LENl pbtFrame[6] = (szData + 1) & 0xff; // LCS pbtFrame[7] = 256 - ((pbtFrame[5] + pbtFrame[6]) & 0xff); // TFI pbtFrame[8] = 0xD4; // DATA - Copy the PN53X command into the packet buffer memcpy(pbtFrame + 9, pbtData, szData); // DCS - Calculate data payload checksum uint8_t btDCS = (256 - 0xD4); for (size_t szPos = 0; szPos < szData; szPos++) { btDCS -= pbtData[szPos]; } pbtFrame[9 + szData] = btDCS; // 0x00 - End of stream marker pbtFrame[szData + 10] = 0x00; (*pszFrame) = szData + PN53x_EXTENDED_FRAME__OVERHEAD; } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "We can't send more than %d bytes in a raw (requested: %" PRIdPTR ")", PN53x_EXTENDED_FRAME__DATA_MAX_LEN, szData); return NFC_ECHIP; } return NFC_SUCCESS; } pn53x_modulation pn53x_nm_to_pm(const nfc_modulation nm) { switch (nm.nmt) { case NMT_ISO14443A: return PM_ISO14443A_106; break; case NMT_ISO14443B: switch (nm.nbr) { case NBR_106: return PM_ISO14443B_106; break; case NBR_212: return PM_ISO14443B_212; break; case NBR_424: return PM_ISO14443B_424; break; case NBR_847: return PM_ISO14443B_847; break; case NBR_UNDEFINED: // Nothing to do... break; } break; case NMT_JEWEL: return PM_JEWEL_106; break; case NMT_FELICA: switch (nm.nbr) { case NBR_212: return PM_FELICA_212; break; case NBR_424: return PM_FELICA_424; break; case NBR_106: case NBR_847: case NBR_UNDEFINED: // Nothing to do... break; } break; case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_DEP: // Nothing to do... break; } return PM_UNDEFINED; } nfc_modulation pn53x_ptt_to_nm(const pn53x_target_type ptt) { switch (ptt) { case PTT_GENERIC_PASSIVE_106: case PTT_GENERIC_PASSIVE_212: case PTT_GENERIC_PASSIVE_424: case PTT_UNDEFINED: // XXX This should not happend, how handle it cleanly ? break; case PTT_MIFARE: case PTT_ISO14443_4A_106: return (const nfc_modulation) { .nmt = NMT_ISO14443A, .nbr = NBR_106 }; break; case PTT_ISO14443_4B_106: case PTT_ISO14443_4B_TCL_106: return (const nfc_modulation) { .nmt = NMT_ISO14443B, .nbr = NBR_106 }; break; case PTT_JEWEL_106: return (const nfc_modulation) { .nmt = NMT_JEWEL, .nbr = NBR_106 }; break; case PTT_FELICA_212: return (const nfc_modulation) { .nmt = NMT_FELICA, .nbr = NBR_212 }; break; case PTT_FELICA_424: return (const nfc_modulation) { .nmt = NMT_FELICA, .nbr = NBR_424 }; break; case PTT_DEP_PASSIVE_106: case PTT_DEP_ACTIVE_106: return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_106 }; break; case PTT_DEP_PASSIVE_212: case PTT_DEP_ACTIVE_212: return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_212 }; break; case PTT_DEP_PASSIVE_424: case PTT_DEP_ACTIVE_424: return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_424 }; break; } // We should never be here, this line silent compilation warning return (const nfc_modulation) { .nmt = NMT_ISO14443A, .nbr = NBR_106 }; } pn53x_target_type pn53x_nm_to_ptt(const nfc_modulation nm) { switch (nm.nmt) { case NMT_ISO14443A: return PTT_MIFARE; // return PTT_ISO14443_4A_106; break; case NMT_ISO14443B: switch (nm.nbr) { case NBR_106: return PTT_ISO14443_4B_106; break; case NBR_UNDEFINED: case NBR_212: case NBR_424: case NBR_847: // Nothing to do... break; } break; case NMT_JEWEL: return PTT_JEWEL_106; break; case NMT_FELICA: switch (nm.nbr) { case NBR_212: return PTT_FELICA_212; break; case NBR_424: return PTT_FELICA_424; break; case NBR_UNDEFINED: case NBR_106: case NBR_847: // Nothing to do... break; } break; case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: case NMT_DEP: // Nothing to do... break; } return PTT_UNDEFINED; } int pn53x_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) { switch (mode) { case N_TARGET: *supported_mt = CHIP_DATA(pnd)->supported_modulation_as_target; break; case N_INITIATOR: *supported_mt = CHIP_DATA(pnd)->supported_modulation_as_initiator; break; default: return NFC_EINVARG; } return NFC_SUCCESS; } int pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) { switch (nmt) { case NMT_FELICA: *supported_br = (nfc_baud_rate *)pn53x_felica_supported_baud_rates; break; case NMT_ISO14443A: *supported_br = (nfc_baud_rate *)pn53x_iso14443a_supported_baud_rates; break; case NMT_ISO14443B: case NMT_ISO14443BI: case NMT_ISO14443B2SR: case NMT_ISO14443B2CT: { if ((CHIP_DATA(pnd)->type != PN533)) { *supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates; } else { *supported_br = (nfc_baud_rate *)pn533_iso14443b_supported_baud_rates; } } break; case NMT_JEWEL: *supported_br = (nfc_baud_rate *)pn53x_jewel_supported_baud_rates; break; case NMT_DEP: *supported_br = (nfc_baud_rate *)pn53x_dep_supported_baud_rates; break; default: return NFC_EINVARG; } return NFC_SUCCESS; } int pn53x_get_information_about(nfc_device *pnd, char **pbuf) { size_t buflen = 2048; *pbuf = malloc(buflen); if (! *pbuf) { return NFC_ESOFT; } char *buf = *pbuf; int res; if ((res = snprintf(buf, buflen, "chip: %s\n", CHIP_DATA(pnd)->firmware_text)) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; if ((res = snprintf(buf, buflen, "initator mode modulations: ")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; const nfc_modulation_type *nmt; if ((res = nfc_device_get_supported_modulation(pnd, N_INITIATOR, &nmt)) < 0) { free(*pbuf); return res; } for (int i = 0; nmt[i]; i++) { if ((res = snprintf(buf, buflen, "%s%s (", (i == 0) ? "" : ", ", str_nfc_modulation_type(nmt[i]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; const nfc_baud_rate *nbr; if ((res = nfc_device_get_supported_baud_rate(pnd, nmt[i], &nbr)) < 0) { free(*pbuf); return res; } for (int j = 0; nbr[j]; j++) { if ((res = snprintf(buf, buflen, "%s%s", (j == 0) ? "" : ", ", str_nfc_baud_rate(nbr[j]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, ")")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, "\n")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; if ((res = snprintf(buf, buflen, "target mode modulations: ")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; if ((res = nfc_device_get_supported_modulation(pnd, N_TARGET, &nmt)) < 0) { free(*pbuf); return res; } for (int i = 0; nmt[i]; i++) { if ((res = snprintf(buf, buflen, "%s%s (", (i == 0) ? "" : ", ", str_nfc_modulation_type(nmt[i]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; const nfc_baud_rate *nbr; if ((res = nfc_device_get_supported_baud_rate(pnd, nmt[i], &nbr)) < 0) { free(*pbuf); return res; } for (int j = 0; nbr[j]; j++) { if ((res = snprintf(buf, buflen, "%s%s", (j == 0) ? "" : ", ", str_nfc_baud_rate(nbr[j]))) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, ")")) < 0) { free(*pbuf); return NFC_ESOFT; } buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } buflen -= res; } if ((res = snprintf(buf, buflen, "\n")) < 0) { free(*pbuf); return NFC_ESOFT; } //buf += res; if (buflen <= (size_t)res) { free(*pbuf); return NFC_EOVFLOW; } //buflen -= res; return NFC_SUCCESS; } void * pn53x_current_target_new(const struct nfc_device *pnd, const nfc_target *pnt) { if (pnt == NULL) { return NULL; } // Keep the current nfc_target for further commands if (CHIP_DATA(pnd)->current_target) { free(CHIP_DATA(pnd)->current_target); } CHIP_DATA(pnd)->current_target = malloc(sizeof(nfc_target)); if (!CHIP_DATA(pnd)->current_target) { return NULL; } memcpy(CHIP_DATA(pnd)->current_target, pnt, sizeof(nfc_target)); return CHIP_DATA(pnd)->current_target; } void pn53x_current_target_free(const struct nfc_device *pnd) { if (CHIP_DATA(pnd)->current_target) { free(CHIP_DATA(pnd)->current_target); CHIP_DATA(pnd)->current_target = NULL; } } bool pn53x_current_target_is(const struct nfc_device *pnd, const nfc_target *pnt) { if ((CHIP_DATA(pnd)->current_target == NULL) || (pnt == NULL)) { return false; } // XXX It will not work if it is not binary-equal to current target if (0 != memcmp(pnt, CHIP_DATA(pnd)->current_target, sizeof(nfc_target))) { return false; } return true; } void * pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io) { pnd->chip_data = malloc(sizeof(struct pn53x_data)); if (!pnd->chip_data) { return NULL; } // Keep I/O functions CHIP_DATA(pnd)->io = io; // Set type to generic (means unknown) CHIP_DATA(pnd)->type = PN53X; // Set power mode to normal, if your device starts in LowVBat (ie. PN532 // UART) the driver layer have to correctly set it. CHIP_DATA(pnd)->power_mode = NORMAL; // PN53x starts in initiator mode CHIP_DATA(pnd)->operating_mode = INITIATOR; // Clear last status byte CHIP_DATA(pnd)->last_status_byte = 0x00; // Set current target to NULL CHIP_DATA(pnd)->current_target = NULL; // Set current sam_mode to normal mode CHIP_DATA(pnd)->sam_mode = PSM_NORMAL; // WriteBack cache is clean CHIP_DATA(pnd)->wb_trigged = false; memset(CHIP_DATA(pnd)->wb_mask, 0x00, PN53X_CACHE_REGISTER_SIZE); // Set default command timeout (350 ms) CHIP_DATA(pnd)->timeout_command = 350; // Set default ATR timeout (103 ms) CHIP_DATA(pnd)->timeout_atr = 103; // Set default communication timeout (52 ms) CHIP_DATA(pnd)->timeout_communication = 52; CHIP_DATA(pnd)->supported_modulation_as_initiator = NULL; CHIP_DATA(pnd)->supported_modulation_as_target = NULL; return pnd->chip_data; } void pn53x_data_free(struct nfc_device *pnd) { // Free current target pn53x_current_target_free(pnd); // Free supported modulation(s) if (CHIP_DATA(pnd)->supported_modulation_as_initiator) { free(CHIP_DATA(pnd)->supported_modulation_as_initiator); } free(pnd->chip_data); } libnfc-1.7.1/libnfc/chips/pn53x.h000066400000000000000000000423301230265671100164530ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file pn53x.h * @brief PN531, PN532 and PN533 common functions */ #ifndef __NFC_CHIPS_PN53X_H__ # define __NFC_CHIPS_PN53X_H__ # include # include "pn53x-internal.h" // Registers and symbols masks used to covers parts within a register // PN53X_REG_CIU_TxMode # define SYMBOL_TX_CRC_ENABLE 0x80 # define SYMBOL_TX_SPEED 0x70 // TX_FRAMING bits explanation: // 00 : ISO/IEC 14443A/MIFARE and Passive Communication mode 106 kbit/s // 01 : Active Communication mode // 10 : FeliCa and Passive Communication mode at 212 kbit/s and 424 kbit/s // 11 : ISO/IEC 14443B # define SYMBOL_TX_FRAMING 0x03 // PN53X_REG_Control_switch_rng # define SYMBOL_CURLIMOFF 0x08 /* When set to 1, the 100 mA current limitations is desactivated. */ # define SYMBOL_SIC_SWITCH_EN 0x10 /* When set to logic 1, the SVDD switch is enabled and the SVDD output delivers power to secure IC and internal pads (SIGIN, SIGOUT and P34). */ # define SYMBOL_RANDOM_DATAREADY 0x02 /* When set to logic 1, a new random number is available. */ // PN53X_REG_CIU_RxMode # define SYMBOL_RX_CRC_ENABLE 0x80 # define SYMBOL_RX_SPEED 0x70 # define SYMBOL_RX_NO_ERROR 0x08 # define SYMBOL_RX_MULTIPLE 0x04 // RX_FRAMING follow same scheme than TX_FRAMING # define SYMBOL_RX_FRAMING 0x03 // PN53X_REG_CIU_TxAuto # define SYMBOL_FORCE_100_ASK 0x40 # define SYMBOL_AUTO_WAKE_UP 0x20 # define SYMBOL_INITIAL_RF_ON 0x04 // PN53X_REG_CIU_ManualRCV # define SYMBOL_PARITY_DISABLE 0x10 // PN53X_REG_CIU_TMode # define SYMBOL_TAUTO 0x80 # define SYMBOL_TPRESCALERHI 0x0F // PN53X_REG_CIU_TPrescaler # define SYMBOL_TPRESCALERLO 0xFF // PN53X_REG_CIU_Command # define SYMBOL_COMMAND 0x0F # define SYMBOL_COMMAND_TRANSCEIVE 0xC // PN53X_REG_CIU_Status2 # define SYMBOL_MF_CRYPTO1_ON 0x08 // PN53X_REG_CIU_FIFOLevel # define SYMBOL_FLUSH_BUFFER 0x80 # define SYMBOL_FIFO_LEVEL 0x7F // PN53X_REG_CIU_Control # define SYMBOL_INITIATOR 0x10 # define SYMBOL_RX_LAST_BITS 0x07 // PN53X_REG_CIU_BitFraming # define SYMBOL_START_SEND 0x80 # define SYMBOL_RX_ALIGN 0x70 # define SYMBOL_TX_LAST_BITS 0x07 // PN53X Support Byte flags #define SUPPORT_ISO14443A 0x01 #define SUPPORT_ISO14443B 0x02 #define SUPPORT_ISO18092 0x04 // Internal parameters flags # define PARAM_NONE 0x00 # define PARAM_NAD_USED 0x01 # define PARAM_DID_USED 0x02 # define PARAM_AUTO_ATR_RES 0x04 # define PARAM_AUTO_RATS 0x10 # define PARAM_14443_4_PICC 0x20 /* Only for PN532 */ # define PARAM_NFC_SECURE 0x20 /* Only for PN533 */ # define PARAM_NO_AMBLE 0x40 /* Only for PN532 */ // Radio Field Configure Items // Configuration Data length # define RFCI_FIELD 0x01 // 1 # define RFCI_TIMING 0x02 // 3 # define RFCI_RETRY_DATA 0x04 // 1 # define RFCI_RETRY_SELECT 0x05 // 3 # define RFCI_ANALOG_TYPE_A_106 0x0A // 11 # define RFCI_ANALOG_TYPE_A_212_424 0x0B // 8 # define RFCI_ANALOG_TYPE_B 0x0C // 3 # define RFCI_ANALOG_TYPE_14443_4 0x0D // 9 /** * @enum pn53x_power_mode * @brief PN53x power mode enumeration */ typedef enum { NORMAL, // In that case, there is no power saved but the PN53x reacts as fast as possible on the host controller interface. POWERDOWN, // Only on PN532, need to be wake up to process commands with a long preamble LOWVBAT // Only on PN532, need to be wake up to process commands with a long preamble and SAMConfiguration command } pn53x_power_mode; /** * @enum pn53x_operating_mode * @brief PN53x operatin mode enumeration */ typedef enum { IDLE, INITIATOR, TARGET, } pn53x_operating_mode; /** * @enum pn532_sam_mode * @brief PN532 SAM mode enumeration */ typedef enum { PSM_NORMAL = 0x01, PSM_VIRTUAL_CARD = 0x02, PSM_WIRED_CARD = 0x03, PSM_DUAL_CARD = 0x04 } pn532_sam_mode; /** * @internal * @struct pn53x_io * @brief PN53x I/O structure */ struct pn53x_io { int (*send)(struct nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout); int (*receive)(struct nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout); }; /* defines */ #define PN53X_CACHE_REGISTER_MIN_ADDRESS PN53X_REG_CIU_Mode #define PN53X_CACHE_REGISTER_MAX_ADDRESS PN53X_REG_CIU_Coll #define PN53X_CACHE_REGISTER_SIZE ((PN53X_CACHE_REGISTER_MAX_ADDRESS - PN53X_CACHE_REGISTER_MIN_ADDRESS) + 1) /** * @internal * @struct pn53x_data * @brief PN53x data structure */ struct pn53x_data { /** Chip type (PN531, PN532 or PN533) */ pn53x_type type; /** Chip firmware text */ char firmware_text[22]; /** Current power mode */ pn53x_power_mode power_mode; /** Current operating mode */ pn53x_operating_mode operating_mode; /** Current emulated target */ nfc_target *current_target; /** Current sam mode (only applicable for PN532) */ pn532_sam_mode sam_mode; /** PN53x I/O functions stored in struct */ const struct pn53x_io *io; /** Last status byte returned by PN53x */ uint8_t last_status_byte; /** Register cache for REG_CIU_BIT_FRAMING, SYMBOL_TX_LAST_BITS: The last TX bits setting, we need to reset this if it does not apply anymore */ uint8_t ui8TxBits; /** Register cache for SetParameters function. */ uint8_t ui8Parameters; /** Last sent command */ uint8_t last_command; /** Interframe timer correction */ int16_t timer_correction; /** Timer prescaler */ uint16_t timer_prescaler; /** WriteBack cache */ uint8_t wb_data[PN53X_CACHE_REGISTER_SIZE]; uint8_t wb_mask[PN53X_CACHE_REGISTER_SIZE]; bool wb_trigged; /** Command timeout */ int timeout_command; /** ATR timeout */ int timeout_atr; /** Communication timeout */ int timeout_communication; /** Supported modulation type */ nfc_modulation_type *supported_modulation_as_initiator; nfc_modulation_type *supported_modulation_as_target; }; #define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data)) /** * @enum pn53x_modulation * @brief NFC modulation enumeration */ typedef enum { /** Undefined modulation */ PM_UNDEFINED = -1, /** ISO14443-A (NXP MIFARE) http://en.wikipedia.org/wiki/MIFARE */ PM_ISO14443A_106 = 0x00, /** JIS X 6319-4 (Sony Felica) http://en.wikipedia.org/wiki/FeliCa */ PM_FELICA_212 = 0x01, /** JIS X 6319-4 (Sony Felica) http://en.wikipedia.org/wiki/FeliCa */ PM_FELICA_424 = 0x02, /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531) */ PM_ISO14443B_106 = 0x03, /** Jewel Topaz (Innovision Research & Development) (Not supported by PN531) */ PM_JEWEL_106 = 0x04, /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ PM_ISO14443B_212 = 0x06, /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ PM_ISO14443B_424 = 0x07, /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ PM_ISO14443B_847 = 0x08, } pn53x_modulation; /** * @enum pn53x_target_type * @brief NFC target type enumeration */ typedef enum { /** Undefined target type */ PTT_UNDEFINED = -1, /** Generic passive 106 kbps (ISO/IEC14443-4A, mifare, DEP) */ PTT_GENERIC_PASSIVE_106 = 0x00, /** Generic passive 212 kbps (FeliCa, DEP) */ PTT_GENERIC_PASSIVE_212 = 0x01, /** Generic passive 424 kbps (FeliCa, DEP) */ PTT_GENERIC_PASSIVE_424 = 0x02, /** Passive 106 kbps ISO/IEC14443-4B */ PTT_ISO14443_4B_106 = 0x03, /** Innovision Jewel tag */ PTT_JEWEL_106 = 0x04, /** Mifare card */ PTT_MIFARE = 0x10, /** FeliCa 212 kbps card */ PTT_FELICA_212 = 0x11, /** FeliCa 424 kbps card */ PTT_FELICA_424 = 0x12, /** Passive 106 kbps ISO/IEC 14443-4A */ PTT_ISO14443_4A_106 = 0x20, /** Passive 106 kbps ISO/IEC 14443-4B with TCL flag */ PTT_ISO14443_4B_TCL_106 = 0x23, /** DEP passive 106 kbps */ PTT_DEP_PASSIVE_106 = 0x40, /** DEP passive 212 kbps */ PTT_DEP_PASSIVE_212 = 0x41, /** DEP passive 424 kbps */ PTT_DEP_PASSIVE_424 = 0x42, /** DEP active 106 kbps */ PTT_DEP_ACTIVE_106 = 0x80, /** DEP active 212 kbps */ PTT_DEP_ACTIVE_212 = 0x81, /** DEP active 424 kbps */ PTT_DEP_ACTIVE_424 = 0x82, } pn53x_target_type; /** * @enum pn53x_target_mode * @brief PN53x target mode enumeration */ typedef enum { /** Configure the PN53x to accept all initiator mode */ PTM_NORMAL = 0x00, /** Configure the PN53x to accept to be initialized only in passive mode */ PTM_PASSIVE_ONLY = 0x01, /** Configure the PN53x to accept to be initialized only as DEP target */ PTM_DEP_ONLY = 0x02, /** Configure the PN532 to accept to be initialized only as ISO/IEC14443-4 PICC */ PTM_ISO14443_4_PICC_ONLY = 0x04 } pn53x_target_mode; extern const uint8_t pn53x_ack_frame[PN53x_ACK_FRAME__LEN]; extern const uint8_t pn53x_nack_frame[PN53x_ACK_FRAME__LEN]; int pn53x_init(struct nfc_device *pnd); int pn53x_transceive(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRxLen, int timeout); int pn53x_set_parameters(struct nfc_device *pnd, const uint8_t ui8Value, const bool bEnable); int pn53x_set_tx_bits(struct nfc_device *pnd, const uint8_t ui8Bits); int pn53x_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtFrame); int pn53x_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBits, uint8_t *pbtRx, uint8_t *pbtRxPar); int pn53x_decode_target_data(const uint8_t *pbtRawData, size_t szRawData, pn53x_type chip_type, nfc_modulation_type nmt, nfc_target_info *pnti); int pn53x_read_register(struct nfc_device *pnd, uint16_t ui16Reg, uint8_t *ui8Value); int pn53x_write_register(struct nfc_device *pnd, uint16_t ui16Reg, uint8_t ui8SymbolMask, uint8_t ui8Value); int pn53x_decode_firmware_version(struct nfc_device *pnd); int pn53x_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value); int pn53x_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable); int pn53x_check_communication(struct nfc_device *pnd); int pn53x_idle(struct nfc_device *pnd); // NFC device as Initiator functions int pn53x_initiator_init(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, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt); int pn53x_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); int pn53x_initiator_select_dep_target(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout); int pn53x_initiator_transceive_bits(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar); int pn53x_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout); int pn53x_initiator_transceive_bits_timed(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar, uint32_t *cycles); int pn53x_initiator_transceive_bytes_timed(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles); int pn53x_initiator_deselect_target(struct nfc_device *pnd); int pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt); // NFC device as Target functions int pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRxLen, int timeout); int pn53x_target_receive_bits(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, uint8_t *pbtRxPar); int pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, int timeout); int pn53x_target_send_bits(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar); int pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout); // Error handling functions const char *pn53x_strerror(const struct nfc_device *pnd); // C wrappers for PN53x commands int pn53x_SetParameters(struct nfc_device *pnd, const uint8_t ui8Value); int pn532_SAMConfiguration(struct nfc_device *pnd, const pn532_sam_mode mode, int timeout); int pn53x_PowerDown(struct nfc_device *pnd); int pn53x_InListPassiveTarget(struct nfc_device *pnd, const pn53x_modulation pmInitModulation, const uint8_t szMaxTargets, const uint8_t *pbtInitiatorData, const size_t szInitiatorDataLen, uint8_t *pbtTargetsData, size_t *pszTargetsData, int timeout); int pn53x_InDeselect(struct nfc_device *pnd, const uint8_t ui8Target); int pn53x_InRelease(struct nfc_device *pnd, const uint8_t ui8Target); int pn53x_InAutoPoll(struct nfc_device *pnd, const pn53x_target_type *ppttTargetTypes, const size_t szTargetTypes, const uint8_t btPollNr, const uint8_t btPeriod, nfc_target *pntTargets, const int timeout); int pn53x_InJumpForDEP(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const uint8_t *pbtPassiveInitiatorData, const uint8_t *pbtNFCID3i, const uint8_t *pbtGB, const size_t szGB, nfc_target *pnt, const int timeout); int pn53x_TgInitAsTarget(struct nfc_device *pnd, pn53x_target_mode ptm, const uint8_t *pbtMifareParams, const uint8_t *pbtTkt, size_t szTkt, const uint8_t *pbtFeliCaParams, const uint8_t *pbtNFCID3t, const uint8_t *pbtGB, const size_t szGB, uint8_t *pbtRx, const size_t szRxLen, uint8_t *pbtModeByte, int timeout); // RFConfiguration int pn53x_RFConfiguration__RF_field(struct nfc_device *pnd, bool bEnable); int pn53x_RFConfiguration__Various_timings(struct nfc_device *pnd, const uint8_t fATR_RES_Timeout, const uint8_t fRetryTimeout); int pn53x_RFConfiguration__MaxRtyCOM(struct nfc_device *pnd, const uint8_t MaxRtyCOM); int pn53x_RFConfiguration__MaxRetries(struct nfc_device *pnd, const uint8_t MxRtyATR, const uint8_t MxRtyPSL, const uint8_t MxRtyPassiveActivation); // Misc int pn53x_check_ack_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen); int pn53x_check_error_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen); int pn53x_build_frame(uint8_t *pbtFrame, size_t *pszFrame, const uint8_t *pbtData, const size_t szData); int pn53x_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); int pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); int pn53x_get_information_about(nfc_device *pnd, char **pbuf); void *pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io); void pn53x_data_free(struct nfc_device *pnd); #endif // __NFC_CHIPS_PN53X_H__ libnfc-1.7.1/libnfc/conf.c000066400000000000000000000177321230265671100153200ustar00rootroot00000000000000/*- * 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: * * 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 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "conf.h" #ifdef CONFFILES #include #include #include #include #include #include #include #include "nfc-internal.h" #include "log.h" #define LOG_CATEGORY "libnfc.config" #define LOG_GROUP NFC_LOG_GROUP_CONFIG #ifndef LIBNFC_SYSCONFDIR // If this define does not already exists, we build it using SYSCONFDIR #ifndef SYSCONFDIR #error "SYSCONFDIR is not defined but required." #endif // SYSCONFDIR #define LIBNFC_SYSCONFDIR SYSCONFDIR"/nfc" #endif // LIBNFC_SYSCONFDIR #define LIBNFC_CONFFILE LIBNFC_SYSCONFDIR"/libnfc.conf" #define LIBNFC_DEVICECONFDIR LIBNFC_SYSCONFDIR"/devices.d" static bool conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const char *key, const char *value), void *data) { FILE *f = fopen(filename, "r"); if (!f) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Unable to open file: %s", filename); return false; } char line[BUFSIZ]; const char *str_regex = "^[[:space:]]*([[:alnum:]_.]+)[[:space:]]*=[[:space:]]*(\"(.+)\"|([^[:space:]]+))[[:space:]]*$"; regex_t preg; if (regcomp(&preg, str_regex, REG_EXTENDED | REG_NOTEOL) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Regular expression used for configuration file parsing is not valid."); fclose(f); return false; } size_t nmatch = preg.re_nsub + 1; regmatch_t *pmatch = malloc(sizeof(*pmatch) * nmatch); if (!pmatch) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not enough memory: malloc failed."); regfree(&preg); fclose(f); return false; } int lineno = 0; while (fgets(line, BUFSIZ, f) != NULL) { lineno++; switch (line[0]) { case '#': case '\n': break; default: { int match; if ((match = regexec(&preg, line, nmatch, pmatch, 0)) == 0) { const size_t key_size = pmatch[1].rm_eo - pmatch[1].rm_so; const off_t value_pmatch = pmatch[3].rm_eo != -1 ? 3 : 4; const size_t value_size = pmatch[value_pmatch].rm_eo - pmatch[value_pmatch].rm_so; char key[key_size + 1]; char value[value_size + 1]; strncpy(key, line + (pmatch[1].rm_so), key_size); key[key_size] = '\0'; strncpy(value, line + (pmatch[value_pmatch].rm_so), value_size); value[value_size] = '\0'; conf_keyvalue(data, key, value); } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line); } } break; } } free(pmatch); regfree(&preg); fclose(f); return false; } static void conf_keyvalue_context(void *data, const char *key, const char *value) { nfc_context *context = (nfc_context *)data; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "key: [%s], value: [%s]", key, value); if (strcmp(key, "allow_autoscan") == 0) { string_as_boolean(value, &(context->allow_autoscan)); } else if (strcmp(key, "allow_intrusive_scan") == 0) { string_as_boolean(value, &(context->allow_intrusive_scan)); } else if (strcmp(key, "log_level") == 0) { context->log_level = atoi(value); } else if (strcmp(key, "device.name") == 0) { if ((context->user_defined_device_count == 0) || strcmp(context->user_defined_devices[context->user_defined_device_count - 1].name, "") != 0) { if (context->user_defined_device_count >= MAX_USER_DEFINED_DEVICES) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Configuration exceeded maximum user-defined devices."); return; } context->user_defined_device_count++; } strncpy(context->user_defined_devices[context->user_defined_device_count - 1].name, value, DEVICE_NAME_LENGTH - 1); context->user_defined_devices[context->user_defined_device_count - 1].name[DEVICE_NAME_LENGTH - 1] = '\0'; } else if (strcmp(key, "device.connstring") == 0) { if ((context->user_defined_device_count == 0) || strcmp(context->user_defined_devices[context->user_defined_device_count - 1].connstring, "") != 0) { if (context->user_defined_device_count >= MAX_USER_DEFINED_DEVICES) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Configuration exceeded maximum user-defined devices."); return; } context->user_defined_device_count++; } strncpy(context->user_defined_devices[context->user_defined_device_count - 1].connstring, value, NFC_BUFSIZE_CONNSTRING - 1); context->user_defined_devices[context->user_defined_device_count - 1].connstring[NFC_BUFSIZE_CONNSTRING - 1] = '\0'; } else if (strcmp(key, "device.optional") == 0) { if ((context->user_defined_device_count == 0) || context->user_defined_devices[context->user_defined_device_count - 1].optional) { if (context->user_defined_device_count >= MAX_USER_DEFINED_DEVICES) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Configuration exceeded maximum user-defined devices."); return; } context->user_defined_device_count++; } if ((strcmp(value, "true") == 0) || (strcmp(value, "True") == 0) || (strcmp(value, "1") == 0)) //optional context->user_defined_devices[context->user_defined_device_count - 1].optional = true; } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Unknown key in config line: %s = %s", key, value); } } static void conf_keyvalue_device(void *data, const char *key, const char *value) { char newkey[BUFSIZ]; sprintf(newkey, "device.%s", key); conf_keyvalue_context(data, newkey, value); } static void conf_devices_load(const char *dirname, nfc_context *context) { DIR *d = opendir(dirname); if (!d) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open directory: %s", dirname); } else { struct dirent *de; #ifdef WIN32 while ((de = readdir(d)) != NULL) { #else struct dirent entry; struct dirent *result; while ((readdir_r(d, &entry, &result) == 0) && (result != NULL)) { de = &entry; #endif if (de->d_name[0] != '.') { const size_t filename_len = strlen(de->d_name); const size_t extension_len = strlen(".conf"); if ((filename_len > extension_len) && (strncmp(".conf", de->d_name + (filename_len - extension_len), extension_len) == 0)) { char filename[BUFSIZ] = LIBNFC_DEVICECONFDIR"/"; strcat(filename, de->d_name); struct stat s; if (stat(filename, &s) == -1) { perror("stat"); continue; } if (S_ISREG(s.st_mode)) { conf_parse_file(filename, conf_keyvalue_device, context); } } } } closedir(d); } } void conf_load(nfc_context *context) { conf_parse_file(LIBNFC_CONFFILE, conf_keyvalue_context, context); conf_devices_load(LIBNFC_DEVICECONFDIR, context); } #endif // CONFFILES libnfc-1.7.1/libnfc/conf.h000066400000000000000000000023051230265671100153130ustar00rootroot00000000000000/*- * 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: * * 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 */ #ifndef __NFC_CONF_H__ #define __NFC_CONF_H__ #include void conf_load(nfc_context *context); #endif // __NFC_CONF_H__ libnfc-1.7.1/libnfc/drivers.h000066400000000000000000000024311230265671100160440ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file drivers.h * @brief Supported drivers header */ #ifndef __NFC_DRIVERS_H__ #define __NFC_DRIVERS_H__ #include extern const struct nfc_driver_list *nfc_drivers; #endif // __NFC_DRIVERS_H__ libnfc-1.7.1/libnfc/drivers/000077500000000000000000000000001230265671100156735ustar00rootroot00000000000000libnfc-1.7.1/libnfc/drivers/Makefile.am000066400000000000000000000022661230265671100177350ustar00rootroot00000000000000# set the include path found by configure AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS) noinst_LTLIBRARIES = libnfcdrivers.la libnfcdrivers_la_SOURCES = libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses libnfcdrivers_la_LIBADD = if DRIVER_ACR122_PCSC_ENABLED libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h endif if DRIVER_ACR122_USB_ENABLED libnfcdrivers_la_SOURCES += acr122_usb.c acr122_usb.h endif if DRIVER_ACR122S_ENABLED libnfcdrivers_la_SOURCES += acr122s.c acr122s.h endif if DRIVER_ARYGON_ENABLED libnfcdrivers_la_SOURCES += arygon.c arygon.h endif if DRIVER_PN53X_USB_ENABLED libnfcdrivers_la_SOURCES += pn53x_usb.c pn53x_usb.h endif if DRIVER_PN532_UART_ENABLED libnfcdrivers_la_SOURCES += pn532_uart.c pn532_uart.h endif if DRIVER_PN532_SPI_ENABLED libnfcdrivers_la_SOURCES += pn532_spi.c pn532_spi.h endif if DRIVER_PN532_I2C_ENABLED libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h endif if PCSC_ENABLED libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@ libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@ endif if LIBUSB_ENABLED libnfcdrivers_la_CFLAGS += @libusb_CFLAGS@ libnfcdrivers_la_LIBADD += @libusb_LIBS@ endif libnfc-1.7.1/libnfc/drivers/acr122_pcsc.c000066400000000000000000000414101230265671100200410ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file acr122_pcsc.c * @brief Driver for ACR122 devices (e.g. Tikitag, Touchatag, ACS ACR122) behind PC/SC */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "chips/pn53x.h" #include "drivers/acr122_pcsc.h" #include "nfc-internal.h" // Bus #ifdef __APPLE__ #include #include #else #include #endif #define ACR122_PCSC_DRIVER_NAME "acr122_pcsc" #if defined (_WIN32) # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500) #elif defined(__APPLE__) # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2)) #elif defined (__FreeBSD__) || defined (__OpenBSD__) # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2)) #elif defined (__linux__) # include // Escape IOCTL tested successfully: # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(1) #else # error "Can't determine serial string for your system" #endif #include #define SCARD_OPERATION_SUCCESS 0x61 #define SCARD_OPERATION_ERROR 0x63 #ifndef SCARD_PROTOCOL_UNDEFINED # define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET #endif #define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS) #define ACR122_PCSC_WRAP_LEN 6 #define ACR122_PCSC_COMMAND_LEN 266 #define ACR122_PCSC_RESPONSE_LEN 268 #define LOG_GROUP NFC_LOG_GROUP_DRIVER #define LOG_CATEGORY "libnfc.driver.acr122_pcsc" // Internal data struct const struct pn53x_io acr122_pcsc_io; // Prototypes char *acr122_pcsc_firmware(nfc_device *pnd); 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 "ACS AET65", // Touchatag using CCID driver version >= 1.4.6 " CCID USB", // ?? NULL }; struct acr122_pcsc_data { SCARDHANDLE hCard; SCARD_IO_REQUEST ioCard; uint8_t abtRx[ACR122_PCSC_RESPONSE_LEN]; size_t szRx; }; #define DRIVER_DATA(pnd) ((struct acr122_pcsc_data*)(pnd->driver_data)) static SCARDCONTEXT _SCardContext; static int _iSCardContextRefCount = 0; static SCARDCONTEXT * acr122_pcsc_get_scardcontext(void) { if (_iSCardContextRefCount == 0) { if (SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &_SCardContext) != SCARD_S_SUCCESS) return NULL; } _iSCardContextRefCount++; return &_SCardContext; } static void acr122_pcsc_free_scardcontext(void) { if (_iSCardContextRefCount) { _iSCardContextRefCount--; if (!_iSCardContextRefCount) { SCardReleaseContext(_SCardContext); } } } #define PCSC_MAX_DEVICES 16 /** * @brief List opened devices * * Probe PCSC to find ACR122 devices (ACR122U and Touchatag/Tikitag). * * @param connstring array of nfc_connstring where found device's connection strings will be stored. * @param connstrings_len size of connstrings array. * @return number of devices found. */ static size_t acr122_pcsc_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { (void) context; size_t szPos = 0; char acDeviceNames[256 + 64 * PCSC_MAX_DEVICES]; size_t szDeviceNamesLen = sizeof(acDeviceNames); SCARDCONTEXT *pscc; int i; // Clear the reader list memset(acDeviceNames, '\0', szDeviceNamesLen); // Test if context succeeded if (!(pscc = acr122_pcsc_get_scardcontext())) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: %s", "PCSC context not found (make sure PCSC daemon is running)."); return 0; } // Retrieve the string array of all available pcsc readers DWORD dwDeviceNamesLen = szDeviceNamesLen; if (SCardListReaders(*pscc, NULL, acDeviceNames, &dwDeviceNamesLen) != SCARD_S_SUCCESS) return 0; size_t device_found = 0; while ((acDeviceNames[szPos] != '\0') && (device_found < connstrings_len)) { bool bSupported = false; for (i = 0; supported_devices[i] && !bSupported; i++) { int l = strlen(supported_devices[i]); bSupported = 0 == strncmp(supported_devices[i], acDeviceNames + szPos, l); } if (bSupported) { // Supported ACR122 device found snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s", ACR122_PCSC_DRIVER_NAME, acDeviceNames + szPos); device_found++; } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "PCSC device [%s] is not NFC capable or not supported by libnfc.", acDeviceNames + szPos); } // Find next device name position while (acDeviceNames[szPos++] != '\0'); } acr122_pcsc_free_scardcontext(); return device_found; } struct acr122_pcsc_descriptor { char *pcsc_device_name; }; static nfc_device * acr122_pcsc_open(const nfc_context *context, const nfc_connstring connstring) { struct acr122_pcsc_descriptor ndd; int connstring_decode_level = connstring_decode(connstring, ACR122_PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); if (connstring_decode_level < 1) { return NULL; } nfc_connstring fullconnstring; if (connstring_decode_level == 1) { // Device was not specified, take the first one we can find size_t szDeviceFound = acr122_pcsc_scan(context, &fullconnstring, 1); if (szDeviceFound < 1) return NULL; connstring_decode_level = connstring_decode(fullconnstring, ACR122_PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); if (connstring_decode_level < 2) { return NULL; } } else { memcpy(fullconnstring, connstring, sizeof(nfc_connstring)); } if (strlen(ndd.pcsc_device_name) < 5) { // We can assume it's a reader ID as pcsc_name always ends with "NN NN" // Device was not specified, only ID, retrieve it size_t index; if (sscanf(ndd.pcsc_device_name, "%4" SCNuPTR, &index) != 1) { free(ndd.pcsc_device_name); return NULL; } nfc_connstring *ncs = malloc(sizeof(nfc_connstring) * (index + 1)); if (!ncs) { perror("malloc"); free(ndd.pcsc_device_name); return NULL; } size_t szDeviceFound = acr122_pcsc_scan(context, ncs, index + 1); if (szDeviceFound < index + 1) { free(ncs); free(ndd.pcsc_device_name); return NULL; } strncpy(fullconnstring, ncs[index], sizeof(nfc_connstring)); fullconnstring[sizeof(nfc_connstring) - 1] = '\0'; free(ncs); connstring_decode_level = connstring_decode(fullconnstring, ACR122_PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); if (connstring_decode_level < 2) { free(ndd.pcsc_device_name); return NULL; } } char *pcFirmware; nfc_device *pnd = nfc_device_new(context, fullconnstring); if (!pnd) { perror("malloc"); goto error; } pnd->driver_data = malloc(sizeof(struct acr122_pcsc_data)); if (!pnd->driver_data) { perror("malloc"); goto error; } // Alloc and init chip's data if (pn53x_data_new(pnd, &acr122_pcsc_io) == NULL) { perror("malloc"); goto error; } SCARDCONTEXT *pscc; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open %s", ndd.pcsc_device_name); // Test if context succeeded if (!(pscc = acr122_pcsc_get_scardcontext())) goto error; // Test if we were able to connect to the "emulator" card if (SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)) != SCARD_S_SUCCESS) { // Connect to ACR122 firmware version >2.0 if (SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)) != SCARD_S_SUCCESS) { // We can not connect to this device. log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed"); goto error; } } // Configure I/O settings for card communication DRIVER_DATA(pnd)->ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST); // Retrieve the current firmware version pcFirmware = acr122_pcsc_firmware(pnd); if (strstr(pcFirmware, FIRMWARE_TEXT) != NULL) { // Done, we found the reader we are looking for snprintf(pnd->name, sizeof(pnd->name), "%s / %s", ndd.pcsc_device_name, pcFirmware); // 50: empirical tuning on Touchatag // 46: empirical tuning on ACR122U CHIP_DATA(pnd)->timer_correction = 50; pnd->driver = &acr122_pcsc_driver; pn53x_init(pnd); free(ndd.pcsc_device_name); return pnd; } error: free(ndd.pcsc_device_name); nfc_device_free(pnd); return NULL; } static void acr122_pcsc_close(nfc_device *pnd) { pn53x_idle(pnd); SCardDisconnect(DRIVER_DATA(pnd)->hCard, SCARD_LEAVE_CARD); acr122_pcsc_free_scardcontext(); pn53x_data_free(pnd); nfc_device_free(pnd); } static int acr122_pcsc_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout) { // FIXME: timeout is not handled (void) timeout; // Make sure the command does not overflow the send buffer if (szData > ACR122_PCSC_COMMAND_LEN) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } // Prepare and transmit the send buffer const size_t szTxBuf = szData + 6; uint8_t abtTxBuf[ACR122_PCSC_WRAP_LEN + ACR122_PCSC_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00, szData + 1, 0xD4 }; memcpy(abtTxBuf + ACR122_PCSC_WRAP_LEN, pbtData, szData); LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTxBuf, szTxBuf); DRIVER_DATA(pnd)->szRx = 0; DWORD dwRxLen = sizeof(DRIVER_DATA(pnd)->abtRx); if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) { /* * In this communication mode, we directly have the response from the * PN532. Save it in the driver data structure so that it can be retrieved * in ac122_receive(). * * Some devices will never enter this state (e.g. Touchatag) but are still * supported through SCardTransmit calls (see bellow). * * This state is generaly reached when the ACR122 has no target in it's * field. */ if (SCardControl(DRIVER_DATA(pnd)->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtTxBuf, szTxBuf, DRIVER_DATA(pnd)->abtRx, ACR122_PCSC_RESPONSE_LEN, &dwRxLen) != SCARD_S_SUCCESS) { pnd->last_error = NFC_EIO; return pnd->last_error; } } else { /* * In T=0 mode, we receive an acknoledge from the MCU, in T=1 mode, we * receive the response from the PN532. */ if (SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), abtTxBuf, szTxBuf, NULL, DRIVER_DATA(pnd)->abtRx, &dwRxLen) != SCARD_S_SUCCESS) { pnd->last_error = NFC_EIO; return pnd->last_error; } } if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_T0) { /* * Check the MCU response */ // Make sure we received the byte-count we expected if (dwRxLen != 2) { pnd->last_error = NFC_EIO; return pnd->last_error; } // Check if the operation was successful, so an answer is available if (DRIVER_DATA(pnd)->abtRx[0] == SCARD_OPERATION_ERROR) { pnd->last_error = NFC_EIO; return pnd->last_error; } } else { DRIVER_DATA(pnd)->szRx = dwRxLen; } return NFC_SUCCESS; } static int acr122_pcsc_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szData, int timeout) { // FIXME: timeout is not handled (void) timeout; int len; uint8_t abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 }; if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_T0) { /* * Retrieve the PN532 response. */ DWORD dwRxLen = sizeof(DRIVER_DATA(pnd)->abtRx); abtRxCmd[4] = DRIVER_DATA(pnd)->abtRx[1]; if (SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), abtRxCmd, sizeof(abtRxCmd), NULL, DRIVER_DATA(pnd)->abtRx, &dwRxLen) != SCARD_S_SUCCESS) { pnd->last_error = NFC_EIO; return pnd->last_error; } DRIVER_DATA(pnd)->szRx = dwRxLen; } else { /* * We already have the PN532 answer, it was saved by acr122_pcsc_send(). */ } LOG_HEX(NFC_LOG_GROUP_COM, "RX", DRIVER_DATA(pnd)->abtRx, DRIVER_DATA(pnd)->szRx); // Make sure we have an emulated answer that fits the return buffer if (DRIVER_DATA(pnd)->szRx < 4 || (DRIVER_DATA(pnd)->szRx - 4) > szData) { pnd->last_error = NFC_EIO; return pnd->last_error; } // Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00 len = DRIVER_DATA(pnd)->szRx - 4; memcpy(pbtData, DRIVER_DATA(pnd)->abtRx + 2, len); return len; } char * acr122_pcsc_firmware(nfc_device *pnd) { uint8_t abtGetFw[5] = { 0xFF, 0x00, 0x48, 0x00, 0x00 }; uint32_t uiResult; static char abtFw[11]; DWORD dwFwLen = sizeof(abtFw); memset(abtFw, 0x00, sizeof(abtFw)); if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) { uiResult = SCardControl(DRIVER_DATA(pnd)->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtGetFw, sizeof(abtGetFw), (uint8_t *) abtFw, dwFwLen - 1, &dwFwLen); } else { uiResult = SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), abtGetFw, sizeof(abtGetFw), NULL, (uint8_t *) abtFw, &dwFwLen); } if (uiResult != SCARD_S_SUCCESS) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "No ACR122 firmware received, Error: %08x", uiResult); } return abtFw; } #if 0 bool acr122_pcsc_led_red(nfc_device *pnd, bool bOn) { uint8_t abtLed[9] = { 0xFF, 0x00, 0x40, 0x05, 0x04, 0x00, 0x00, 0x00, 0x00 }; uint8_t abtBuf[2]; DWORD dwBufLen = sizeof(abtBuf); (void) bOn; if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED) { return (SCardControl(DRIVER_DATA(pnd)->hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, abtLed, sizeof(abtLed), abtBuf, dwBufLen, &dwBufLen) == SCARD_S_SUCCESS); } else { return (SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), abtLed, sizeof(abtLed), NULL, abtBuf, &dwBufLen) == SCARD_S_SUCCESS); } } #endif const struct pn53x_io acr122_pcsc_io = { .send = acr122_pcsc_send, .receive = acr122_pcsc_receive, }; const struct nfc_driver acr122_pcsc_driver = { .name = ACR122_PCSC_DRIVER_NAME, .scan = acr122_pcsc_scan, .open = acr122_pcsc_open, .close = acr122_pcsc_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = NULL, // No secure-element support .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = NULL, // Abort is not supported in this driver .idle = pn53x_idle, /* Even if PN532, PowerDown is not recommended on those devices */ .powerdown = NULL, }; libnfc-1.7.1/libnfc/drivers/acr122_pcsc.h000066400000000000000000000025301230265671100200460ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file acr122_pcsc.h * @brief Driver for ACR122 devices (behind PC/SC daemon) */ #ifndef __NFC_DRIVER_ACR122_PCSC_H__ #define __NFC_DRIVER_ACR122_PCSC_H__ #include extern const struct nfc_driver acr122_pcsc_driver; #endif // ! __NFC_DRIVER_ACR122_PCSC_H__ libnfc-1.7.1/libnfc/drivers/acr122_usb.c000066400000000000000000000707451230265671100177170ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file acr122_usb.c * @brief Driver for ACR122 using direct USB (without PCSC) */ /* * This implementation was written based on information provided by the * following documents: * * Smart Card CCID * Specification for Integrated Circuit(s) Cards Interface Devices * Revision 1.1 * April 22rd, 2005 * http://www.usb.org/developers/devclass_docs/DWG_Smart-Card_CCID_Rev110.pdf * * ACR122U NFC Reader * Application Programming Interface * Revision 1.2 * http://acs.com.hk/drivers/eng/API_ACR122U.pdf */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H /* Thanks to d18c7db and Okko for example code */ #include #include #include #include #include #include #include #include "nfc-internal.h" #include "buses/usbbus.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "drivers/acr122_usb.h" #define ACR122_USB_DRIVER_NAME "acr122_usb" #define LOG_GROUP NFC_LOG_GROUP_DRIVER #define LOG_CATEGORY "libnfc.driver.acr122_usb" #define USB_INFINITE_TIMEOUT 0 #define DRIVER_DATA(pnd) ((struct acr122_usb_data*)(pnd->driver_data)) /* USB activity trace for PN533, ACR122 and Touchatag -------------------------------------------------------------------- PN533 0000ff02fe d402 2a00 0000ff00ff00 ACK 0000ff06fa d50333020707 e500 -------------------------------------------------------------------- Acr122U PICC pseudo-APDU through PCSC Escape mechanism: 6b07000000000a000000 ff00000002 d402 PC_to_RDR_Escape APDU Len..... ClInP1P2Lc Slot=0 pseudo-APDU DirectTransmit Seq=0a RFU=000000 8308000000000a028100 d50332010407 9000 RDR_to_PC_Escape SW: OK Len..... Slot=0 Seq=0a Slot Status=02 ?? Slot Error=81 ?? RFU=00 -------------------------------------------------------------------- Touchatag (Acr122U SAM) pseudo-APDU mechanism: 6f07000000000e000000 ff00000002 d402 PC_to_RDR_XfrBlock APDU Len..... ClInP1P2Lc Slot=0 pseudo-APDU DirectTransmit Seq=0e BWI=00 RFU=0000 8002000000000e000000 6108 RDR_to_PC_DataBlock SW: more data: 8 bytes Slot=0 Seq=0e Slot Status=00 Slot Error=00 RFU=00 6f05000000000f000000 ffc0000008 pseudo-ADPU GetResponse 8008000000000f000000 d50332010407 9000 SW: OK -------------------------------------------------------------------- Apparently Acr122U PICC can also work without Escape (even if there is no card): 6f070000000000000000 ff00000002 d402 PC_to_RDR_XfrBlock APDU Len..... ClInP1P2Lc Slot=0 pseudo-APDU DirectTransmit Seq=00 BWI=00 RFU=0000 80080000000000008100 d50332010407 9000 SW: OK */ #pragma pack(1) struct ccid_header { uint8_t bMessageType; uint32_t dwLength; uint8_t bSlot; uint8_t bSeq; uint8_t bMessageSpecific[3]; }; struct apdu_header { uint8_t bClass; uint8_t bIns; uint8_t bP1; uint8_t bP2; uint8_t bLen; }; struct acr122_usb_tama_frame { struct ccid_header ccid_header; struct apdu_header apdu_header; uint8_t tama_header; uint8_t tama_payload[254]; // According to ACR122U manual: Pseudo APDUs (Section 6.0), Lc is 1-byte long (Data In: 255-bytes). }; struct acr122_usb_apdu_frame { struct ccid_header ccid_header; struct apdu_header apdu_header; uint8_t apdu_payload[255]; // APDU Lc is 1-byte long }; #pragma pack() // Internal data struct struct acr122_usb_data { usb_dev_handle *pudh; uint32_t uiEndPointIn; uint32_t uiEndPointOut; uint32_t uiMaxPacketSize; volatile bool abort_flag; // Keep some buffers to reduce memcpy() usage struct acr122_usb_tama_frame tama_frame; struct acr122_usb_apdu_frame apdu_frame; }; // CCID Bulk-Out messages type #define PC_to_RDR_IccPowerOn 0x62 #define PC_to_RDR_XfrBlock 0x6f #define RDR_to_PC_DataBlock 0x80 // ISO 7816-4 #define SW1_More_Data_Available 0x61 #define SW1_Warning_with_NV_changed 0x63 #define PN53x_Specific_Application_Level_Error_Code 0x7f // This frame template is copied at init time // Its designed for TAMA sending but is also used for simple ADPU frame: acr122_build_frame_from_apdu() will overwrite needed bytes const uint8_t acr122_usb_frame_template[] = { PC_to_RDR_XfrBlock, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // CCID header 0xff, 0x00, 0x00, 0x00, 0x00, // ADPU header 0xd4, // PN532 direction }; // APDUs instructions #define APDU_GetAdditionnalData 0xc0 // Internal io struct const struct pn53x_io acr122_usb_io; // Prototypes static int acr122_usb_init(nfc_device *pnd); static int acr122_usb_ack(nfc_device *pnd); static int acr122_usb_send_apdu(nfc_device *pnd, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *const data, size_t data_len, const uint8_t le, uint8_t *out, const size_t out_size); static int acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) { int res = usb_bulk_read(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, timeout); if (res > 0) { LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, res); } else if (res < 0) { if (res != -USB_TIMEDOUT) { res = NFC_EIO; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", _usb_strerror(res)); } else { res = NFC_ETIMEOUT; } } return res; } static int acr122_usb_bulk_write(struct acr122_usb_data *data, uint8_t abtTx[], const size_t szTx, const int timeout) { LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx); int res = usb_bulk_write(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, timeout); if (res > 0) { // HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details if ((res % data->uiMaxPacketSize) == 0) { usb_bulk_write(data->pudh, data->uiEndPointOut, "\0", 0, timeout); } } else if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", _usb_strerror(res)); if (res == -USB_TIMEDOUT) { res = NFC_ETIMEOUT; } else { res = NFC_EIO; } } return res; } struct acr122_usb_supported_device { uint16_t vendor_id; uint16_t product_id; const char *name; }; const struct acr122_usb_supported_device acr122_usb_supported_devices[] = { { 0x072F, 0x2200, "ACS ACR122" }, { 0x072F, 0x90CC, "Touchatag" }, }; // Find transfer endpoints for bulk transfers static void acr122_usb_get_end_points(struct usb_device *dev, struct acr122_usb_data *data) { uint32_t uiIndex; uint32_t uiEndPoint; struct usb_interface_descriptor *puid = dev->config->interface->altsetting; // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out for (uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) { // Only accept bulk transfer endpoints (ignore interrupt endpoints) if (puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue; // Copy the endpoint to a local var, makes it more readable code uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress; // Test if we dealing with a bulk IN endpoint if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) { data->uiEndPointIn = uiEndPoint; data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; } // Test if we dealing with a bulk OUT endpoint if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) { data->uiEndPointOut = uiEndPoint; data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; } } } static size_t acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { (void)context; usb_prepare(); size_t device_found = 0; uint32_t uiBusIndex = 0; struct usb_bus *bus; for (bus = usb_get_busses(); bus; bus = bus->next) { struct usb_device *dev; for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++) { for (size_t n = 0; n < sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); n++) { if ((acr122_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && (acr122_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { // Make sure there are 2 endpoints available // with libusb-win32 we got some null pointers so be robust before looking at endpoints: if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL) { // Nope, we maybe want the next one, let's try to find another continue; } if (dev->config->interface->altsetting->bNumEndpoints < 2) { // Nope, we maybe want the next one, let's try to find another continue; } usb_dev_handle *udev = usb_open(dev); if (udev == NULL) continue; // Set configuration // 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); device_found++; // Test if we reach the maximum "wanted" devices if (device_found == connstrings_len) { return device_found; } } } } } return device_found; } struct acr122_usb_descriptor { char *dirname; char *filename; }; static bool acr122_usb_get_usb_device_name(struct usb_device *dev, usb_dev_handle *udev, char *buffer, size_t len) { *buffer = '\0'; if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { if (udev) { usb_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); if (strlen(buffer) > 0) strcpy(buffer + strlen(buffer), " / "); usb_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer)); } } if (!*buffer) { for (size_t n = 0; n < sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); n++) { if ((acr122_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && (acr122_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { strncpy(buffer, acr122_usb_supported_devices[n].name, len); buffer[len - 1] = '\0'; return true; } } } return false; } static nfc_device * acr122_usb_open(const nfc_context *context, const nfc_connstring connstring) { nfc_device *pnd = NULL; struct acr122_usb_descriptor desc = { NULL, NULL }; int connstring_decode_level = connstring_decode(connstring, ACR122_USB_DRIVER_NAME, "usb", &desc.dirname, &desc.filename); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d element(s) have been decoded from \"%s\"", connstring_decode_level, connstring); if (connstring_decode_level < 1) { goto free_mem; } struct acr122_usb_data data = { .pudh = NULL, .uiEndPointIn = 0, .uiEndPointOut = 0, }; struct usb_bus *bus; struct usb_device *dev; usb_prepare(); for (bus = usb_get_busses(); bus; bus = bus->next) { if (connstring_decode_level > 1) { // A specific bus have been specified if (0 != strcmp(bus->dirname, desc.dirname)) continue; } for (dev = bus->devices; dev; dev = dev->next) { if (connstring_decode_level > 2) { // A specific dev have been specified if (0 != strcmp(dev->filename, desc.filename)) continue; } // Open the USB device if ((data.pudh = usb_open(dev)) == NULL) continue; // Reset device usb_reset(data.pudh); // Retrieve end points acr122_usb_get_end_points(dev, &data); // Claim interface int res = usb_claim_interface(data.pudh, 0); if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", _usb_strerror(res)); usb_close(data.pudh); // we failed to use the specified device 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; } // Allocate memory for the device info and specification, fill it and return the info pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); goto error; } acr122_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name)); pnd->driver_data = malloc(sizeof(struct acr122_usb_data)); if (!pnd->driver_data) { perror("malloc"); goto error; } *DRIVER_DATA(pnd) = data; // Alloc and init chip's data if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) { perror("malloc"); goto error; } memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); memcpy(&(DRIVER_DATA(pnd)->apdu_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); CHIP_DATA(pnd)->timer_correction = 46; // empirical tuning pnd->driver = &acr122_usb_driver; if (acr122_usb_init(pnd) < 0) { usb_close(data.pudh); goto error; } DRIVER_DATA(pnd)->abort_flag = false; goto free_mem; } } // We ran out of devices before the index required goto free_mem; error: // Free allocated structure on error. nfc_device_free(pnd); pnd = NULL; free_mem: free(desc.dirname); free(desc.filename); return pnd; } static void acr122_usb_close(nfc_device *pnd) { acr122_usb_ack(pnd); pn53x_idle(pnd); int res; if ((res = usb_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", _usb_strerror(res)); } if ((res = usb_close(DRIVER_DATA(pnd)->pudh)) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to close USB connection (%s)", _usb_strerror(res)); } pn53x_data_free(pnd); nfc_device_free(pnd); } #if !defined(htole32) uint32_t htole32(uint32_t u32); uint32_t htole32(uint32_t u32) { union { uint8_t arr[4]; uint32_t u32; } u; for (int i = 0; i < 4; i++) { u.arr[i] = (u32 & 0xff); u32 >>= 8; } return u.u32; } #endif /* !defined(htole32) */ static int acr122_build_frame_from_apdu(nfc_device *pnd, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *data, const size_t data_len, const uint8_t le) { if (data_len > sizeof(DRIVER_DATA(pnd)->apdu_frame.apdu_payload)) return NFC_EINVARG; if ((data == NULL) && (data_len != 0)) return NFC_EINVARG; DRIVER_DATA(pnd)->apdu_frame.ccid_header.dwLength = htole32(data_len + sizeof(struct apdu_header)); DRIVER_DATA(pnd)->apdu_frame.apdu_header.bIns = ins; DRIVER_DATA(pnd)->apdu_frame.apdu_header.bP1 = p1; DRIVER_DATA(pnd)->apdu_frame.apdu_header.bP2 = p2; if (data) { // bLen is Lc when data != NULL DRIVER_DATA(pnd)->apdu_frame.apdu_header.bLen = data_len; memcpy(DRIVER_DATA(pnd)->apdu_frame.apdu_payload, data, data_len); } else { // bLen is Le when no data. DRIVER_DATA(pnd)->apdu_frame.apdu_header.bLen = le; } return (sizeof(struct ccid_header) + sizeof(struct apdu_header) + data_len); } static int acr122_build_frame_from_tama(nfc_device *pnd, const uint8_t *tama, const size_t tama_len) { if (tama_len > sizeof(DRIVER_DATA(pnd)->tama_frame.tama_payload)) return NFC_EINVARG; DRIVER_DATA(pnd)->tama_frame.ccid_header.dwLength = htole32(tama_len + sizeof(struct apdu_header) + 1); DRIVER_DATA(pnd)->tama_frame.apdu_header.bLen = tama_len + 1; memcpy(DRIVER_DATA(pnd)->tama_frame.tama_payload, tama, tama_len); return (sizeof(struct ccid_header) + sizeof(struct apdu_header) + 1 + tama_len); } static int acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) { int res; if ((res = acr122_build_frame_from_tama(pnd, pbtData, szData)) < 0) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, timeout)) < 0) { pnd->last_error = res; return pnd->last_error; } return NFC_SUCCESS; } #define USB_TIMEOUT_PER_PASS 200 static int acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) { off_t offset = 0; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; int res; /* * If no timeout is specified but the command is blocking, force a 200ms (USB_TIMEOUT_PER_PASS) * timeout to allow breaking the loop if the user wants to stop it. */ int usb_timeout; int remaining_time = timeout; 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 remaining_time -= USB_TIMEOUT_PER_PASS; if (remaining_time <= 0) { pnd->last_error = NFC_ETIMEOUT; return pnd->last_error; } else { usb_timeout = MIN(remaining_time, USB_TIMEOUT_PER_PASS); } } res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usb_timeout); uint8_t attempted_response = RDR_to_PC_DataBlock; size_t len; if (res == NFC_ETIMEOUT) { if (DRIVER_DATA(pnd)->abort_flag) { DRIVER_DATA(pnd)->abort_flag = false; acr122_usb_ack(pnd); pnd->last_error = NFC_EOPABORTED; return pnd->last_error; } else { goto read; } } if (res < 12) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame"); // try to interrupt current device state acr122_usb_ack(pnd); pnd->last_error = NFC_EIO; return pnd->last_error; } if (abtRxBuf[offset] != attempted_response) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame header mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset++; len = abtRxBuf[offset++]; 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"); pnd->last_error = NFC_EIO; return pnd->last_error; } if (abtRxBuf[10] != SW1_More_Data_Available) { if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == PN53x_Specific_Application_Level_Error_Code)) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 has detected an error at the application level"); } else if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == 0x00)) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 didn't reply"); } else { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unexpected Status Word (SW1: %02x SW2: %02x)", abtRxBuf[10], abtRxBuf[11]); } pnd->last_error = NFC_EIO; return pnd->last_error; } res = acr122_usb_send_apdu(pnd, APDU_GetAdditionnalData, 0x00, 0x00, NULL, 0, abtRxBuf[11], abtRxBuf, sizeof(abtRxBuf)); if (res == NFC_ETIMEOUT) { if (DRIVER_DATA(pnd)->abort_flag) { DRIVER_DATA(pnd)->abort_flag = false; acr122_usb_ack(pnd); pnd->last_error = NFC_EOPABORTED; return pnd->last_error; } else { goto read; // FIXME May cause some trouble on Touchatag, right ? } } if (res < 12) { // try to interrupt current device state acr122_usb_ack(pnd); pnd->last_error = NFC_EIO; return pnd->last_error; } } offset = 0; if (abtRxBuf[offset] != attempted_response) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame header mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset++; // XXX In CCID specification, len is a 32-bits (dword), do we need to decode more than 1 byte ? (0-255 bytes for PN532 reply) len = abtRxBuf[offset++]; if ((abtRxBuf[offset] != 0x00) && (abtRxBuf[offset + 1] != 0x00) && (abtRxBuf[offset + 2] != 0x00)) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not implemented: only 1-byte length is supported, please report this bug with a full trace."); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 3; if (len < 4) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Too small reply"); pnd->last_error = NFC_EIO; return pnd->last_error; } len -= 4; // We skip 2 bytes for PN532 direction byte (D5) and command byte (CMD+1), then 2 bytes for APDU status (90 00). if (len > szDataLen) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); pnd->last_error = NFC_EOVFLOW; return pnd->last_error; } // Skip CCID remaining bytes offset += 2; // bSlot and bSeq are not used offset += 2; // XXX bStatus and bError should maybe checked ? offset += 1; // bRFU should be 0x00 // TFI + PD0 (CC+1) if (abtRxBuf[offset] != 0xD5) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 1; if (abtRxBuf[offset] != CHIP_DATA(pnd)->last_command + 1) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 1; memcpy(pbtData, abtRxBuf + offset, len); return len; } int acr122_usb_ack(nfc_device *pnd) { (void) pnd; int res = 0; uint8_t acr122_ack_frame[] = { GetFirmwareVersion }; // We can't send a PN532's ACK frame, so we use a normal command to cancel current command log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Abort"); if ((res = acr122_build_frame_from_tama(pnd, acr122_ack_frame, sizeof(acr122_ack_frame))) < 0) return res; if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, 1000)) < 0) return res; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000); return res; } static int acr122_usb_send_apdu(nfc_device *pnd, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *const data, size_t data_len, const uint8_t le, uint8_t *out, const size_t out_size) { int res; size_t frame_len = acr122_build_frame_from_apdu(pnd, ins, p1, p2, data, data_len, le); if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->apdu_frame), frame_len, 1000)) < 0) return res; if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), out, out_size, 1000)) < 0) return res; return res; } int acr122_usb_init(nfc_device *pnd) { int res = 0; int i; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; /* // See ACR122 manual: "Bi-Color LED and Buzzer Control" section uint8_t acr122u_get_led_state_frame[] = { 0x6b, // CCID 0x09, // lenght of frame 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding // frame: 0xff, // Class 0x00, // INS 0x40, // P1: Get LED state command 0x00, // P2: LED state control 0x04, // Lc 0x00, 0x00, 0x00, 0x00, // Blinking duration control }; log_put (LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Get LED state"); if ((res = acr122_usb_bulk_write (DRIVER_DATA (pnd), (uint8_t *) acr122u_get_led_state_frame, sizeof (acr122u_get_led_state_frame), 1000)) < 0) return res; if ((res = acr122_usb_bulk_read (DRIVER_DATA (pnd), abtRxBuf, sizeof (abtRxBuf), 1000)) < 0) return res; */ if ((res = pn53x_set_property_int(pnd, NP_TIMEOUT_COMMAND, 1000)) < 0) return res; // Power On ICC uint8_t ccid_frame[] = { PC_to_RDR_IccPowerOn, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 }; if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), ccid_frame, sizeof(struct ccid_header), 1000)) < 0) return res; if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000)) < 0) return res; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 PICC Operating Parameters"); if ((res = acr122_usb_send_apdu(pnd, 0x00, 0x51, 0x00, NULL, 0, 0, abtRxBuf, sizeof(abtRxBuf))) < 0) return res; res = 0; for (i = 0; i < 3; i++) { if (res < 0) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 init failed, trying again..."); if ((res = pn53x_init(pnd)) >= 0) break; } if (res < 0) return res; return NFC_SUCCESS; } static int acr122_usb_abort_command(nfc_device *pnd) { DRIVER_DATA(pnd)->abort_flag = true; return NFC_SUCCESS; } const struct pn53x_io acr122_usb_io = { .send = acr122_usb_send, .receive = acr122_usb_receive, }; const struct nfc_driver acr122_usb_driver = { .name = ACR122_USB_DRIVER_NAME, .scan_type = NOT_INTRUSIVE, .scan = acr122_usb_scan, .open = acr122_usb_open, .close = acr122_usb_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = NULL, // No secure-element support .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = acr122_usb_abort_command, .idle = pn53x_idle, /* Even if PN532, PowerDown is not recommended on those devices */ .powerdown = NULL, }; libnfc-1.7.1/libnfc/drivers/acr122_usb.h000066400000000000000000000025501230265671100177110ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file acr122_usb.h * @brief Driver for ACR122 devices using direct USB connection (without PCSC) */ #ifndef __NFC_DRIVER_ACR122_USB_H__ #define __NFC_DRIVER_ACR122_USB_H__ #include extern const struct nfc_driver acr122_usb_driver; #endif // ! __NFC_DRIVER_ACR122_USB_H__ libnfc-1.7.1/libnfc/drivers/acr122s.c000066400000000000000000000464061230265671100172260ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2011 Anugrah Redja Kusuma * * 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 */ /** * @file acr122s.c * @brief Driver for ACS ACR122S devices */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "acr122s.h" #include #include #include #include #include #include #include "drivers.h" #include "nfc-internal.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "uart.h" #define ACR122S_DEFAULT_SPEED 9600 #define ACR122S_DRIVER_NAME "ACR122S" #define LOG_CATEGORY "libnfc.driver.acr122s" #define LOG_GROUP NFC_LOG_GROUP_DRIVER // Internal data structs struct acr122s_data { serial_port port; uint8_t seq; #ifndef WIN32 int abort_fds[2]; #else volatile bool abort_flag; #endif }; const struct pn53x_io acr122s_io; #define STX 2 #define ETX 3 #define APDU_SIZE(p) ((uint32_t) (p[2] | p[3] << 8 | p[4] << 16 | p[5] << 24)) #define FRAME_OVERHEAD 13 #define FRAME_SIZE(p) (APDU_SIZE(p) + FRAME_OVERHEAD) #define MAX_FRAME_SIZE (FRAME_OVERHEAD + 5 + 255) enum { ICC_POWER_ON_REQ_MSG = 0x62, ICC_POWER_OFF_REQ_MSG = 0x63, XFR_BLOCK_REQ_MSG = 0x6F, ICC_POWER_ON_RES_MSG = 0x80, ICC_POWER_OFF_RES_MSG = 0x81, XFR_BLOCK_RES_MSG = 0x80, }; enum { POWER_AUTO = 0, POWER_5_0_V = 1, POWER_3_0_V = 2, POWER_1_8_V = 3, }; #pragma pack(push, 1) struct icc_power_on_req { uint8_t message_type; uint32_t length; uint8_t slot; uint8_t seq; uint8_t power_select; uint8_t rfu[2]; }; struct icc_power_on_res { uint8_t message_type; uint32_t length; uint8_t slot; uint8_t seq; uint8_t status; uint8_t error; uint8_t chain_parameter; }; struct icc_power_off_req { uint8_t message_type; uint32_t length; uint8_t slot; uint8_t seq; uint8_t rfu[3]; }; struct icc_power_off_res { uint8_t message_type; uint32_t length; uint8_t slot; uint8_t seq; uint8_t status; uint8_t error; uint8_t clock_status; }; struct xfr_block_req { uint8_t message_type; uint32_t length; uint8_t slot; uint8_t seq; uint8_t bwi; uint8_t rfu[2]; }; struct xfr_block_res { uint8_t message_type; uint32_t length; uint8_t slot; uint8_t seq; uint8_t status; uint8_t error; uint8_t chain_parameter; }; struct apdu_header { uint8_t class; uint8_t ins; uint8_t p1; uint8_t p2; uint8_t length; }; #pragma pack(pop) #define DRIVER_DATA(pnd) ((struct acr122s_data *) (pnd->driver_data)) /** * Fix a command frame with a valid prefix, checksum, and suffix. * * @param frame is command frame to fix * @note command frame length (uint32_t at offset 2) should be valid */ static void acr122s_fix_frame(uint8_t *frame) { size_t frame_size = FRAME_SIZE(frame); frame[0] = STX; frame[frame_size - 1] = ETX; uint8_t *csum = frame + frame_size - 2; *csum = 0; for (uint8_t *p = frame + 1; p < csum; p++) *csum ^= *p; } /** * Send a command frame to ACR122S and check its ACK status. * * @param: pnd is target nfc device * @param: cmd is command frame to send * @param: timeout * @return 0 if success */ static int acr122s_send_frame(nfc_device *pnd, uint8_t *frame, int timeout) { size_t frame_size = FRAME_SIZE(frame); uint8_t ack[4]; uint8_t positive_ack[4] = { STX, 0, 0, ETX }; serial_port port = DRIVER_DATA(pnd)->port; int ret; void *abort_p; #ifndef WIN32 abort_p = &(DRIVER_DATA(pnd)->abort_fds[1]); #else abort_p = &(DRIVER_DATA(pnd)->abort_flag); #endif if ((ret = uart_send(port, frame, frame_size, timeout)) < 0) return ret; if ((ret = uart_receive(port, ack, 4, abort_p, timeout)) < 0) return ret; if (memcmp(ack, positive_ack, 4) != 0) { pnd->last_error = NFC_EIO; return pnd->last_error; } struct xfr_block_req *req = (struct xfr_block_req *) &frame[1]; DRIVER_DATA(pnd)->seq = req->seq + 1; return 0; } /** * Receive response frame after a successfull acr122s_send_command(). * * @param: pnd is target nfc device * @param: frame is buffer where received response frame will be stored * @param: frame_size is frame size * @param: abort_p * @param: timeout * @note returned frame size can be fetched using FRAME_SIZE macro * * @return 0 if success */ static int acr122s_recv_frame(nfc_device *pnd, uint8_t *frame, size_t frame_size, void *abort_p, int timeout) { if (frame_size < 13) { pnd->last_error = NFC_EINVARG; return pnd->last_error; } int ret; serial_port port = DRIVER_DATA(pnd)->port; if ((ret = uart_receive(port, frame, 11, abort_p, timeout)) != 0) return ret; // Is buffer sufficient to store response? if (frame_size < FRAME_SIZE(frame)) { pnd->last_error = NFC_EIO; return pnd->last_error; } size_t remaining = FRAME_SIZE(frame) - 11; if ((ret = uart_receive(port, frame + 11, remaining, abort_p, timeout)) != 0) return ret; struct xfr_block_res *res = (struct xfr_block_res *) &frame[1]; if ((uint8_t)(res->seq + 1) != DRIVER_DATA(pnd)->seq) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid response sequence number."); pnd->last_error = NFC_EIO; return pnd->last_error; } return 0; } #define APDU_OVERHEAD (FRAME_OVERHEAD + 5) /** * Convert host uint32 to litle endian uint32 */ static uint32_t le32(uint32_t val) { uint32_t res; uint8_t *p = (uint8_t *) &res; p[0] = val; p[1] = val >> 8; p[2] = val >> 16; p[3] = val >> 24; return res; } /** * Build an ACR122S command frame from a PN532 command. * * @param pnd is device for which the command frame will be generated * @param frame is where the resulting command frame will be generated * @param frame_size is the passed command frame size * @param p1 * @param p2 * @param data is PN532 APDU data without the direction prefix (0xD4) * @param data_size is APDU data size * @param should_prefix 1 if prefix 0xD4 should be inserted before APDU data, 0 if not * * @return true if frame built successfully */ static bool acr122s_build_frame(nfc_device *pnd, uint8_t *frame, size_t frame_size, uint8_t p1, uint8_t p2, const uint8_t *data, size_t data_size, int should_prefix) { if (frame_size < data_size + APDU_OVERHEAD + should_prefix) return false; if (data_size + should_prefix > 255) return false; if (data == NULL) return false; struct xfr_block_req *req = (struct xfr_block_req *) &frame[1]; req->message_type = XFR_BLOCK_REQ_MSG; req->length = le32(5 + data_size + should_prefix); req->slot = 0; req->seq = DRIVER_DATA(pnd)->seq; req->bwi = 0; req->rfu[0] = 0; req->rfu[1] = 0; struct apdu_header *header = (struct apdu_header *) &frame[11]; header->class = 0xff; header->ins = 0; header->p1 = p1; header->p2 = p2; header->length = data_size + should_prefix; uint8_t *buf = (uint8_t *) &frame[16]; if (should_prefix) *buf++ = 0xD4; memcpy(buf, data, data_size); acr122s_fix_frame(frame); return true; } static int acr122s_activate_sam(nfc_device *pnd) { uint8_t cmd[13]; memset(cmd, 0, sizeof(cmd)); cmd[1] = ICC_POWER_ON_REQ_MSG; acr122s_fix_frame(cmd); uint8_t resp[MAX_FRAME_SIZE]; int ret; if ((ret = acr122s_send_frame(pnd, cmd, 0)) != 0) return ret; if ((ret = acr122s_recv_frame(pnd, resp, MAX_FRAME_SIZE, 0, 0)) != 0) return ret; CHIP_DATA(pnd)->power_mode = NORMAL; return 0; } static int acr122s_deactivate_sam(nfc_device *pnd) { uint8_t cmd[13]; memset(cmd, 0, sizeof(cmd)); cmd[1] = ICC_POWER_OFF_REQ_MSG; acr122s_fix_frame(cmd); uint8_t resp[MAX_FRAME_SIZE]; int ret; if ((ret = acr122s_send_frame(pnd, cmd, 0)) != 0) return ret; if ((ret = acr122s_recv_frame(pnd, resp, MAX_FRAME_SIZE, 0, 0)) != 0) return ret; CHIP_DATA(pnd)->power_mode = LOWVBAT; return 0; } static int acr122s_get_firmware_version(nfc_device *pnd, char *version, size_t length) { int ret; uint8_t cmd[MAX_FRAME_SIZE]; if (! acr122s_build_frame(pnd, cmd, sizeof(cmd), 0x48, 0, NULL, 0, 0)) { return NFC_EINVARG; } if ((ret = acr122s_send_frame(pnd, cmd, 1000)) != 0) return ret; if ((ret = acr122s_recv_frame(pnd, cmd, sizeof(cmd), 0, 0)) != 0) return ret; size_t len = APDU_SIZE(cmd); if (len + 1 > length) len = length - 1; memcpy(version, cmd + 11, len); version[len] = 0; return 0; } struct acr122s_descriptor { char *port; uint32_t speed; }; static size_t acr122s_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; serial_port sp; char **acPorts = uart_list_ports(); const char *acPort; int iDevice = 0; while ((acPort = acPorts[iDevice++])) { sp = uart_open(acPort); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find ACR122S device on serial port: %s at %d bauds.", acPort, ACR122S_DEFAULT_SPEED); if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { // We need to flush input to be sure first reply does not comes from older byte transceive uart_flush_input(sp, true); uart_set_speed(sp, ACR122S_DEFAULT_SPEED); nfc_connstring connstring; snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, ACR122S_DRIVER_NAME, acPort, ACR122S_DEFAULT_SPEED); nfc_device *pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); uart_close(sp); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } pnd->driver = &acr122s_driver; pnd->driver_data = malloc(sizeof(struct acr122s_data)); if (!pnd->driver_data) { perror("malloc"); uart_close(sp); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } DRIVER_DATA(pnd)->port = sp; DRIVER_DATA(pnd)->seq = 0; #ifndef WIN32 if (pipe(DRIVER_DATA(pnd)->abort_fds) < 0) { uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif if (pn53x_data_new(pnd, &acr122s_io) == NULL) { perror("malloc"); uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } CHIP_DATA(pnd)->type = PN532; CHIP_DATA(pnd)->power_mode = NORMAL; char version[32]; int ret = acr122s_get_firmware_version(pnd, version, sizeof(version)); if (ret == 0 && strncmp("ACR122S", version, 7) != 0) { ret = -1; } uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); if (ret != 0) continue; // ACR122S reader is found memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring)); device_found++; // Test if we reach the maximum "wanted" devices if (device_found >= connstrings_len) break; } } iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return device_found; } static void acr122s_close(nfc_device *pnd) { acr122s_deactivate_sam(pnd); pn53x_idle(pnd); uart_close(DRIVER_DATA(pnd)->port); #ifndef WIN32 // Release file descriptors used for abort mecanism close(DRIVER_DATA(pnd)->abort_fds[0]); close(DRIVER_DATA(pnd)->abort_fds[1]); #endif pn53x_data_free(pnd); nfc_device_free(pnd); } static nfc_device * acr122s_open(const nfc_context *context, const nfc_connstring connstring) { serial_port sp; nfc_device *pnd; struct acr122s_descriptor ndd; char *speed_s; int connstring_decode_level = connstring_decode(connstring, ACR122S_DRIVER_NAME, NULL, &ndd.port, &speed_s); if (connstring_decode_level == 3) { ndd.speed = 0; if (sscanf(speed_s, "%10"PRIu32, &ndd.speed) != 1) { // speed_s is not a number free(ndd.port); free(speed_s); return NULL; } free(speed_s); } if (connstring_decode_level < 2) { return NULL; } if (connstring_decode_level < 3) { ndd.speed = ACR122S_DEFAULT_SPEED; } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to connect to: %s at %d bauds.", ndd.port, ndd.speed); sp = uart_open(ndd.port); if (sp == INVALID_SERIAL_PORT) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", ndd.port); free(ndd.port); return NULL; } if (sp == CLAIMED_SERIAL_PORT) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", ndd.port); free(ndd.port); return NULL; } uart_flush_input(sp, true); uart_set_speed(sp, ndd.speed); pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); free(ndd.port); uart_close(sp); return NULL; } pnd->driver = &acr122s_driver; strcpy(pnd->name, ACR122S_DRIVER_NAME); free(ndd.port); pnd->driver_data = malloc(sizeof(struct acr122s_data)); if (!pnd->driver_data) { perror("malloc"); uart_close(sp); nfc_device_free(pnd); return NULL; } DRIVER_DATA(pnd)->port = sp; DRIVER_DATA(pnd)->seq = 0; #ifndef WIN32 if (pipe(DRIVER_DATA(pnd)->abort_fds) < 0) { uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); return NULL; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif if (pn53x_data_new(pnd, &acr122s_io) == NULL) { perror("malloc"); uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); return NULL; } CHIP_DATA(pnd)->type = PN532; #if 1 // Retrieve firmware version char version[DEVICE_NAME_LENGTH]; if (acr122s_get_firmware_version(pnd, version, sizeof(version)) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Cannot get reader firmware."); acr122s_close(pnd); return NULL; } if (strncmp(version, "ACR122S", 7) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid firmware version: %s", version); acr122s_close(pnd); return NULL; } snprintf(pnd->name, sizeof(pnd->name), "%s", version); // Activate SAM before operating if (acr122s_activate_sam(pnd) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Cannot activate SAM."); acr122s_close(pnd); return NULL; } #endif if (pn53x_init(pnd) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Failed initializing PN532 chip."); acr122s_close(pnd); return NULL; } return pnd; } static int acr122s_send(nfc_device *pnd, const uint8_t *buf, const size_t buf_len, int timeout) { uart_flush_input(DRIVER_DATA(pnd)->port, false); uint8_t cmd[MAX_FRAME_SIZE]; if (! acr122s_build_frame(pnd, cmd, sizeof(cmd), 0, 0, buf, buf_len, 1)) { return NFC_EINVARG; } int ret; if ((ret = acr122s_send_frame(pnd, cmd, timeout)) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); pnd->last_error = ret; return pnd->last_error; } return NFC_SUCCESS; } static int acr122s_receive(nfc_device *pnd, uint8_t *buf, size_t buf_len, int timeout) { void *abort_p; #ifndef WIN32 abort_p = &(DRIVER_DATA(pnd)->abort_fds[1]); #else abort_p = &(DRIVER_DATA(pnd)->abort_flag); #endif uint8_t tmp[MAX_FRAME_SIZE]; pnd->last_error = acr122s_recv_frame(pnd, tmp, sizeof(tmp), abort_p, timeout); if (abort_p && (NFC_EOPABORTED == pnd->last_error)) { pnd->last_error = NFC_EOPABORTED; return pnd->last_error; } if (pnd->last_error < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); return -1; } size_t data_len = FRAME_SIZE(tmp) - 17; if (data_len > buf_len) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Receive buffer too small. (buf_len: %" PRIuPTR ", data_len: %" PRIuPTR ")", buf_len, data_len); pnd->last_error = NFC_EIO; return pnd->last_error; } memcpy(buf, tmp + 13, data_len); return data_len; } static int acr122s_abort_command(nfc_device *pnd) { if (pnd) { #ifndef WIN32 close(DRIVER_DATA(pnd)->abort_fds[0]); close(DRIVER_DATA(pnd)->abort_fds[1]); if (pipe(DRIVER_DATA(pnd)->abort_fds) < 0) { return NFC_ESOFT; } #else DRIVER_DATA(pnd)->abort_flag = true; #endif } return NFC_SUCCESS; } const struct pn53x_io acr122s_io = { .send = acr122s_send, .receive = acr122s_receive, }; const struct nfc_driver acr122s_driver = { .name = ACR122S_DRIVER_NAME, .scan_type = INTRUSIVE, .scan = acr122s_scan, .open = acr122s_open, .close = acr122s_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = NULL, // No secure-element support .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = acr122s_abort_command, .idle = pn53x_idle, /* Even if PN532, PowerDown is not recommended on those devices */ .powerdown = NULL, }; libnfc-1.7.1/libnfc/drivers/acr122s.h000066400000000000000000000024251230265671100172240ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file acr122s.h * @brief Driver for ACS ACR122S devices */ #ifndef __NFC_DRIVER_ACR122S_H__ #define __NFC_DRIVER_ACR122S_H__ #include extern const struct nfc_driver acr122s_driver; #endif libnfc-1.7.1/libnfc/drivers/arygon.c000066400000000000000000000476251230265671100173540ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file arygon.c * @brief ARYGON readers driver * * This driver can handle ARYGON readers that use UART as bus. * UART connection can be direct (host<->arygon_uc) or could be provided by internal USB to serial interface (e.g. host<->ftdi_chip<->arygon_uc) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "arygon.h" #include #include #include #include #include #include #include "drivers.h" #include "nfc-internal.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "uart.h" /** @def DEV_ARYGON_PROTOCOL_ARYGON_ASCII * @brief High level language in ASCII format. (Common µC commands and Mifare® commands) */ #define DEV_ARYGON_PROTOCOL_ARYGON_ASCII '0' /** @def DEV_ARYGON_MODE_HL_ASCII * @brief High level language in Binary format With AddressingByte for party line. (Common µC commands and Mifare® commands) */ #define DEV_ARYGON_PROTOCOL_ARYGON_BINARY_WAB '1' /** @def DEV_ARYGON_PROTOCOL_TAMA * @brief Philips protocol (TAMA language) in binary format. */ #define DEV_ARYGON_PROTOCOL_TAMA '2' /** @def DEV_ARYGON_PROTOCOL_TAMA_WAB * @brief Philips protocol (TAMA language) in binary With AddressingByte for party line. */ #define DEV_ARYGON_PROTOCOL_TAMA_WAB '3' #define ARYGON_DEFAULT_SPEED 9600 #define ARYGON_DRIVER_NAME "arygon" #define LOG_CATEGORY "libnfc.driver.arygon" #define LOG_GROUP NFC_LOG_GROUP_DRIVER #define DRIVER_DATA(pnd) ((struct arygon_data*)(pnd->driver_data)) // Internal data structs const struct pn53x_io arygon_tama_io; struct arygon_data { serial_port port; #ifndef WIN32 int iAbortFds[2]; #else volatile bool abort_flag; #endif }; // ARYGON frames static const uint8_t arygon_error_none[] = "FF000000\x0d\x0a"; static const uint8_t arygon_error_incomplete_command[] = "FF0C0000\x0d\x0a"; static const uint8_t arygon_error_unknown_mode[] = "FF060000\x0d\x0a"; // Prototypes int arygon_reset_tama(nfc_device *pnd); void arygon_firmware(nfc_device *pnd, char *str); static size_t arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; serial_port sp; char **acPorts = uart_list_ports(); const char *acPort; int iDevice = 0; while ((acPort = acPorts[iDevice++])) { sp = uart_open(acPort); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find ARYGON device on serial port: %s at %d bauds.", acPort, ARYGON_DEFAULT_SPEED); if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { // We need to flush input to be sure first reply does not comes from older byte transceive uart_flush_input(sp, true); uart_set_speed(sp, ARYGON_DEFAULT_SPEED); nfc_connstring connstring; snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, ARYGON_DRIVER_NAME, acPort, ARYGON_DEFAULT_SPEED); nfc_device *pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); uart_close(sp); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } pnd->driver = &arygon_driver; pnd->driver_data = malloc(sizeof(struct arygon_data)); if (!pnd->driver_data) { perror("malloc"); uart_close(sp); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data if (pn53x_data_new(pnd, &arygon_tama_io) == NULL) { perror("malloc"); uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } #ifndef WIN32 // pipe-based abort mecanism if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif int res = arygon_reset_tama(pnd); uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); if (res < 0) { continue; } // ARYGON reader is found memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring)); device_found++; // Test if we reach the maximum "wanted" devices if (device_found >= connstrings_len) break; } } iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return device_found; } struct arygon_descriptor { char *port; uint32_t speed; }; static void arygon_close_step2(nfc_device *pnd) { // Release UART port uart_close(DRIVER_DATA(pnd)->port); #ifndef WIN32 // Release file descriptors used for abort mecanism close(DRIVER_DATA(pnd)->iAbortFds[0]); close(DRIVER_DATA(pnd)->iAbortFds[1]); #endif pn53x_data_free(pnd); nfc_device_free(pnd); } static void arygon_close(nfc_device *pnd) { pn53x_idle(pnd); arygon_close_step2(pnd); } static nfc_device * arygon_open(const nfc_context *context, const nfc_connstring connstring) { struct arygon_descriptor ndd; char *speed_s; int connstring_decode_level = connstring_decode(connstring, ARYGON_DRIVER_NAME, NULL, &ndd.port, &speed_s); if (connstring_decode_level == 3) { ndd.speed = 0; if (sscanf(speed_s, "%10"PRIu32, &ndd.speed) != 1) { // speed_s is not a number free(ndd.port); free(speed_s); return NULL; } free(speed_s); } if (connstring_decode_level < 2) { return NULL; } if (connstring_decode_level < 3) { ndd.speed = ARYGON_DEFAULT_SPEED; } serial_port sp; nfc_device *pnd = NULL; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d bauds.", ndd.port, ndd.speed); sp = uart_open(ndd.port); if (sp == INVALID_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", ndd.port); if (sp == CLAIMED_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", ndd.port); if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) { free(ndd.port); return NULL; } // We need to flush input to be sure first reply does not comes from older byte transceive uart_flush_input(sp, true); uart_set_speed(sp, ndd.speed); // We have a connection pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); free(ndd.port); uart_close(sp); return NULL; } snprintf(pnd->name, sizeof(pnd->name), "%s:%s", ARYGON_DRIVER_NAME, ndd.port); free(ndd.port); pnd->driver_data = malloc(sizeof(struct arygon_data)); if (!pnd->driver_data) { perror("malloc"); uart_close(sp); nfc_device_free(pnd); return NULL; } DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data if (pn53x_data_new(pnd, &arygon_tama_io) == NULL) { perror("malloc"); uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); return NULL; } // The PN53x chip opened to ARYGON MCU doesn't seems to be in LowVBat mode CHIP_DATA(pnd)->power_mode = NORMAL; // empirical tuning CHIP_DATA(pnd)->timer_correction = 46; pnd->driver = &arygon_driver; #ifndef WIN32 // pipe-based abort mecanism if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); return NULL; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif // Check communication using "Reset TAMA" command if (arygon_reset_tama(pnd) < 0) { arygon_close_step2(pnd); return NULL; } char arygon_firmware_version[10]; arygon_firmware(pnd, arygon_firmware_version); char *pcName; pcName = strdup(pnd->name); snprintf(pnd->name, sizeof(pnd->name), "%s %s", pcName, arygon_firmware_version); free(pcName); pn53x_init(pnd); return pnd; } #define ARYGON_TX_BUFFER_LEN (PN53x_NORMAL_FRAME__DATA_MAX_LEN + PN53x_NORMAL_FRAME__OVERHEAD + 1) #define ARYGON_RX_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD) static int arygon_tama_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout) { int res = 0; // Before sending anything, we need to discard from any junk bytes uart_flush_input(DRIVER_DATA(pnd)->port, false); uint8_t abtFrame[ARYGON_TX_BUFFER_LEN] = { DEV_ARYGON_PROTOCOL_TAMA, 0x00, 0x00, 0xff }; // Every packet must start with "0x32 0x00 0x00 0xff" size_t szFrame = 0; if (szData > PN53x_NORMAL_FRAME__DATA_MAX_LEN) { // ARYGON Reader with PN532 equipped does not support extended frame (bug in ARYGON firmware?) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ARYGON device does not support more than %d bytes as payload (requested: %" PRIdPTR ")", PN53x_NORMAL_FRAME__DATA_MAX_LEN, szData); pnd->last_error = NFC_EDEVNOTSUPP; return pnd->last_error; } if ((res = pn53x_build_frame(abtFrame + 1, &szFrame, pbtData, szData)) < 0) { pnd->last_error = res; return pnd->last_error; } if ((res = uart_send(DRIVER_DATA(pnd)->port, abtFrame, szFrame + 1, timeout)) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); pnd->last_error = res; return pnd->last_error; } uint8_t abtRxBuf[PN53x_ACK_FRAME__LEN]; if ((res = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, sizeof(abtRxBuf), 0, timeout)) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to read ACK"); pnd->last_error = res; return pnd->last_error; } if (pn53x_check_ack_frame(pnd, abtRxBuf, sizeof(abtRxBuf)) == 0) { // The PN53x is running the sent command } else if (0 == memcmp(arygon_error_unknown_mode, abtRxBuf, sizeof(abtRxBuf))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Bad frame format."); // We have already read 6 bytes and arygon_error_unknown_mode is 10 bytes long // so we have to read 4 remaining bytes to be synchronized at the next receiving pass. pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 4, 0, timeout); return pnd->last_error; } else { return pnd->last_error; } return NFC_SUCCESS; } static int arygon_abort(nfc_device *pnd) { // Send a valid TAMA packet to wakup the PN53x (we will not have an answer, according to Arygon manual) uint8_t dummy[] = { 0x32, 0x00, 0x00, 0xff, 0x09, 0xf7, 0xd4, 0x00, 0x00, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0xbe, 0x00 }; uart_send(DRIVER_DATA(pnd)->port, dummy, sizeof(dummy), 0); // Using Arygon device we can't send ACK frame to abort the running command return pn53x_check_communication(pnd); } static int arygon_tama_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout) { uint8_t abtRxBuf[5]; size_t len; void *abort_p = NULL; #ifndef WIN32 abort_p = &(DRIVER_DATA(pnd)->iAbortFds[1]); #else abort_p = (void *) & (DRIVER_DATA(pnd)->abort_flag); #endif pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 5, abort_p, timeout); if (abort_p && (NFC_EOPABORTED == pnd->last_error)) { arygon_abort(pnd); /* last_error got reset by arygon_abort() */ pnd->last_error = NFC_EOPABORTED; return pnd->last_error; } if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); return pnd->last_error; } const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } if ((0x01 == abtRxBuf[3]) && (0xff == abtRxBuf[4])) { // Error frame uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 3, 0, timeout); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected"); pnd->last_error = NFC_EIO; return pnd->last_error; } else if ((0xff == abtRxBuf[3]) && (0xff == abtRxBuf[4])) { // Extended frame // ARYGON devices does not support extended frame sending abort(); } else { // Normal frame if (256 != (abtRxBuf[3] + abtRxBuf[4])) { // TODO: Retry log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } // abtRxBuf[3] (LEN) include TFI + (CC+1) len = abtRxBuf[3] - 2; } if (len > szDataLen) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); pnd->last_error = NFC_EIO; return pnd->last_error; } // TFI + PD0 (CC+1) pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); return pnd->last_error; } if (abtRxBuf[0] != 0xD5) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } if (abtRxBuf[1] != CHIP_DATA(pnd)->last_command + 1) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed"); pnd->last_error = NFC_EIO; return pnd->last_error; } if (len) { pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, pbtData, len, 0, timeout); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); return pnd->last_error; } } pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); return pnd->last_error; } uint8_t btDCS = (256 - 0xD5); btDCS -= CHIP_DATA(pnd)->last_command + 1; for (size_t szPos = 0; szPos < len; szPos++) { btDCS -= pbtData[szPos]; } if (btDCS != abtRxBuf[0]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } if (0x00 != abtRxBuf[1]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } // The PN53x command is done and we successfully received the reply return len; } void arygon_firmware(nfc_device *pnd, char *str) { const uint8_t arygon_firmware_version_cmd[] = { DEV_ARYGON_PROTOCOL_ARYGON_ASCII, 'a', 'v' }; uint8_t abtRx[16]; size_t szRx = sizeof(abtRx); int res = uart_send(DRIVER_DATA(pnd)->port, arygon_firmware_version_cmd, sizeof(arygon_firmware_version_cmd), 0); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to send ARYGON firmware command."); return; } res = uart_receive(DRIVER_DATA(pnd)->port, abtRx, szRx, 0, 0); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to retrieve ARYGON firmware version."); return; } if (0 == memcmp(abtRx, arygon_error_none, 6)) { uint8_t *p = abtRx + 6; unsigned int szData; sscanf((const char *)p, "%02x%9s", &szData, p); if (szData > 9) szData = 9; memcpy(str, p, szData); *(str + szData) = '\0'; } } int arygon_reset_tama(nfc_device *pnd) { const uint8_t arygon_reset_tama_cmd[] = { DEV_ARYGON_PROTOCOL_ARYGON_ASCII, 'a', 'r' }; uint8_t abtRx[10]; // Attempted response is 10 bytes long size_t szRx = sizeof(abtRx); int res; uart_send(DRIVER_DATA(pnd)->port, arygon_reset_tama_cmd, sizeof(arygon_reset_tama_cmd), 500); // Two reply are possible from ARYGON device: arygon_error_none (ie. in case the byte is well-sent) // or arygon_error_unknown_mode (ie. in case of the first byte was bad-transmitted) res = uart_receive(DRIVER_DATA(pnd)->port, abtRx, szRx, 0, 1000); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "No reply to 'reset TAMA' command."); pnd->last_error = res; return pnd->last_error; } if (0 != memcmp(abtRx, arygon_error_none, sizeof(arygon_error_none) - 1)) { pnd->last_error = NFC_EIO; return pnd->last_error; } return NFC_SUCCESS; } static int arygon_abort_command(nfc_device *pnd) { if (pnd) { #ifndef WIN32 close(DRIVER_DATA(pnd)->iAbortFds[0]); if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { return NFC_ESOFT; } #else DRIVER_DATA(pnd)->abort_flag = true; #endif } return NFC_SUCCESS; } const struct pn53x_io arygon_tama_io = { .send = arygon_tama_send, .receive = arygon_tama_receive, }; const struct nfc_driver arygon_driver = { .name = ARYGON_DRIVER_NAME, .scan_type = INTRUSIVE, .scan = arygon_scan, .open = arygon_open, .close = arygon_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = NULL, // No secure-element support .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = arygon_abort_command, .idle = pn53x_idle, /* Even if PN532, PowerDown is not recommended on those devices */ .powerdown = NULL, }; libnfc-1.7.1/libnfc/drivers/arygon.h000066400000000000000000000025141230265671100173450ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file arygon.h * @brief Driver for PN53x-equipped ARYGON device connected using UART */ #ifndef __NFC_DRIVER_ARYGON_H__ #define __NFC_DRIVER_ARYGON_H__ #include extern const struct nfc_driver arygon_driver; #endif // ! __NFC_DRIVER_ARYGON_H__ libnfc-1.7.1/libnfc/drivers/pn532_i2c.c000066400000000000000000000450661230265671100174560ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Laurent Latil * * 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 */ /** * @file pn532_i2c.c * @brief PN532 driver using I2C bus. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "pn532_i2c.h" #include #include #include #include #include #include #include #include "drivers.h" #include "nfc-internal.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "buses/i2c.h" #define PN532_I2C_DRIVER_NAME "pn532_i2c" #define LOG_CATEGORY "libnfc.driver.pn532_i2c" #define LOG_GROUP NFC_LOG_GROUP_DRIVER // I2C address of the PN532 chip. #define PN532_I2C_ADDR 0x24 // Internal data structs const struct pn53x_io pn532_i2c_io; struct pn532_i2c_data { i2c_device dev; volatile bool abort_flag; }; /* Delay for the loop waiting for READY frame (in ms) */ #define PN532_RDY_LOOP_DELAY 90 const struct timespec rdyDelay = { .tv_sec = 0, .tv_nsec = PN532_RDY_LOOP_DELAY * 1000 * 1000 }; /* Private Functions Prototypes */ static nfc_device *pn532_i2c_open(const nfc_context *context, const nfc_connstring connstring); static void pn532_i2c_close(nfc_device *pnd); static int pn532_i2c_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout); static int pn532_i2c_ack(nfc_device *pnd); static int pn532_i2c_abort_command(nfc_device *pnd); static int pn532_i2c_wakeup(nfc_device *pnd); static int pn532_i2c_wait_rdyframe(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout); static size_t pn532_i2c_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len); #define DRIVER_DATA(pnd) ((struct pn532_i2c_data*)(pnd->driver_data)) /** * @brief Scan all available I2C buses to find PN532 devices. * * @param context NFC context. * @param connstrings array of 'nfc_connstring' buffer (allocated by caller). It is used to store the * connection info strings of all I2C PN532 devices found. * @param connstrings_len length of the connstrings array. * @return number of PN532 devices found on all I2C buses. */ static size_t pn532_i2c_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; i2c_device id; char **i2cPorts = i2c_list_ports(); const char *i2cPort; int iDevice = 0; while ((i2cPort = i2cPorts[iDevice++])) { id = i2c_open(i2cPort, PN532_I2C_ADDR); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find PN532 device on I2C bus %s.", i2cPort); if ((id != INVALID_I2C_ADDRESS) && (id != INVALID_I2C_BUS)) { nfc_connstring connstring; snprintf(connstring, sizeof(nfc_connstring), "%s:%s", PN532_I2C_DRIVER_NAME, i2cPort); nfc_device *pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); i2c_close(id); iDevice = 0; while ((i2cPort = i2cPorts[iDevice++])) { free((void *)i2cPort); } free(i2cPorts); return 0; } pnd->driver = &pn532_i2c_driver; pnd->driver_data = malloc(sizeof(struct pn532_i2c_data)); if (!pnd->driver_data) { perror("malloc"); i2c_close(id); nfc_device_free(pnd); iDevice = 0; while ((i2cPort = i2cPorts[iDevice++])) { free((void *)i2cPort); } free(i2cPorts); return 0; } DRIVER_DATA(pnd)->dev = id; // Alloc and init chip's data if (pn53x_data_new(pnd, &pn532_i2c_io) == NULL) { perror("malloc"); i2c_close(DRIVER_DATA(pnd)->dev); nfc_device_free(pnd); iDevice = 0; while ((i2cPort = i2cPorts[iDevice++])) { free((void *)i2cPort); } free(i2cPorts); return 0; } // SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532 CHIP_DATA(pnd)->type = PN532; // This device starts in LowVBat power mode CHIP_DATA(pnd)->power_mode = LOWVBAT; DRIVER_DATA(pnd)->abort_flag = false; // Check communication using "Diagnose" command, with "Communication test" (0x00) int res = pn53x_check_communication(pnd); i2c_close(DRIVER_DATA(pnd)->dev); pn53x_data_free(pnd); nfc_device_free(pnd); if (res < 0) { continue; } memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring)); device_found++; // Test if we reach the maximum "wanted" devices if (device_found >= connstrings_len) break; } } iDevice = 0; while ((i2cPort = i2cPorts[iDevice++])) { free((void *)i2cPort); } free(i2cPorts); return device_found; } /** * @brief Close I2C connection to the PN532 device. * * @param pnd pointer on the device to close. */ static void pn532_i2c_close(nfc_device *pnd) { pn53x_idle(pnd); i2c_close(DRIVER_DATA(pnd)->dev); pn53x_data_free(pnd); nfc_device_free(pnd); } /** * @brief Open an I2C connection to the PN532 device. * * @param context NFC context. * @param connstring connection info to the device ( pn532_i2c: ). * @return pointer to the device, or NULL in case of error. */ static nfc_device * pn532_i2c_open(const nfc_context *context, const nfc_connstring connstring) { char *i2c_devname; i2c_device i2c_dev; nfc_device *pnd; int connstring_decode_level = connstring_decode(connstring, PN532_I2C_DRIVER_NAME, NULL, &i2c_devname, NULL); switch (connstring_decode_level) { case 2: break; case 1: break; case 0: return NULL; } i2c_dev = i2c_open(i2c_devname, PN532_I2C_ADDR); if (i2c_dev == INVALID_I2C_BUS || i2c_dev == INVALID_I2C_ADDRESS) { return NULL; } pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); i2c_close(i2c_dev); return NULL; } snprintf(pnd->name, sizeof(pnd->name), "%s:%s", PN532_I2C_DRIVER_NAME, i2c_devname); pnd->driver_data = malloc(sizeof(struct pn532_i2c_data)); if (!pnd->driver_data) { perror("malloc"); i2c_close(i2c_dev); nfc_device_free(pnd); return NULL; } DRIVER_DATA(pnd)->dev = i2c_dev; // Alloc and init chip's data if (pn53x_data_new(pnd, &pn532_i2c_io) == NULL) { perror("malloc"); i2c_close(i2c_dev); nfc_device_free(pnd); return NULL; } // SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532 CHIP_DATA(pnd)->type = PN532; // This device starts in LowVBat mode CHIP_DATA(pnd)->power_mode = LOWVBAT; // empirical tuning CHIP_DATA(pnd)->timer_correction = 48; pnd->driver = &pn532_i2c_driver; DRIVER_DATA(pnd)->abort_flag = false; // Check communication using "Diagnose" command, with "Communication test" (0x00) if (pn53x_check_communication(pnd) < 0) { nfc_perror(pnd, "pn53x_check_communication"); pn532_i2c_close(pnd); return NULL; } pn53x_init(pnd); return pnd; } static int pn532_i2c_wakeup(nfc_device *pnd) { /* No specific. PN532 holds SCL during wakeup time */ CHIP_DATA(pnd)->power_mode = NORMAL; // PN532 should now be awake return NFC_SUCCESS; } #define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD) /** * @brief Send data to the PN532 device. * * @param pnd pointer on the NFC device. * @param pbtData buffer containing frame data. * @param szData size of the buffer. * @param timeout timeout before aborting the operation (in ms). * @return NFC_SUCCESS if operation is successful, or error code. */ static int pn532_i2c_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout) { int res = 0; // Discard any existing data ? switch (CHIP_DATA(pnd)->power_mode) { case LOWVBAT: { /** PN532C106 wakeup. */ if ((res = pn532_i2c_wakeup(pnd)) < 0) { return res; } // According to PN532 application note, C106 appendix: to go out Low Vbat mode and enter in normal mode we need to send a SAMConfiguration command if ((res = pn532_SAMConfiguration(pnd, PSM_NORMAL, 1000)) < 0) { return res; } } break; case POWERDOWN: { if ((res = pn532_i2c_wakeup(pnd)) < 0) { return res; } } break; case NORMAL: // Nothing to do :) break; }; uint8_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" size_t szFrame = 0; if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) { pnd->last_error = res; return pnd->last_error; } res = i2c_write(DRIVER_DATA(pnd)->dev, abtFrame, szFrame); if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); pnd->last_error = res; return pnd->last_error; } uint8_t abtRxBuf[PN53x_ACK_FRAME__LEN]; // Wait for the ACK frame res = pn532_i2c_wait_rdyframe(pnd, abtRxBuf, sizeof(abtRxBuf), timeout); if (res < 0) { if (res == NFC_EOPABORTED) { // Send an ACK frame from host to abort the command. pn532_i2c_ack(pnd); } pnd->last_error = res; return pnd->last_error; } if (pn53x_check_ack_frame(pnd, abtRxBuf, res) == 0) { // The PN53x is running the sent command } else { return pnd->last_error; } return NFC_SUCCESS; } /** * @brief Read data from the PN532 device until getting a frame with RDY bit set * * @param pnd pointer on the NFC device. * @param pbtData buffer used to store the received frame data. * @param szDataLen allocated size of buffer. * @param timeout timeout delay before aborting the operation (in ms). Use 0 for no timeout. * @return length (in bytes) of the received frame, or NFC_ETIMEOUT if timeout delay has expired, * NFC_EOPABORTED if operation has been aborted, NFC_EIO in case of IO failure */ static int pn532_i2c_wait_rdyframe(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout) { bool done = false; int res; struct timeval start_tv, cur_tv; long long duration; // Actual I2C response frame includes an additional status byte, // so we use a temporary buffer to read the I2C frame uint8_t i2cRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN + 1]; if (timeout > 0) { // If a timeout is specified, get current timestamp gettimeofday(&start_tv, NULL); } do { // Wait a little bit before reading nanosleep(&rdyDelay, (struct timespec *) NULL); int recCount = i2c_read(DRIVER_DATA(pnd)->dev, i2cRx, szDataLen + 1); if (DRIVER_DATA(pnd)->abort_flag) { // Reset abort flag DRIVER_DATA(pnd)->abort_flag = false; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Wait for a READY frame has been aborted."); return NFC_EOPABORTED; } if (recCount <= 0) { done = true; res = NFC_EIO; } else { const uint8_t rdy = i2cRx[0]; if (rdy & 1) { int copyLength; done = true; res = recCount - 1; copyLength = MIN(res, (int)szDataLen); memcpy(pbtData, &(i2cRx[1]), copyLength); } else { /* Not ready yet. Check for elapsed timeout. */ if (timeout > 0) { gettimeofday(&cur_tv, NULL); duration = (cur_tv.tv_sec - start_tv.tv_sec) * 1000000L + (cur_tv.tv_usec - start_tv.tv_usec); if (duration / 1000 > timeout) { res = NFC_ETIMEOUT; done = true; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout reached with no READY frame."); } } } } } while (!done); return res; } /** * @brief Read a response frame from the PN532 device. * * @param pnd pointer on the NFC device. * @param pbtData buffer used to store the response frame data. * @param szDataLen allocated size of buffer. * @param timeout timeout delay before aborting the operation (in ms). Use 0 for no timeout. * @return length (in bytes) of the response, or NFC_ETIMEOUT if timeout delay has expired, * NFC_EOPABORTED if operation has been aborted, NFC_EIO in case of IO failure */ static int pn532_i2c_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout) { uint8_t frameBuf[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; int frameLength; int TFI_idx; size_t len; frameLength = pn532_i2c_wait_rdyframe(pnd, frameBuf, sizeof(frameBuf), timeout); if (NFC_EOPABORTED == pnd->last_error) { return pn532_i2c_ack(pnd); } if (frameLength < 0) { goto error; } const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; if (0 != (memcmp(frameBuf, pn53x_preamble, 3))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); pnd->last_error = NFC_EIO; goto error; } if ((0x01 == frameBuf[3]) && (0xff == frameBuf[4])) { uint8_t errorCode = frameBuf[5]; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Application level error detected (%d)", errorCode); pnd->last_error = NFC_EIO; goto error; } else if ((0xff == frameBuf[3]) && (0xff == frameBuf[4])) { // Extended frame len = (frameBuf[5] << 8) + frameBuf[6]; // Verify length checksum if (((frameBuf[5] + frameBuf[6] + frameBuf[7]) % 256) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Length checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } TFI_idx = 8; } else { // Normal frame len = frameBuf[3]; // Verify length checksum if ((uint8_t)(frameBuf[3] + frameBuf[4])) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } TFI_idx = 5; } if ((len - 2) > szDataLen) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); pnd->last_error = NFC_EIO; goto error; } uint8_t TFI = frameBuf[TFI_idx]; if (TFI != 0xD5) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); pnd->last_error = NFC_EIO; goto error; } if (frameBuf[TFI_idx + 1] != CHIP_DATA(pnd)->last_command + 1) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Command Code verification failed. (got %d, expected %d)", frameBuf[TFI_idx + 1], CHIP_DATA(pnd)->last_command + 1); pnd->last_error = NFC_EIO; goto error; } uint8_t DCS = frameBuf[TFI_idx + len]; uint8_t btDCS = DCS; // Compute data checksum for (size_t i = 0; i < len; i++) { btDCS += frameBuf[TFI_idx + i]; } if (btDCS != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Data checksum mismatch (DCS = %02x, btDCS = %d)", DCS, btDCS); pnd->last_error = NFC_EIO; goto error; } if (0x00 != frameBuf[TFI_idx + len + 1]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Frame postamble mismatch (got %d)", frameBuf[frameLength - 1]); pnd->last_error = NFC_EIO; goto error; } memcpy(pbtData, &frameBuf[TFI_idx + 2], len - 2); /* The PN53x command is done and we successfully received the reply */ return len - 2; error: return pnd->last_error; } /** * @brief Send an ACK frame to the PN532 device. * * @param pnd pointer on the NFC device. * @return NFC_SUCCESS on success, otherwise an error code */ int pn532_i2c_ack(nfc_device *pnd) { return i2c_write(DRIVER_DATA(pnd)->dev, pn53x_ack_frame, sizeof(pn53x_ack_frame)); } /** * @brief Abort any pending operation * * @param pnd pointer on the NFC device. * @return NFC_SUCCESS */ static int pn532_i2c_abort_command(nfc_device *pnd) { if (pnd) { DRIVER_DATA(pnd)->abort_flag = true; } return NFC_SUCCESS; } const struct pn53x_io pn532_i2c_io = { .send = pn532_i2c_send, .receive = pn532_i2c_receive, }; const struct nfc_driver pn532_i2c_driver = { .name = PN532_I2C_DRIVER_NAME, .scan_type = INTRUSIVE, .scan = pn532_i2c_scan, .open = pn532_i2c_open, .close = pn532_i2c_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = pn532_initiator_init_secure_element, .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = pn532_i2c_abort_command, .idle = pn53x_idle, .powerdown = pn53x_PowerDown, }; libnfc-1.7.1/libnfc/drivers/pn532_i2c.h000066400000000000000000000026271230265671100174570ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Laurent Latil * * 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 */ /** * @file pn532_i2c.h * @brief Driver for PN532 connected through I2C bus */ #ifndef __NFC_DRIVER_PN532_I2C_H__ #define __NFC_DRIVER_PN532_I2C_H__ #include /* Reference to the I2C driver structure */ extern const struct nfc_driver pn532_i2c_driver; #endif // ! __NFC_DRIVER_I2C_H__ libnfc-1.7.1/libnfc/drivers/pn532_spi.c000066400000000000000000000523671230265671100175760ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Evgeny Boger * * 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 */ /** * @file pn532_spi.c * @brief PN532 driver using SPI bus */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "pn532_spi.h" #include #include #include #include #include "drivers.h" #include "nfc-internal.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "spi.h" #define PN532_SPI_DEFAULT_SPEED 1000000 // 1 MHz #define PN532_SPI_DRIVER_NAME "pn532_spi" #define PN532_SPI_MODE SPI_MODE_0 #define LOG_CATEGORY "libnfc.driver.pn532_spi" #define LOG_GROUP NFC_LOG_GROUP_DRIVER #ifndef _WIN32 // Needed by sleep() under Unix # include # include # define msleep(x) do { \ struct timespec xsleep; \ xsleep.tv_sec = x / 1000; \ xsleep.tv_nsec = (x - xsleep.tv_sec * 1000) * 1000 * 1000; \ nanosleep(&xsleep, NULL); \ } while (0) #else // Needed by Sleep() under Windows # include # define msleep Sleep #endif // Internal data structs const struct pn53x_io pn532_spi_io; struct pn532_spi_data { spi_port port; volatile bool abort_flag; }; static const uint8_t pn532_spi_cmd_dataread = 0x03; static const uint8_t pn532_spi_cmd_datawrite = 0x01; // Prototypes int pn532_spi_ack(nfc_device *pnd); int pn532_spi_wakeup(nfc_device *pnd); #define DRIVER_DATA(pnd) ((struct pn532_spi_data*)(pnd->driver_data)) static size_t pn532_spi_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; spi_port sp; char **acPorts = spi_list_ports(); const char *acPort; int iDevice = 0; while ((acPort = acPorts[iDevice++])) { sp = spi_open(acPort); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find PN532 device on SPI port: %s at %d Hz.", acPort, PN532_SPI_DEFAULT_SPEED); if ((sp != INVALID_SPI_PORT) && (sp != CLAIMED_SPI_PORT)) { // Serial port claimed but we need to check if a PN532_SPI is opened. spi_set_speed(sp, PN532_SPI_DEFAULT_SPEED); spi_set_mode(sp, PN532_SPI_MODE); nfc_connstring connstring; snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, PN532_SPI_DRIVER_NAME, acPort, PN532_SPI_DEFAULT_SPEED); nfc_device *pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); spi_close(sp); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } pnd->driver = &pn532_spi_driver; pnd->driver_data = malloc(sizeof(struct pn532_spi_data)); if (!pnd->driver_data) { perror("malloc"); spi_close(sp); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data if (pn53x_data_new(pnd, &pn532_spi_io) == NULL) { perror("malloc"); spi_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } // SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532 CHIP_DATA(pnd)->type = PN532; // This device starts in LowVBat power mode CHIP_DATA(pnd)->power_mode = LOWVBAT; DRIVER_DATA(pnd)->abort_flag = false; // Check communication using "Diagnose" command, with "Communication test" (0x00) int res = pn53x_check_communication(pnd); spi_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); if (res < 0) { continue; } memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring)); device_found++; // Test if we reach the maximum "wanted" devices if (device_found >= connstrings_len) break; } } iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return device_found; } struct pn532_spi_descriptor { char *port; uint32_t speed; }; static void pn532_spi_close(nfc_device *pnd) { pn53x_idle(pnd); // Release SPI port spi_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); } static nfc_device * pn532_spi_open(const nfc_context *context, const nfc_connstring connstring) { struct pn532_spi_descriptor ndd; char *speed_s; int connstring_decode_level = connstring_decode(connstring, PN532_SPI_DRIVER_NAME, NULL, &ndd.port, &speed_s); if (connstring_decode_level == 3) { ndd.speed = 0; if (sscanf(speed_s, "%10"PRIu32, &ndd.speed) != 1) { // speed_s is not a number free(ndd.port); free(speed_s); return NULL; } free(speed_s); } if (connstring_decode_level < 2) { return NULL; } if (connstring_decode_level < 3) { ndd.speed = PN532_SPI_DEFAULT_SPEED; } spi_port sp; nfc_device *pnd = NULL; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d Hz.", ndd.port, ndd.speed); sp = spi_open(ndd.port); if (sp == INVALID_SPI_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid SPI port: %s", ndd.port); if (sp == CLAIMED_SPI_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "SPI port already claimed: %s", ndd.port); if ((sp == CLAIMED_SPI_PORT) || (sp == INVALID_SPI_PORT)) { free(ndd.port); return NULL; } spi_set_speed(sp, ndd.speed); spi_set_mode(sp, PN532_SPI_MODE); // We have a connection pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); free(ndd.port); spi_close(sp); return NULL; } snprintf(pnd->name, sizeof(pnd->name), "%s:%s", PN532_SPI_DRIVER_NAME, ndd.port); free(ndd.port); pnd->driver_data = malloc(sizeof(struct pn532_spi_data)); if (!pnd->driver_data) { perror("malloc"); spi_close(sp); nfc_device_free(pnd); return NULL; } DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data if (pn53x_data_new(pnd, &pn532_spi_io) == NULL) { perror("malloc"); spi_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); return NULL; } // SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532 CHIP_DATA(pnd)->type = PN532; // This device starts in LowVBat mode CHIP_DATA(pnd)->power_mode = LOWVBAT; // empirical tuning CHIP_DATA(pnd)->timer_correction = 48; pnd->driver = &pn532_spi_driver; DRIVER_DATA(pnd)->abort_flag = false; // Check communication using "Diagnose" command, with "Communication test" (0x00) if (pn53x_check_communication(pnd) < 0) { nfc_perror(pnd, "pn53x_check_communication"); pn532_spi_close(pnd); return NULL; } pn53x_init(pnd); return pnd; } static int pn532_spi_read_spi_status(nfc_device *pnd) { static const uint8_t pn532_spi_statread_cmd = 0x02; uint8_t spi_status = 0; int res = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_statread_cmd, 1, &spi_status, 1, true); if (res != NFC_SUCCESS) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to read SPI status"); return res; } return spi_status; } int pn532_spi_wakeup(nfc_device *pnd) { /* SPI wakeup is basically activating chipselect for several ms. * To do so, we are sending harmless command at very low speed */ int res; const uint32_t prev_port_speed = spi_get_speed(DRIVER_DATA(pnd)->port); // Try to get byte from the SPI line. If PN532 is powered down, the byte will be 0xff (MISO line is high) uint8_t spi_byte = 0; res = spi_receive(DRIVER_DATA(pnd)->port, &spi_byte, 1, true); if (res != NFC_SUCCESS) { return res; } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Got %x byte from SPI line before wakeup", spi_byte); CHIP_DATA(pnd)->power_mode = NORMAL; // PN532 will be awake soon msleep(1); if (spi_byte == 0xff) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Wakeup is needed"); spi_set_speed(DRIVER_DATA(pnd)->port, 5000); // set slow speed res = pn532_SAMConfiguration(pnd, PSM_NORMAL, 1000); // wakeup by sending SAMConfiguration, which works just fine spi_set_speed(DRIVER_DATA(pnd)->port, prev_port_speed); } return res; } #define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD) static int pn532_spi_wait_for_data(nfc_device *pnd, int timeout) { static const uint8_t pn532_spi_ready = 0x01; static const int pn532_spi_poll_interval = 10; //ms int timer = 0; int ret; while ((ret = pn532_spi_read_spi_status(pnd)) != pn532_spi_ready) { if (ret < 0) { return ret; } if (DRIVER_DATA(pnd)->abort_flag) { DRIVER_DATA(pnd)->abort_flag = false; return NFC_EOPABORTED; } if (timeout > 0) { timer += pn532_spi_poll_interval; if (timer > timeout) { return NFC_ETIMEOUT; } msleep(pn532_spi_poll_interval); } } return NFC_SUCCESS; } static int pn532_spi_receive_next_chunk(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen) { // According to datasheet, the entire read operation should be done at once // However, it seems impossible to do since the length of the frame is stored in the frame // itself and it's impossible to manually set CS to low between two read operations // It's possible to read the response frame in a series of read operations, provided // each read operation is preceded by SPI_DATAREAD byte from the host. // Unfortunately, the PN532 sends first byte of the second and successive response chunks // at the same time as host sends SPI_DATAREAD byte // Many hardware SPI implementations are half-duplex, so it's became impossible to read this // first response byte // The following hack is used here: we first try to receive data from PN532 without SPI_DATAREAD // and then begin full-featured read operation // The PN532 does not shift the internal register on the receive operation, which allows us to read the whole response // The example transfer log is as follows: // CS ..._/---\___________________________/---\________/------\_____________/-----\_________/---\____________/---... // MOSI (host=>pn532) ... 0x03 0x00 0x00 0x00 0x00 0x00 0x03 0x00 0x00 0x03 0x00 // MISO (pn532<=host) ... 0x01 0x00 0xff 0x02 0xfe 0xd5 0xd5 0x15 0x16 0x16 0x00 // linux send/receive s r r r r r s r r s r // |<-- data -->| |<-data->| |<-data->| |<-data->| |<-data->| // |<-- first chunk -->| |<-- second chunk -->| |<-- third chunk -->| // The response frame is 0x00 0xff 0x02 0xfe 0xd5 0x15 0x16 0x00 int res = spi_receive(DRIVER_DATA(pnd)->port, pbtData, 1, true); if (res != NFC_SUCCESS) { return res; } res = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, pbtData + 1, szDataLen - 1, true); return res; } static int pn532_spi_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout) { uint8_t abtRxBuf[5]; size_t len; pnd->last_error = pn532_spi_wait_for_data(pnd, timeout); if (NFC_EOPABORTED == pnd->last_error) { return pn532_spi_ack(pnd); } if (pnd->last_error != NFC_SUCCESS) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to wait for SPI data. (RX)"); goto error; } pnd->last_error = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf , 4, true); if (pnd->last_error < 0) { goto error; } const uint8_t pn53x_long_preamble[3] = { 0x00, 0x00, 0xff }; if (0 == (memcmp(abtRxBuf, pn53x_long_preamble, 3))) { // long preamble // omit first byte for (size_t i = 0; i < 3; ++i) { abtRxBuf[i] = abtRxBuf[i + 1]; } // need one more byte pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf + 3, 1); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive one more byte for long preamble frame. (RX)"); goto error; } } const uint8_t pn53x_preamble[2] = { 0x00, 0xff }; if (0 != (memcmp(abtRxBuf, pn53x_preamble, 2))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", " preamble+start code mismatch"); pnd->last_error = NFC_EIO; goto error; } if ((0x01 == abtRxBuf[2]) && (0xff == abtRxBuf[3])) { // Error frame pn532_spi_receive_next_chunk(pnd, abtRxBuf, 3); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected"); pnd->last_error = NFC_EIO; goto error; } else if ((0xff == abtRxBuf[2]) && (0xff == abtRxBuf[3])) { // Extended frame pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf, 3); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } // (abtRxBuf[0] << 8) + abtRxBuf[1] (LEN) include TFI + (CC+1) len = (abtRxBuf[0] << 8) + abtRxBuf[1] - 2; if (((abtRxBuf[0] + abtRxBuf[1] + abtRxBuf[2]) % 256) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } } else { // Normal frame if (256 != (abtRxBuf[2] + abtRxBuf[3])) { // TODO: Retry log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } // abtRxBuf[3] (LEN) include TFI + (CC+1) len = abtRxBuf[2] - 2; } if (len > szDataLen) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %zu, len: %zu)", szDataLen, len); pnd->last_error = NFC_EIO; goto error; } // TFI + PD0 (CC+1) pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf, 2); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } if (abtRxBuf[0] != 0xD5) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); pnd->last_error = NFC_EIO; goto error; } if (abtRxBuf[1] != CHIP_DATA(pnd)->last_command + 1) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed"); pnd->last_error = NFC_EIO; goto error; } if (len) { pnd->last_error = pn532_spi_receive_next_chunk(pnd, pbtData, len); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } } pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf, 2); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } uint8_t btDCS = (256 - 0xD5); btDCS -= CHIP_DATA(pnd)->last_command + 1; for (size_t szPos = 0; szPos < len; szPos++) { btDCS -= pbtData[szPos]; } if (btDCS != abtRxBuf[0]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } if (0x00 != abtRxBuf[1]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch"); pnd->last_error = NFC_EIO; goto error; } // The PN53x command is done and we successfully received the reply return len; error: return pnd->last_error; } static int pn532_spi_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout) { int res = 0; switch (CHIP_DATA(pnd)->power_mode) { case LOWVBAT: { /** PN532C106 wakeup. */ if ((res = pn532_spi_wakeup(pnd)) < 0) { return res; } // According to PN532 application note, C106 appendix: to go out Low Vbat mode and enter in normal mode we need to send a SAMConfiguration command if ((res = pn532_SAMConfiguration(pnd, PSM_NORMAL, 1000)) < 0) { return res; } } break; case POWERDOWN: { if ((res = pn532_spi_wakeup(pnd)) < 0) { return res; } } break; case NORMAL: // Nothing to do :) break; }; uint8_t abtFrame[PN532_BUFFER_LEN + 1] = { pn532_spi_cmd_datawrite, 0x00, 0x00, 0xff }; // SPI data transfer starts with DATAWRITE (0x01) byte, Every packet must start with "00 00 ff" size_t szFrame = 0; if ((res = pn53x_build_frame(abtFrame + 1, &szFrame, pbtData, szData)) < 0) { pnd->last_error = res; return pnd->last_error; } res = spi_send(DRIVER_DATA(pnd)->port, abtFrame, szFrame, true); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); pnd->last_error = res; return pnd->last_error; } res = pn532_spi_wait_for_data(pnd, timeout); if (res != NFC_SUCCESS) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to wait for SPI data. (RX)"); pnd->last_error = res; return pnd->last_error; } uint8_t abtRxBuf[PN53x_ACK_FRAME__LEN]; res = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf, sizeof(abtRxBuf), true); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to read ACK"); pnd->last_error = res; return pnd->last_error; } if (pn53x_check_ack_frame(pnd, abtRxBuf, sizeof(abtRxBuf)) == 0) { // The PN53x is running the sent command } else { return pnd->last_error; } return NFC_SUCCESS; } int pn532_spi_ack(nfc_device *pnd) { const size_t ack_frame_len = (sizeof(pn53x_ack_frame) / sizeof(pn53x_ack_frame[0])); uint8_t ack_tx_buf [1 + ack_frame_len]; ack_tx_buf[0] = pn532_spi_cmd_datawrite; memcpy(ack_tx_buf + 1, pn53x_ack_frame, ack_frame_len); int res = spi_send(DRIVER_DATA(pnd)->port, ack_tx_buf, ack_frame_len + 1, true); return res; } static int pn532_spi_abort_command(nfc_device *pnd) { if (pnd) { DRIVER_DATA(pnd)->abort_flag = true; } return NFC_SUCCESS; } const struct pn53x_io pn532_spi_io = { .send = pn532_spi_send, .receive = pn532_spi_receive, }; const struct nfc_driver pn532_spi_driver = { .name = PN532_SPI_DRIVER_NAME, .scan_type = INTRUSIVE, .scan = pn532_spi_scan, .open = pn532_spi_open, .close = pn532_spi_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = pn532_initiator_init_secure_element, .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = pn532_spi_abort_command, .idle = pn53x_idle, .powerdown = pn53x_PowerDown, }; libnfc-1.7.1/libnfc/drivers/pn532_spi.h000066400000000000000000000025501230265671100175700ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Evgeny Boger * * 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 */ /** * @file pn532_spi.h * @brief Driver for PN532 connected in SPI */ #ifndef __NFC_DRIVER_PN532_SPI_H__ #define __NFC_DRIVER_PN532_SPI_H__ #include extern const struct nfc_driver pn532_spi_driver; #endif // ! __NFC_DRIVER_PN532_SPI_H__ libnfc-1.7.1/libnfc/drivers/pn532_uart.c000066400000000000000000000426571230265671100177570ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file pn532_uart.c * @brief PN532 driver using UART bus (UART, RS232, etc.) */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "pn532_uart.h" #include #include #include #include #include #include "drivers.h" #include "nfc-internal.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "uart.h" #define PN532_UART_DEFAULT_SPEED 115200 #define PN532_UART_DRIVER_NAME "pn532_uart" #define LOG_CATEGORY "libnfc.driver.pn532_uart" #define LOG_GROUP NFC_LOG_GROUP_DRIVER // Internal data structs const struct pn53x_io pn532_uart_io; struct pn532_uart_data { serial_port port; #ifndef WIN32 int iAbortFds[2]; #else volatile bool abort_flag; #endif }; // Prototypes int pn532_uart_ack(nfc_device *pnd); int pn532_uart_wakeup(nfc_device *pnd); #define DRIVER_DATA(pnd) ((struct pn532_uart_data*)(pnd->driver_data)) static size_t pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; serial_port sp; char **acPorts = uart_list_ports(); const char *acPort; int iDevice = 0; while ((acPort = acPorts[iDevice++])) { sp = uart_open(acPort); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find PN532 device on serial port: %s at %d bauds.", acPort, PN532_UART_DEFAULT_SPEED); if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { // We need to flush input to be sure first reply does not comes from older byte transceive uart_flush_input(sp, true); // Serial port claimed but we need to check if a PN532_UART is opened. uart_set_speed(sp, PN532_UART_DEFAULT_SPEED); nfc_connstring connstring; snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, PN532_UART_DRIVER_NAME, acPort, PN532_UART_DEFAULT_SPEED); nfc_device *pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); uart_close(sp); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } pnd->driver = &pn532_uart_driver; pnd->driver_data = malloc(sizeof(struct pn532_uart_data)); if (!pnd->driver_data) { perror("malloc"); uart_close(sp); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data if (pn53x_data_new(pnd, &pn532_uart_io) == NULL) { perror("malloc"); uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } // SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532 CHIP_DATA(pnd)->type = PN532; // This device starts in LowVBat power mode CHIP_DATA(pnd)->power_mode = LOWVBAT; #ifndef WIN32 // pipe-based abort mecanism if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return 0; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif // Check communication using "Diagnose" command, with "Communication test" (0x00) int res = pn53x_check_communication(pnd); uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); if (res < 0) { continue; } memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring)); device_found++; // Test if we reach the maximum "wanted" devices if (device_found >= connstrings_len) break; } } iDevice = 0; while ((acPort = acPorts[iDevice++])) { free((void *)acPort); } free(acPorts); return device_found; } struct pn532_uart_descriptor { char *port; uint32_t speed; }; static void pn532_uart_close(nfc_device *pnd) { pn53x_idle(pnd); // Release UART port uart_close(DRIVER_DATA(pnd)->port); #ifndef WIN32 // Release file descriptors used for abort mecanism close(DRIVER_DATA(pnd)->iAbortFds[0]); close(DRIVER_DATA(pnd)->iAbortFds[1]); #endif pn53x_data_free(pnd); nfc_device_free(pnd); } static nfc_device * pn532_uart_open(const nfc_context *context, const nfc_connstring connstring) { struct pn532_uart_descriptor ndd; char *speed_s; int connstring_decode_level = connstring_decode(connstring, PN532_UART_DRIVER_NAME, NULL, &ndd.port, &speed_s); if (connstring_decode_level == 3) { ndd.speed = 0; if (sscanf(speed_s, "%10"PRIu32, &ndd.speed) != 1) { // speed_s is not a number free(ndd.port); free(speed_s); return NULL; } free(speed_s); } if (connstring_decode_level < 2) { return NULL; } if (connstring_decode_level < 3) { ndd.speed = PN532_UART_DEFAULT_SPEED; } serial_port sp; nfc_device *pnd = NULL; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d bauds.", ndd.port, ndd.speed); sp = uart_open(ndd.port); if (sp == INVALID_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", ndd.port); if (sp == CLAIMED_SERIAL_PORT) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", ndd.port); if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) { free(ndd.port); return NULL; } // We need to flush input to be sure first reply does not comes from older byte transceive uart_flush_input(sp, true); uart_set_speed(sp, ndd.speed); // We have a connection pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); free(ndd.port); uart_close(sp); return NULL; } snprintf(pnd->name, sizeof(pnd->name), "%s:%s", PN532_UART_DRIVER_NAME, ndd.port); free(ndd.port); pnd->driver_data = malloc(sizeof(struct pn532_uart_data)); if (!pnd->driver_data) { perror("malloc"); uart_close(sp); nfc_device_free(pnd); return NULL; } DRIVER_DATA(pnd)->port = sp; // Alloc and init chip's data if (pn53x_data_new(pnd, &pn532_uart_io) == NULL) { perror("malloc"); uart_close(DRIVER_DATA(pnd)->port); nfc_device_free(pnd); return NULL; } // SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532 CHIP_DATA(pnd)->type = PN532; // This device starts in LowVBat mode CHIP_DATA(pnd)->power_mode = LOWVBAT; // empirical tuning CHIP_DATA(pnd)->timer_correction = 48; pnd->driver = &pn532_uart_driver; #ifndef WIN32 // pipe-based abort mecanism if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { uart_close(DRIVER_DATA(pnd)->port); pn53x_data_free(pnd); nfc_device_free(pnd); return NULL; } #else DRIVER_DATA(pnd)->abort_flag = false; #endif // Check communication using "Diagnose" command, with "Communication test" (0x00) if (pn53x_check_communication(pnd) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "pn53x_check_communication error"); pn532_uart_close(pnd); return NULL; } pn53x_init(pnd); return pnd; } int pn532_uart_wakeup(nfc_device *pnd) { /* High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for PN532 being wakeup. */ const uint8_t pn532_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int res = uart_send(DRIVER_DATA(pnd)->port, pn532_wakeup_preamble, sizeof(pn532_wakeup_preamble), 0); CHIP_DATA(pnd)->power_mode = NORMAL; // PN532 should now be awake return res; } #define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD) static int pn532_uart_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout) { int res = 0; // Before sending anything, we need to discard from any junk bytes uart_flush_input(DRIVER_DATA(pnd)->port, false); switch (CHIP_DATA(pnd)->power_mode) { case LOWVBAT: { /** PN532C106 wakeup. */ if ((res = pn532_uart_wakeup(pnd)) < 0) { return res; } // According to PN532 application note, C106 appendix: to go out Low Vbat mode and enter in normal mode we need to send a SAMConfiguration command if ((res = pn532_SAMConfiguration(pnd, PSM_NORMAL, 1000)) < 0) { return res; } } break; case POWERDOWN: { if ((res = pn532_uart_wakeup(pnd)) < 0) { return res; } } break; case NORMAL: // Nothing to do :) break; }; uint8_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" size_t szFrame = 0; if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) { pnd->last_error = res; return pnd->last_error; } res = uart_send(DRIVER_DATA(pnd)->port, abtFrame, szFrame, timeout); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); pnd->last_error = res; return pnd->last_error; } uint8_t abtRxBuf[PN53x_ACK_FRAME__LEN]; res = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, sizeof(abtRxBuf), 0, timeout); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to read ACK"); pnd->last_error = res; return pnd->last_error; } if (pn53x_check_ack_frame(pnd, abtRxBuf, sizeof(abtRxBuf)) == 0) { // The PN53x is running the sent command } else { return pnd->last_error; } return NFC_SUCCESS; } static int pn532_uart_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout) { uint8_t abtRxBuf[5]; size_t len; void *abort_p = NULL; #ifndef WIN32 abort_p = &(DRIVER_DATA(pnd)->iAbortFds[1]); #else abort_p = (void *) & (DRIVER_DATA(pnd)->abort_flag); #endif pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 5, abort_p, timeout); if (abort_p && (NFC_EOPABORTED == pnd->last_error)) { pn532_uart_ack(pnd); return NFC_EOPABORTED; } if (pnd->last_error < 0) { goto error; } const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); pnd->last_error = NFC_EIO; goto error; } if ((0x01 == abtRxBuf[3]) && (0xff == abtRxBuf[4])) { // Error frame uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 3, 0, timeout); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected"); pnd->last_error = NFC_EIO; goto error; } else if ((0xff == abtRxBuf[3]) && (0xff == abtRxBuf[4])) { // Extended frame pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 3, 0, timeout); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } // (abtRxBuf[0] << 8) + abtRxBuf[1] (LEN) include TFI + (CC+1) len = (abtRxBuf[0] << 8) + abtRxBuf[1] - 2; if (((abtRxBuf[0] + abtRxBuf[1] + abtRxBuf[2]) % 256) != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } } else { // Normal frame if (256 != (abtRxBuf[3] + abtRxBuf[4])) { // TODO: Retry log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } // abtRxBuf[3] (LEN) include TFI + (CC+1) len = abtRxBuf[3] - 2; } if (len > szDataLen) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); pnd->last_error = NFC_EIO; goto error; } // TFI + PD0 (CC+1) pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } if (abtRxBuf[0] != 0xD5) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); pnd->last_error = NFC_EIO; goto error; } if (abtRxBuf[1] != CHIP_DATA(pnd)->last_command + 1) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed"); pnd->last_error = NFC_EIO; goto error; } if (len) { pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, pbtData, len, 0, timeout); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } } pnd->last_error = uart_receive(DRIVER_DATA(pnd)->port, abtRxBuf, 2, 0, timeout); if (pnd->last_error != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)"); goto error; } uint8_t btDCS = (256 - 0xD5); btDCS -= CHIP_DATA(pnd)->last_command + 1; for (size_t szPos = 0; szPos < len; szPos++) { btDCS -= pbtData[szPos]; } if (btDCS != abtRxBuf[0]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch"); pnd->last_error = NFC_EIO; goto error; } if (0x00 != abtRxBuf[1]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch"); pnd->last_error = NFC_EIO; goto error; } // The PN53x command is done and we successfully received the reply return len; error: uart_flush_input(DRIVER_DATA(pnd)->port, true); return pnd->last_error; } int pn532_uart_ack(nfc_device *pnd) { if (POWERDOWN == CHIP_DATA(pnd)->power_mode) { int res = 0; if ((res = pn532_uart_wakeup(pnd)) < 0) { return res; } } return (uart_send(DRIVER_DATA(pnd)->port, pn53x_ack_frame, sizeof(pn53x_ack_frame), 0)); } static int pn532_uart_abort_command(nfc_device *pnd) { if (pnd) { #ifndef WIN32 close(DRIVER_DATA(pnd)->iAbortFds[0]); if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { return NFC_ESOFT; } #else DRIVER_DATA(pnd)->abort_flag = true; #endif } return NFC_SUCCESS; } const struct pn53x_io pn532_uart_io = { .send = pn532_uart_send, .receive = pn532_uart_receive, }; const struct nfc_driver pn532_uart_driver = { .name = PN532_UART_DRIVER_NAME, .scan_type = INTRUSIVE, .scan = pn532_uart_scan, .open = pn532_uart_open, .close = pn532_uart_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = pn532_initiator_init_secure_element, .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = pn532_uart_abort_command, .idle = pn53x_idle, .powerdown = pn53x_PowerDown, }; libnfc-1.7.1/libnfc/drivers/pn532_uart.h000066400000000000000000000025141230265671100177500ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file pn532_uart.h * @brief Driver for PN532 connected in UART (HSU) */ #ifndef __NFC_DRIVER_PN532_UART_H__ #define __NFC_DRIVER_PN532_UART_H__ #include extern const struct nfc_driver pn532_uart_driver; #endif // ! __NFC_DRIVER_PN532_UART_H__ libnfc-1.7.1/libnfc/drivers/pn53x_usb.c000066400000000000000000000626361230265671100177020ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file pn53x_usb.c * @brief Driver for PN53x using USB */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H /* Thanks to d18c7db and Okko for example code */ #include #include #include #include #include #include #include #include "nfc-internal.h" #include "buses/usbbus.h" #include "chips/pn53x.h" #include "chips/pn53x-internal.h" #include "drivers/pn53x_usb.h" #define PN53X_USB_DRIVER_NAME "pn53x_usb" #define LOG_CATEGORY "libnfc.driver.pn53x_usb" #define LOG_GROUP NFC_LOG_GROUP_DRIVER #define USB_INFINITE_TIMEOUT 0 #define DRIVER_DATA(pnd) ((struct pn53x_usb_data*)(pnd->driver_data)) typedef enum { UNKNOWN, NXP_PN531, SONY_PN531, NXP_PN533, ASK_LOGO, SCM_SCL3711, SONY_RCS360 } pn53x_usb_model; // Internal data struct struct pn53x_usb_data { usb_dev_handle *pudh; pn53x_usb_model model; uint32_t uiEndPointIn; uint32_t uiEndPointOut; uint32_t uiMaxPacketSize; volatile bool abort_flag; }; // Internal io struct const struct pn53x_io pn53x_usb_io; // Prototypes bool pn53x_usb_get_usb_device_name(struct usb_device *dev, usb_dev_handle *udev, char *buffer, size_t len); int pn53x_usb_init(nfc_device *pnd); static int pn53x_usb_bulk_read(struct pn53x_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) { int res = usb_bulk_read(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, timeout); if (res > 0) { LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, res); } else if (res < 0) { if (res != -USB_TIMEDOUT) log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", _usb_strerror(res)); } return res; } static int pn53x_usb_bulk_write(struct pn53x_usb_data *data, uint8_t abtTx[], const size_t szTx, const int timeout) { LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx); int res = usb_bulk_write(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, timeout); if (res > 0) { // HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details if ((res % data->uiMaxPacketSize) == 0) { usb_bulk_write(data->pudh, data->uiEndPointOut, "\0", 0, timeout); } } else { log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", _usb_strerror(res)); } return res; } struct pn53x_usb_supported_device { uint16_t vendor_id; uint16_t product_id; pn53x_usb_model model; const char *name; }; const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = { { 0x04CC, 0x0531, NXP_PN531, "Philips / PN531" }, { 0x04CC, 0x2533, NXP_PN533, "NXP / PN533" }, { 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW" }, { 0x054c, 0x0193, SONY_PN531, "Sony / PN531" }, { 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO" }, { 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]" } }; static pn53x_usb_model pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id) { for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { if ((vendor_id == pn53x_usb_supported_devices[n].vendor_id) && (product_id == pn53x_usb_supported_devices[n].product_id)) return pn53x_usb_supported_devices[n].model; } return UNKNOWN; } int pn53x_usb_ack(nfc_device *pnd); // Find transfer endpoints for bulk transfers static void pn53x_usb_get_end_points(struct usb_device *dev, struct pn53x_usb_data *data) { uint32_t uiIndex; uint32_t uiEndPoint; struct usb_interface_descriptor *puid = dev->config->interface->altsetting; // 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out for (uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) { // Only accept bulk transfer endpoints (ignore interrupt endpoints) if (puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue; // Copy the endpoint to a local var, makes it more readable code uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress; // Test if we dealing with a bulk IN endpoint if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN) { data->uiEndPointIn = uiEndPoint; data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; } // Test if we dealing with a bulk OUT endpoint if ((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT) { data->uiEndPointOut = uiEndPoint; data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize; } } } static size_t pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { (void)context; usb_prepare(); size_t device_found = 0; uint32_t uiBusIndex = 0; struct usb_bus *bus; for (bus = usb_get_busses(); bus; bus = bus->next) { struct usb_device *dev; for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++) { for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && (pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { // Make sure there are 2 endpoints available // with libusb-win32 we got some null pointers so be robust before looking at endpoints: if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL) { // Nope, we maybe want the next one, let's try to find another continue; } if (dev->config->interface->altsetting->bNumEndpoints < 2) { // Nope, we maybe want the next one, let's try to find another continue; } usb_dev_handle *udev = usb_open(dev); if (udev == NULL) continue; // Set configuration int res = usb_set_configuration(udev, 1); if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", _usb_strerror(res)); usb_close(udev); // we failed to use the device continue; } // 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); device_found++; // Test if we reach the maximum "wanted" devices if (device_found == connstrings_len) { return device_found; } } } } } return device_found; } struct pn53x_usb_descriptor { char *dirname; char *filename; }; bool pn53x_usb_get_usb_device_name(struct usb_device *dev, usb_dev_handle *udev, char *buffer, size_t len) { *buffer = '\0'; if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { if (udev) { usb_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); if (strlen(buffer) > 0) strcpy(buffer + strlen(buffer), " / "); usb_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer)); } } if (!*buffer) { for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && (pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { strncpy(buffer, pn53x_usb_supported_devices[n].name, len); buffer[len - 1] = '\0'; return true; } } } return false; } static nfc_device * pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) { nfc_device *pnd = NULL; struct pn53x_usb_descriptor desc = { NULL, NULL }; int connstring_decode_level = connstring_decode(connstring, PN53X_USB_DRIVER_NAME, "usb", &desc.dirname, &desc.filename); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d element(s) have been decoded from \"%s\"", connstring_decode_level, connstring); if (connstring_decode_level < 1) { goto free_mem; } struct pn53x_usb_data data = { .pudh = NULL, .uiEndPointIn = 0, .uiEndPointOut = 0, }; struct usb_bus *bus; struct usb_device *dev; usb_prepare(); for (bus = usb_get_busses(); bus; bus = bus->next) { if (connstring_decode_level > 1) { // A specific bus have been specified if (0 != strcmp(bus->dirname, desc.dirname)) continue; } for (dev = bus->devices; dev; dev = dev->next) { if (connstring_decode_level > 2) { // A specific dev have been specified if (0 != strcmp(dev->filename, desc.filename)) continue; } // Open the USB device if ((data.pudh = usb_open(dev)) == NULL) continue; // Retrieve end points pn53x_usb_get_end_points(dev, &data); // Set configuration int res = usb_set_configuration(data.pudh, 1); if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", _usb_strerror(res)); if (EPERM == -res) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: Please double check USB permissions for device %04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); } usb_close(data.pudh); // we failed to use the specified device goto free_mem; } res = usb_claim_interface(data.pudh, 0); if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", _usb_strerror(res)); usb_close(data.pudh); // we failed to use the specified device goto free_mem; } data.model = pn53x_usb_get_device_model(dev->descriptor.idVendor, dev->descriptor.idProduct); // Allocate memory for the device info and specification, fill it and return the info pnd = nfc_device_new(context, connstring); if (!pnd) { perror("malloc"); goto error; } pn53x_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name)); pnd->driver_data = malloc(sizeof(struct pn53x_usb_data)); if (!pnd->driver_data) { perror("malloc"); goto error; } *DRIVER_DATA(pnd) = data; // Alloc and init chip's data if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) { perror("malloc"); goto error; } switch (DRIVER_DATA(pnd)->model) { // empirical tuning case ASK_LOGO: CHIP_DATA(pnd)->timer_correction = 50; break; case SCM_SCL3711: case NXP_PN533: CHIP_DATA(pnd)->timer_correction = 46; break; case NXP_PN531: CHIP_DATA(pnd)->timer_correction = 50; break; case SONY_PN531: CHIP_DATA(pnd)->timer_correction = 54; break; case SONY_RCS360: case UNKNOWN: CHIP_DATA(pnd)->timer_correction = 0; // TODO: allow user to know if timed functions are available break; } pnd->driver = &pn53x_usb_driver; // HACK1: Send first an ACK as Abort command, to reset chip before talking to it: pn53x_usb_ack(pnd); // HACK2: Then send a GetFirmware command to resync USB toggle bit between host & device // in case host used set_configuration and expects the device to have reset its toggle bit, which PN53x doesn't do if (pn53x_usb_init(pnd) < 0) { usb_close(data.pudh); goto error; } DRIVER_DATA(pnd)->abort_flag = false; goto free_mem; } } // We ran out of devices before the index required goto free_mem; error: // Free allocated structure on error. nfc_device_free(pnd); pnd = NULL; free_mem: free(desc.dirname); free(desc.filename); return pnd; } static void pn53x_usb_close(nfc_device *pnd) { pn53x_usb_ack(pnd); if (DRIVER_DATA(pnd)->model == ASK_LOGO) { /* Set P30, P31, P32, P33, P35 to logic 1 and P34 to 0 logic */ /* ie. Switch all LEDs off and turn off progressive field */ pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P32) | _BV(P33) | _BV(P35)); } pn53x_idle(pnd); int res; if ((res = usb_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", _usb_strerror(res)); } if ((res = usb_close(DRIVER_DATA(pnd)->pudh)) < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to close USB connection (%s)", _usb_strerror(res)); } pn53x_data_free(pnd); nfc_device_free(pnd); } #define PN53X_USB_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD) static int pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) { uint8_t abtFrame[PN53X_USB_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" size_t szFrame = 0; int res = 0; if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) { pnd->last_error = res; return pnd->last_error; } if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), abtFrame, szFrame, timeout)) < 0) { pnd->last_error = res; return pnd->last_error; } uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN]; if ((res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), timeout)) < 0) { // try to interrupt current device state pn53x_usb_ack(pnd); pnd->last_error = res; return pnd->last_error; } if (pn53x_check_ack_frame(pnd, abtRxBuf, res) == 0) { // The PN53x is running the sent command } else { // For some reasons (eg. send another command while a previous one is // running), the PN533 sometimes directly replies the response packet // instead of ACK frame, so we send a NACK frame to force PN533 to resend // response packet. With this hack, the nextly executed function (ie. // pn53x_usb_receive()) will be able to retreive the correct response // packet. // FIXME Sony reader is also affected by this bug but NACK is not supported if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *)pn53x_nack_frame, sizeof(pn53x_nack_frame), timeout)) < 0) { pnd->last_error = res; // try to interrupt current device state pn53x_usb_ack(pnd); return pnd->last_error; } } return NFC_SUCCESS; } #define USB_TIMEOUT_PER_PASS 200 static int pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) { size_t len; off_t offset = 0; uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN]; int res; /* * If no timeout is specified but the command is blocking, force a 200ms (USB_TIMEOUT_PER_PASS) * timeout to allow breaking the loop if the user wants to stop it. */ int usb_timeout; int remaining_time = timeout; 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 remaining_time -= USB_TIMEOUT_PER_PASS; if (remaining_time <= 0) { pnd->last_error = NFC_ETIMEOUT; return pnd->last_error; } else { usb_timeout = MIN(remaining_time, USB_TIMEOUT_PER_PASS); } } res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usb_timeout); if (res == -USB_TIMEDOUT) { if (DRIVER_DATA(pnd)->abort_flag) { DRIVER_DATA(pnd)->abort_flag = false; pn53x_usb_ack(pnd); pnd->last_error = NFC_EOPABORTED; return pnd->last_error; } else { goto read; } } if (res < 0) { // try to interrupt current device state pn53x_usb_ack(pnd); pnd->last_error = res; return pnd->last_error; } const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 3; if ((0x01 == abtRxBuf[offset]) && (0xff == abtRxBuf[offset + 1])) { // Error frame log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected"); pnd->last_error = NFC_EIO; return pnd->last_error; } else if ((0xff == abtRxBuf[offset]) && (0xff == abtRxBuf[offset + 1])) { // Extended frame offset += 2; // (abtRxBuf[offset] << 8) + abtRxBuf[offset + 1] (LEN) include TFI + (CC+1) len = (abtRxBuf[offset] << 8) + abtRxBuf[offset + 1] - 2; if (((abtRxBuf[offset] + abtRxBuf[offset + 1] + abtRxBuf[offset + 2]) % 256) != 0) { // TODO: Retry log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 3; } else { // Normal frame if (256 != (abtRxBuf[offset] + abtRxBuf[offset + 1])) { // TODO: Retry log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } // abtRxBuf[3] (LEN) include TFI + (CC+1) len = abtRxBuf[offset] - 2; offset += 2; } if (len > szDataLen) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); pnd->last_error = NFC_EIO; return pnd->last_error; } // TFI + PD0 (CC+1) if (abtRxBuf[offset] != 0xD5) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 1; if (abtRxBuf[offset] != CHIP_DATA(pnd)->last_command + 1) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 1; memcpy(pbtData, abtRxBuf + offset, len); offset += len; uint8_t btDCS = (256 - 0xD5); btDCS -= CHIP_DATA(pnd)->last_command + 1; for (size_t szPos = 0; szPos < len; szPos++) { btDCS -= pbtData[szPos]; } if (btDCS != abtRxBuf[offset]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } offset += 1; if (0x00 != abtRxBuf[offset]) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch"); pnd->last_error = NFC_EIO; return pnd->last_error; } // The PN53x command is done and we successfully received the reply pnd->last_error = 0; return len; } int pn53x_usb_ack(nfc_device *pnd) { return pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *) pn53x_ack_frame, sizeof(pn53x_ack_frame), 1000); } int pn53x_usb_init(nfc_device *pnd) { int res = 0; // Sometimes PN53x USB doesn't reply ACK one the first frame, so we need to send a dummy one... //pn53x_check_communication (pnd); // Sony RC-S360 doesn't support this command for now so let's use a get_firmware_version instead: const uint8_t abtCmd[] = { GetFirmwareVersion }; pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); // ...and we don't care about error pnd->last_error = 0; if (SONY_RCS360 == DRIVER_DATA(pnd)->model) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "SONY RC-S360 initialization."); const uint8_t abtCmd2[] = { 0x18, 0x01 }; pn53x_transceive(pnd, abtCmd2, sizeof(abtCmd2), NULL, 0, -1); pn53x_usb_ack(pnd); } if ((res = pn53x_init(pnd)) < 0) return res; if (ASK_LOGO == DRIVER_DATA(pnd)->model) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ASK LoGO initialization."); /* Internal registers */ /* Disable 100mA current limit, Power on Secure IC (SVDD) */ pn53x_write_register(pnd, PN53X_REG_Control_switch_rng, 0xFF, SYMBOL_CURLIMOFF | SYMBOL_SIC_SWITCH_EN | SYMBOL_RANDOM_DATAREADY); /* Select the signal to be output on SIGOUT: Modulation signal (envelope) from the internal coder */ pn53x_write_register(pnd, PN53X_REG_CIU_TxSel, 0xFF, 0x14); /* SFR Registers */ /* Setup push-pulls for pins from P30 to P35 */ pn53x_write_register(pnd, PN53X_SFR_P3CFGB, 0xFF, 0x37); /* On ASK LoGO hardware: LEDs port bits definition: * LED 1: bit 2 (P32) * LED 2: bit 1 (P31) * LED 3: bit 0 or 3 (depending of hardware revision) (P30 or P33) * LED 4: bit 5 (P35) Notes: * Set logical 0 to switch LED on; logical 1 to switch LED off. * Bit 4 should be maintained at 1 to keep RF field on. Progressive field activation: The ASK LoGO hardware can progressively power-up the antenna. To use this feature we have to switch on the field by switching on the field on PN533 (RFConfiguration) then set P34 to '1', and cut-off the field by switching off the field on PN533 then set P34 to '0'. */ /* Set P30, P31, P33, P35 to logic 1 and P32, P34 to 0 logic */ /* ie. Switch LED1 on and turn off progressive field */ pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P33) | _BV(P35)); } return NFC_SUCCESS; } static int pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) { int res = 0; if ((res = pn53x_set_property_bool(pnd, property, bEnable)) < 0) return res; switch (DRIVER_DATA(pnd)->model) { case ASK_LOGO: 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) return NFC_ECHIP; } break; case SCM_SCL3711: if (NP_ACTIVATE_FIELD == property) { // Switch on/off LED according to ACTIVATE_FIELD option if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0) return res; } break; case NXP_PN531: case NXP_PN533: case SONY_PN531: case SONY_RCS360: case UNKNOWN: // Nothing to do. break; } return NFC_SUCCESS; } static int pn53x_usb_abort_command(nfc_device *pnd) { DRIVER_DATA(pnd)->abort_flag = true; return NFC_SUCCESS; } const struct pn53x_io pn53x_usb_io = { .send = pn53x_usb_send, .receive = pn53x_usb_receive, }; const struct nfc_driver pn53x_usb_driver = { .name = PN53X_USB_DRIVER_NAME, .scan_type = NOT_INTRUSIVE, .scan = pn53x_usb_scan, .open = pn53x_usb_open, .close = pn53x_usb_close, .strerror = pn53x_strerror, .initiator_init = pn53x_initiator_init, .initiator_init_secure_element = NULL, // No secure-element support .initiator_select_passive_target = pn53x_initiator_select_passive_target, .initiator_poll_target = pn53x_initiator_poll_target, .initiator_select_dep_target = pn53x_initiator_select_dep_target, .initiator_deselect_target = pn53x_initiator_deselect_target, .initiator_transceive_bytes = pn53x_initiator_transceive_bytes, .initiator_transceive_bits = pn53x_initiator_transceive_bits, .initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed, .initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed, .initiator_target_is_present = pn53x_initiator_target_is_present, .target_init = pn53x_target_init, .target_send_bytes = pn53x_target_send_bytes, .target_receive_bytes = pn53x_target_receive_bytes, .target_send_bits = pn53x_target_send_bits, .target_receive_bits = pn53x_target_receive_bits, .device_set_property_bool = pn53x_usb_set_property_bool, .device_set_property_int = pn53x_set_property_int, .get_supported_modulation = pn53x_get_supported_modulation, .get_supported_baud_rate = pn53x_get_supported_baud_rate, .device_get_information_about = pn53x_get_information_about, .abort_command = pn53x_usb_abort_command, .idle = pn53x_idle, .powerdown = pn53x_PowerDown, }; libnfc-1.7.1/libnfc/drivers/pn53x_usb.h000066400000000000000000000024721230265671100176770ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file pn53x_usb.h * @brief Drive for PN53x USB devices */ #ifndef __NFC_DRIVER_PN53X_USB_H__ #define __NFC_DRIVER_PN53X_USB_H__ #include extern const struct nfc_driver pn53x_usb_driver; #endif // ! __NFC_DRIVER_PN53X_USB_H__ libnfc-1.7.1/libnfc/iso14443-subr.c000066400000000000000000000072431230265671100165320ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file iso14443-subr.c * @brief Defines some function extracted for ISO/IEC 14443 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include "nfc-internal.h" /** * @brief CRC_A * */ void iso14443a_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) { uint8_t bt; uint32_t wCrc = 0x6363; do { bt = *pbtData++; bt = (bt ^ (uint8_t)(wCrc & 0x00FF)); bt = (bt ^ (bt << 4)); wCrc = (wCrc >> 8) ^ ((uint32_t) bt << 8) ^ ((uint32_t) bt << 3) ^ ((uint32_t) bt >> 4); } while (--szLen); *pbtCrc++ = (uint8_t)(wCrc & 0xFF); *pbtCrc = (uint8_t)((wCrc >> 8) & 0xFF); } /** * @brief Append CRC_A * */ void iso14443a_crc_append(uint8_t *pbtData, size_t szLen) { iso14443a_crc(pbtData, szLen, pbtData + szLen); } /** * @brief CRC_B * */ void iso14443b_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) { uint8_t bt; uint32_t wCrc = 0xFFFF; do { bt = *pbtData++; bt = (bt ^ (uint8_t)(wCrc & 0x00FF)); bt = (bt ^ (bt << 4)); wCrc = (wCrc >> 8) ^ ((uint32_t) bt << 8) ^ ((uint32_t) bt << 3) ^ ((uint32_t) bt >> 4); } while (--szLen); wCrc = ~wCrc; *pbtCrc++ = (uint8_t)(wCrc & 0xFF); *pbtCrc = (uint8_t)((wCrc >> 8) & 0xFF); } /** * @brief Append CRC_B * */ void iso14443b_crc_append(uint8_t *pbtData, size_t szLen) { iso14443b_crc(pbtData, szLen, pbtData + szLen); } /** * @brief Locate historical bytes * @see ISO/IEC 14443-4 (5.2.7 Historical bytes) */ uint8_t * iso14443a_locate_historical_bytes(uint8_t *pbtAts, size_t szAts, size_t *pszTk) { if (szAts) { size_t offset = 1; if (pbtAts[0] & 0x10) { // TA offset++; } if (pbtAts[0] & 0x20) { // TB offset++; } if (pbtAts[0] & 0x40) { // TC offset++; } if (szAts > offset) { *pszTk = (szAts - offset); return (pbtAts + offset); } } *pszTk = 0; return NULL; } /** * @brief Add cascade tags (0x88) in UID * @see ISO/IEC 14443-3 (6.4.4 UID contents and cascade levels) */ void iso14443_cascade_uid(const uint8_t abtUID[], const size_t szUID, uint8_t *pbtCascadedUID, size_t *pszCascadedUID) { switch (szUID) { case 7: pbtCascadedUID[0] = 0x88; memcpy(pbtCascadedUID + 1, abtUID, 7); *pszCascadedUID = 8; break; case 10: pbtCascadedUID[0] = 0x88; memcpy(pbtCascadedUID + 1, abtUID, 3); pbtCascadedUID[4] = 0x88; memcpy(pbtCascadedUID + 5, abtUID + 3, 7); *pszCascadedUID = 12; break; case 4: default: memcpy(pbtCascadedUID, abtUID, szUID); *pszCascadedUID = szUID; break; } } libnfc-1.7.1/libnfc/iso7816.h000066400000000000000000000032501230265671100155060ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file iso7816.h * @brief Defines some macros extracted for ISO/IEC 7816-4 */ #ifndef __LIBNFC_ISO7816_H__ #define __LIBNFC_ISO7816_H__ #define ISO7816_C_APDU_COMMAND_HEADER_LEN 4 #define ISO7816_SHORT_APDU_MAX_DATA_LEN 256 #define ISO7816_SHORT_C_APDU_MAX_OVERHEAD 2 #define ISO7816_SHORT_R_APDU_RESPONSE_TRAILER_LEN 2 #define ISO7816_SHORT_C_APDU_MAX_LEN (ISO7816_C_APDU_COMMAND_HEADER_LEN + ISO7816_SHORT_APDU_MAX_DATA_LEN + ISO7816_SHORT_C_APDU_MAX_OVERHEAD) #define ISO7816_SHORT_R_APDU_MAX_LEN (ISO7816_SHORT_APDU_MAX_DATA_LEN + ISO7816_SHORT_R_APDU_RESPONSE_TRAILER_LEN) #endif /* !__LIBNFC_ISO7816_H__ */ libnfc-1.7.1/libnfc/log-internal.c000066400000000000000000000026111230265671100167540ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Alex Lian * * 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 */ #include "log-internal.h" #include #include void log_vput_internal(const char *format, va_list args) { vfprintf(stderr, format, args); } void log_put_internal(const char *format, ...) { va_list va; va_start(va, format); vfprintf(stderr, format, va); va_end(va); } libnfc-1.7.1/libnfc/log-internal.h000066400000000000000000000030001230265671100167520ustar00rootroot00000000000000/*- * 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: * * 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 */ #ifndef __LOG_INTERNAL_H__ #define __LOG_INTERNAL_H__ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include // Internal methods so different platforms can route the logging // Offering both forms of the variadic function // These are implemented in the log_ specific file void log_put_internal(const char *format, ...); void log_vput_internal(const char *format, va_list args); #endif // __LOG_INTERNAL_H__ libnfc-1.7.1/libnfc/log.c000066400000000000000000000053171230265671100151500ustar00rootroot00000000000000/*- * 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: * * 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 */ #include "log.h" #include #include #include #include #include #include #include const char * log_priority_to_str(const int priority) { switch (priority) { case NFC_LOG_PRIORITY_ERROR: return "error"; case NFC_LOG_PRIORITY_INFO: return "info"; case NFC_LOG_PRIORITY_DEBUG: return "debug"; default: break; } return "unknown"; } #ifdef LOG #include "log-internal.h" void log_init(const nfc_context *context) { #ifdef ENVVARS char str[32]; sprintf(str, "%"PRIu32, context->log_level); setenv("LIBNFC_LOG_LEVEL", str, 1); #else (void)context; #endif } void log_exit(void) { } void log_put(const uint8_t group, const char *category, const uint8_t priority, const char *format, ...) { char *env_log_level = NULL; #ifdef ENVVARS env_log_level = getenv("LIBNFC_LOG_LEVEL"); #endif uint32_t log_level; if (NULL == env_log_level) { // LIBNFC_LOG_LEVEL is not set #ifdef DEBUG log_level = 3; #else log_level = 1; #endif } else { log_level = atoi(env_log_level); } // printf("log_level = %"PRIu32" group = %"PRIu8" priority = %"PRIu8"\n", log_level, group, priority); if (log_level) { // If log is not disabled by log_level=none if (((log_level & 0x00000003) >= priority) || // Global log level (((log_level >> (group * 2)) & 0x00000003) >= priority)) { // Group log level va_list va; va_start(va, format); log_put_internal("%s\t%s\t", log_priority_to_str(priority), category); log_vput_internal(format, va); log_put_internal("\n"); va_end(va); } } } #endif // LOG libnfc-1.7.1/libnfc/log.h000066400000000000000000000100151230265671100151440ustar00rootroot00000000000000/*- * 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: * * 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 */ #ifndef __LOG_H__ #define __LOG_H__ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "nfc-internal.h" #define NFC_LOG_PRIORITY_NONE 0 #define NFC_LOG_PRIORITY_ERROR 1 #define NFC_LOG_PRIORITY_INFO 2 #define NFC_LOG_PRIORITY_DEBUG 3 #define NFC_LOG_GROUP_GENERAL 1 #define NFC_LOG_GROUP_CONFIG 2 #define NFC_LOG_GROUP_CHIP 3 #define NFC_LOG_GROUP_DRIVER 4 #define NFC_LOG_GROUP_COM 5 #define NFC_LOG_GROUP_LIBUSB 6 /* To enable log only for one (or more) group, you can use this formula: log_level = NFC_LOG_PRIORITY(main) + NFC_LOG_PRIORITY(group) * 2 ^ (NFC_LOG_GROUP(group) * 2) Examples: * Main log level is NONE and only communication group log is set to DEBUG verbosity (for rx/tx trace): LIBNFC_LOG_LEVEL=3072 // 0+3072 * Main log level is ERROR and driver layer log is set to DEBUG level: LIBNFC_LOG_LEVEL=769 // 1+768 * Main log level is ERROR, driver layer is set to INFO and communication is set to DEBUG: LIBNFC_LOG_LEVEL=3585 // 1+512+3072 */ //int log_priority_to_int(const char* priority); const char *log_priority_to_str(const int priority); #if defined LOG # ifndef __has_attribute # define __has_attribute(x) 0 # endif # if __has_attribute(format) || defined(__GNUC__) # define __has_attribute_format 1 # endif void log_init(const nfc_context *context); void log_exit(void); void log_put(const uint8_t group, const char *category, const uint8_t priority, const char *format, ...) # if __has_attribute_format __attribute__((format(printf, 4, 5))) # endif ; #else // No logging #define log_init(nfc_context) ((void) 0) #define log_exit() ((void) 0) #define log_put(group, category, priority, format, ...) do {} while (0) #endif // LOG /** * @macro LOG_HEX * @brief Log a byte-array in hexadecimal format * Max values: pcTag of 121 bytes + ": " + 300 bytes of data+ "\0" => acBuf of 1024 bytes */ # ifdef LOG # define LOG_HEX(group, pcTag, pbtData, szBytes) do { \ size_t __szPos; \ char __acBuf[1024]; \ size_t __szBuf = 0; \ if ((int)szBytes < 0) { \ fprintf (stderr, "%s:%d: Attempt to print %d bytes!\n", __FILE__, __LINE__, (int)szBytes); \ log_put (group, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s:%d: Attempt to print %d bytes!\n", __FILE__, __LINE__, (int)szBytes); \ abort(); \ break; \ } \ snprintf (__acBuf + __szBuf, sizeof(__acBuf) - __szBuf, "%s: ", pcTag); \ __szBuf += strlen (pcTag) + 2; \ for (__szPos=0; (__szPos < (size_t)(szBytes)) && (__szBuf < sizeof(__acBuf)); __szPos++) { \ snprintf (__acBuf + __szBuf, sizeof(__acBuf) - __szBuf, "%02x ",((uint8_t *)(pbtData))[__szPos]); \ __szBuf += 3; \ } \ log_put (group, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", __acBuf); \ } while (0); # else # define LOG_HEX(group, pcTag, pbtData, szBytes) do { \ (void) group; \ (void) pcTag; \ (void) pbtData; \ (void) szBytes; \ } while (0); # endif #endif // __LOG_H__ libnfc-1.7.1/libnfc/mirror-subr.c000066400000000000000000000063601230265671100166510ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file mirror-subr.c * @brief Mirror bytes */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include "mirror-subr.h" static const uint8_t ByteMirror[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff }; uint8_t mirror(uint8_t bt) { return ByteMirror[bt]; } static void mirror_bytes(uint8_t *pbts, size_t szLen) { size_t szByteNr; for (szByteNr = 0; szByteNr < szLen; szByteNr++) { *pbts = ByteMirror[*pbts]; pbts++; } } uint32_t mirror32(uint32_t ui32Bits) { mirror_bytes((uint8_t *) & ui32Bits, 4); return ui32Bits; } uint64_t mirror64(uint64_t ui64Bits) { mirror_bytes((uint8_t *) & ui64Bits, 8); return ui64Bits; } libnfc-1.7.1/libnfc/mirror-subr.h000066400000000000000000000026461230265671100166610ustar00rootroot00000000000000/*- * 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: * * 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 * * * @file mirror-subr.h * @brief Mirror bytes */ #ifndef _LIBNFC_MIRROR_SUBR_H_ # define _LIBNFC_MIRROR_SUBR_H_ # include # include uint8_t mirror(uint8_t bt); uint32_t mirror32(uint32_t ui32Bits); uint64_t mirror64(uint64_t ui64Bits); void mirror_uint8_ts(uint8_t *pbts, size_t szLen); #endif // _LIBNFC_MIRROR_SUBR_H_ libnfc-1.7.1/libnfc/nfc-device.c000066400000000000000000000041721230265671100163700ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc-device.c * @brief Provide internal function to manipulate nfc_device type */ #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include "nfc-internal.h" nfc_device * nfc_device_new(const nfc_context *context, const nfc_connstring connstring) { nfc_device *res = malloc(sizeof(*res)); if (!res) { return NULL; } // Store associated context res->context = context; // Variables initiatialization // Note: Actually, these initialization will be overwritten while the device // will be setup. Putting them to _false_ while the default is _true_ ensure we // send the command to the chip res->bCrc = false; res->bPar = false; res->bEasyFraming = false; res->bInfiniteSelect = false; res->bAutoIso14443_4 = false; res->last_error = 0; memcpy(res->connstring, connstring, sizeof(res->connstring)); res->driver_data = NULL; res->chip_data = NULL; return res; } void nfc_device_free(nfc_device *dev) { if (dev) { free(dev->driver_data); free(dev); } } libnfc-1.7.1/libnfc/nfc-emulation.c000066400000000000000000000047211230265671100171260ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc-emulation.c * @brief Provide a small API to ease emulation in libnfc */ #include #include #include "iso7816.h" /** @ingroup emulation * @brief Emulate a target * @return Returns 0 on success, otherwise returns libnfc's error code (negative value). * * @param pnd \a nfc_device struct pointer that represents currently used device * @param emulator \nfc_emulator struct point that handles input/output functions * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_emulate_target(nfc_device *pnd, struct nfc_emulator *emulator, const int timeout) { uint8_t abtRx[ISO7816_SHORT_R_APDU_MAX_LEN]; uint8_t abtTx[ISO7816_SHORT_C_APDU_MAX_LEN]; int res; if ((res = nfc_target_init(pnd, emulator->target, abtRx, sizeof(abtRx), timeout)) < 0) { return res; } size_t szRx = res; int io_res = res; while (io_res >= 0) { io_res = emulator->state_machine->io(emulator, abtRx, szRx, abtTx, sizeof(abtTx)); if (io_res > 0) { if ((res = nfc_target_send_bytes(pnd, abtTx, io_res, timeout)) < 0) { return res; } } if (io_res >= 0) { if ((res = nfc_target_receive_bytes(pnd, abtRx, sizeof(abtRx), timeout)) < 0) { return res; } szRx = res; } } return io_res; } libnfc-1.7.1/libnfc/nfc-internal.c000066400000000000000000000164271230265671100167530ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc-internal.c * @brief Provide some useful internal functions */ #include #include "nfc-internal.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef CONFFILES #include "conf.h" #endif #include #include #include #define LOG_GROUP NFC_LOG_GROUP_GENERAL #define LOG_CATEGORY "libnfc.general" void string_as_boolean(const char *s, bool *value) { if (s) { if (!(*value)) { if ((strcmp(s, "yes") == 0) || (strcmp(s, "true") == 0) || (strcmp(s, "1") == 0)) { *value = true; return; } } else { if ((strcmp(s, "no") == 0) || (strcmp(s, "false") == 0) || (strcmp(s, "0") == 0)) { *value = false; return; } } } } nfc_context * nfc_context_new(void) { nfc_context *res = malloc(sizeof(*res)); if (!res) { return NULL; } // Set default context values res->allow_autoscan = true; res->allow_intrusive_scan = false; #ifdef DEBUG res->log_level = 3; #else res->log_level = 1; #endif // Clear user defined devices array for (int i = 0; i < MAX_USER_DEFINED_DEVICES; i++) { strcpy(res->user_defined_devices[i].name, ""); strcpy(res->user_defined_devices[i].connstring, ""); res->user_defined_devices[i].optional = false; } res->user_defined_device_count = 0; #ifdef ENVVARS // Load user defined device from environment variable at first char *envvar = getenv("LIBNFC_DEFAULT_DEVICE"); if (envvar) { strcpy(res->user_defined_devices[0].name, "user defined default device"); strncpy(res->user_defined_devices[0].connstring, envvar, NFC_BUFSIZE_CONNSTRING); res->user_defined_devices[0].connstring[NFC_BUFSIZE_CONNSTRING - 1] = '\0'; res->user_defined_device_count++; } #endif // ENVVARS #ifdef CONFFILES // Load options from configuration file (ie. /etc/nfc/libnfc.conf) conf_load(res); #endif // CONFFILES #ifdef ENVVARS // Environment variables // Load user defined device from environment variable as the only reader envvar = getenv("LIBNFC_DEVICE"); if (envvar) { strcpy(res->user_defined_devices[0].name, "user defined device"); strncpy(res->user_defined_devices[0].connstring, envvar, NFC_BUFSIZE_CONNSTRING); res->user_defined_devices[0].connstring[NFC_BUFSIZE_CONNSTRING - 1] = '\0'; res->user_defined_device_count = 1; } // Load "auto scan" option envvar = getenv("LIBNFC_AUTO_SCAN"); string_as_boolean(envvar, &(res->allow_autoscan)); // Load "intrusive scan" option envvar = getenv("LIBNFC_INTRUSIVE_SCAN"); string_as_boolean(envvar, &(res->allow_intrusive_scan)); // log level envvar = getenv("LIBNFC_LOG_LEVEL"); if (envvar) { res->log_level = atoi(envvar); } #endif // ENVVARS // Initialize log before use it... log_init(res); // Debug context state #if defined DEBUG log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_NONE, "log_level is set to %"PRIu32, res->log_level); #else log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "log_level is set to %"PRIu32, res->log_level); #endif log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "allow_autoscan is set to %s", (res->allow_autoscan) ? "true" : "false"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "allow_intrusive_scan is set to %s", (res->allow_intrusive_scan) ? "true" : "false"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d device(s) defined by user", res->user_defined_device_count); for (uint32_t i = 0; i < res->user_defined_device_count; i++) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, " #%d name: \"%s\", connstring: \"%s\"", i, res->user_defined_devices[i].name, res->user_defined_devices[i].connstring); } return res; } void nfc_context_free(nfc_context *context) { log_exit(); free(context); } void prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData) { switch (nm.nmt) { 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: { // 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: { // polling payload must be present (see ISO/IEC 18092 11.2.2.5) *ppbtInitiatorData = (uint8_t *) "\x00\xff\xff\x01\x00"; *pszInitiatorData = 5; } break; case NMT_ISO14443A: case NMT_JEWEL: case NMT_DEP: *ppbtInitiatorData = NULL; *pszInitiatorData = 0; break; } } int connstring_decode(const nfc_connstring connstring, const char *driver_name, const char *bus_name, char **pparam1, char **pparam2) { if (driver_name == NULL) { driver_name = ""; } if (bus_name == NULL) { bus_name = ""; } int n = strlen(connstring) + 1; char *param0 = malloc(n); if (param0 == NULL) { perror("malloc"); return 0; } char *param1 = malloc(n); if (param1 == NULL) { perror("malloc"); free(param0); return 0; } char *param2 = malloc(n); if (param2 == NULL) { perror("malloc"); free(param0); free(param1); return 0; } char format[32]; snprintf(format, sizeof(format), "%%%i[^:]:%%%i[^:]:%%%i[^:]", n - 1, n - 1, n - 1); int res = sscanf(connstring, format, param0, param1, param2); if (res < 1 || ((0 != strcmp(param0, driver_name)) && (bus_name != NULL) && (0 != strcmp(param0, bus_name)))) { // Driver name does not match. res = 0; } if (pparam1 != NULL) { if (res < 2) { free(param1); *pparam1 = NULL; } else { *pparam1 = param1; } } else { free(param1); } if (pparam2 != NULL) { if (res < 3) { free(param2); *pparam2 = NULL; } else { *pparam2 = param2; } } else { free(param2); } free(param0); return res; } libnfc-1.7.1/libnfc/nfc-internal.h000066400000000000000000000210121230265671100167420ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc-internal.h * @brief Internal defines and macros */ #ifndef __NFC_INTERNAL_H__ #define __NFC_INTERNAL_H__ #include #include # include #include "nfc/nfc.h" #include "log.h" /** * @macro HAL * @brief Execute corresponding driver function if exists. */ #define HAL( FUNCTION, ... ) pnd->last_error = 0; \ if (pnd->driver->FUNCTION) { \ return pnd->driver->FUNCTION( __VA_ARGS__ ); \ } else { \ pnd->last_error = NFC_EDEVNOTSUPP; \ return false; \ } #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif /* * Buffer management macros. * * The following macros ease setting-up and using buffers: * BUFFER_INIT (data, 5); // data -> [ xx, xx, xx, xx, xx ] * BUFFER_SIZE (data); // size -> 0 * BUFFER_APPEND (data, 0x12); // data -> [ 12, xx, xx, xx, xx ] * BUFFER_SIZE (data); // size -> 1 * uint16_t x = 0x3456; // We suppose we are little endian * BUFFER_APPEND_BYTES (data, x, 2); * // data -> [ 12, 56, 34, xx, xx ] * BUFFER_SIZE (data); // size -> 3 * BUFFER_APPEND_LE (data, x, 2, sizeof (x)); * // data -> [ 12, 56, 34, 34, 56 ] * BUFFER_SIZE (data); // size -> 5 */ /* * Initialise a buffer named buffer_name of size bytes. */ #define BUFFER_INIT(buffer_name, size) \ uint8_t buffer_name[size]; \ size_t __##buffer_name##_n = 0 /* * Create a wrapper for an existing buffer. * BEWARE! It eats children! */ #define BUFFER_ALIAS(buffer_name, origin) \ uint8_t *buffer_name = (void *)origin; \ size_t __##buffer_name##_n = 0; #define BUFFER_SIZE(buffer_name) (__##buffer_name##_n) #define BUFFER_CLEAR(buffer_name) (__##buffer_name##_n = 0) /* * Append one byte of data to the buffer buffer_name. */ #define BUFFER_APPEND(buffer_name, data) \ do { \ buffer_name[__##buffer_name##_n++] = data; \ } while (0) /* * Append size bytes of data to the buffer buffer_name. */ #define BUFFER_APPEND_BYTES(buffer_name, data, size) \ do { \ size_t __n = 0; \ while (__n < size) { \ buffer_name[__##buffer_name##_n++] = ((uint8_t *)data)[__n++]; \ } \ } while (0) typedef enum { NOT_INTRUSIVE, INTRUSIVE, NOT_AVAILABLE, } scan_type_enum; struct nfc_driver { const char *name; const scan_type_enum scan_type; size_t (*scan)(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len); struct nfc_device *(*open)(const nfc_context *context, const nfc_connstring connstring); void (*close)(struct nfc_device *pnd); const char *(*strerror)(const struct nfc_device *pnd); int (*initiator_init)(struct nfc_device *pnd); int (*initiator_init_secure_element)(struct nfc_device *pnd); int (*initiator_select_passive_target)(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt); int (*initiator_poll_target)(struct nfc_device *pnd, const nfc_modulation *pnmModulations, const size_t szModulations, const uint8_t uiPollNr, const uint8_t btPeriod, nfc_target *pnt); int (*initiator_select_dep_target)(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout); int (*initiator_deselect_target)(struct nfc_device *pnd); int (*initiator_transceive_bytes)(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout); int (*initiator_transceive_bits)(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar); int (*initiator_transceive_bytes_timed)(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles); int (*initiator_transceive_bits_timed)(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, uint8_t *pbtRxPar, uint32_t *cycles); int (*initiator_target_is_present)(struct nfc_device *pnd, const nfc_target *pnt); int (*target_init)(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout); int (*target_send_bytes)(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout); int (*target_receive_bytes)(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, int timeout); int (*target_send_bits)(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar); int (*target_receive_bits)(struct nfc_device *pnd, uint8_t *pbtRx, const size_t szRxLen, uint8_t *pbtRxPar); int (*device_set_property_bool)(struct nfc_device *pnd, const nfc_property property, const bool bEnable); int (*device_set_property_int)(struct nfc_device *pnd, const nfc_property property, const int value); int (*get_supported_modulation)(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); int (*get_supported_baud_rate)(struct nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); int (*device_get_information_about)(struct nfc_device *pnd, char **buf); int (*abort_command)(struct nfc_device *pnd); int (*idle)(struct nfc_device *pnd); int (*powerdown)(struct nfc_device *pnd); }; # define DEVICE_NAME_LENGTH 256 # define DEVICE_PORT_LENGTH 64 #define MAX_USER_DEFINED_DEVICES 4 struct nfc_user_defined_device { char name[DEVICE_NAME_LENGTH]; nfc_connstring connstring; bool optional; }; /** * @struct nfc_context * @brief NFC library context * Struct which contains internal options, references, pointers, etc. used by library */ struct nfc_context { bool allow_autoscan; bool allow_intrusive_scan; uint32_t log_level; struct nfc_user_defined_device user_defined_devices[MAX_USER_DEFINED_DEVICES]; unsigned int user_defined_device_count; }; nfc_context *nfc_context_new(void); void nfc_context_free(nfc_context *context); /** * @struct nfc_device * @brief NFC device information */ struct nfc_device { const nfc_context *context; const struct nfc_driver *driver; void *driver_data; void *chip_data; /** Device name string, including device wrapper firmware */ char name[DEVICE_NAME_LENGTH]; /** Device connection string */ nfc_connstring connstring; /** Is the CRC automaticly added, checked and removed from the frames */ bool bCrc; /** Does the chip handle parity bits, all parities are handled as data */ bool bPar; /** Should the chip handle frames encapsulation and chaining */ bool bEasyFraming; /** Should the chip try forever on select? */ bool bInfiniteSelect; /** Should the chip switch automatically activate ISO14443-4 when selecting tags supporting it? */ bool bAutoIso14443_4; /** Supported modulation encoded in a byte */ uint8_t btSupportByte; /** Last reported error */ int last_error; }; nfc_device *nfc_device_new(const nfc_context *context, const nfc_connstring connstring); void nfc_device_free(nfc_device *dev); void string_as_boolean(const char *s, bool *value); void iso14443_cascade_uid(const uint8_t abtUID[], const size_t szUID, uint8_t *pbtCascadedUID, size_t *pszCascadedUID); void prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData); int connstring_decode(const nfc_connstring connstring, const char *driver_name, const char *bus_name, char **pparam1, char **pparam2); #endif // __NFC_INTERNAL_H__ libnfc-1.7.1/libnfc/nfc.c000066400000000000000000001432111230265671100151310ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file nfc.c * @brief NFC library implementation */ /** * @defgroup lib Library initialization/deinitialization * This page details how to initialize and deinitialize libnfc. Initialization * must be performed before using any libnfc functionality, and similarly you * must not call any libnfc functions after deinitialization. */ /** * @defgroup dev NFC Device/Hardware manipulation * The functionality documented below is designed to help with the following * operations: * - Enumerating the NFC devices currently attached to the system * - Opening and closing the chosen device */ /** * @defgroup initiator NFC initiator * This page details how to act as "reader". */ /** * @defgroup target NFC target * This page details how to act as tag (i.e. MIFARE Classic) or NFC target device. */ /** * @defgroup error Error reporting * Most libnfc functions return 0 on success or one of error codes defined on failure. */ /** * @defgroup data Special data accessors * The functionnality documented below allow to access to special data as device name or device connstring. */ /** * @defgroup properties Properties accessors * The functionnality documented below allow to configure parameters and registers. */ /** * @defgroup misc Miscellaneous * */ /** * @defgroup string-converter To-string converters * The functionnality documented below allow to retreive some information in text format. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "nfc-internal.h" #include "target-subr.h" #include "drivers.h" #if defined (DRIVER_ACR122_PCSC_ENABLED) # include "drivers/acr122_pcsc.h" #endif /* DRIVER_ACR122_PCSC_ENABLED */ #if defined (DRIVER_ACR122_USB_ENABLED) # include "drivers/acr122_usb.h" #endif /* DRIVER_ACR122_USB_ENABLED */ #if defined (DRIVER_ACR122S_ENABLED) # include "drivers/acr122s.h" #endif /* DRIVER_ACR122S_ENABLED */ #if defined (DRIVER_PN53X_USB_ENABLED) # include "drivers/pn53x_usb.h" #endif /* DRIVER_PN53X_USB_ENABLED */ #if defined (DRIVER_ARYGON_ENABLED) # include "drivers/arygon.h" #endif /* DRIVER_ARYGON_ENABLED */ #if defined (DRIVER_PN532_UART_ENABLED) # include "drivers/pn532_uart.h" #endif /* DRIVER_PN532_UART_ENABLED */ #if defined (DRIVER_PN532_SPI_ENABLED) # include "drivers/pn532_spi.h" #endif /* DRIVER_PN532_SPI_ENABLED */ #if defined (DRIVER_PN532_I2C_ENABLED) # include "drivers/pn532_i2c.h" #endif /* DRIVER_PN532_I2C_ENABLED */ #define LOG_CATEGORY "libnfc.general" #define LOG_GROUP NFC_LOG_GROUP_GENERAL struct nfc_driver_list { const struct nfc_driver_list *next; const struct nfc_driver *driver; }; const struct nfc_driver_list *nfc_drivers = NULL; 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_ACR122_PCSC_ENABLED) nfc_register_driver(&acr122_pcsc_driver); #endif /* DRIVER_ACR122_PCSC_ENABLED */ #if defined (DRIVER_ACR122_USB_ENABLED) nfc_register_driver(&acr122_usb_driver); #endif /* DRIVER_ACR122_USB_ENABLED */ #if defined (DRIVER_ACR122S_ENABLED) nfc_register_driver(&acr122s_driver); #endif /* DRIVER_ACR122S_ENABLED */ #if defined (DRIVER_PN532_UART_ENABLED) nfc_register_driver(&pn532_uart_driver); #endif /* DRIVER_PN532_UART_ENABLED */ #if defined (DRIVER_PN532_SPI_ENABLED) nfc_register_driver(&pn532_spi_driver); #endif /* DRIVER_PN532_SPI_ENABLED */ #if defined (DRIVER_PN532_I2C_ENABLED) nfc_register_driver(&pn532_i2c_driver); #endif /* DRIVER_PN532_I2C_ENABLED */ #if defined (DRIVER_ARYGON_ENABLED) nfc_register_driver(&arygon_driver); #endif /* DRIVER_ARYGON_ENABLED */ } /** @ingroup lib * @brief Register an NFC device driver with libnfc. * This function registers a driver with libnfc, the caller is responsible of managing the lifetime of the * driver and make sure that any resources associated with the driver are available after registration. * @param pnd Pointer to an NFC device driver to be registered. * @retval NFC_SUCCESS If the driver registration succeeds. */ int nfc_register_driver(const struct nfc_driver *ndr) { if (!ndr) return NFC_EINVARG; struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list)); if (!pndl) return NFC_ESOFT; pndl->driver = ndr; pndl->next = nfc_drivers; nfc_drivers = pndl; return NFC_SUCCESS; } /** @ingroup lib * @brief Initialize libnfc. * This function must be called before calling any other libnfc function * @param context Output location for nfc_context */ void nfc_init(nfc_context **context) { *context = nfc_context_new(); if (!*context) { perror("malloc"); return; } if (!nfc_drivers) nfc_drivers_init(); } /** @ingroup lib * @brief Deinitialize libnfc. * Should be called after closing all open devices and before your application terminates. * @param context The context to deinitialize */ void nfc_exit(nfc_context *context) { while (nfc_drivers) { struct nfc_driver_list *pndl = (struct nfc_driver_list *) nfc_drivers; nfc_drivers = pndl->next; free(pndl); } nfc_context_free(context); } /** @ingroup dev * @brief Open a NFC device * @param context The context to operate on. * @param connstring The device connection string if specific device is wanted, \c NULL otherwise * @return Returns pointer to a \a nfc_device struct if successfull; otherwise returns \c NULL value. * * If \e connstring is \c NULL, the first available device from \a nfc_list_devices function is used. * * If \e connstring is set, this function will try to claim the right device using information provided by \e connstring. * * When it has successfully claimed a NFC device, memory is allocated to save the device information. * It will return a pointer to a \a nfc_device struct. * This pointer should be supplied by every next functions of libnfc that should perform an action with this device. * * @note Depending on the desired operation mode, the device needs to be configured by using nfc_initiator_init() or nfc_target_init(), * optionally followed by manual tuning of the parameters if the default parameters are not suiting your goals. */ nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring) { nfc_device *pnd = NULL; nfc_connstring ncs; if (connstring == NULL) { if (!nfc_list_devices(context, &ncs, 1)) { return NULL; } } else { strncpy(ncs, connstring, sizeof(nfc_connstring)); ncs[sizeof(nfc_connstring) - 1] = '\0'; } // Search through the device list for an available device const struct nfc_driver_list *pndl = nfc_drivers; while (pndl) { const struct nfc_driver *ndr = pndl->driver; // Specific device is requested: using device description if (0 != strncmp(ndr->name, ncs, strlen(ndr->name))) { // Check if connstring driver is usb -> accept any driver *_usb if ((0 != strncmp("usb", ncs, strlen("usb"))) || 0 != strncmp("_usb", ndr->name + (strlen(ndr->name) - 4), 4)) { pndl = pndl->next; continue; } } pnd = ndr->open(context, ncs); // Test if the opening was successful if (pnd == NULL) { if (0 == strncmp("usb", ncs, strlen("usb"))) { // We've to test the other usb drivers before giving up pndl = pndl->next; continue; } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open \"%s\".", ncs); return NULL; } for (uint32_t i = 0; i > context->user_defined_device_count; i++) { if (strcmp(ncs, context->user_defined_devices[i].connstring) == 0) { // This is a device sets by user, we use the device name given by user strcpy(pnd->name, context->user_defined_devices[i].name); break; } } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "\"%s\" (%s) has been claimed.", pnd->name, pnd->connstring); return pnd; } // Too bad, no driver can decode connstring log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "No driver available to handle \"%s\".", ncs); return NULL; } /** @ingroup dev * @brief Close from a NFC device * @param pnd \a nfc_device struct pointer that represent currently used device * * Initiator's selected tag is closed and the device, including allocated \a nfc_device struct, is released. */ void nfc_close(nfc_device *pnd) { if (pnd) { // Close, clean up and release the device pnd->driver->close(pnd); } } /** @ingroup dev * @brief Scan for discoverable supported devices (ie. only available for some drivers) * @return Returns the number of devices found. * @param context The context to operate on, or NULL for the default context. * @param connstrings array of \a nfc_connstring. * @param connstrings_len size of the \a connstrings array. * */ size_t nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; #ifdef CONFFILES // Load manually configured devices (from config file and env variables) // TODO From env var... for (uint32_t i = 0; i < context->user_defined_device_count; i++) { if (context->user_defined_devices[i].optional) { // let's make sure the device exists nfc_device *pnd = NULL; #ifdef ENVVARS char *env_log_level = getenv("LIBNFC_LOG_LEVEL"); char *old_env_log_level = NULL; // do it silently if (env_log_level) { if ((old_env_log_level = malloc(strlen(env_log_level) + 1)) == NULL) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to malloc()"); return 0; } strcpy(old_env_log_level, env_log_level); } setenv("LIBNFC_LOG_LEVEL", "0", 1); #endif // ENVVARS pnd = nfc_open(context, context->user_defined_devices[i].connstring); #ifdef ENVVARS if (old_env_log_level) { setenv("LIBNFC_LOG_LEVEL", old_env_log_level, 1); free(old_env_log_level); } else { unsetenv("LIBNFC_LOG_LEVEL"); } #endif // ENVVARS if (pnd) { nfc_close(pnd); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "User device %s found", context->user_defined_devices[i].name); strcpy((char *)(connstrings + device_found), context->user_defined_devices[i].connstring); device_found ++; if (device_found == connstrings_len) break; } } else { // manual choice is not marked as optional so let's take it blindly strcpy((char *)(connstrings + device_found), context->user_defined_devices[i].connstring); device_found++; if (device_found >= connstrings_len) return device_found; } } #endif // CONFFILES // Device auto-detection if (context->allow_autoscan) { const struct nfc_driver_list *pndl = nfc_drivers; while (pndl) { const struct nfc_driver *ndr = pndl->driver; if ((ndr->scan_type == NOT_INTRUSIVE) || ((context->allow_intrusive_scan) && (ndr->scan_type == INTRUSIVE))) { size_t _device_found = ndr->scan(context, connstrings + (device_found), connstrings_len - (device_found)); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%ld device(s) found using %s driver", (unsigned long) _device_found, ndr->name); if (_device_found > 0) { device_found += _device_found; if (device_found == connstrings_len) break; } } // scan_type is INTRUSIVE but not allowed or NOT_AVAILABLE pndl = pndl->next; } } else if (context->user_defined_device_count == 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: %s" , "user must specify device(s) manually when autoscan is disabled"); } return device_found; } /** @ingroup properties * @brief Set a device's integer-property value * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param property \a nfc_property which will be set * @param value integer value * * Sets integer property. * * @see nfc_property enum values */ int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value) { HAL(device_set_property_int, pnd, property, value); } /** @ingroup properties * @brief Set a device's boolean-property value * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param property \a nfc_property which will be set * @param bEnable boolean to activate/disactivate the property * * Configures parameters and registers that control for example timing, * modulation, frame and error handling. There are different categories for * configuring the \e PN53X chip features (handle, activate, infinite and * accept). */ int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) { HAL(device_set_property_bool, pnd, property, bEnable); } /** @ingroup initiator * @brief Initialize NFC device as initiator (reader) * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * * The NFC device is configured to function as RFID reader. * After initialization it can be used to communicate to passive RFID tags and active NFC devices. * The reader will act as initiator to communicate peer 2 peer (NFCIP) to other active NFC devices. * - Crc is handled by the device (NP_HANDLE_CRC = true) * - Parity is handled the device (NP_HANDLE_PARITY = true) * - Cryto1 cipher is disabled (NP_ACTIVATE_CRYPTO1 = false) * - Easy framing is enabled (NP_EASY_FRAMING = true) * - Auto-switching in ISO14443-4 mode is enabled (NP_AUTO_ISO14443_4 = true) * - Invalid frames are not accepted (NP_ACCEPT_INVALID_FRAMES = false) * - Multiple frames are not accepted (NP_ACCEPT_MULTIPLE_FRAMES = false) * - 14443-A mode is activated (NP_FORCE_ISO14443_A = true) * - speed is set to 106 kbps (NP_FORCE_SPEED_106 = true) * - Let the device try forever to find a target (NP_INFINITE_SELECT = true) * - RF field is shortly dropped (if it was enabled) then activated again */ int nfc_initiator_init(nfc_device *pnd) { int res = 0; // Drop the field for a while if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) return res; // Enable field so more power consuming cards can power themselves up if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true)) < 0) return res; // Let the device try forever to find a target/tag if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return res; // Activate auto ISO14443-4 switching by default if ((res = nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true)) < 0) return res; // Force 14443-A mode if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_ISO14443_A, true)) < 0) return res; // Force speed at 106kbps if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_SPEED_106, true)) < 0) return res; // Disallow invalid frame if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_INVALID_FRAMES, false)) < 0) return res; // Disallow multiple frames if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_MULTIPLE_FRAMES, false)) < 0) return res; HAL(initiator_init, pnd); } /** @ingroup initiator * @brief Initialize NFC device as initiator with its secure element initiator (reader) * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * * The NFC device is configured to function as secure element reader. * After initialization it can be used to communicate with the secure element. * @note RF field is desactvated in order to some power */ int nfc_initiator_init_secure_element(nfc_device *pnd) { HAL(initiator_init_secure_element, pnd); } /** @ingroup initiator * @brief Select a passive or emulated tag * @return Returns selected passive target count on success, otherwise returns libnfc's error code (negative value) * * @param pnd \a nfc_device struct pointer that represent currently used device * @param nm desired modulation * @param pbtInitData optional initiator data, NULL for using the default values. * @param szInitData length of initiator data \a pbtInitData. * @note pbtInitData is used with different kind of data depending on modulation type: * - for an ISO/IEC 14443 type A modulation, pbbInitData contains the UID you want to select; * - for an ISO/IEC 14443 type B modulation, pbbInitData contains Application Family Identifier (AFI) (see ISO/IEC 14443-3) and optionally a second byte = 0x01 if you want to use probabilistic approach instead of timeslot approach; * - for a FeliCa modulation, pbbInitData contains a 5-byte polling payload (see ISO/IEC 18092 11.2.2.5). * - for ISO14443B', ASK CTx and ST SRx, see corresponding standards * - if NULL, default values adequate for the chosen modulation will be used. * * @param[out] pnt \a nfc_target struct pointer which will filled if available * * The NFC device will try to find one available passive tag or emulated tag. * * The chip needs to know with what kind of tag it is dealing with, therefore * the initial modulation and speed (106, 212 or 424 kbps) should be supplied. */ int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt) { uint8_t *abtInit = NULL; uint8_t abtTmpInit[MAX(12, szInitData)]; size_t szInit = 0; if (szInitData == 0) { // Provide default values, if any prepare_initiator_data(nm, &abtInit, &szInit); } else if (nm.nmt == NMT_ISO14443A) { abtInit = abtTmpInit; iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit); } else { abtInit = abtTmpInit; memcpy(abtInit, pbtInitData, szInitData); szInit = szInitData; } HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt); } /** @ingroup initiator * @brief List passive or emulated tags * @return Returns the number of targets found on success, otherwise returns libnfc's error code (negative value) * * @param pnd \a nfc_device struct pointer that represent currently used device * @param nm desired modulation * @param[out] ant array of \a nfc_target that will be filled with targets info * @param szTargets size of \a ant (will be the max targets listed) * * The NFC device will try to find the available passive tags. Some NFC devices * are capable to emulate passive tags. The standards (ISO18092 and ECMA-340) * describe the modulation that can be used for reader to passive * communications. The chip needs to know with what kind of tag it is dealing * with, therefore the initial modulation and speed (106, 212 or 424 kbps) * should be supplied. */ int nfc_initiator_list_passive_targets(nfc_device *pnd, const nfc_modulation nm, nfc_target ant[], const size_t szTargets) { nfc_target nt; size_t szTargetFound = 0; uint8_t *pbtInitData = NULL; size_t szInitDataLen = 0; int res = 0; pnd->last_error = 0; // Let the reader only try once to find a tag bool bInfiniteSelect = pnd->bInfiniteSelect; if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) { return res; } prepare_initiator_data(nm, &pbtInitData, &szInitDataLen); while (nfc_initiator_select_passive_target(pnd, nm, pbtInitData, szInitDataLen, &nt) > 0) { size_t i; bool seen = false; // Check if we've already seen this tag for (i = 0; i < szTargetFound; i++) { if (memcmp(&(ant[i]), &nt, sizeof(nfc_target)) == 0) { seen = true; } } if (seen) { break; } memcpy(&(ant[szTargetFound]), &nt, sizeof(nfc_target)); szTargetFound++; if (szTargets == szTargetFound) { break; } nfc_initiator_deselect_target(pnd); // deselect has no effect on FeliCa and Jewel cards so we'll stop after one... // ISO/IEC 14443 B' cards are polled at 100% probability so it's not possible to detect correctly two cards at the same time if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) { break; } } if (bInfiniteSelect) { if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) { return res; } } return szTargetFound; } /** @ingroup initiator * @brief Polling for NFC targets * @return Returns polled targets count, otherwise returns libnfc's error code (negative value). * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pnmModulations desired modulations * @param szModulations size of \a pnmModulations * @param uiPollNr specifies the number of polling (0x01 – 0xFE: 1 up to 254 polling, 0xFF: Endless polling) * @note one polling is a polling for each desired target type * @param uiPeriod indicates the polling period in units of 150 ms (0x01 – 0x0F: 150ms – 2.25s) * @note e.g. if uiPeriod=10, it will poll each desired target type during 1.5s * @param[out] pnt pointer on \a nfc_target (over)writable struct */ int nfc_initiator_poll_target(nfc_device *pnd, const nfc_modulation *pnmModulations, const size_t szModulations, const uint8_t uiPollNr, const uint8_t uiPeriod, nfc_target *pnt) { HAL(initiator_poll_target, pnd, pnmModulations, szModulations, uiPollNr, uiPeriod, pnt); } /** @ingroup initiator * @brief Select a target and request active or passive mode for D.E.P. (Data Exchange Protocol) * @return Returns selected D.E.P targets count on success, otherwise returns libnfc's error code (negative value). * * @param pnd \a nfc_device struct pointer that represent currently used device * @param ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode) * @param nbr desired baud rate * @param ndiInitiator pointer \a nfc_dep_info struct that contains \e NFCID3 and \e General \e Bytes to set to the initiator device (optionnal, can be \e NULL) * @param[out] pnt is a \a nfc_target struct pointer where target information will be put. * @param timeout in milliseconds * * The NFC device will try to find an available D.E.P. target. The standards * (ISO18092 and ECMA-340) describe the modulation that can be used for reader * to passive communications. * * @note \a nfc_dep_info will be returned when the target was acquired successfully. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_initiator_select_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout) { HAL(initiator_select_dep_target, pnd, ndm, nbr, pndiInitiator, pnt, timeout); } /** @ingroup initiator * @brief Poll a target and request active or passive mode for D.E.P. (Data Exchange Protocol) * @return Returns selected D.E.P targets count on success, otherwise returns libnfc's error code (negative value). * * @param pnd \a nfc_device struct pointer that represent currently used device * @param ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode) * @param nbr desired baud rate * @param ndiInitiator pointer \a nfc_dep_info struct that contains \e NFCID3 and \e General \e Bytes to set to the initiator device (optionnal, can be \e NULL) * @param[out] pnt is a \a nfc_target struct pointer where target information will be put. * @param timeout in milliseconds * * The NFC device will try to find an available D.E.P. target. The standards * (ISO18092 and ECMA-340) describe the modulation that can be used for reader * to passive communications. * * @note \a nfc_dep_info will be returned when the target was acquired successfully. */ int nfc_initiator_poll_dep_target(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout) { const int period = 300; int remaining_time = timeout; int res; int result = 0; bool bInfiniteSelect = pnd->bInfiniteSelect; if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return res; while (remaining_time > 0) { if ((res = nfc_initiator_select_dep_target(pnd, ndm, nbr, pndiInitiator, pnt, period)) < 0) { if (res != NFC_ETIMEOUT) { result = res; goto end; } } if (res == 1) { result = res; goto end; } remaining_time -= period; } end: if (! bInfiniteSelect) { if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) { return res; } } return result; } /** @ingroup initiator * @brief Deselect a selected passive or emulated tag * @return Returns 0 on success, otherwise returns libnfc's error code (negative value). * @param pnd \a nfc_device struct pointer that represents currently used device * * After selecting and communicating with a passive tag, this function could be * used to deactivate and release the tag. This is very useful when there are * multiple tags available in the field. It is possible to use the \fn * nfc_initiator_select_passive_target() function to select the first available * tag, test it for the available features and support, deselect it and skip to * the next tag until the correct tag is found. */ int nfc_initiator_deselect_target(nfc_device *pnd) { HAL(initiator_deselect_target, pnd); } /** @ingroup initiator * @brief Send data to target then retrieve data from target * @return Returns received bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represents currently used device * @param pbtTx contains a byte array of the frame that needs to be transmitted. * @param szTx contains the length in bytes. * @param[out] pbtRx response from the target * @param szRx size of \a pbtRx (Will return NFC_EOVFLOW if RX exceeds this size) * @param timeout in milliseconds * * The NFC device (configured as initiator) will transmit the supplied bytes (\a pbtTx) to the target. * It waits for the response and stores the received bytes in the \a pbtRx byte array. * * If \a NP_EASY_FRAMING option is disabled the frames will sent and received in raw mode: \e PN53x will not handle input neither output data. * * The parity bits are handled by the \e PN53x chip. The CRC can be generated automatically or handled manually. * Using this function, frames can be communicated very fast via the NFC initiator to the tag. * * Tests show that on average this way of communicating is much faster than using the regular driver/middle-ware (often supplied by manufacturers). * * @warning The configuration option \a NP_HANDLE_PARITY must be set to \c true (the default value). * * @note When used with MIFARE Classic, NFC_EMFCAUTHFAIL error is returned if authentication command failed. You need to re-select the tag to operate with. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout) { HAL(initiator_transceive_bytes, pnd, pbtTx, szTx, pbtRx, szRx, timeout) } /** @ingroup initiator * @brief Transceive raw bit-frames to a target * @return Returns received bits count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represents currently used device * @param pbtTx contains a byte array of the frame that needs to be transmitted. * @param szTxBits contains the length in bits. * * @note For example the REQA (0x26) command (first anti-collision command of * ISO14443-A) must be precise 7 bits long. This is not possible by using * nfc_initiator_transceive_bytes(). With that function you can only * communicate frames that consist of full bytes. When you send a full byte (8 * bits + 1 parity) with the value of REQA (0x26), a tag will simply not * respond. More information about this can be found in the anti-collision * example (\e nfc-anticol). * * @param pbtTxPar parameter contains a byte array of the corresponding parity bits needed to send per byte. * * @note For example if you send the SELECT_ALL (0x93, 0x20) = [ 10010011, * 00100000 ] command, you have to supply the following parity bytes (0x01, * 0x00) to define the correct odd parity bits. This is only an example to * explain how it works, if you just are sending two bytes with ISO14443-A * compliant parity bits you better can use the * nfc_initiator_transceive_bytes() function. * * @param[out] pbtRx response from the target * @param szRx size of \a pbtRx (Will return NFC_EOVFLOW if RX exceeds this size) * @param[out] pbtRxPar parameter contains a byte array of the corresponding parity bits * * The NFC device (configured as \e initiator) will transmit low-level messages * where only the modulation is handled by the \e PN53x chip. Construction of * the frame (data, CRC and parity) is completely done by libnfc. This can be * very useful for testing purposes. Some protocols (e.g. MIFARE Classic) * require to violate the ISO14443-A standard by sending incorrect parity and * CRC bytes. Using this feature you are able to simulate these frames. */ int nfc_initiator_transceive_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar) { (void)szRx; HAL(initiator_transceive_bits, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar); } /** @ingroup initiator * @brief Send data to target then retrieve data from target * @return Returns received bytes count on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represents currently used device * @param pbtTx contains a byte array of the frame that needs to be transmitted. * @param szTx contains the length in bytes. * @param[out] pbtRx response from the target * @param szRx size of \a pbtRx (Will return NFC_EOVFLOW if RX exceeds this size) * * This function is similar to nfc_initiator_transceive_bytes() with the following differences: * - A precise cycles counter will indicate the number of cycles between emission & reception of frames. * - It only supports mode with \a NP_EASY_FRAMING option disabled. * - Overall communication with the host is heavier and slower. * * Timer control: * By default timer configuration tries to maximize the precision, which also limits the maximum * cycles count before saturation/timeout. * E.g. with PN53x it can count up to 65535 cycles, so about 4.8ms, with a precision of about 73ns. * - If you're ok with the defaults, set *cycles = 0 before calling this function. * - If you need to count more cycles, set *cycles to the maximum you expect but don't forget * you'll loose in precision and it'll take more time before timeout, so don't abuse! * * @warning The configuration option \a NP_EASY_FRAMING must be set to \c false. * @warning The configuration option \a NP_HANDLE_PARITY must be set to \c true (the default value). */ int nfc_initiator_transceive_bytes_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles) { HAL(initiator_transceive_bytes_timed, pnd, pbtTx, szTx, pbtRx, szRx, cycles); } /** @ingroup initiator * @brief Check target presence * @return Returns 0 on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pnt a \a nfc_target struct pointer where desired target information was stored (optionnal, can be \e NULL). * This function tests if \a nfc_target (or last selected tag if \e NULL) is currently present on NFC device. * @warning The target have to be selected before check its presence * @warning To run the test, one or more commands will be sent to target */ int nfc_initiator_target_is_present(nfc_device *pnd, const nfc_target *pnt) { HAL(initiator_target_is_present, pnd, pnt); } /** @ingroup initiator * @brief Transceive raw bit-frames to a target * @return Returns received bits count on success, otherwise returns libnfc's error code * * This function is similar to nfc_initiator_transceive_bits() with the following differences: * - A precise cycles counter will indicate the number of cycles between emission & reception of frames. * - It only supports mode with \a NP_EASY_FRAMING option disabled and CRC must be handled manually. * - Overall communication with the host is heavier and slower. * * Timer control: * By default timer configuration tries to maximize the precision, which also limits the maximum * cycles count before saturation/timeout. * E.g. with PN53x it can count up to 65535 cycles, so about 4.8ms, with a precision of about 73ns. * - If you're ok with the defaults, set *cycles = 0 before calling this function. * - If you need to count more cycles, set *cycles to the maximum you expect but don't forget * you'll loose in precision and it'll take more time before timeout, so don't abuse! * * @warning The configuration option \a NP_EASY_FRAMING must be set to \c false. * @warning The configuration option \a NP_HANDLE_CRC must be set to \c false. * @warning The configuration option \a NP_HANDLE_PARITY must be set to \c true (the default value). */ int nfc_initiator_transceive_bits_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar, uint32_t *cycles) { (void)szRx; HAL(initiator_transceive_bits_timed, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar, cycles); } /** @ingroup target * @brief Initialize NFC device as an emulated tag * @return Returns received bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pnt pointer to \a nfc_target struct that represents the wanted emulated target * * @note \a pnt can be updated by this function: if you set NBR_UNDEFINED * and/or NDM_UNDEFINED (ie. for DEP mode), these fields will be updated. * * @param[out] pbtRx Rx buffer pointer * @param[out] szRx received bytes count * @param timeout in milliseconds * * This function initializes NFC device in \e target mode in order to emulate a * tag using the specified \a nfc_target_mode_t. * - Crc is handled by the device (NP_HANDLE_CRC = true) * - Parity is handled the device (NP_HANDLE_PARITY = true) * - Cryto1 cipher is disabled (NP_ACTIVATE_CRYPTO1 = false) * - Auto-switching in ISO14443-4 mode is enabled (NP_AUTO_ISO14443_4 = true) * - Easy framing is disabled (NP_EASY_FRAMING = false) * - Invalid frames are not accepted (NP_ACCEPT_INVALID_FRAMES = false) * - Multiple frames are not accepted (NP_ACCEPT_MULTIPLE_FRAMES = false) * - RF field is dropped * * @warning Be aware that this function will wait (hang) until a command is * received that is not part of the anti-collision. The RATS command for * example would wake up the emulator. After this is received, the send and * receive functions can be used. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout) { int res = 0; // Disallow invalid frame if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_INVALID_FRAMES, false)) < 0) return res; // Disallow multiple frames if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_MULTIPLE_FRAMES, false)) < 0) return res; // Make sure we reset the CRC and parity to chip handling. if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true)) < 0) return res; if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true)) < 0) return res; // Activate auto ISO14443-4 switching by default if ((res = nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true)) < 0) return res; // Activate "easy framing" feature by default if ((res = nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) return res; // Deactivate the CRYPTO1 cipher, it may could cause problems when still active if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_CRYPTO1, false)) < 0) return res; // Drop explicitely the field if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) return res; HAL(target_init, pnd, pnt, pbtRx, szRx, timeout); } /** @ingroup dev * @brief Turn NFC device in idle mode * @return Returns 0 on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device * * This function switch the device in idle mode. * In initiator mode, the RF field is turned off and the device is set to low power mode (if avaible); * In target mode, the emulation is stoped (no target available from external initiator) and the device is set to low power mode (if avaible). */ int nfc_idle(nfc_device *pnd) { HAL(idle, pnd); } /** @ingroup dev * @brief Abort current running command * @return Returns 0 on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device * * Some commands (ie. nfc_target_init()) are blocking functions and will return only in particular conditions (ie. external initiator request). * This function attempt to abort the current running command. * * @note The blocking function (ie. nfc_target_init()) will failed with DEABORT error. */ int nfc_abort_command(nfc_device *pnd) { HAL(abort_command, pnd); } /** @ingroup target * @brief Send bytes and APDU frames * @return Returns sent bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtTx pointer to Tx buffer * @param szTx size of Tx buffer * @param timeout in milliseconds * * This function make the NFC device (configured as \e target) send byte frames * (e.g. APDU responses) to the \e initiator. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout) { HAL(target_send_bytes, pnd, pbtTx, szTx, timeout); } /** @ingroup target * @brief Receive bytes and APDU frames * @return Returns received bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtRx pointer to Rx buffer * @param szRx size of Rx buffer * @param timeout in milliseconds * * This function retrieves bytes frames (e.g. ADPU) sent by the \e initiator to the NFC device (configured as \e target). * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout) { HAL(target_receive_bytes, pnd, pbtRx, szRx, timeout); } /** @ingroup target * @brief Send raw bit-frames * @return Returns sent bits count on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtTx pointer to Tx buffer * @param szTxBits size of Tx buffer * @param pbtTxPar parameter contains a byte array of the corresponding parity bits needed to send per byte. * This function can be used to transmit (raw) bit-frames to the \e initiator * using the specified NFC device (configured as \e target). */ int nfc_target_send_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar) { HAL(target_send_bits, pnd, pbtTx, szTxBits, pbtTxPar); } /** @ingroup target * @brief Receive bit-frames * @return Returns received bits count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtRx pointer to Rx buffer * @param szRx size of Rx buffer * @param[out] pbtRxPar parameter contains a byte array of the corresponding parity bits * * This function makes it possible to receive (raw) bit-frames. It returns all * the messages that are stored in the FIFO buffer of the \e PN53x chip. It * does not require to send any frame and thereby could be used to snoop frames * that are transmitted by a nearby \e initiator. @note Check out the * NP_ACCEPT_MULTIPLE_FRAMES configuration option to avoid losing transmitted * frames. */ int nfc_target_receive_bits(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar) { HAL(target_receive_bits, pnd, pbtRx, szRx, pbtRxPar); } static struct sErrorMessage { int iErrorCode; const char *pcErrorMsg; } sErrorMessages[] = { /* Chip-level errors (internal errors, RF errors, etc.) */ { NFC_SUCCESS, "Success" }, { NFC_EIO, "Input / Output Error" }, { NFC_EINVARG, "Invalid argument(s)" }, { NFC_EDEVNOTSUPP, "Not Supported by Device" }, { NFC_ENOTSUCHDEV, "No Such Device" }, { NFC_EOVFLOW, "Buffer Overflow" }, { NFC_ETIMEOUT, "Timeout" }, { NFC_EOPABORTED, "Operation Aborted" }, { NFC_ENOTIMPL, "Not (yet) Implemented" }, { NFC_ETGRELEASED, "Target Released" }, { NFC_EMFCAUTHFAIL, "Mifare Authentication Failed" }, { NFC_ERFTRANS, "RF Transmission Error" }, { NFC_ECHIP, "Device's Internal Chip Error" }, }; /** @ingroup error * @brief Return the last error string * @return Returns a string * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_strerror(const nfc_device *pnd) { const char *pcRes = "Unknown error"; size_t i; for (i = 0; i < (sizeof(sErrorMessages) / sizeof(struct sErrorMessage)); i++) { if (sErrorMessages[i].iErrorCode == pnd->last_error) { pcRes = sErrorMessages[i].pcErrorMsg; break; } } return pcRes; } /** @ingroup error * @brief Renders the last error in pcStrErrBuf for a maximum size of szBufLen chars * @return Returns 0 upon success * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pcStrErrBuf a string that contains the last error. * @param szBufLen size of buffer */ int nfc_strerror_r(const nfc_device *pnd, char *pcStrErrBuf, size_t szBufLen) { return (snprintf(pcStrErrBuf, szBufLen, "%s", nfc_strerror(pnd)) < 0) ? -1 : 0; } /** @ingroup error * @brief Display the last error occured on a nfc_device * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pcString a string */ void nfc_perror(const nfc_device *pnd, const char *pcString) { fprintf(stderr, "%s: %s\n", pcString, nfc_strerror(pnd)); } /** @ingroup error * @brief Returns last error occured on a nfc_device * @return Returns an integer that represents to libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device */ int nfc_device_get_last_error(const nfc_device *pnd) { return pnd->last_error; } /* Special data accessors */ /** @ingroup data * @brief Returns the device name * @return Returns a string with the device name * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_device_get_name(nfc_device *pnd) { return pnd->name; } /** @ingroup data * @brief Returns the device connection string * @return Returns a string with the device connstring * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_device_get_connstring(nfc_device *pnd) { return pnd->connstring; } /** @ingroup data * @brief Get supported modulations. * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param mode \a nfc_mode. * @param supported_mt pointer of \a nfc_modulation_type array. * */ int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) { HAL(get_supported_modulation, pnd, mode, supported_mt); } /** @ingroup data * @brief Get supported baud rates. * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param nmt \a nfc_modulation_type. * @param supported_br pointer of \a nfc_baud_rate array. * */ int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) { HAL(get_supported_baud_rate, pnd, nmt, supported_br); } /* Misc. functions */ /** @ingroup misc * @brief Returns the library version * @return Returns a string with the library version * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_version(void) { #ifdef GIT_REVISION return GIT_REVISION; #else return PACKAGE_VERSION; #endif // GIT_REVISION } /** @ingroup misc * @brief Free buffer allocated by libnfc * * @param pointer on buffer that needs to be freed */ void nfc_free(void *p) { free(p); } /** @ingroup misc * @brief Print information about NFC device * @return Upon successful return, this function returns the number of characters printed (excluding the null byte used to end output to strings), otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param buf pointer where string will be allocated, then information printed * * @warning *buf must be freed using nfc_free() */ int nfc_device_get_information_about(nfc_device *pnd, char **buf) { HAL(device_get_information_about, pnd, buf); } /** @ingroup string-converter * @brief Convert \a nfc_baud_rate value to string * @return Returns nfc baud rate * @param \a nfc_baud_rate to convert */ const char * str_nfc_baud_rate(const nfc_baud_rate nbr) { switch (nbr) { case NBR_UNDEFINED: return "undefined baud rate"; break; case NBR_106: return "106 kbps"; break; case NBR_212: return "212 kbps"; break; case NBR_424: return "424 kbps"; break; case NBR_847: return "847 kbps"; break; } // Should never go there.. return ""; } /** @ingroup string-converter * @brief Convert \a nfc_modulation_type value to string * @return Returns nfc modulation type * @param \a nfc_modulation_type to convert */ const char * str_nfc_modulation_type(const nfc_modulation_type nmt) { switch (nmt) { case NMT_ISO14443A: return "ISO/IEC 14443A"; break; case NMT_ISO14443B: return "ISO/IEC 14443-4B"; break; case NMT_ISO14443BI: return "ISO/IEC 14443-4B'"; break; case NMT_ISO14443B2CT: return "ISO/IEC 14443-2B ASK CTx"; break; case NMT_ISO14443B2SR: return "ISO/IEC 14443-2B ST SRx"; break; case NMT_FELICA: return "FeliCa"; break; case NMT_JEWEL: return "Innovision Jewel"; break; case NMT_DEP: return "D.E.P."; break; } // Should never go there.. return ""; } /** @ingroup string-converter * @brief Convert \a nfc_modulation_type value to string * @return Upon successful return, this function returns the number of characters printed (excluding the null byte used to end output to strings), otherwise returns libnfc's error code (negative value) * @param nt \a nfc_target struct to print * @param buf pointer where string will be allocated, then nfc target information printed * * @warning *buf must be freed using nfc_free() */ int str_nfc_target(char **buf, const nfc_target *pnt, bool verbose) { *buf = malloc(4096); if (! *buf) return NFC_ESOFT; (*buf)[0] = '\0'; snprint_nfc_target(*buf, 4096, pnt, verbose); return strlen(*buf); } libnfc-1.7.1/libnfc/target-subr.c000066400000000000000000000634201230265671100166250ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file target-subr.c * @brief Target-related subroutines. (ie. determine target type, print target, etc.) */ #include #include #include "target-subr.h" struct card_atqa { uint16_t atqa; uint16_t mask; char type[128]; // list of up to 8 SAK values compatible with this ATQA int saklist[8]; }; struct card_sak { uint8_t sak; uint8_t mask; char type[128]; }; struct card_atqa const_ca[] = { { 0x0044, 0xffff, "MIFARE Ultralight", {0, -1} }, { 0x0044, 0xffff, "MIFARE Ultralight C", {0, -1} }, { 0x0004, 0xff0f, "MIFARE Mini 0.3K", {1, -1} }, { 0x0004, 0xff0f, "MIFARE Classic 1K", {2, -1} }, { 0x0002, 0xff0f, "MIFARE Classic 4K", {3, -1} }, { 0x0004, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)", {4, 5, 6, 7, 8, 9, -1} }, { 0x0002, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)", {4, 5, 6, 7, 8, 9, -1} }, { 0x0044, 0xffff, "MIFARE Plus (7 Byte UID)", {4, 5, 6, 7, 8, 9, -1} }, { 0x0042, 0xffff, "MIFARE Plus (7 Byte UID)", {4, 5, 6, 7, 8, 9, -1} }, { 0x0344, 0xffff, "MIFARE DESFire", {10, 11, -1} }, { 0x0044, 0xffff, "P3SR008", { -1} }, // TODO we need SAK info { 0x0004, 0xf0ff, "SmartMX with MIFARE 1K emulation", {12, -1} }, { 0x0002, 0xf0ff, "SmartMX with MIFARE 4K emulation", {12, -1} }, { 0x0048, 0xf0ff, "SmartMX with 7 Byte UID", {12, -1} } }; struct card_sak const_cs[] = { {0x00, 0xff, "" }, // 00 MIFARE Ultralight / Ultralight C {0x09, 0xff, "" }, // 01 MIFARE Mini 0.3K {0x08, 0xff, "" }, // 02 MIFARE Classic 1K {0x18, 0xff, "" }, // 03 MIFARE Classik 4K {0x08, 0xff, " 2K, Security level 1" }, // 04 MIFARE Plus {0x18, 0xff, " 4K, Security level 1" }, // 05 MIFARE Plus {0x10, 0xff, " 2K, Security level 2" }, // 06 MIFARE Plus {0x11, 0xff, " 4K, Security level 2" }, // 07 MIFARE Plus {0x20, 0xff, " 2K, Security level 3" }, // 08 MIFARE Plus {0x20, 0xff, " 4K, Security level 3" }, // 09 MIFARE Plus {0x20, 0xff, " 4K" }, // 10 MIFARE DESFire {0x20, 0xff, " EV1 2K/4K/8K" }, // 11 MIFARE DESFire {0x00, 0x00, "" }, // 12 SmartMX }; int snprint_hex(char *dst, size_t size, const uint8_t *pbtData, const size_t szBytes) { size_t szPos; size_t res = 0; for (szPos = 0; szPos < szBytes; szPos++) { res += snprintf(dst + res, size - res, "%02x ", pbtData[szPos]); } res += snprintf(dst + res, size - res, "\n"); return res; } #define SAK_UID_NOT_COMPLETE 0x04 #define SAK_ISO14443_4_COMPLIANT 0x20 #define SAK_ISO18092_COMPLIANT 0x40 void snprint_nfc_iso14443a_info(char *dst, size_t size, const nfc_iso14443a_info *pnai, bool verbose) { int off = 0; off += snprintf(dst + off, size - off, " ATQA (SENS_RES): "); off += snprint_hex(dst + off, size - off, pnai->abtAtqa, 2); if (verbose) { off += snprintf(dst + off, size - off, "* UID size: "); switch ((pnai->abtAtqa[1] & 0xc0) >> 6) { case 0: off += snprintf(dst + off, size - off, "single\n"); break; case 1: off += snprintf(dst + off, size - off, "double\n"); break; case 2: off += snprintf(dst + off, size - off, "triple\n"); break; case 3: off += snprintf(dst + off, size - off, "RFU\n"); break; } off += snprintf(dst + off, size - off, "* bit frame anticollision "); switch (pnai->abtAtqa[1] & 0x1f) { case 0x01: case 0x02: case 0x04: case 0x08: case 0x10: off += snprintf(dst + off, size - off, "supported\n"); break; default: off += snprintf(dst + off, size - off, "not supported\n"); break; } } off += snprintf(dst + off, size - off, " UID (NFCID%c): ", (pnai->abtUid[0] == 0x08 ? '3' : '1')); off += snprint_hex(dst + off, size - off, pnai->abtUid, pnai->szUidLen); if (verbose) { if (pnai->abtUid[0] == 0x08) { off += snprintf(dst + off, size - off, "* Random UID\n"); } } off += snprintf(dst + off, size - off, " SAK (SEL_RES): "); off += snprint_hex(dst + off, size - off, &pnai->btSak, 1); if (verbose) { if (pnai->btSak & SAK_UID_NOT_COMPLETE) { off += snprintf(dst + off, size - off, "* Warning! Cascade bit set: UID not complete\n"); } if (pnai->btSak & SAK_ISO14443_4_COMPLIANT) { off += snprintf(dst + off, size - off, "* Compliant with ISO/IEC 14443-4\n"); } else { off += snprintf(dst + off, size - off, "* Not compliant with ISO/IEC 14443-4\n"); } if (pnai->btSak & SAK_ISO18092_COMPLIANT) { off += snprintf(dst + off, size - off, "* Compliant with ISO/IEC 18092\n"); } else { off += snprintf(dst + off, size - off, "* Not compliant with ISO/IEC 18092\n"); } } if (pnai->szAtsLen) { off += snprintf(dst + off, size - off, " ATS: "); off += snprint_hex(dst + off, size - off, pnai->abtAts, pnai->szAtsLen); } if (pnai->szAtsLen && verbose) { // Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select) const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 }; off += snprintf(dst + off, size - off, "* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[pnai->abtAts[0] & 0x0F]); size_t offset = 1; if (pnai->abtAts[0] & 0x10) { // TA(1) present uint8_t TA = pnai->abtAts[offset]; offset++; off += snprintf(dst + off, size - off, "* Bit Rate Capability:\n"); if (TA == 0) { off += snprintf(dst + off, size - off, " * PICC supports only 106 kbits/s in both directions\n"); } if (TA & 1 << 7) { off += snprintf(dst + off, size - off, " * Same bitrate in both directions mandatory\n"); } if (TA & 1 << 4) { off += snprintf(dst + off, size - off, " * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n"); } if (TA & 1 << 5) { off += snprintf(dst + off, size - off, " * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n"); } if (TA & 1 << 6) { off += snprintf(dst + off, size - off, " * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n"); } if (TA & 1 << 0) { off += snprintf(dst + off, size - off, " * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n"); } if (TA & 1 << 1) { off += snprintf(dst + off, size - off, " * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n"); } if (TA & 1 << 2) { off += snprintf(dst + off, size - off, " * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n"); } if (TA & 1 << 3) { off += snprintf(dst + off, size - off, " * ERROR unknown value\n"); } } if (pnai->abtAts[0] & 0x20) { // TB(1) present uint8_t TB = pnai->abtAts[offset]; offset++; off += snprintf(dst + off, size - off, "* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((TB & 0xf0) >> 4)) / 13560.0); if ((TB & 0x0f) == 0) { off += snprintf(dst + off, size - off, "* No Start-up Frame Guard Time required\n"); } else { off += snprintf(dst + off, size - off, "* Start-up Frame Guard Time: %.4g ms\n", 256.0 * 16.0 * (1 << (TB & 0x0f)) / 13560.0); } } if (pnai->abtAts[0] & 0x40) { // TC(1) present uint8_t TC = pnai->abtAts[offset]; offset++; if (TC & 0x1) { off += snprintf(dst + off, size - off, "* Node Address supported\n"); } else { off += snprintf(dst + off, size - off, "* Node Address not supported\n"); } if (TC & 0x2) { off += snprintf(dst + off, size - off, "* Card IDentifier supported\n"); } else { off += snprintf(dst + off, size - off, "* Card IDentifier not supported\n"); } } if (pnai->szAtsLen > offset) { off += snprintf(dst + off, size - off, "* Historical bytes Tk: "); off += snprint_hex(dst + off, size - off, pnai->abtAts + offset, (pnai->szAtsLen - offset)); uint8_t CIB = pnai->abtAts[offset]; offset++; if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) { off += snprintf(dst + off, size - off, " * Proprietary format\n"); if (CIB == 0xc1) { off += snprintf(dst + off, size - off, " * Tag byte: Mifare or virtual cards of various types\n"); uint8_t L = pnai->abtAts[offset]; offset++; if (L != (pnai->szAtsLen - offset)) { off += snprintf(dst + off, size - off, " * Warning: Type Identification Coding length (%i)", L); off += snprintf(dst + off, size - off, " not matching Tk length (%" PRIdPTR ")\n", (pnai->szAtsLen - offset)); } if ((pnai->szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes uint8_t CTC = pnai->abtAts[offset]; offset++; off += snprintf(dst + off, size - off, " * Chip Type: "); switch (CTC & 0xf0) { case 0x00: off += snprintf(dst + off, size - off, "(Multiple) Virtual Cards\n"); break; case 0x10: off += snprintf(dst + off, size - off, "Mifare DESFire\n"); break; case 0x20: off += snprintf(dst + off, size - off, "Mifare Plus\n"); break; default: off += snprintf(dst + off, size - off, "RFU\n"); break; } off += snprintf(dst + off, size - off, " * Memory size: "); switch (CTC & 0x0f) { case 0x00: off += snprintf(dst + off, size - off, "<1 kbyte\n"); break; case 0x01: off += snprintf(dst + off, size - off, "1 kbyte\n"); break; case 0x02: off += snprintf(dst + off, size - off, "2 kbyte\n"); break; case 0x03: off += snprintf(dst + off, size - off, "4 kbyte\n"); break; case 0x04: off += snprintf(dst + off, size - off, "8 kbyte\n"); break; case 0x0f: off += snprintf(dst + off, size - off, "Unspecified\n"); break; default: off += snprintf(dst + off, size - off, "RFU\n"); break; } } if ((pnai->szAtsLen - offset) > 0) { // Omit 2 CRC bytes uint8_t CVC = pnai->abtAts[offset]; offset++; off += snprintf(dst + off, size - off, " * Chip Status: "); switch (CVC & 0xf0) { case 0x00: off += snprintf(dst + off, size - off, "Engineering sample\n"); break; case 0x20: off += snprintf(dst + off, size - off, "Released\n"); break; default: off += snprintf(dst + off, size - off, "RFU\n"); break; } off += snprintf(dst + off, size - off, " * Chip Generation: "); switch (CVC & 0x0f) { case 0x00: off += snprintf(dst + off, size - off, "Generation 1\n"); break; case 0x01: off += snprintf(dst + off, size - off, "Generation 2\n"); break; case 0x02: off += snprintf(dst + off, size - off, "Generation 3\n"); break; case 0x0f: off += snprintf(dst + off, size - off, "Unspecified\n"); break; default: off += snprintf(dst + off, size - off, "RFU\n"); break; } } if ((pnai->szAtsLen - offset) > 0) { // Omit 2 CRC bytes uint8_t VCS = pnai->abtAts[offset]; offset++; off += snprintf(dst + off, size - off, " * Specifics (Virtual Card Selection):\n"); if ((VCS & 0x09) == 0x00) { off += snprintf(dst + off, size - off, " * Only VCSL supported\n"); } else if ((VCS & 0x09) == 0x01) { off += snprintf(dst + off, size - off, " * VCS, VCSL and SVC supported\n"); } if ((VCS & 0x0e) == 0x00) { off += snprintf(dst + off, size - off, " * SL1, SL2(?), SL3 supported\n"); } else if ((VCS & 0x0e) == 0x02) { off += snprintf(dst + off, size - off, " * SL3 only card\n"); } else if ((VCS & 0x0f) == 0x0e) { off += snprintf(dst + off, size - off, " * No VCS command supported\n"); } else if ((VCS & 0x0f) == 0x0f) { off += snprintf(dst + off, size - off, " * Unspecified\n"); } else { off += snprintf(dst + off, size - off, " * RFU\n"); } } } } else { if (CIB == 0x00) { off += snprintf(dst + off, size - off, " * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n"); off += snprintf(dst + off, size - off, " followed by a mandatory status indicator (the last three bytes, not in TLV)\n"); off += snprintf(dst + off, size - off, " See ISO/IEC 7816-4 8.1.1.3 for more info\n"); } if (CIB == 0x10) { off += snprintf(dst + off, size - off, " * DIR data reference: %02x\n", pnai->abtAts[offset]); } if (CIB == 0x80) { if (pnai->szAtsLen == offset) { off += snprintf(dst + off, size - off, " * No COMPACT-TLV objects found, no status found\n"); } else { off += snprintf(dst + off, size - off, " * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n"); off += snprintf(dst + off, size - off, " the last data object may carry a status indicator of one, two or three bytes.\n"); off += snprintf(dst + off, size - off, " See ISO/IEC 7816-4 8.1.1.3 for more info\n"); } } } } } if (verbose) { off += snprintf(dst + off, size - off, "\nFingerprinting based on MIFARE type Identification Procedure:\n"); // AN10833 uint16_t atqa = 0; uint8_t sak = 0; uint8_t i, j; bool found_possible_match = false; atqa = (((uint16_t)pnai->abtAtqa[0] & 0xff) << 8); atqa += (((uint16_t)pnai->abtAtqa[1] & 0xff)); sak = ((uint8_t)pnai->btSak & 0xff); for (i = 0; i < sizeof(const_ca) / sizeof(const_ca[0]); i++) { if ((atqa & const_ca[i].mask) == const_ca[i].atqa) { for (j = 0; (j < sizeof(const_ca[i].saklist) / sizeof(const_ca[i].saklist[0])) && (const_ca[i].saklist[j] >= 0); j++) { int sakindex = const_ca[i].saklist[j]; if ((sak & const_cs[sakindex].mask) == const_cs[sakindex].sak) { off += snprintf(dst + off, size - off, "* %s%s\n", const_ca[i].type, const_cs[sakindex].type); found_possible_match = true; } } } } // Other matches not described in // AN10833 MIFARE Type Identification Procedure // but seen in the field: off += snprintf(dst + off, size - off, "Other possible matches based on ATQA & SAK values:\n"); uint32_t atqasak = 0; atqasak += (((uint32_t)pnai->abtAtqa[0] & 0xff) << 16); atqasak += (((uint32_t)pnai->abtAtqa[1] & 0xff) << 8); atqasak += ((uint32_t)pnai->btSak & 0xff); switch (atqasak) { case 0x000488: off += snprintf(dst + off, size - off, "* Mifare Classic 1K Infineon\n"); found_possible_match = true; break; case 0x000298: off += snprintf(dst + off, size - off, "* Gemplus MPCOS\n"); found_possible_match = true; break; case 0x030428: off += snprintf(dst + off, size - off, "* JCOP31\n"); found_possible_match = true; break; case 0x004820: off += snprintf(dst + off, size - off, "* JCOP31 v2.4.1\n"); off += snprintf(dst + off, size - off, "* JCOP31 v2.2\n"); found_possible_match = true; break; case 0x000428: off += snprintf(dst + off, size - off, "* JCOP31 v2.3.1\n"); found_possible_match = true; break; case 0x000453: off += snprintf(dst + off, size - off, "* Fudan FM1208SH01\n"); found_possible_match = true; break; case 0x000820: off += snprintf(dst + off, size - off, "* Fudan FM1208\n"); found_possible_match = true; break; case 0x000238: off += snprintf(dst + off, size - off, "* MFC 4K emulated by Nokia 6212 Classic\n"); found_possible_match = true; break; case 0x000838: off += snprintf(dst + off, size - off, "* MFC 4K emulated by Nokia 6131 NFC\n"); found_possible_match = true; break; } if (! found_possible_match) { snprintf(dst + off, size - off, "* Unknown card, sorry\n"); } } } void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info *pnfi, bool verbose) { (void) verbose; int off = 0; off += snprintf(dst + off, size - off, " ID (NFCID2): "); off += snprint_hex(dst + off, size - off, pnfi->abtId, 8); off += snprintf(dst + off, size - off, " Parameter (PAD): "); off += snprint_hex(dst + off, size - off, pnfi->abtPad, 8); off += snprintf(dst + off, size - off, " System Code (SC): "); snprint_hex(dst + off, size - off, pnfi->abtSysCode, 2); } void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose) { (void) verbose; int off = 0; off += snprintf(dst + off, size - off, " ATQA (SENS_RES): "); off += snprint_hex(dst + off, size - off, pnji->btSensRes, 2); off += snprintf(dst + off, size - off, " 4-LSB JEWELID: "); snprint_hex(dst + off, size - off, pnji->btId, 4); } #define PI_ISO14443_4_SUPPORTED 0x01 #define PI_NAD_SUPPORTED 0x01 #define PI_CID_SUPPORTED 0x02 void snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info *pnbi, bool verbose) { int off = 0; off += snprintf(dst + off, size - off, " PUPI: "); off += snprint_hex(dst + off, size - off, pnbi->abtPupi, 4); off += snprintf(dst + off, size - off, " Application Data: "); off += snprint_hex(dst + off, size - off, pnbi->abtApplicationData, 4); off += snprintf(dst + off, size - off, " Protocol Info: "); off += snprint_hex(dst + off, size - off, pnbi->abtProtocolInfo, 3); if (verbose) { off += snprintf(dst + off, size - off, "* Bit Rate Capability:\n"); if (pnbi->abtProtocolInfo[0] == 0) { off += snprintf(dst + off, size - off, " * PICC supports only 106 kbits/s in both directions\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 7) { off += snprintf(dst + off, size - off, " * Same bitrate in both directions mandatory\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 4) { off += snprintf(dst + off, size - off, " * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 5) { off += snprintf(dst + off, size - off, " * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 6) { off += snprintf(dst + off, size - off, " * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 0) { off += snprintf(dst + off, size - off, " * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 1) { off += snprintf(dst + off, size - off, " * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 2) { off += snprintf(dst + off, size - off, " * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n"); } if (pnbi->abtProtocolInfo[0] & 1 << 3) { off += snprintf(dst + off, size - off, " * ERROR unknown value\n"); } if ((pnbi->abtProtocolInfo[1] & 0xf0) <= 0x80) { const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 }; off += snprintf(dst + off, size - off, "* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((pnbi->abtProtocolInfo[1] & 0xf0) >> 4)]); } if ((pnbi->abtProtocolInfo[1] & 0x01) == PI_ISO14443_4_SUPPORTED) { // in principle low nibble could only be 0000 or 0001 and other values are RFU // but in practice we found 0011 so let's use only last bit for -4 compatibility off += snprintf(dst + off, size - off, "* Protocol types supported: ISO/IEC 14443-4\n"); } off += snprintf(dst + off, size - off, "* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((pnbi->abtProtocolInfo[2] & 0xf0) >> 4)) / 13560.0); if ((pnbi->abtProtocolInfo[2] & (PI_NAD_SUPPORTED | PI_CID_SUPPORTED)) != 0) { off += snprintf(dst + off, size - off, "* Frame options supported: "); if ((pnbi->abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) off += snprintf(dst + off, size - off, "NAD "); if ((pnbi->abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) off += snprintf(dst + off, size - off, "CID "); snprintf(dst + off, size - off, "\n"); } } } void snprint_nfc_iso14443bi_info(char *dst, size_t size, const nfc_iso14443bi_info *pnii, bool verbose) { int off = 0; off += snprintf(dst + off, size - off, " DIV: "); off += snprint_hex(dst + off, size - off, pnii->abtDIV, 4); if (verbose) { int version = (pnii->btVerLog & 0x1e) >> 1; off += snprintf(dst + off, size - off, " Software Version: "); if (version == 15) { off += snprintf(dst + off, size - off, "Undefined\n"); } else { off += snprintf(dst + off, size - off, "%i\n", version); } if ((pnii->btVerLog & 0x80) && (pnii->btConfig & 0x80)) { off += snprintf(dst + off, size - off, " Wait Enable: yes"); } } if ((pnii->btVerLog & 0x80) && (pnii->btConfig & 0x40)) { off += snprintf(dst + off, size - off, " ATS: "); snprint_hex(dst + off, size - off, pnii->abtAtr, pnii->szAtrLen); } } void snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info *pnsi, bool verbose) { (void) verbose; int off = 0; off += snprintf(dst + off, size - off, " UID: "); snprint_hex(dst + off, size - off, pnsi->abtUID, 8); } void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose) { (void) verbose; int off = 0; uint32_t uid; uid = (pnci->abtUID[3] << 24) + (pnci->abtUID[2] << 16) + (pnci->abtUID[1] << 8) + pnci->abtUID[0]; off += snprintf(dst + off, size - off, " UID: "); off += snprint_hex(dst + off, size - off, pnci->abtUID, sizeof(pnci->abtUID)); off += snprintf(dst + off, size - off, " UID (decimal): %010u\n", uid); off += snprintf(dst + off, size - off, " Product Code: %02X\n", pnci->btProdCode); snprintf(dst + off, size - off, " Fab Code: %02X\n", pnci->btFabCode); } void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info *pndi, bool verbose) { (void) verbose; int off = 0; off += snprintf(dst + off, size - off, " NFCID3: "); off += snprint_hex(dst + off, size - off, pndi->abtNFCID3, 10); off += snprintf(dst + off, size - off, " BS: %02x\n", pndi->btBS); off += snprintf(dst + off, size - off, " BR: %02x\n", pndi->btBR); off += snprintf(dst + off, size - off, " TO: %02x\n", pndi->btTO); off += snprintf(dst + off, size - off, " PP: %02x\n", pndi->btPP); if (pndi->szGB) { off += snprintf(dst + off, size - off, "General Bytes: "); snprint_hex(dst + off, size - off, pndi->abtGB, pndi->szGB); } } void snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose) { if (NULL != pnt) { int off = 0; off += snprintf(dst + off, size - off, "%s (%s%s) target:\n", str_nfc_modulation_type(pnt->nm.nmt), str_nfc_baud_rate(pnt->nm.nbr), (pnt->nm.nmt != NMT_DEP) ? "" : (pnt->nti.ndi.ndm == NDM_ACTIVE) ? "active mode" : "passive mode"); switch (pnt->nm.nmt) { case NMT_ISO14443A: snprint_nfc_iso14443a_info(dst + off, size - off, &pnt->nti.nai, verbose); break; case NMT_JEWEL: snprint_nfc_jewel_info(dst + off, size - off, &pnt->nti.nji, verbose); break; case NMT_FELICA: snprint_nfc_felica_info(dst + off, size - off, &pnt->nti.nfi, verbose); break; case NMT_ISO14443B: snprint_nfc_iso14443b_info(dst + off, size - off, &pnt->nti.nbi, verbose); break; case NMT_ISO14443BI: snprint_nfc_iso14443bi_info(dst + off, size - off, &pnt->nti.nii, verbose); break; case NMT_ISO14443B2SR: snprint_nfc_iso14443b2sr_info(dst + off, size - off, &pnt->nti.nsi, verbose); break; case NMT_ISO14443B2CT: snprint_nfc_iso14443b2ct_info(dst + off, size - off, &pnt->nti.nci, verbose); break; case NMT_DEP: snprint_nfc_dep_info(dst + off, size - off, &pnt->nti.ndi, verbose); break; } } } libnfc-1.7.1/libnfc/target-subr.h000066400000000000000000000043371230265671100166340ustar00rootroot00000000000000/*- * 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: * * 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 */ /** * @file target-subr.c * @brief Target-related subroutines. (ie. determine target type, print target, etc.) */ #ifndef _TARGET_SUBR_H_ #define _TARGET_SUBR_H_ int snprint_hex(char *dst, size_t size, const uint8_t *pbtData, const size_t szLen); void snprint_nfc_iso14443a_info(char *dst, size_t size, const nfc_iso14443a_info *pnai, bool verbose); 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_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); void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info *pndi, bool verbose); void snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose); #endif libnfc-1.7.1/m4/000077500000000000000000000000001230265671100133005ustar00rootroot00000000000000libnfc-1.7.1/m4/libnfc_check_libusb.m4000066400000000000000000000046471230265671100175070ustar00rootroot00000000000000dnl Check for LIBUSB dnl On success, HAVE_LIBUSB is set to 1 and PKG_CONFIG_REQUIRES is filled when dnl libusb is found using pkg-config AC_DEFUN([LIBNFC_CHECK_LIBUSB], [ if test x"$libusb_required" = "xyes"; then HAVE_LIBUSB=0 AC_ARG_WITH([libusb-win32], [AS_HELP_STRING([--with-libusb-win32], [use libusb-win32 from the following location])], [LIBUSB_WIN32_DIR=$withval], [LIBUSB_WIN32_DIR=""]) # --with-libusb-win32 directory have been set if test "x$LIBUSB_WIN32_DIR" != "x"; then AC_MSG_NOTICE(["use libusb-win32 from $LIBUSB_WIN32_DIR"]) libusb_CFLAGS="-I$LIBUSB_WIN32_DIR/include" libusb_LIBS="-L$LIBUSB_WIN32_DIR/lib/gcc -lusb" HAVE_LIBUSB=1 fi # Search using libusb module using pkg-config if test x"$HAVE_LIBUSB" = "x0"; then if test x"$PKG_CONFIG" != "x"; then PKG_CHECK_MODULES([libusb], [libusb], [HAVE_LIBUSB=1], [HAVE_LIBUSB=0]) if test x"$HAVE_LIBUSB" = "x1"; then if test x"$PKG_CONFIG_REQUIRES" != x""; then PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES," fi PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES libusb" fi fi fi # Search using libusb-legacy module using pkg-config if test x"$HAVE_LIBUSB" = "x0"; then if test x"$PKG_CONFIG" != "x"; then PKG_CHECK_MODULES([libusb], [libusb-legacy], [HAVE_LIBUSB=1], [HAVE_LIBUSB=0]) if test x"$HAVE_LIBUSB" = "x1"; then if test x"$PKG_CONFIG_REQUIRES" != x""; then PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES," fi PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES libusb" fi fi fi # Search using libusb-config if test x"$HAVE_LIBUSB" = "x0"; then AC_PATH_PROG(libusb_CONFIG,libusb-config) if test x"$libusb_CONFIG" != "x" ; then libusb_CFLAGS=`$libusb_CONFIG --cflags` libusb_LIBS=`$libusb_CONFIG --libs` HAVE_LIBUSB=1 fi fi # Search the library and headers directly (last chance) if test x"$HAVE_LIBUSB" = "x0"; then AC_CHECK_HEADER(usb.h, [], [AC_MSG_ERROR([The libusb headers are missing])]) AC_CHECK_LIB(usb, libusb_init, [], [AC_MSG_ERROR([The libusb library is missing])]) libusb_LIBS="-lusb" HAVE_LIBUSB=1 fi if test x"$HAVE_LIBUSB" = "x0"; then AC_MSG_ERROR([libusb is mandatory.]) fi AC_SUBST(libusb_LIBS) AC_SUBST(libusb_CFLAGS) fi ]) libnfc-1.7.1/m4/libnfc_check_pcsc.m4000066400000000000000000000023121230265671100171420ustar00rootroot00000000000000dnl Check for PCSC presence (if required) dnl On success, HAVE_PCSC is set to 1 and PKG_CONFIG_REQUIRES is filled when dnl libpcsclite is found using pkg-config AC_DEFUN([LIBNFC_CHECK_PCSC], [ if test "x$pcsc_required" = "xyes"; then PKG_CHECK_MODULES([libpcsclite], [libpcsclite], [HAVE_PCSC=1], [HAVE_PCSC=0]) if test x"$HAVE_PCSC" = "x1" ; then if test x"$PKG_CONFIG_REQUIRES" != x""; then PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES," fi PKG_CONFIG_REQUIRES="$PKG_CONFIG_REQUIRES libpcsclite" fi case "$host" in *darwin*) if test x"$HAVE_PCSC" = "x0" ; then AC_MSG_CHECKING(for PC/SC) libpcsclite_LIBS="-Wl,-framework,PCSC" libpcsclite_CFLAGS="" HAVE_PCSC=1 AC_MSG_RESULT(yes: darwin PC/SC framework) fi ;; *mingw*) dnl FIXME Find a way to cross-compile for Windows HAVE_PCSC=0 AC_MSG_RESULT(no: Windows PC/SC framework) ;; *) if test x"$HAVE_PCSC" = "x0" ; then AC_MSG_ERROR([libpcsclite is required for building the acr122_pcsc driver.]) fi ;; esac AC_SUBST(libpcsclite_LIBS) AC_SUBST(libpcsclite_CFLAGS) fi ]) libnfc-1.7.1/m4/libnfc_drivers.m4000066400000000000000000000122551230265671100165420ustar00rootroot00000000000000dnl Handle drivers arguments list 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.]), [ case "${withval}" in yes | no) dnl ignore calls without any arguments DRIVER_BUILD_LIST="default" AC_MSG_RESULT(default drivers) ;; *) DRIVER_BUILD_LIST=`echo ${withval} | sed "s/,/ /g"` AC_MSG_RESULT(${DRIVER_BUILD_LIST}) ;; esac ], [ DRIVER_BUILD_LIST="default" AC_MSG_RESULT(default drivers) ] ) case "${DRIVER_BUILD_LIST}" in default) DRIVER_BUILD_LIST="acr122_usb acr122s arygon pn53x_usb pn532_uart" if test x"$spi_available" = x"yes" then DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi" fi if test x"$i2c_available" = x"yes" then DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c" fi ;; all) DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart" if test x"$spi_available" = x"yes" then DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi" fi if test x"$i2c_available" = x"yes" then DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c" fi ;; esac DRIVERS_CFLAGS="" driver_acr122_pcsc_enabled="no" driver_acr122_usb_enabled="no" driver_acr122s_enabled="no" driver_pn53x_usb_enabled="no" driver_arygon_enabled="no" driver_pn532_uart_enabled="no" driver_pn532_spi_enabled="no" driver_pn532_i2c_enabled="no" for driver in ${DRIVER_BUILD_LIST} do case "${driver}" in acr122_pcsc) pcsc_required="yes" driver_acr122_pcsc_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_ACR122_PCSC_ENABLED" ;; acr122_usb) libusb_required="yes" driver_acr122_usb_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_ACR122_USB_ENABLED" ;; acr122s) uart_required="yes" driver_acr122s_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_ACR122S_ENABLED" ;; pn53x_usb) libusb_required="yes" driver_pn53x_usb_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN53X_USB_ENABLED" ;; arygon) uart_required="yes" driver_arygon_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_ARYGON_ENABLED" ;; pn532_uart) uart_required="yes" driver_pn532_uart_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_UART_ENABLED" ;; pn532_spi) spi_required="yes" driver_pn532_spi_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_SPI_ENABLED" ;; pn532_i2c) i2c_required="yes" driver_pn532_i2c_enabled="yes" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED" ;; *) AC_MSG_ERROR([Unknow driver: $driver]) ;; esac done AC_SUBST(DRIVERS_CFLAGS) AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_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]) AM_CONDITIONAL(DRIVER_ARYGON_ENABLED, [test x"$driver_arygon_enabled" = xyes]) 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]) ]) AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[ echo echo "Selected drivers:" echo " acr122_pcsc...... $driver_acr122_pcsc_enabled" echo " acr122_usb....... $driver_acr122_usb_enabled" echo " acr122s.......... $driver_acr122s_enabled" echo " arygon........... $driver_arygon_enabled" 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" ]) libnfc-1.7.1/m4/readline.m4000066400000000000000000000031621230265671100153270ustar00rootroot00000000000000dnl Based on wojtekka's m4 from http://wloc.wsinf.edu.pl/~kklos/ekg-20080219/m4/readline.m4 AC_DEFUN([AC_CHECK_READLINE],[ AC_SUBST(READLINE_LIBS) AC_SUBST(READLINE_INCLUDES) AC_ARG_WITH(readline, [[ --with-readline[=dir] Compile with readline/locate base dir]], if test "x$withval" = "xno" ; then without_readline=yes elif test "x$withval" != "xyes" ; then with_arg="$withval/include:-L$withval/lib $withval/include/readline:-L$withval/lib" fi) AC_MSG_CHECKING(for readline.h) if test "x$cross_compiling" == "xyes"; then without_readline=yes fi if test "x$without_readline" != "xyes"; then for i in $with_arg \ /usr/include: \ /usr/local/include:-L/usr/local/lib \ /usr/pkg/include:-L/usr/pkg/lib; do incl=`echo "$i" | sed 's/:.*//'` lib=`echo "$i" | sed 's/.*://'` if test -f $incl/readline/readline.h ; then AC_MSG_RESULT($incl/readline/readline.h) READLINE_LIBS="$lib -lreadline" if test "$incl" != "/usr/include"; then READLINE_INCLUDES="-I$incl/readline -I$incl" else READLINE_INCLUDES="-I$incl/readline" fi AC_DEFINE(HAVE_READLINE, 1, [define if you have readline]) have_readline=yes break elif test -f $incl/readline.h -a "x$incl" != "x/usr/include"; then AC_MSG_RESULT($incl/readline.h) READLINE_LIBS="$lib -lreadline" READLINE_INCLUDES="-I$incl" AC_DEFINE(HAVE_READLINE, 1, [define if you have readline]) have_readline=yes break fi done fi if test "x$have_readline" != "xyes"; then AC_MSG_RESULT(not found) fi ]) libnfc-1.7.1/make_release.sh000077500000000000000000000031041230265671100157320ustar00rootroot00000000000000#! /bin/sh # Stop script on first error. set -e # Retrieve libnfc version from configure.ac LIBNFC_VERSION=$(grep AC_INIT configure.ac | sed 's/^.*\[libnfc\],\[\(.*\)\],\[.*/\1/g') echo "=== Building release archive for libnfc $LIBNFC_VERSION ===" # Easiest part: GNU/linux, BSD and other POSIX systems. LIBNFC_AUTOTOOLS_ARCHIVE=libnfc-$LIBNFC_VERSION.tar.gz echo ">>> Cleaning sources..." # First, clean what we can rm -f configure config.h config.h.in autoreconf -is --force && ./configure && make distclean git clean -dfX echo "<<< Sources cleaned." if [ ! -f $LIBNFC_AUTOTOOLS_ARCHIVE ]; then echo ">>> Autotooled archive generation..." # Second, generate dist archive (and test it) autoreconf -is --force && ./configure && make distcheck # Finally, clean up make distclean echo "<<< Autotooled archive generated." else echo "--- Autotooled archive (GNU/Linux, BSD, etc.) is already done: skipped." fi # Documentation part echo "=== Building documentation archive for libnfc $LIBNFC_VERSION ===" LIBNFC_DOC_DIR=libnfc-doc-$LIBNFC_VERSION LIBNFC_DOC_ARCHIVE=$LIBNFC_DOC_DIR.zip if [ ! -f $LIBNFC_DOC_ARCHIVE ]; then echo ">>> Documentation archive generation..." if [ -d $LIBNFC_DOC_DIR ]; then rm -rf $LIBNFC_DOC_DIR fi # Build documentation autoreconf -is --force && ./configure --enable-doc && make doc || false # Create archive cp -r doc/html $LIBNFC_DOC_DIR zip -r $LIBNFC_DOC_ARCHIVE $LIBNFC_DOC_DIR # Clean up rm -rf $LIBNFC_DOC_DIR make distclean echo "<<< Documentation archive generated." else echo "--- Documentation archive is already done: skipped." fi libnfc-1.7.1/manual-test-results.txt000066400000000000000000000166701230265671100174640ustar00rootroot00000000000000#,0# rev, program, local device, distant device, status #,1# (to sort easily: sort -k2 -t, manual-test-results.txt) #,2###################################################### r736, nfc-anticol, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, DESfire, OK r736, nfc-anticol, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, MFC, OK r736, nfc-anticol, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, UL, OK r846, nfc-anticol, ARYGON 00V5.1 (/dev/ttyUSB0) - PN532 v1.4 (APDB2UA33), MFC, OK r736, nfc-anticol, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, DESfire, OK r736, nfc-anticol, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, MFC, OK r736, nfc-anticol, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, UL, OK r1013, nfc-anticol, ASK / LoGO - PN533 v2.7, DESfire, OK r1013, nfc-anticol, ASK / LoGO - PN533 v2.7, MFC, OK r1013, nfc-anticol, ASK / LoGO - PN533 v2.7, UL, OK r1013, nfc-anticol, ASK / LoGO - PN533 v2.7, ULC, OK r736, nfc-dep-initiator, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, OK r1036, nfc-dep-initiator, ASK / LoGO - PN533 v2.7, Nokia 6212 Classic, OK r736, nfc-dep-target, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, OK r1036, nfc-dep-target, ASK / LoGO - PN533 v2.7, Nokia 6212 Classic, OK but USB device is not reacheable after that r736, nfc-emulate-forum-tag4, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, ctrl-c & use, FAIL r744, nfc-emulate-forum-tag4, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, Nokia 6131 NFC, OK r736, nfc-emulate-forum-tag4, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, Nokia 6212 Classic, OK r744, nfc-emulate-tag, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, Cardman 5321, OK r744, nfc-emulate-tag, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, CardMan 5321, OK r736, nfc-emulate-tag, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, ctrl-c & use, FAIL r736, nfc-emulate-tag, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, OK r736, nfc-emulate-tag, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, OK r736, nfc-emulate-tag, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, ctrl-c & use, OK r736, nfc-emulate-uid, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, ctrl-c & use, FAIL r744, nfc-emulate-uid, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, emulate + ctrl-c & use, FAIL r736, nfc-emulate-uid, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4 + nfc-anticol 2x, OK r736, nfc-emulate-uid, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, ctrl-c & use, OK r736, nfc-list, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, 2 DESfire, OK r736, nfc-list, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, 2 UL, OK r736, nfc-list, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, JCOP, OK r736, nfc-list, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, MFC, OK r736, nfc-list, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, topaz, OK r736, nfc-list, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, typeB Calypso, OK r736, nfc-list, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, ULC, OK r736, nfc-list, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, DESFire, OK r846, nfc-list, ARYGON 00V5.1 (/dev/ttyUSB0) - PN532 v1.4 (APDB2UA33), MFC, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, 2 DESfire, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, 2 UL, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, DESFire, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, JCOP, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, MFC, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, topaz, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, typeB Calypso, OK r736, nfc-list, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, ULC, OK r1013, nfc-list, ASK / LoGO - PN533 v2.7, DESfire, OK r1013, nfc-list, ASK / LoGO - PN533 v2.7, MFC, OK r1013, nfc-list, ASK / LoGO - PN533 v2.7, UL, OK r1013, nfc-list, ASK / LoGO - PN533 v2.7, ULC, OK r1036, nfc-list, ASK / LoGO - PN533 v2.7, DESFire, OK r736, nfc-mfclassic r a foo, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, MFC, OK r846, nfc-mfclassic r a foo, ARYGON 00V5.1 (/dev/ttyUSB0) - PN532 v1.4 (APDB2UA33), MFC, OK r736, nfc-mfclassic r a foo, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, MFC, OK r1013, nfc-mfclassic r a foo, ASK / LoGO - PN533 v2.7, MFC, OK r736, nfc-mfultralight r foo, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, UL, OK r736, nfc-mfultralight r foo, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, UL, OK r1013, nfc-mfultralight r foo, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, UL, OK r739, nfc-poll, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, 2 DESfire, OK r739, nfc-poll, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, 2 UL, OK r739, nfc-poll, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, JCOP, OK r739, nfc-poll, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, MFC, OK r739, nfc-poll, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, topaz, OK r739, nfc-poll, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, typeB Calypso, OK r739, nfc-poll, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, ULC, OK r846, nfc-poll, ARYGON 00V5.1 (/dev/ttyUSB0) - PN532 v1.4 (APDB2UA33), MFC, FAIL r849, nfc-poll, ARYGON 00V5.1 (/dev/ttyUSB0) - PN532 v1.4 (APDB2UA33), MFC, OK r736, pn53x-diagnose, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, N/A, OK r736, pn53x-diagnose, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, N/A, OK r846, pn53x-diagnose, ARYGON 00V5.1 (/dev/ttyUSB0) - PN532 v1.4 (APDB2UA33), N/A, FAIL r849, pn53x-diagnose, ARYGON 00V5.1 (/dev/ttyUSB0) - PN532 v1.4 (APDB2UA33), N/A, OK r736, pn53x-diagnose, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, N/A, OK r891, pn53x-diagnose, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, N/A, OK r891, pn53x-diagnose, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, N/A, OK r891, pn53x-diagnose, ASK / LoGO - PN533 v2.7, N/A, OK r1013, pn53x-diagnose, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, N/A, FAIL r1013, pn53x-diagnose, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, N/A, FAIL r1013, pn53x-diagnose, NXP / PN533 - PN533 v2.7, N/A, FAIL r1013, pn53x-diagnose, ASK / LoGO - PN533 v2.7, N/A, FAIL r1015, pn53x-diagnose, ASK / LoGO - PN533 v2.7, N/A, OK r1015, pn53x-diagnose, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4, N/A, OK r1015, pn53x-diagnose, NXP / PN533 - PN533 v2.7, N/A, OK r1015, pn53x-diagnose, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, N/A, OK r744, pn53x-sam (mode 1), Philips / PN531 - PN531 v4.2 + SAM, CardMan 5321, OK r736, pn53x-tamashell < pn53x-tamashell-scripts/UltraLightRead.cmd, ACS ACR122U PICC Interface 00 00 / ACR122U102 - PN532 v1.4, ultralight, OK r736, pn53x-tamashell < pn53x-tamashell-scripts/UltraLightRead.cmd, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, UL, OK r1013, pn53x-tamashell < pn53x-tamashell-scripts/UltraLightRead.cmd, ACS ACR 38U-CCID 00 00 / ACR122U102 - PN532 v1.4,UL, OK r1013, pn53x-tamashell < pn53x-tamashell-scripts/UltraLightRead.cmd, SCM Micro / SCL3711-NFC&RW - PN533 v2.7, UL, OK r1013, pn53x-tamashell < pn53x-tamashell-scripts/UltraLightRead.cmd, NXP / PN533 - PN533 v2.7, UL, OK r1013, pn53x-tamashell < pn53x-tamashell-scripts/UltraLightRead.cmd, ASK / LoGO - PN533 v2.7, UL, FAIL libnfc-1.7.1/mingw-cross-configure.sh000066400000000000000000000055001230265671100175430ustar00rootroot00000000000000#!/bin/sh WITH_USB=1 LIBUSB_WIN32_BIN_VERSION="1.2.6.0" LIBUSB_WIN32_BIN_ARCHIVE="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION.zip" LIBUSB_WIN32_BIN_URL="http://freefr.dl.sourceforge.net/project/libusb-win32/libusb-win32-releases/$LIBUSB_WIN32_BIN_VERSION/$LIBUSB_WIN32_BIN_ARCHIVE" LIBUSB_WIN32_BIN_DIR="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION" if [ "$WITH_USB" = "1" ]; then if [ ! -d $LIBUSB_WIN32_BIN_DIR ]; then wget -c $LIBUSB_WIN32_BIN_URL unzip $LIBUSB_WIN32_BIN_ARCHIVE fi fi MINGW="${MINGW:=i686-w64-mingw32}" MINGW_DIR="/usr/$MINGW" # Use MinGW binaries before others #export PATH=$MINGW_DIR/bin:$PATH # Set CPATH to MinGW include files export CPATH=$MINGW_DIR/include export LD_LIBRARY_PATH=$MINGW_DIR/lib export LD_RUN_PATH=$MINGW_DIR/lib # Force pkg-config to search in cross environement directory export PKG_CONFIG_LIBDIR=$MINGW_DIR/lib/pkgconfig # Stop compilation on first error export CFLAGS="-Wfatal-errors" # Include default MinGW include directory, and libnfc's win32 files export CFLAGS="$CFLAGS -I$MINGW_DIR/include -I$PWD/contrib/win32" if [ "$MINGW" = "i686-w64-mingw32" ]; then # mingw-64 includes winscard.a and winscard.h # # It is not enough to set libpcsclite_LIBS to "-lwinscard", because it is # forgotten when libnfc is created with libtool. That's why we are setting # LIBS. export LIBS="-lwinscard" echo "MinGW-w64 ships all requirements libnfc." echo "Unfortunately the MinGW-w64 header are currently" echo "buggy. Also, Libtool doesn't support MinGW-w64" echo "very well." echo "" echo "Warning ________________________________________" echo "You will only be able to compile libnfc.dll, but" echo "none of the executables (see utils and examples)." echo "" # You can fix winbase.h by adding the following lines: # #include # #include # But the problem with Libtool remains. else if [ -z "$libpcsclite_LIBS$libpcsclite_CFLAGS" ]; then echo "Error __________________________________________" echo "You need to get the PC/SC library from a Windows" echo "machine and the appropriate header files. Then" echo "specify libpcsclite_LIBS=.../WinScard.dll and" echo "libpcsclite_CFLAGS=-I..." fi exit 1 fi ## Configure to cross-compile using mingw32msvc if [ "$WITH_USB" = "1" ]; then # with direct-USB drivers (use libusb-win32) DRIVERS="all" else # with UART divers only (can be tested under wine) DRIVERS="pn532_uart,arygon" fi if [ ! -x configure ]; then autoreconf -is fi ./configure --target=$MINGW --host=$MINGW \ --with-drivers=$DRIVERS \ --with-libusb-win32=$PWD/$LIBUSB_WIN32_BIN_DIR \ $* if [ "$MINGW" = "i686-w64-mingw32" ]; then # due to the buggy headers from MINGW-64 we always add "contrib/windows.h", # otherwise some windows types won't be available. echo "#include \"contrib/windows.h\"" >> config.h fi libnfc-1.7.1/test/000077500000000000000000000000001230265671100137375ustar00rootroot00000000000000libnfc-1.7.1/test/Makefile.am000066400000000000000000000025751230265671100160040ustar00rootroot00000000000000# $Id$ AM_CPPFLAGS = $(CUTTER_CFLAGS) $(LIBNFC_CFLAGS) LIBS = $(CUTTER_LIBS) if WITH_CUTTER TESTS = run-test.sh TESTS_ENVIRONMENT = NO_MAKE=yes CUTTER="$(CUTTER)" cutter_unit_test_libs = \ test_access_storm.la \ test_dep_active.la \ test_device_modes_as_dep.la \ test_dep_passive.la \ test_register_access.la \ test_register_endianness.la if WITH_DEBUG noinst_LTLIBRARIES = $(cutter_unit_test_libs) else check_LTLIBRARIES = $(cutter_unit_test_libs) endif AM_LDFLAGS = -module -rpath $(libdir) -avoid-version -no-undefined test_access_storm_la_SOURCES = test_access_storm.c test_access_storm_la_LIBADD = $(top_builddir)/libnfc/libnfc.la test_dep_active_la_SOURCES = test_dep_active.c test_dep_active_la_LIBADD = $(top_builddir)/libnfc/libnfc.la \ $(top_builddir)/utils/libnfcutils.la test_device_modes_as_dep_la_SOURCES = test_device_modes_as_dep.c test_device_modes_as_dep_la_LIBADD = $(top_builddir)/libnfc/libnfc.la test_dep_passive_la_SOURCES = test_dep_passive.c test_dep_passive_la_LIBADD = $(top_builddir)/libnfc/libnfc.la test_register_access_la_SOURCES = test_register_access.c test_register_access_la_LIBADD = $(top_builddir)/libnfc/libnfc.la test_register_endianness_la_SOURCES = test_register_endianness.c test_register_endianness_la_LIBADD = $(top_builddir)/libnfc/libnfc.la echo-cutter: @echo $(CUTTER) EXTRA_DIST = run-test.sh CLEANFILES = *.gcno endif libnfc-1.7.1/test/run-test.sh000077500000000000000000000007751230265671100160700ustar00rootroot00000000000000#!/bin/sh export BASE_DIR="`dirname $0`" if test -z "$NO_MAKE"; then make -C "$BASE_DIR/../" > /dev/null || exit 1 fi if test -z "$CUTTER"; then CUTTER="`make -s -C "$BASE_DIR" echo-cutter`" fi "$CUTTER" --keep-opening-modules -s "$BASE_DIR" "$@" "$BASE_DIR" # ^^^^^^^^^^^^^^^^^^^^^^ # FIXME: Remove this workaround once cutter has been fixed upstream. # Bug report: # http://sourceforge.net/mailarchive/forum.php?thread_name=20100626123941.GA258%40blogreen.org&forum_name=cutter-users-en libnfc-1.7.1/test/test_access_storm.c000066400000000000000000000026471230265671100176400ustar00rootroot00000000000000#include #include #define NTESTS 10 #define MAX_DEVICE_COUNT 8 #define MAX_TARGET_COUNT 8 /* * This is basically a stress-test to ensure we don't left a device in an * inconsistent state after use. */ void test_access_storm(void); void test_access_storm(void) { int n = NTESTS; nfc_connstring connstrings[MAX_DEVICE_COUNT]; int res = 0; nfc_context *context; nfc_init(&context); size_t ref_device_count = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (!ref_device_count) cut_omit("No NFC device found"); while (n) { size_t device_count = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); cut_assert_equal_int(ref_device_count, device_count, cut_message("device count")); for (volatile size_t i = 0; i < device_count; i++) { nfc_device *device; nfc_target ant[MAX_TARGET_COUNT]; device = nfc_open(context, connstrings[i]); cut_assert_not_null(device, cut_message("nfc_open")); res = nfc_initiator_init(device); cut_assert_equal_int(0, res, cut_message("nfc_initiator_init")); const nfc_modulation nm = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; res = nfc_initiator_list_passive_targets(device, nm, ant, MAX_TARGET_COUNT); cut_assert_operator_int(res, >= , 0, cut_message("nfc_initiator_list_passive_targets")); nfc_close(device); } n--; } nfc_exit(context); } libnfc-1.7.1/test/test_dep_active.c000066400000000000000000000145541230265671100172560ustar00rootroot00000000000000#include #include #include #include #include "nfc/nfc.h" #include "../utils/nfc-utils.h" void test_dep_active(void); #define INITIATOR 0 #define TARGET 1 pthread_t threads[2]; nfc_context *context; nfc_connstring connstrings[2]; nfc_device *devices[2]; intptr_t result[2]; static void abort_test_by_keypress(int sig) { (void) sig; printf("\033[0;1;31mSIGINT\033[0m"); nfc_abort_command(devices[INITIATOR]); nfc_abort_command(devices[TARGET]); } void cut_setup(void) { nfc_init(&context); size_t n = nfc_list_devices(context, connstrings, 2); if (n < 2) { cut_omit("At least two NFC devices must be plugged-in to run this test"); } devices[TARGET] = nfc_open(context, connstrings[TARGET]); devices[INITIATOR] = nfc_open(context, connstrings[INITIATOR]); signal(SIGINT, abort_test_by_keypress); } void cut_teardown(void) { nfc_close(devices[TARGET]); nfc_close(devices[INITIATOR]); nfc_exit(context); } struct thread_data { nfc_device *device; void *cut_test_context; nfc_baud_rate nbr; }; static void * target_thread(void *arg) { intptr_t thread_res = 0; nfc_device *device = ((struct thread_data *) arg)->device; cut_set_current_test_context(((struct thread_data *) arg)->cut_test_context); printf("=========== TARGET %s =========\n", nfc_device_get_name(device)); nfc_target nt = { .nm = { .nmt = NMT_DEP, .nbr = NBR_UNDEFINED }, .nti = { .ndi = { .abtNFCID3 = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA }, .szGB = 4, .abtGB = { 0x12, 0x34, 0x56, 0x78 }, .ndm = NDM_ACTIVE, /* These bytes are not used by nfc_target_init: the chip will provide them automatically to the initiator */ .btDID = 0x00, .btBS = 0x00, .btBR = 0x00, .btTO = 0x00, .btPP = 0x01, }, }, }; uint8_t abtRx[1024]; int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 0); cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); const uint8_t abtAttRx[] = "Hello DEP target!"; cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } const uint8_t abtTx[] = "Hello DEP initiator!"; res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); if (res <= 0) { thread_res = -1; return (void *) thread_res; } return (void *) thread_res; } static void * initiator_thread(void *arg) { intptr_t thread_res = 0; nfc_device *device = ((struct thread_data *) arg)->device; cut_set_current_test_context(((struct thread_data *) arg)->cut_test_context); nfc_baud_rate nbr = (((struct thread_data *) arg)->nbr); /* * Wait some time for the other thread to initialise NFC device as target */ sleep(1); printf("=========== INITIATOR %s =========\n", nfc_device_get_name(device)); int res = nfc_initiator_init(device); cut_assert_equal_int(0, res, cut_message("Can't initialize NFC device as initiator: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } nfc_target nt; // Active mode printf("=========== INITIATOR %s (Active mode / %s Kbps) =========\n", nfc_device_get_name(device), str_nfc_baud_rate(nbr)); res = nfc_initiator_select_dep_target(device, NDM_ACTIVE, nbr, NULL, &nt, 1000); cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(nbr, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_int(NDM_ACTIVE, nt.nti.ndi.ndm, cut_message("Invalid target DEP mode")); cut_assert_equal_memory("\x12\x34\x56\x78", 4, nt.nti.ndi.abtGB, nt.nti.ndi.szGB, cut_message("Invalid target general bytes")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } const uint8_t abtTx[] = "Hello DEP target!"; uint8_t abtRx[1024]; res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); const uint8_t abtAttRx[] = "Hello DEP initiator!"; cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data (as initiator)")); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_deselect_target(device); cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } return (void *) thread_res; } void test_dep_active(void) { nfc_baud_rate nbrs[3] = { NBR_106, NBR_212, NBR_424}; CutTestContext *test_context = cut_get_current_test_context(); struct thread_data target_data = { .device = devices[TARGET], .cut_test_context = test_context, }; struct thread_data initiator_data = { .device = devices[INITIATOR], .cut_test_context = test_context, }; for (int i = 0; i < 3; i++) { initiator_data.nbr = nbrs[i]; int res; if ((res = pthread_create(&(threads[TARGET]), NULL, target_thread, &target_data))) cut_fail("pthread_create() returned %d", res); if ((res = pthread_create(&(threads[INITIATOR]), NULL, initiator_thread, &initiator_data))) cut_fail("pthread_create() returned %d", res); if ((res = pthread_join(threads[INITIATOR], (void *) &result[INITIATOR]))) cut_fail("pthread_join() returned %d", res); if ((res = pthread_join(threads[TARGET], (void *) &result[TARGET]))) cut_fail("pthread_join() returned %d", res); cut_assert_equal_int(0, result[INITIATOR], cut_message("Unexpected initiator return code")); cut_assert_equal_int(0, result[TARGET], cut_message("Unexpected target return code")); } } libnfc-1.7.1/test/test_dep_passive.c000066400000000000000000000306771230265671100174610ustar00rootroot00000000000000#include #include #include #include #include "nfc/nfc.h" void test_dep_passive(void); #define INITIATOR 0 #define TARGET 1 pthread_t threads[2]; nfc_context *context; nfc_connstring connstrings[2]; nfc_device *devices[2]; intptr_t result[2]; static void abort_test_by_keypress(int sig) { (void) sig; printf("\033[0;1;31mSIGINT\033[0m"); nfc_abort_command(devices[INITIATOR]); nfc_abort_command(devices[TARGET]); } void cut_setup(void) { nfc_init(&context); size_t n = nfc_list_devices(context, connstrings, 2); if (n < 2) { cut_omit("At least two NFC devices must be plugged-in to run this test"); } devices[TARGET] = nfc_open(context, connstrings[TARGET]); devices[INITIATOR] = nfc_open(context, connstrings[INITIATOR]); signal(SIGINT, abort_test_by_keypress); } void cut_teardown(void) { nfc_close(devices[TARGET]); nfc_close(devices[INITIATOR]); nfc_exit(context); } struct thread_data { nfc_device *device; void *cut_test_context; }; static void * target_thread(void *arg) { intptr_t thread_res = 0; nfc_device *device = ((struct thread_data *) arg)->device; cut_set_current_test_context(((struct thread_data *) arg)->cut_test_context); printf("=========== TARGET %s =========\n", nfc_device_get_name(device)); nfc_target nt = { .nm = { .nmt = NMT_DEP, .nbr = NBR_UNDEFINED }, .nti = { .ndi = { .abtNFCID3 = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA }, .szGB = 4, .abtGB = { 0x12, 0x34, 0x56, 0x78 }, .ndm = NDM_PASSIVE, /* These bytes are not used by nfc_target_init: the chip will provide them automatically to the initiator */ .btDID = 0x00, .btBS = 0x00, .btBR = 0x00, .btTO = 0x00, .btPP = 0x01, }, }, }; uint8_t abtRx[1024]; size_t szRx = sizeof(abtRx); int res = nfc_target_init(device, &nt, abtRx, szRx, 0); cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } // First pass res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); const uint8_t abtAttRx[] = "Hello DEP target!"; cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } const uint8_t abtTx[] = "Hello DEP initiator!"; res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); if (res <= 0) { thread_res = -1; return (void *) thread_res; } // Second pass res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); if (res <= 0) { thread_res = -1; return (void *) thread_res; } // Third pass res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); if (res <= 0) { thread_res = -1; return (void *) thread_res; } // Fourth pass res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); if (res <= 0) { thread_res = -1; return (void *) thread_res; } return (void *) thread_res; } static void * initiator_thread(void *arg) { intptr_t thread_res = 0; nfc_device *device = ((struct thread_data *) arg)->device; cut_set_current_test_context(((struct thread_data *) arg)->cut_test_context); /* * Wait some time for the other thread to initialise NFC device as target */ sleep(1); printf("=========== INITIATOR %s =========\n", nfc_device_get_name(device)); int res = nfc_initiator_init(device); cut_assert_equal_int(0, res, cut_message("Can't initialize NFC device as initiator: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } nfc_target nt; // Passive mode / 106Kbps printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device)); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt, 5000); cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NBR_106, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_int(NDM_PASSIVE, nt.nti.ndi.ndm, cut_message("Invalid target DEP mode")); cut_assert_equal_memory("\x12\x34\x56\x78", 4, nt.nti.ndi.abtGB, nt.nti.ndi.szGB, cut_message("Invalid target general bytes")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } const uint8_t abtTx[] = "Hello DEP target!"; uint8_t abtRx[1024]; res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); const uint8_t abtAttRx[] = "Hello DEP initiator!"; cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_deselect_target(device); cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } // Passive mode / 212Kbps (second pass) printf("=========== INITIATOR %s (Passive mode / 212Kbps) =========\n", nfc_device_get_name(device)); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000); cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_int(NDM_PASSIVE, nt.nti.ndi.ndm, cut_message("Invalid target DEP mode")); cut_assert_equal_memory("\x12\x34\x56\x78", 4, nt.nti.ndi.abtGB, nt.nti.ndi.szGB, cut_message("Invalid target general bytes")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 1000); cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_deselect_target(device); cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } // Passive mode / 212Kbps printf("=========== INITIATOR %s (Passive mode / 212Kbps, second pass) =========\n", nfc_device_get_name(device)); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000); cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_int(NDM_PASSIVE, nt.nti.ndi.ndm, cut_message("Invalid target DEP mode")); cut_assert_equal_memory("\x12\x34\x56\x78", 4, nt.nti.ndi.abtGB, nt.nti.ndi.szGB, cut_message("Invalid target general bytes")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_deselect_target(device); cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } // Passive mode / 424Kbps printf("=========== INITIATOR %s (Passive mode / 424Kbps) =========\n", nfc_device_get_name(device)); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_424, NULL, &nt, 1000); cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NBR_424, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_int(NDM_PASSIVE, nt.nti.ndi.ndm, cut_message("Invalid target DEP mode")); cut_assert_equal_memory("\x12\x34\x56\x78", 4, nt.nti.ndi.abtGB, nt.nti.ndi.szGB, cut_message("Invalid target general bytes")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_deselect_target(device); cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } return (void *) thread_res; } void test_dep_passive(void) { int res; CutTestContext *test_context = cut_get_current_test_context(); struct thread_data target_data = { .device = devices[TARGET], .cut_test_context = test_context, }; if ((res = pthread_create(&(threads[TARGET]), NULL, target_thread, &target_data))) cut_fail("pthread_create() returned %d", res); struct thread_data initiator_data = { .device = devices[INITIATOR], .cut_test_context = test_context, }; if ((res = pthread_create(&(threads[INITIATOR]), NULL, initiator_thread, &initiator_data))) cut_fail("pthread_create() returned %d", res); if ((res = pthread_join(threads[INITIATOR], (void *) &result[INITIATOR]))) cut_fail("pthread_join() returned %d", res); if ((res = pthread_join(threads[TARGET], (void *) &result[TARGET]))) cut_fail("pthread_join() returned %d", res); cut_assert_equal_int(0, result[INITIATOR], cut_message("Unexpected initiator return code")); cut_assert_equal_int(0, result[TARGET], cut_message("Unexpected target return code")); } libnfc-1.7.1/test/test_device_modes_as_dep.c000066400000000000000000000165421230265671100211130ustar00rootroot00000000000000#include #include #include #include #include "nfc/nfc.h" #include "../utils/nfc-utils.h" void test_dep_states(void); pthread_t threads[2]; nfc_context *context; nfc_connstring connstrings[2]; nfc_device *first_device, *second_device; intptr_t result[2]; static void abort_test_by_keypress(int sig) { (void) sig; printf("\033[0;1;31mSIGINT\033[0m"); nfc_abort_command(first_device); nfc_abort_command(second_device); } void cut_setup(void) { nfc_init(&context); size_t n = nfc_list_devices(context, connstrings, 2); if (n < 2) { cut_omit("At least two NFC devices must be plugged-in to run this test"); } second_device = nfc_open(context, connstrings[0]); first_device = nfc_open(context, connstrings[1]); signal(SIGINT, abort_test_by_keypress); } void cut_teardown(void) { nfc_close(second_device); nfc_close(first_device); nfc_exit(context); } struct thread_data { nfc_device *device; void *cut_test_context; }; static void * target_thread(void *arg) { intptr_t thread_res = 0; nfc_device *device = ((struct thread_data *) arg)->device; cut_set_current_test_context(((struct thread_data *) arg)->cut_test_context); printf("=========== TARGET %s =========\n", nfc_device_get_name(device)); nfc_target nt; uint8_t abtRx[1024]; // 1) nfc_target_init should take target in idle mode int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, >= , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } // 2) act as target nfc_target nt1 = { .nm = { .nmt = NMT_DEP, .nbr = NBR_UNDEFINED }, .nti = { .ndi = { .abtNFCID3 = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA }, .szGB = 4, .abtGB = { 0x12, 0x34, 0x56, 0x78 }, .ndm = NDM_PASSIVE, /* These bytes are not used by nfc_target_init: the chip will provide them automatically to the initiator */ .btDID = 0x00, .btBS = 0x00, .btBR = 0x00, .btTO = 0x00, .btPP = 0x01, }, }, }; sleep(6); res = nfc_target_init(device, &nt1, abtRx, sizeof(abtRx), 0); cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); const uint8_t abtAttRx[] = "Hello DEP target!"; cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } const uint8_t abtTx[] = "Hello DEP initiator!"; res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); if (res <= 0) { thread_res = -1; return (void *) thread_res; } // 3) idle mode sleep(1); nfc_idle(device); return (void *) thread_res; } static void * initiator_thread(void *arg) { intptr_t thread_res = 0; nfc_device *device = ((struct thread_data *) arg)->device; cut_set_current_test_context(((struct thread_data *) arg)->cut_test_context); /* * Wait some time for the other thread to initialise NFC device as target */ sleep(5); printf("=========== INITIATOR %s =========\n", nfc_device_get_name(device)); int res = nfc_initiator_init(device); cut_assert_equal_int(0, res, cut_message("Can't initialize NFC device as initiator: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } // 1) As other device should be in idle mode, nfc_initiator_poll_dep_target should return 0 nfc_target nt; res = nfc_initiator_poll_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt, 1000); cut_assert_equal_int(0, res, cut_message("Problem with nfc_idle")); if (res != 0) { thread_res = -1; return (void *) thread_res; } // 2 As other device should be in target mode, nfc_initiator_poll_dep_target should be positive. nfc_target nt1; // Passive mode / 106Kbps printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device)); res = nfc_initiator_poll_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt1, 5000); cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_equal_int(NMT_DEP, nt1.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NBR_106, nt1.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt1.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_int(NDM_PASSIVE, nt1.nti.ndi.ndm, cut_message("Invalid target DEP mode")); cut_assert_equal_memory("\x12\x34\x56\x78", 4, nt1.nti.ndi.abtGB, nt1.nti.ndi.szGB, cut_message("Invalid target general bytes")); if (res <= 0) { thread_res = -1; return (void *) thread_res; } const uint8_t abtTx[] = "Hello DEP target!"; uint8_t abtRx[1024]; res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500); cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); const uint8_t abtAttRx[] = "Hello DEP initiator!"; cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); if (res < 0) { thread_res = -1; return (void *) thread_res; } res = nfc_initiator_deselect_target(device); cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); if (res < 0) { thread_res = -1; return (void *) thread_res; } // 3) As other device should be in idle mode, nfc_initiator_poll_dep_target should return 0 nfc_target nt2; res = nfc_initiator_poll_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt2, 1000); cut_assert_equal_int(0, res, cut_message("Problem with nfc_idle")); if (res != 0) { thread_res = -1; return (void *) thread_res; } return (void *) thread_res; } void test_dep_states(void) { CutTestContext *test_context = cut_get_current_test_context(); struct thread_data target_data = { .device = first_device, .cut_test_context = test_context, }; struct thread_data initiator_data = { .device = second_device, .cut_test_context = test_context, }; for (int i = 0; i < 2; i++) { int res; if ((res = pthread_create(&(threads[1]), NULL, target_thread, &target_data))) cut_fail("pthread_create() returned %d", res); if ((res = pthread_create(&(threads[0]), NULL, initiator_thread, &initiator_data))) cut_fail("pthread_create() returned %d", res); if ((res = pthread_join(threads[0], (void *) &result[0]))) cut_fail("pthread_join() returned %d", res); if ((res = pthread_join(threads[1], (void *) &result[1]))) cut_fail("pthread_join() returned %d", res); cut_assert_equal_int(0, result[0], cut_message("Unexpected initiator return code")); cut_assert_equal_int(0, result[1], cut_message("Unexpected target return code")); // initiator --> target, target --> initiator target_data.device = second_device; initiator_data.device = first_device; } } libnfc-1.7.1/test/test_register_access.c000066400000000000000000000031051230265671100203060ustar00rootroot00000000000000#include #include #include "chips/pn53x.h" #define MAX_DEVICE_COUNT 1 #define MAX_TARGET_COUNT 1 void test_register_access(void); void test_register_access(void) { nfc_connstring connstrings[MAX_DEVICE_COUNT]; int res = 0; nfc_context *context; nfc_init(&context); size_t device_count = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (!device_count) cut_omit("No NFC device found"); nfc_device *device; device = nfc_open(context, connstrings[0]); cut_assert_not_null(device, cut_message("nfc_open")); uint8_t value; /* Set a 0xAA test value in writable register memory to test register access */ res = pn53x_write_register(device, PN53X_REG_CIU_TxMode, 0xFF, 0xAA); cut_assert_equal_int(0, res, cut_message("write register value to 0xAA")); /* Get test value from register memory */ res = pn53x_read_register(device, PN53X_REG_CIU_TxMode, &value); cut_assert_equal_int(0, res, cut_message("read register value")); cut_assert_equal_uint(0xAA, value, cut_message("check register value")); /* Set a 0x55 test value in writable register memory to test register access */ res = pn53x_write_register(device, PN53X_REG_CIU_TxMode, 0xFF, 0x55); cut_assert_equal_int(0, res, cut_message("write register value to 0x55")); /* Get test value from register memory */ res = pn53x_read_register(device, PN53X_REG_CIU_TxMode, &value); cut_assert_equal_int(0, res, cut_message("read register value")); cut_assert_equal_uint(0x55, value, cut_message("check register value")); nfc_close(device); nfc_exit(context); } libnfc-1.7.1/test/test_register_endianness.c000066400000000000000000000016701230265671100212010ustar00rootroot00000000000000#include #include #define MAX_DEVICE_COUNT 1 #define MAX_TARGET_COUNT 1 void test_register_endianness(void); #include "chips/pn53x.h" void test_register_endianness(void) { nfc_connstring connstrings[MAX_DEVICE_COUNT]; int res = 0; nfc_context *context; nfc_init(&context); size_t device_count = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (!device_count) cut_omit("No NFC device found"); nfc_device *device; device = nfc_open(context, connstrings[0]); cut_assert_not_null(device, cut_message("nfc_open")); uint8_t value; /* Read valid XRAM memory */ res = pn53x_read_register(device, 0xF0FF, &value); cut_assert_equal_int(0, res, cut_message("read register 0xF0FF")); /* Read invalid SFR register */ res = pn53x_read_register(device, 0xFFF0, &value); cut_assert_equal_int(-1, res, cut_message("read register 0xFFF0")); nfc_close(device); nfc_exit(context); } libnfc-1.7.1/utils/000077500000000000000000000000001230265671100141205ustar00rootroot00000000000000libnfc-1.7.1/utils/CMakeLists.txt000066400000000000000000000036401230265671100166630ustar00rootroot00000000000000SET(UTILS-SOURCES nfc-emulate-forum-tag4 nfc-jewel nfc-list nfc-mfclassic nfc-mfultralight nfc-read-forum-tag3 nfc-relay-picc nfc-scan-device ) ADD_LIBRARY(nfcutils STATIC nfc-utils.c ) TARGET_LINK_LIBRARIES(nfcutils nfc) # Examples FOREACH(source ${UTILS-SOURCES}) SET (TARGETS ${source}.c) IF(WIN32) SET(RC_COMMENT "${PACKAGE_NAME} utility") SET(RC_INTERNAL_NAME ${source}) SET(RC_ORIGINAL_NAME ${source}.exe) SET(RC_FILE_TYPE VFT_APP) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY) LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc) ENDIF(WIN32) IF(${source} MATCHES "nfc-jewel") LIST(APPEND TARGETS jewel) ENDIF(${source} MATCHES "nfc-jewel") IF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic")) LIST(APPEND TARGETS mifare) ENDIF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic")) IF(WIN32) IF(${source} MATCHES "nfc-scan-device") LIST(APPEND TARGETS ../contrib/win32/stdlib) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32) ENDIF(${source} MATCHES "nfc-scan-device") ENDIF(WIN32) ADD_EXECUTABLE(${source} ${TARGETS}) TARGET_LINK_LIBRARIES(${source} nfc) TARGET_LINK_LIBRARIES(${source} nfcutils) INSTALL(TARGETS ${source} RUNTIME DESTINATION bin COMPONENT utils) ENDFOREACH(source) #install required libraries IF(WIN32) INCLUDE(InstallRequiredSystemLibraries) CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/cmake/FixBundle.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake @ONLY) INSTALL(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake) ENDIF(WIN32) IF(NOT WIN32) # Manuals for the examples FILE(GLOB manuals "${CMAKE_CURRENT_SOURCE_DIR}/*.1") INSTALL(FILES ${manuals} DESTINATION ${SHARE_INSTALL_PREFIX}/man/man1 COMPONENT manuals) ENDIF(NOT WIN32) libnfc-1.7.1/utils/Makefile.am000066400000000000000000000031651230265671100161610ustar00rootroot00000000000000bin_PROGRAMS = \ nfc-emulate-forum-tag4 \ nfc-jewel \ nfc-list \ nfc-mfclassic \ nfc-mfultralight \ nfc-read-forum-tag3 \ nfc-relay-picc \ nfc-scan-device # set the include path found by configure AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS) noinst_LTLIBRARIES = libnfcutils.la libnfcutils_la_SOURCES = nfc-utils.c nfc_emulate_forum_tag4_SOURCES = nfc-emulate-forum-tag4.c nfc-utils.h nfc_emulate_forum_tag4_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la nfc_jewel_SOURCES = nfc-jewel.c jewel.c jewel.h nfc-utils.h nfc_jewel_LDADD = $(top_builddir)/libnfc/libnfc.la nfc_list_SOURCES = nfc-list.c nfc-utils.h nfc_list_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la nfc_mfclassic_SOURCES = nfc-mfclassic.c mifare.c mifare.h nfc-utils.h nfc_mfclassic_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la nfc_mfultralight_SOURCES = nfc-mfultralight.c mifare.c mifare.h nfc-utils.h nfc_mfultralight_LDADD = $(top_builddir)/libnfc/libnfc.la nfc_read_forum_tag3_SOURCES = nfc-read-forum-tag3.c nfc-utils.h nfc_read_forum_tag3_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la nfc_relay_picc_SOURCES = nfc-relay-picc.c nfc-utils.h nfc_relay_picc_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la nfc_scan_device_SOURCES = nfc-scan-device.c nfc-utils.h nfc_scan_device_LDADD = $(top_builddir)/libnfc/libnfc.la \ libnfcutils.la dist_man_MANS = \ nfc-emulate-forum-tag4.1 \ nfc-jewel.1 \ nfc-list.1 \ nfc-mfclassic.1 \ nfc-mfultralight.1 \ nfc-read-forum-tag3.1 \ nfc-relay-picc.1 \ nfc-scan-device.1 EXTRA_DIST = CMakeLists.txt libnfc-1.7.1/utils/jewel.c000066400000000000000000000071131230265671100153740ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2014 Pim 't Hart * * 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 jewel.c * @brief provide samples structs and functions to manipulate Jewel Topaz tags using libnfc */ #include "jewel.h" #include #include /** * @brief Execute a Jewel Topaz Command * @return Returns true if action was successfully performed; otherwise returns false. * @param req The request * @param res The response * */ bool nfc_initiator_jewel_cmd(nfc_device *pnd, const jewel_req req, jewel_res *pres) { size_t nLenReq; size_t nLenRes; switch (req.rid.btCmd) { case TC_RID: nLenReq = sizeof(jewel_req_rid); nLenRes = sizeof(jewel_res_rid); break; case TC_RALL: nLenReq = sizeof(jewel_req_rall); nLenRes = sizeof(jewel_res_rall); break; case TC_READ: nLenReq = sizeof(jewel_req_read); nLenRes = sizeof(jewel_res_read); break; case TC_WRITEE: nLenReq = sizeof(jewel_req_writee); nLenRes = sizeof(jewel_res_writee); break; case TC_WRITENE: nLenReq = sizeof(jewel_req_writene); nLenRes = sizeof(jewel_res_writene); break; case TC_RSEG: nLenReq = sizeof(jewel_req_rseg); nLenRes = sizeof(jewel_res_rseg); break; case TC_READ8: nLenReq = sizeof(jewel_req_read8); nLenRes = sizeof(jewel_res_read8); break; case TC_WRITEE8: nLenReq = sizeof(jewel_req_writee8); nLenRes = sizeof(jewel_res_writee8); break; case TC_WRITENE8: nLenReq = sizeof(jewel_req_writene8); nLenRes = sizeof(jewel_res_writene8); break; default: return false; break; } if (nfc_initiator_transceive_bytes(pnd, (uint8_t *)&req, nLenReq, (uint8_t *)pres, nLenRes, -1) < 0) { nfc_perror(pnd, "nfc_initiator_transceive_bytes"); return false; } return true; } libnfc-1.7.1/utils/jewel.h000066400000000000000000000123471230265671100154060ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2014 Pim 't Hart * * 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 jewel.h * @brief provide samples structs and functions to manipulate Jewel Topaz tags using libnfc */ #ifndef _LIBNFC_JEWEL_H_ # define _LIBNFC_JEWEL_H_ # include // Compiler directive, set struct alignment to 1 uint8_t for compatibility # pragma pack(1) typedef enum { TC_RID = 0x78, // Read ID // List of commands (Static memory model) TC_RALL = 0x00, // Real All TC_READ = 0x01, // Read (single byte) TC_WRITEE = 0x53, // Write-with-Erase (single byte) TC_WRITENE = 0x1A, // Write-without-Erase (single byte) // List of commands (Dynamic memory model) TC_RSEG = 0x10, // Read segment TC_READ8 = 0x02, // Read (8-bytes) TC_WRITEE8 = 0x54, // Write-with-Erase (8 bytes) TC_WRITENE8 = 0x1B // Write-without-Erase (8 byes) } jewel_cmd; // Jewel request typedef struct { uint8_t btCmd; } jewel_req_rid; typedef struct { uint8_t btCmd; } jewel_req_rall; typedef struct { uint8_t btCmd; uint8_t btAdd; } jewel_req_read; typedef struct { uint8_t btCmd; uint8_t btAdd; uint8_t btDat; } jewel_req_writee; typedef struct { uint8_t btCmd; uint8_t btAdd; uint8_t btDat; } jewel_req_writene; typedef struct { uint8_t btCmd; uint8_t btAddS; } jewel_req_rseg; typedef struct { uint8_t btCmd; uint8_t btAdd8; } jewel_req_read8; typedef struct { uint8_t btCmd; uint8_t btAdd8; uint8_t abtDat[8]; } jewel_req_writee8; typedef struct { uint8_t btCmd; uint8_t btAdd8; uint8_t abtDat[8]; } jewel_req_writene8; typedef union { jewel_req_rid rid; jewel_req_rall rall; jewel_req_read read; jewel_req_writee writee; jewel_req_writene writene; jewel_req_rseg rseg; jewel_req_read8 read8; jewel_req_writee8 writee8; jewel_req_writene8 writene8; } jewel_req; // Jewel responses typedef struct { uint8_t abtHr[2]; uint8_t abtUid[4]; // 4-LSB from UID } jewel_res_rid; typedef struct { uint8_t abtHr[2]; uint8_t abtDat[104]; // Block 0 - E, but not block D (reserved) } jewel_res_rall; typedef struct { uint8_t btDat; } jewel_res_read; typedef struct { uint8_t btDat; } jewel_res_writee; typedef struct { uint8_t btDat; } jewel_res_writene; typedef struct { uint8_t abtDat[128]; } jewel_res_rseg; typedef struct { uint8_t abtDat[8]; } jewel_res_read8; typedef struct { uint8_t abtDat[8]; } jewel_res_writee8; typedef struct { uint8_t abtDat[8]; } jewel_res_writene8; typedef union { jewel_res_rid rid; jewel_res_rall rall; jewel_res_read read; jewel_res_writee writee; jewel_res_writene writene; jewel_res_rseg rseg; jewel_res_read8 read8; jewel_res_writee8 writee8; jewel_res_writene8 writene8; } jewel_res; // Jewel tag typedef struct { uint8_t abtUid[7]; uint8_t btReserved; } jewel_block_uid; typedef struct { uint8_t abtData[8]; } jewel_block_data; typedef struct { uint8_t abtReserved[8]; } jewel_block_reserved; typedef struct { uint8_t abtLock[2]; uint8_t abtOtp[6]; } jewel_block_lockotp; typedef struct { jewel_block_uid bu; jewel_block_data abd[12]; jewel_block_reserved br; jewel_block_lockotp bl; } jewel_tag_blocks; typedef struct { uint8_t abtData[120]; } jewel_tag_data; typedef union { jewel_tag_blocks ttb; jewel_tag_data ttd; } jewel_tag; // Reset struct alignment to default # pragma pack() bool nfc_initiator_jewel_cmd(nfc_device *pnd, const jewel_req req, jewel_res *pres); #endif // _LIBNFC_JEWEL_H_ libnfc-1.7.1/utils/mifare.c000066400000000000000000000123771230265671100155410ustar00rootroot00000000000000/*- * 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 mifare.c * @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc */ #include "mifare.h" #include #include /** * @brief Execute a MIFARE Classic Command * @return Returns true if action was successfully performed; otherwise returns false. * @param pmp Some commands need additional information. This information should be supplied in the mifare_param union. * * The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number. * @note There are three different types of information (Authenticate, Data and Value). * * First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID. * They are both used to initialize the internal cipher-state of the PN53X chip. * After a successful authentication it will be possible to execute other commands (e.g. Read/Write). * The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process. */ bool nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp) { uint8_t abtRx[265]; size_t szParamLen; uint8_t abtCmd[265]; //bool bEasyFraming; abtCmd[0] = mc; // The MIFARE Classic command abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff) switch (mc) { // Read and store command have no parameter case MC_READ: case MC_STORE: szParamLen = 0; break; // Authenticate command case MC_AUTH_A: case MC_AUTH_B: szParamLen = sizeof(struct mifare_param_auth); break; // Data command case MC_WRITE: szParamLen = sizeof(struct mifare_param_data); break; // Value command case MC_DECREMENT: case MC_INCREMENT: case MC_TRANSFER: szParamLen = sizeof(struct mifare_param_value); break; // Please fix your code, you never should reach this statement default: return false; break; } // When available, copy the parameter bytes if (szParamLen) memcpy(abtCmd + 2, (uint8_t *) pmp, szParamLen); // FIXME: Save and restore bEasyFraming // bEasyFraming = nfc_device_get_property_bool (pnd, NP_EASY_FRAMING, &bEasyFraming); if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); return false; } // Fire the mifare command int res; if ((res = nfc_initiator_transceive_bytes(pnd, abtCmd, 2 + szParamLen, abtRx, sizeof(abtRx), -1)) < 0) { if (res == NFC_ERFTRANS) { // "Invalid received frame", usual means we are // authenticated on a sector but the requested MIFARE cmd (read, write) // is not permitted by current acces bytes; // So there is nothing to do here. } else { nfc_perror(pnd, "nfc_initiator_transceive_bytes"); } // XXX nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming); return false; } /* XXX if (nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming) < 0) { nfc_perror (pnd, "nfc_device_set_property_bool"); return false; } */ // When we have executed a read command, copy the received bytes into the param if (mc == MC_READ) { if (res == 16) { memcpy(pmp->mpd.abtData, abtRx, 16); } else { return false; } } // Command succesfully executed return true; } libnfc-1.7.1/utils/mifare.h000066400000000000000000000100551230265671100155350ustar00rootroot00000000000000/*- * 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 mifare.h * @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc */ #ifndef _LIBNFC_MIFARE_H_ # define _LIBNFC_MIFARE_H_ # include // Compiler directive, set struct alignment to 1 uint8_t for compatibility # pragma pack(1) typedef enum { MC_AUTH_A = 0x60, MC_AUTH_B = 0x61, MC_READ = 0x30, MC_WRITE = 0xA0, MC_TRANSFER = 0xB0, MC_DECREMENT = 0xC0, MC_INCREMENT = 0xC1, MC_STORE = 0xC2 } mifare_cmd; // MIFARE command params struct mifare_param_auth { uint8_t abtKey[6]; uint8_t abtAuthUid[4]; }; struct mifare_param_data { uint8_t abtData[16]; }; struct mifare_param_value { uint8_t abtValue[4]; }; typedef union { struct mifare_param_auth mpa; struct mifare_param_data mpd; struct mifare_param_value mpv; } mifare_param; // Reset struct alignment to default # pragma pack() bool nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp); // Compiler directive, set struct alignment to 1 uint8_t for compatibility # pragma pack(1) // MIFARE Classic typedef struct { uint8_t abtUID[4]; // beware for 7bytes UID it goes over next fields uint8_t btBCC; uint8_t btSAK; // beware it's not always exactly SAK uint8_t abtATQA[2]; uint8_t abtManufacturer[8]; } mifare_classic_block_manufacturer; typedef struct { uint8_t abtData[16]; } mifare_classic_block_data; typedef struct { uint8_t abtKeyA[6]; uint8_t abtAccessBits[4]; uint8_t abtKeyB[6]; } mifare_classic_block_trailer; typedef union { mifare_classic_block_manufacturer mbm; mifare_classic_block_data mbd; mifare_classic_block_trailer mbt; } mifare_classic_block; typedef struct { mifare_classic_block amb[256]; } mifare_classic_tag; // MIFARE Ultralight typedef struct { uint8_t sn0[3]; uint8_t btBCC0; uint8_t sn1[4]; uint8_t btBCC1; uint8_t internal; uint8_t lock[2]; uint8_t otp[4]; } mifareul_block_manufacturer; typedef struct { uint8_t abtData[16]; } mifareul_block_data; typedef union { mifareul_block_manufacturer mbm; mifareul_block_data mbd; } mifareul_block; typedef struct { mifareul_block amb[4]; } mifareul_tag; // Reset struct alignment to default # pragma pack() #endif // _LIBNFC_MIFARE_H_ libnfc-1.7.1/utils/nfc-emulate-forum-tag4.1000066400000000000000000000036651230265671100203770ustar00rootroot00000000000000.Dd March 12, 2011 .Dt NFC-EMULATE-FORUM-TAG4 1 URM .Sh NAME .Nm nfc-emulate-forum-tag4 .Nd NFC Forum tag type 4 emulation command line demonstration tool .Sh SYNOPSIS .Nm .Op -1 .Op infile Op outfile .Sh DESCRIPTION .Nm is a demonstration tool that emulates a NFC Forum tag type 4 v2.0 (or v1.0) with NDEF content. .Pp .Ar -1 can be provided to force old Tag Type 4 version 1.0 behavior. .Pp .Ar infile is the file which contains NDEF message you want to share with the NFC-Forum compliant initiator device (e.g. Nokia 6212 Classic for a v1.0 tag) .Pp If you want to save a shared content by the initiator device, we have to give .Ar outfile argument to point where the NDEF message will be saved. .Pp This example uses the hardware capability of PN532 to handle ISO/IEC 14443-4 low-level frames like RATS/ATS, WTX, etc. .Pp All devices compliant with NFC-Forum Tag Type 4 (Version 2.0 or 1.0) can be used with this example in read-write mode. .Pp If no argument is given, a default NDEF file is available. .Sh IMPLEMENTATION NOTES You can specify the same .Ar infile and .Ar outfile .Sh IMPORTANT Only PN532 equipped devices can use this example. (e.g. PN532 breakout board) .Pp ACR122 devices (like touchatag, etc.) can be used by this example, but if something goes wrong, you will have to unplug/replug your device. This is not a .Em libnfc's bug, this problem is due to ACR122's internal MCU in front of NFC chip (PN532). .Sh BUGS Please report any bugs on the .Em libnfc issue tracker at: .Em http://code.google.com/p/libnfc/issues .Sh LICENCE .Em libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .Em libnfc-utils and .Em libnfc-examples are covered by the BSD 2-Clause license. .Sh AUTHORS .An Roel Verdult Aq roel@libnfc.org .An Romain Tartière Aq romain@libnfc.org .An Romuald Conty Aq romuald@libnfc.org .Pp This manual page was written by Romuald Conty. It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/utils/nfc-emulate-forum-tag4.c000066400000000000000000000313601230265671100204520ustar00rootroot00000000000000/*- * 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-emulate-forum-tag4.c * @brief Emulates a NFC Forum Tag Type 4 v2.0 (or v1.0) with a NDEF message */ /* * This implementation was written based on information provided by the * following documents: * * NFC Forum Type 4 Tag Operation * Technical Specification * NFCForum-TS-Type-4-Tag_1.0 - 2007-03-13 * NFCForum-TS-Type-4-Tag_2.0 - 2010-11-18 */ // Notes & differences with nfc-emulate-tag: // - This example only works with PN532 because it relies on // its internal handling of ISO14443-4 specificities. // - Thanks to this internal handling & injection of WTX frames, // this example works on readers very strict on timing #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include #include #include "nfc-utils.h" static nfc_device *pnd; static nfc_context *context; static bool quiet_output = false; // Version of the emulated type4 tag: static int type4v = 2; #define SYMBOL_PARAM_fISO14443_4_PICC 0x20 typedef enum { NONE, CC_FILE, NDEF_FILE } file; struct nfcforum_tag4_ndef_data { uint8_t *ndef_file; size_t ndef_file_len; }; struct nfcforum_tag4_state_machine_data { file current_file; }; uint8_t nfcforum_capability_container[] = { 0x00, 0x0F, /* CCLEN 15 bytes */ 0x20, /* Mapping version 2.0, use option -1 to force v1.0 */ 0x00, 0x54, /* MLe Maximum R-ADPU data size */ // Notes: // - I (Romuald) don't know why Nokia 6212 Classic refuses the NDEF message if MLe is more than 0xFD (any suggests are welcome); // - ARYGON devices doesn't support extended frame sending, consequently these devices can't sent more than 0xFE bytes as APDU, so 0xFB APDU data bytes. // - I (Romuald) don't know why ARYGON device doesn't ACK when MLe > 0x54 (ARYGON frame length = 0xC2 (192 bytes)) 0x00, 0xFF, /* MLc Maximum C-ADPU data size */ 0x04, /* T field of the NDEF File-Control TLV */ 0x06, /* L field of the NDEF File-Control TLV */ /* V field of the NDEF File-Control TLV */ 0xE1, 0x04, /* File identifier */ 0xFF, 0xFE, /* Maximum NDEF Size */ 0x00, /* NDEF file read access condition */ 0x00, /* NDEF file write access condition */ }; /* C-ADPU offsets */ #define CLA 0 #define INS 1 #define P1 2 #define P2 3 #define LC 4 #define DATA 5 #define ISO144434A_RATS 0xE0 static int nfcforum_tag4_io(struct nfc_emulator *emulator, const uint8_t *data_in, const size_t data_in_len, uint8_t *data_out, const size_t data_out_len) { int res = 0; struct nfcforum_tag4_ndef_data *ndef_data = (struct nfcforum_tag4_ndef_data *)(emulator->user_data); struct nfcforum_tag4_state_machine_data *state_machine_data = (struct nfcforum_tag4_state_machine_data *)(emulator->state_machine->data); if (data_in_len == 0) { // No input data, nothing to do return res; } // Show transmitted command if (!quiet_output) { printf(" In: "); print_hex(data_in, data_in_len); } if (data_in_len >= 4) { if (data_in[CLA] != 0x00) return -ENOTSUP; #define ISO7816_SELECT 0xA4 #define ISO7816_READ_BINARY 0xB0 #define ISO7816_UPDATE_BINARY 0xD6 switch (data_in[INS]) { case ISO7816_SELECT: switch (data_in[P1]) { case 0x00: /* Select by ID */ if ((data_in[P2] | 0x0C) != 0x0C) return -ENOTSUP; const uint8_t ndef_capability_container[] = { 0xE1, 0x03 }; const uint8_t ndef_file[] = { 0xE1, 0x04 }; if ((data_in[LC] == sizeof(ndef_capability_container)) && (0 == memcmp(ndef_capability_container, data_in + DATA, data_in[LC]))) { memcpy(data_out, "\x90\x00", res = 2); state_machine_data->current_file = CC_FILE; } else if ((data_in[LC] == sizeof(ndef_file)) && (0 == memcmp(ndef_file, data_in + DATA, data_in[LC]))) { memcpy(data_out, "\x90\x00", res = 2); state_machine_data->current_file = NDEF_FILE; } else { memcpy(data_out, "\x6a\x00", res = 2); state_machine_data->current_file = NONE; } break; case 0x04: /* Select by name */ if (data_in[P2] != 0x00) return -ENOTSUP; const uint8_t ndef_tag_application_name_v1[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x00 }; const uint8_t ndef_tag_application_name_v2[] = { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 }; if ((type4v == 1) && (data_in[LC] == sizeof(ndef_tag_application_name_v1)) && (0 == memcmp(ndef_tag_application_name_v1, data_in + DATA, data_in[LC]))) memcpy(data_out, "\x90\x00", res = 2); else if ((type4v == 2) && (data_in[LC] == sizeof(ndef_tag_application_name_v2)) && (0 == memcmp(ndef_tag_application_name_v2, data_in + DATA, data_in[LC]))) memcpy(data_out, "\x90\x00", res = 2); else memcpy(data_out, "\x6a\x82", res = 2); break; default: return -ENOTSUP; } break; case ISO7816_READ_BINARY: if ((size_t)(data_in[LC] + 2) > data_out_len) { return -ENOSPC; } switch (state_machine_data->current_file) { case NONE: memcpy(data_out, "\x6a\x82", res = 2); break; case CC_FILE: memcpy(data_out, nfcforum_capability_container + (data_in[P1] << 8) + data_in[P2], data_in[LC]); memcpy(data_out + data_in[LC], "\x90\x00", 2); res = data_in[LC] + 2; break; case NDEF_FILE: memcpy(data_out, ndef_data->ndef_file + (data_in[P1] << 8) + data_in[P2], data_in[LC]); memcpy(data_out + data_in[LC], "\x90\x00", 2); res = data_in[LC] + 2; break; } break; case ISO7816_UPDATE_BINARY: memcpy(ndef_data->ndef_file + (data_in[P1] << 8) + data_in[P2], data_in + DATA, data_in[LC]); if ((data_in[P1] << 8) + data_in[P2] == 0) { ndef_data->ndef_file_len = (ndef_data->ndef_file[0] << 8) + ndef_data->ndef_file[1] + 2; } memcpy(data_out, "\x90\x00", res = 2); break; default: // Unknown if (!quiet_output) { printf("Unknown frame, emulated target abort.\n"); } res = -ENOTSUP; } } else { res = -ENOTSUP; } // Show transmitted command if (!quiet_output) { if (res < 0) { ERR("%s (%d)", strerror(-res), -res); } else { printf(" Out: "); print_hex(data_out, res); } } return res; } static void stop_emulation(int sig) { (void) sig; if (pnd != NULL) { nfc_abort_command(pnd); } else { nfc_exit(context); exit(EXIT_FAILURE); } } static int ndef_message_load(char *filename, struct nfcforum_tag4_ndef_data *tag_data) { struct stat sb; FILE *F; if (!(F = fopen(filename, "r"))) { printf("File not found or not accessible '%s'\n", filename); return -1; } if (stat(filename, &sb) < 0) { printf("File not found or not accessible '%s'\n", filename); fclose(F); return -1; } /* Check file size */ if (sb.st_size > 0xFFFF) { printf("File size too large '%s'\n", filename); fclose(F); return -1; } tag_data->ndef_file_len = sb.st_size + 2; tag_data->ndef_file[0] = (uint8_t)(sb.st_size >> 8); tag_data->ndef_file[1] = (uint8_t)(sb.st_size); if (1 != fread(tag_data->ndef_file + 2, sb.st_size, 1, F)) { printf("Can't read from %s\n", filename); fclose(F); return -1; } fclose(F); return sb.st_size; } static int ndef_message_save(char *filename, struct nfcforum_tag4_ndef_data *tag_data) { FILE *F; if (!(F = fopen(filename, "w"))) { printf("fopen (%s, w)\n", filename); return -1; } if (1 != fwrite(tag_data->ndef_file + 2, tag_data->ndef_file_len - 2, 1, F)) { printf("fwrite (%d)\n", (int) tag_data->ndef_file_len - 2); fclose(F); return -1; } fclose(F); return tag_data->ndef_file_len - 2; } static void usage(char *progname) { fprintf(stderr, "usage: %s [-1] [infile [outfile]]\n", progname); fprintf(stderr, " -1: force Tag Type 4 v1.0 (default is v2.0)\n"); } int main(int argc, char *argv[]) { int options = 0; nfc_target nt = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_UNDEFINED, // Will be updated by nfc_target_init() }, .nti = { .nai = { .abtAtqa = { 0x00, 0x04 }, .abtUid = { 0x08, 0x00, 0xb0, 0x0b }, .szUidLen = 4, .btSak = 0x20, .abtAts = { 0x75, 0x33, 0x92, 0x03 }, /* Not used by PN532 */ .szAtsLen = 4, }, }, }; uint8_t ndef_file[0xfffe] = { 0x00, 33, 0xd1, 0x02, 0x1c, 0x53, 0x70, 0x91, 0x01, 0x09, 0x54, 0x02, 0x65, 0x6e, 0x4c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x51, 0x01, 0x0b, 0x55, 0x03, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x2e, 0x6f, 0x72, 0x67 }; struct nfcforum_tag4_ndef_data nfcforum_tag4_data = { .ndef_file = ndef_file, .ndef_file_len = ndef_file[1] + 2, }; struct nfcforum_tag4_state_machine_data state_machine_data = { .current_file = NONE, }; struct nfc_emulation_state_machine state_machine = { .io = nfcforum_tag4_io, .data = &state_machine_data, }; struct nfc_emulator emulator = { .target = &nt, .state_machine = &state_machine, .user_data = &nfcforum_tag4_data, }; if ((argc > (1 + options)) && (0 == strcmp("-h", argv[1 + options]))) { usage(argv[0]); exit(EXIT_SUCCESS); } if ((argc > (1 + options)) && (0 == strcmp("-1", argv[1 + options]))) { type4v = 1; nfcforum_capability_container[2] = 0x10; options += 1; } if (argc > (3 + options)) { usage(argv[0]); exit(EXIT_FAILURE); } // If some file is provided load it if (argc >= (2 + options)) { if (ndef_message_load(argv[1 + options], &nfcforum_tag4_data) < 0) { printf("Can't load NDEF file '%s'\n", argv[1 + options]); exit(EXIT_FAILURE); } } nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)\n"); exit(EXIT_FAILURE); } // Try to open the NFC reader pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Unable to open NFC device"); nfc_exit(context); exit(EXIT_FAILURE); } signal(SIGINT, stop_emulation); printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); printf("Emulating NDEF tag now, please touch it with a second NFC device\n"); if (0 != nfc_emulate_target(pnd, &emulator, 0)) { // contains already nfc_target_init() call nfc_perror(pnd, "nfc_emulate_target"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (argc == (3 + options)) { if (ndef_message_save(argv[2 + options], &nfcforum_tag4_data) < 0) { printf("Can't save NDEF file '%s'", argv[2 + options]); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-jewel.1000066400000000000000000000023251230265671100160560ustar00rootroot00000000000000.TH nfc-jewel 1 "Feb 02, 2014" "libnfc" "NFC Utilities" .SH NAME nfc-jewel \- Jewel command line tool .SH SYNOPSIS .B nfc-jewel .RI \fR\fBr\fR|\fBw\fR .IR DUMP .SH DESCRIPTION .B nfc-jewel is a Jewel tool that allows one to read or write a tag data to/from a .IR DUMP file. Jewel tag by Broadcom, previously Innovision, uses a binary Dump file to store data for all sectors. Be cautious that some parts of a Jewel memory can be written only once and some parts are used as lock bits, so please read the tag documentation before experimenting too much! .SH OPTIONS .BR r " | " w Perform read from ( .B r ) or write to ( .B w ) card. .TP .IR DUMP JeWel Dump (JWD) used to write (card to JWD) or (JWD to card) .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult , .br Romuald Conty . .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/utils/nfc-jewel.c000066400000000000000000000210761230265671100161440ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2014 Pim 't Hart * * 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-jewel.c * @brief Jewel dump/restore tool */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include "nfc-utils.h" #include "jewel.h" static nfc_device *pnd; static nfc_target nt; static jewel_req req; static jewel_res res; static jewel_tag ttDump; static uint32_t uiBlocks = 0x0E; static uint32_t uiBytesPerBlock = 0x08; static const nfc_modulation nmJewel = { .nmt = NMT_JEWEL, .nbr = NBR_106, }; static void print_success_or_failure(bool bFailure, uint32_t *uiCounter) { printf("%c", (bFailure) ? 'x' : '.'); if (uiCounter) *uiCounter += (bFailure) ? 0 : 1; } static bool read_card(void) { uint32_t block; uint32_t byte; bool bFailure = false; uint32_t uiReadBlocks = 0; printf("Reading %d blocks |", uiBlocks + 1); for (block = 0; block <= uiBlocks; block++) { for (byte = 0; byte < uiBytesPerBlock; byte++) { // Try to read the byte req.read.btCmd = TC_READ; req.read.btAdd = (block << 3) + byte; if (nfc_initiator_jewel_cmd(pnd, req, &res)) { ttDump.ttd.abtData[(block << 3) + byte] = res.read.btDat; } else { bFailure = true; break; } } print_success_or_failure(bFailure, &uiReadBlocks); fflush(stdout); } printf("|\n"); printf("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1); return (!bFailure); } static bool write_card(void) { uint32_t block; uint32_t byte; bool bFailure = false; uint32_t uiWrittenBlocks = 0; uint32_t uiSkippedBlocks = 0; uint32_t uiPartialBlocks = 0; char buffer[BUFSIZ]; bool write_otp; bool write_lock; printf("Write Lock bytes ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); } write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y')); printf("Write OTP bytes ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); } write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y')); printf("Writing %d pages |", uiBlocks + 1); // Skip block 0 - as far as I know there are no Jewel tags with block 0 writeable printf("s"); uiSkippedBlocks++; for (block = uiSkippedBlocks; block <= uiBlocks; block++) { // Skip block 0x0D - it is reserved for internal use and can't be written if (block == 0x0D) { printf("s"); uiSkippedBlocks++; continue; } // Skip block 0X0E if lock-bits and OTP shouldn't be written if ((block == 0x0E) && (!write_lock) && (!write_otp)) { printf("s"); uiSkippedBlocks++; continue; } // Write block 0x0E partially if lock-bits or OTP shouldn't be written if ((block == 0x0E) && (!write_lock || !write_otp)) { printf("p"); uiPartialBlocks++; } for (byte = 0; byte < uiBytesPerBlock; byte++) { if ((block == 0x0E) && (byte == 0 || byte == 1) && (!write_lock)) { continue; } if ((block == 0x0E) && (byte > 1) && (!write_otp)) { continue; } // 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, nmJewel, NULL, 0, &nt) <= 0) { ERR("tag was removed"); return false; } bFailure = false; } req.writee.btCmd = TC_WRITEE; req.writee.btAdd = (block << 3) + byte; req.writee.btDat = ttDump.ttd.abtData[(block << 3) + byte]; if (!nfc_initiator_jewel_cmd(pnd, req, &res)) { bFailure = true; } } print_success_or_failure(bFailure, &uiWrittenBlocks); fflush(stdout); } printf("|\n"); printf("Done, %d of %d blocks written (%d blocks partial, %d blocks skipped).\n", uiWrittenBlocks, uiBlocks + 1, uiPartialBlocks, uiSkippedBlocks); return true; } int main(int argc, const char *argv[]) { bool bReadAction; FILE *pfDump; if (argc < 3) { printf("\n"); printf("%s r|w \n", argv[0]); printf("\n"); printf("r|w - Perform read from or write to card\n"); printf(" - JeWel Dump (JWD) used to write (card to JWD) or (JWD to card)\n"); printf("\n"); exit(EXIT_FAILURE); } DBG("\nChecking arguments and settings\n"); bReadAction = tolower((int)((unsigned char) * (argv[1])) == 'r'); if (bReadAction) { memset(&ttDump, 0x00, sizeof(ttDump)); } else { pfDump = fopen(argv[2], "rb"); if (pfDump == NULL) { ERR("Could not open dump file: %s\n", argv[2]); exit(EXIT_FAILURE); } if (fread(&ttDump, 1, sizeof(ttDump), pfDump) != sizeof(ttDump)) { ERR("Could not read from dump file: %s\n", argv[2]); fclose(pfDump); exit(EXIT_FAILURE); } fclose(pfDump); } DBG("Successfully opened the dump file\n"); nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Try to open the NFC device pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Error opening NFC device"); nfc_exit(context); exit(EXIT_FAILURE); } if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Let the device 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"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); // Try to find a Jewel tag if (nfc_initiator_select_passive_target(pnd, nmJewel, NULL, 0, &nt) <= 0) { ERR("no tag was found\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Get the info from the current tag printf("Found Jewel card with UID: "); size_t szPos; for (szPos = 0; szPos < 4; szPos++) { printf("%02x", nt.nti.nji.btId[szPos]); } printf("\n"); if (bReadAction) { if (read_card()) { printf("Writing data to file: %s ... ", argv[2]); fflush(stdout); pfDump = fopen(argv[2], "wb"); if (pfDump == NULL) { printf("Could not open file: %s\n", argv[2]); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (fwrite(&ttDump, 1, sizeof(ttDump), pfDump) != sizeof(ttDump)) { printf("Could not write to file: %s\n", argv[2]); fclose(pfDump); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } fclose(pfDump); printf("Done.\n"); } } else { write_card(); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-list.1000066400000000000000000000035001230265671100157170ustar00rootroot00000000000000.TH nfc-list 1 "June 26, 2009" "libnfc" "NFC Utilities" .SH NAME nfc-list \- list NFC targets .SH SYNOPSIS .B nfc-list [ .I options ] .SH DESCRIPTION .B nfc-list is a utility for listing any available tags like ISO14443-A, FeliCa, Jewel or ISO14443-B (according to the device capabilities). It may detect several tags at once thanks to a mechanism called anti-collision but all types of tags don't support anti-collision and there is some physical limitation of the number of tags the reader can discover. This tool displays all available information at selection time. .SH OPTIONS .TP .B \-v Tells .I nfc-list to be verbose and display detailed information about the targets shown. 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) 8: ISO14443B 16: ISO14443B' 32: ISO14443B-2 ST SRx 64: ISO14443B-2 ASK CTx 128: Jewel So 255 (default) polls for all types. Note that if 16, 32 or 64 then 8 is selected too. .SH EXAMPLE For an ISO/IEC 14443-A tag (i.e.Mifare DESFire): ATQA (SENS_RES): 03 44 UID (NFCID1): 04 45 35 01 db 24 80 SAK (SEL_RES): 20 ATS (ATR): 75 77 81 02 80 .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult , .br Romain Tartière , .br Romuald Conty . .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/utils/nfc-list.c000066400000000000000000000212771230265671100160140ustar00rootroot00000000000000/*- * 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-list.c * @brief Lists the first target present of each founded device */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "nfc-utils.h" #define MAX_DEVICE_COUNT 16 #define MAX_TARGET_COUNT 16 static nfc_device *pnd; static void print_usage(const char *progname) { printf("usage: %s [-v] [-t X]\n", progname); printf(" -v\t verbose display\n"); printf(" -t X\t poll only for types according to bitfield X:\n"); printf("\t 1: ISO14443A\n"); printf("\t 2: Felica (212 kbps)\n"); printf("\t 4: Felica (424 kbps)\n"); printf("\t 8: ISO14443B\n"); printf("\t 16: ISO14443B'\n"); printf("\t 32: ISO14443B-2 ST SRx\n"); printf("\t 64: ISO14443B-2 ASK CTx\n"); printf("\t 128: Jewel\n"); printf("\tSo 255 (default) polls for all types.\n"); printf("\tNote that if 16, 32 or 64 then 8 is selected too.\n"); } int main(int argc, const char *argv[]) { (void) argc; const char *acLibnfcVersion; size_t i; bool verbose = false; int res = 0; int mask = 0xff; int arg; nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); 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")) { print_usage(argv[0]); exit(EXIT_SUCCESS); } else if (0 == strcmp(argv[arg], "-v")) { verbose = true; } else if ((0 == strcmp(argv[arg], "-t")) && (arg + 1 < argc)) { arg++; mask = atoi(argv[arg]); if ((mask < 1) || (mask > 255)) { 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) mask |= 0x08; } else { ERR("%s is not supported option.", argv[arg]); print_usage(argv[0]); exit(EXIT_FAILURE); } } /* Lazy way to open an NFC device */ #if 0 pnd = nfc_open(context, NULL); #endif /* Use connection string if specific device is wanted, * i.e. PN532 UART device on /dev/ttyUSB1 */ #if 0 pnd = nfc_open(context, "pn532_uart:/dev/ttyUSB1"); #endif nfc_connstring connstrings[MAX_DEVICE_COUNT]; size_t szDeviceFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (szDeviceFound == 0) { printf("No NFC device found.\n"); } for (i = 0; i < szDeviceFound; i++) { nfc_target ant[MAX_TARGET_COUNT]; pnd = nfc_open(context, connstrings[i]); if (pnd == NULL) { ERR("Unable to open NFC device: %s", connstrings[i]); continue; } if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); nfc_modulation nm; if (mask & 0x1) { nm.nmt = NMT_ISO14443A; nm.nbr = NBR_106; // List ISO14443A targets if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d ISO14443A 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 & 0x02) { nm.nmt = NMT_FELICA; nm.nbr = NBR_212; // List Felica tags if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d Felica (212 kbps) 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 & 0x04) { nm.nmt = NMT_FELICA; nm.nbr = NBR_424; if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d Felica (424 kbps) 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 & 0x08) { nm.nmt = NMT_ISO14443B; nm.nbr = NBR_106; // List ISO14443B targets if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d ISO14443B 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 & 0x10) { nm.nmt = NMT_ISO14443BI; nm.nbr = NBR_106; // List ISO14443B' targets if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d ISO14443B' 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 & 0x20) { nm.nmt = NMT_ISO14443B2SR; nm.nbr = NBR_106; // List ISO14443B-2 ST SRx family targets if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d ISO14443B-2 ST SRx 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 & 0x40) { nm.nmt = NMT_ISO14443B2CT; nm.nbr = NBR_106; // List ISO14443B-2 ASK CTx family targets if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d ISO14443B-2 ASK CTx 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 & 0x80) { nm.nmt = NMT_JEWEL; nm.nbr = NBR_106; // List Jewel targets if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { int n; if (verbose || (res > 0)) { printf("%d Jewel passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":"); } for (n = 0; n < res; n++) { print_nfc_target(&ant[n], verbose); printf("\n"); } } } nfc_close(pnd); } nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-mfclassic.1000066400000000000000000000057611230265671100167230ustar00rootroot00000000000000.TH nfc-mfclassic 1 "Nov 02, 2009" "libnfc" "NFC Utilities" .SH NAME nfc-mfclassic \- MIFARE Classic command line tool .SH SYNOPSIS .B nfc-mfclassic .RI \fR\fBf\fR|\fR\fBr\fR|\fR\fBR\fR|\fBw\fR\fR|\fBW\fR .RI \fR\fBa\fR|\fR\fBA\fR|\fBb\fR\fR|\fBB\fR .IR DUMP .RI [ .IR KEYS .RI [\fR\fBf\fR] .RI ] .SH DESCRIPTION .B nfc-mfclassic is a MIFARE Classic tool that allow to read or write .IR DUMP file using MIFARE keys provided in .IR KEYS file. MIFARE Classic tag is one of the most widely used RFID tags. The firmware in the NFC controller supports authenticating, reading and writing to/from MIFARE Classic tags. This tool demonstrates the speed of this library and its ease-of-use. It's possible to read and write the complete content of a MIFARE Classic 4KB tag within 1 second. It uses a binary MIFARE Dump file (MFD) to store the keys and data for all sectors. Be cautious that some parts of a MIFARE Classic memory are used for r/w access of the rest of the memory, so please read the tag documentation before experimenting too much! The .B f option to format the card will reset all keys to FFFFFFFFFFFF, all data to 00 and all ACLs to default. The .B W option allows writing of special MIFARE cards that can be 'unlocked' to allow block 0 to be overwritten. This includes UID and manufacturer data. Take care when amending UIDs to set the correct BCC (UID checksum). Currently only 4 byte UIDs are supported. Similarly, the .B R option allows an 'unlocked' read. This bypasses authentication and allows reading of the Key A and Key B data regardless of ACLs. R/W errors on some blocks can be either considered as critical or ignored. To halt on first error, specify keys with lowercase ( .B a or .B b ). To ignore such errors, use uppercase ( .B A or .B B ). *** Note that .B W and .B R options only work on special versions of MIFARE 1K cards (Chinese clones). .SH OPTIONS .TP .BR f " | " r " | " R " | " w " | " W Perform format ( .B f ) or read from ( .B r ) or unlocked read from ( .B R ) or write to ( .B w ) or unlocked write to ( .B W ) card. .TP .BR a " | " A " | " b " | " B Use A or B MIFARE keys. Halt on errors ( .B a | .B b ) or tolerate errors ( .B A | .B B ). .TP .IR DUMP MiFare Dump (MFD) used to write (card to MFD) or (MFD to card) .TP .IR KEYS MiFare Dump (MFD) that contains the keys (optional). Data part of the dump is ignored. .TP .B f Force using the keyfile .IR KEYS even if UID does not match (optional). .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Adam Laurie , .br Roel Verdult , .br Romain Tartière , .br Romuald Conty . .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/utils/nfc-mfclassic.c000066400000000000000000000545351230265671100170100ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2011-2013 Adam Laurie * * 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-mfclassic.c * @brief MIFARE Classic manipulation example */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include "mifare.h" #include "nfc-utils.h" static nfc_context *context; static nfc_device *pnd; static nfc_target nt; static mifare_param mp; static mifare_classic_tag mtKeys; static mifare_classic_tag mtDump; static bool bUseKeyA; static bool bUseKeyFile; static bool bForceKeyFile; static bool bTolerateFailures; static bool bFormatCard; static bool magic2 = false; static uint8_t uiBlocks; static uint8_t keys[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd, 0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56 }; static uint8_t default_key[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static uint8_t default_acl[] = {0xff, 0x07, 0x80, 0x69}; static const nfc_modulation nmMifare = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; static size_t num_keys = sizeof(keys) / 6; #define MAX_FRAME_LEN 264 static uint8_t abtRx[MAX_FRAME_LEN]; static int szRxBits; uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 }; // special unlock command uint8_t abtUnlock1[1] = { 0x40 }; uint8_t abtUnlock2[1] = { 0x43 }; static bool transmit_bits(const uint8_t *pbtTx, const size_t szTxBits) { // Show transmitted command printf("Sent bits: "); print_hex_bits(pbtTx, szTxBits); // Transmit the bit frame command, we don't use the arbitrary parity feature if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0) return false; // Show received answer printf("Received bits: "); print_hex_bits(abtRx, szRxBits); // Succesful transfer return true; } static bool transmit_bytes(const uint8_t *pbtTx, const size_t szTx) { // Show transmitted command printf("Sent bits: "); print_hex(pbtTx, szTx); // Transmit the command bytes int res; if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0) return false; // Show received answer printf("Received bits: "); print_hex(abtRx, res); // Succesful transfer return true; } static void print_success_or_failure(bool bFailure, uint32_t *uiBlockCounter) { printf("%c", (bFailure) ? 'x' : '.'); if (uiBlockCounter && !bFailure) *uiBlockCounter += 1; } static bool is_first_block(uint32_t uiBlock) { // Test if we are in the small or big sectors if (uiBlock < 128) return ((uiBlock) % 4 == 0); else return ((uiBlock) % 16 == 0); } static bool is_trailer_block(uint32_t uiBlock) { // Test if we are in the small or big sectors if (uiBlock < 128) return ((uiBlock + 1) % 4 == 0); else return ((uiBlock + 1) % 16 == 0); } static uint32_t get_trailer_block(uint32_t uiFirstBlock) { // Test if we are in the small or big sectors uint32_t trailer_block = 0; if (uiFirstBlock < 128) { trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4)); } else { trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16)); } return trailer_block; } static bool authenticate(uint32_t uiBlock) { mifare_cmd mc; uint32_t uiTrailerBlock; // Set the authentication information (uid) memcpy(mp.mpa.abtAuthUid, nt.nti.nai.abtUid + nt.nti.nai.szUidLen - 4, 4); // Should we use key A or B? mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B; // Key file authentication. if (bUseKeyFile) { // Locate the trailer (with the keys) used for this sector uiTrailerBlock = get_trailer_block(uiBlock); // Extract the right key from dump file if (bUseKeyA) memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, 6); else memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, 6); // 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) { 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)) { if (bUseKeyA) memcpy(mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, 6); else memcpy(mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, 6); return true; } if (nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL) <= 0) { ERR("tag was removed"); return false; } } } return false; } static bool unlock_card(void) { if (magic2) { printf("Don't use R/W with this card, this is not required!\n"); return false; } // Configure the CRC if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { nfc_perror(pnd, "nfc_configure"); return false; } // Use raw send/receive methods if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { nfc_perror(pnd, "nfc_configure"); return false; } iso14443a_crc_append(abtHalt, 2); transmit_bytes(abtHalt, 4); // now send unlock if (!transmit_bits(abtUnlock1, 7)) { printf("unlock failure!\n"); return false; } if (!transmit_bytes(abtUnlock2, 1)) { printf("unlock failure!\n"); return false; } // reset reader // Configure the CRC if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); return false; } // Switch off raw send/receive methods if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); return false; } return true; } static int get_rats(void) { int res; uint8_t abtRats[2] = { 0xe0, 0x50}; // Use raw send/receive methods if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { nfc_perror(pnd, "nfc_configure"); return -1; } res = nfc_initiator_transceive_bytes(pnd, abtRats, sizeof(abtRats), abtRx, sizeof(abtRx), 0); if (res > 0) { // ISO14443-4 card, turn RF field off/on to access ISO14443-3 again if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false) < 0) { nfc_perror(pnd, "nfc_configure"); return -1; } if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true) < 0) { nfc_perror(pnd, "nfc_configure"); return -1; } } // Reselect tag if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { printf("Error: tag disappeared\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } return res; } static bool read_card(int read_unlocked) { int32_t iBlock; bool bFailure = false; uint32_t uiReadBlocks = 0; if (read_unlocked) if (!unlock_card()) return false; printf("Reading out %d blocks |", uiBlocks + 1); // Read the card from end to begin for (iBlock = uiBlocks; iBlock >= 0; iBlock--) { // Authenticate everytime we reach a trailer block if (is_trailer_block(iBlock)) { if (bFailure) { // When a failure occured we need to redo the anti-collision if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { printf("!\nError: tag was removed\n"); return false; } bFailure = false; } fflush(stdout); // Try to authenticate for the current sector if (!read_unlocked && !authenticate(iBlock)) { printf("!\nError: authentication failed for block 0x%02x\n", iBlock); return false; } // Try to read out the trailer if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) { if (read_unlocked) { memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16); } 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, 6); memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpd.abtData + 6, 4); memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, 6); } } else { printf("!\nfailed to read trailer block 0x%02x\n", iBlock); bFailure = true; } } else { // Make sure a earlier readout did not fail if (!bFailure) { // Try to read out the data block if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) { memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16); } else { printf("!\nError: unable to read block 0x%02x\n", iBlock); bFailure = true; } } } // Show if the readout went well for each block print_success_or_failure(bFailure, &uiReadBlocks); if ((! bTolerateFailures) && bFailure) return false; } printf("|\n"); printf("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1); fflush(stdout); return true; } static bool write_card(int write_block_zero) { uint32_t uiBlock; bool bFailure = false; uint32_t uiWriteBlocks = 0; if (write_block_zero) if (!unlock_card()) return false; printf("Writing %d blocks |", uiBlocks + 1); // Write the card from begin to end; for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { // Authenticate everytime we reach the first sector of a new block if (is_first_block(uiBlock)) { if (bFailure) { // When a failure occured we need to redo the anti-collision if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { printf("!\nError: tag was removed\n"); return false; } bFailure = false; } fflush(stdout); // Try to authenticate for the current sector if (!write_block_zero && !authenticate(uiBlock)) { 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.mpd.abtData, default_key, 6); memcpy(mp.mpd.abtData + 6, default_acl, 4); memcpy(mp.mpd.abtData + 10, default_key, 6); } else { // Copy the keys over from our key dump and store the retrieved access bits memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbt.abtKeyA, 6); memcpy(mp.mpd.abtData + 6, mtDump.amb[uiBlock].mbt.abtAccessBits, 4); memcpy(mp.mpd.abtData + 10, mtDump.amb[uiBlock].mbt.abtKeyB, 6); } // 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, 16); else memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16); // do not write a block 0 with incorrect BCC - card will be made invalid! if (uiBlock == 0) { if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { printf("!\nError: incorrect BCC in MFD file!\n"); printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]); return false; } } if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) bFailure = true; } } // Show if the write went well for each block print_success_or_failure(bFailure, &uiWriteBlocks); if ((! bTolerateFailures) && bFailure) return false; } printf("|\n"); printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1); fflush(stdout); return true; } typedef enum { ACTION_READ, ACTION_WRITE, ACTION_USAGE } action_t; static void print_usage(const char *pcProgramName) { printf("Usage: "); printf("%s f|r|R|w|W a|b [ [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"); 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(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n"); printf(" - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); printf(" - MiFare Dump (MFD) that contain the keys (optional)\n"); printf(" f - Force using the keyfile even if UID does not match (optional)\n"); printf("Examples: \n\n"); printf(" Read card to file, using key A:\n\n"); printf(" %s r a mycard.mfd\n\n", pcProgramName); printf(" Write file to blank card, using key A:\n\n"); printf(" %s w a mycard.mfd\n\n", pcProgramName); printf(" Write new data and/or keys to previously written card, using key A:\n\n"); printf(" %s w a newdata.mfd mycard.mfd\n\n", pcProgramName); printf(" Format/wipe card (note two passes required to ensure writes for all ACL cases):\n\n"); printf(" %s f A dummy.mfd keyfile.mfd f\n", pcProgramName); printf(" %s f B dummy.mfd keyfile.mfd f\n\n", pcProgramName); } int main(int argc, const char *argv[]) { action_t atAction = ACTION_USAGE; uint8_t *pbtUID; int unlock = 0; if (argc < 2) { print_usage(argv[0]); exit(EXIT_FAILURE); } const char *command = argv[1]; if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) { if (argc < 4) { print_usage(argv[0]); exit(EXIT_FAILURE); } atAction = ACTION_READ; if (strcmp(command, "R") == 0) unlock = 1; bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); bUseKeyFile = (argc > 4); bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) { if (argc < 4) { print_usage(argv[0]); exit(EXIT_FAILURE); } atAction = ACTION_WRITE; if (strcmp(command, "W") == 0) unlock = 1; bFormatCard = (strcmp(command, "f") == 0); bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); bUseKeyFile = (argc > 4); bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); } if (atAction == ACTION_USAGE) { print_usage(argv[0]); exit(EXIT_FAILURE); } // We don't know yet the card size so let's read only the UID from the keyfile for the moment if (bUseKeyFile) { FILE *pfKeys = fopen(argv[4], "rb"); if (pfKeys == NULL) { printf("Could not open keys file: %s\n", argv[4]); exit(EXIT_FAILURE); } if (fread(&mtKeys, 1, 4, pfKeys) != 4) { printf("Could not read UID from key file: %s\n", argv[4]); fclose(pfKeys); exit(EXIT_FAILURE); } fclose(pfKeys); } nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Try to open the NFC reader pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Error opening NFC reader"); nfc_exit(context); exit(EXIT_FAILURE); } if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); 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"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Disable ISO14443-4 switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance. if (nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, false) < 0) { nfc_perror(pnd, "nfc_device_set_property_bool"); 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 if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { printf("Error: no tag was found\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Test if we are dealing with a MIFARE compatible tag if ((nt.nti.nai.btSak & 0x08) == 0) { printf("Warning: tag is probably not a MFC!\n"); } // Get the info from the current tag pbtUID = nt.nti.nai.abtUid; if (bUseKeyFile) { uint8_t fileUid[4]; memcpy(fileUid, mtKeys.amb[0].mbm.abtUID, 4); // Compare if key dump UID is the same as the current tag UID, at least for the first 4 bytes if (memcmp(pbtUID, fileUid, 4) != 0) { printf("Expected MIFARE Classic card with UID starting as: %02x%02x%02x%02x\n", fileUid[0], fileUid[1], fileUid[2], fileUid[3]); printf("Got card with UID starting as: %02x%02x%02x%02x\n", pbtUID[0], pbtUID[1], pbtUID[2], pbtUID[3]); if (! bForceKeyFile) { printf("Aborting!\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } } } printf("Found MIFARE Classic card:\n"); print_nfc_target(&nt, false); // Guessing size if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02) // 4K uiBlocks = 0xff; else if ((nt.nti.nai.btSak & 0x01) == 0x01) // 320b uiBlocks = 0x13; else // 1K/2K, checked through RATS uiBlocks = 0x3f; // Testing RATS int res; if ((res = get_rats()) > 0) { if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05) && (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f) && ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) { // MIFARE Plus 2K uiBlocks = 0x7f; } // 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 %i-byte card\n", (uiBlocks + 1) * 16); if (bUseKeyFile) { FILE *pfKeys = fopen(argv[4], "rb"); if (pfKeys == NULL) { printf("Could not open keys file: %s\n", argv[4]); exit(EXIT_FAILURE); } if (fread(&mtKeys, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfKeys) != (uiBlocks + 1) * sizeof(mifare_classic_block)) { printf("Could not read keys file: %s\n", argv[4]); fclose(pfKeys); exit(EXIT_FAILURE); } fclose(pfKeys); } if (atAction == ACTION_READ) { memset(&mtDump, 0x00, sizeof(mtDump)); } else { FILE *pfDump = fopen(argv[3], "rb"); if (pfDump == NULL) { printf("Could not open dump file: %s\n", argv[3]); exit(EXIT_FAILURE); } if (fread(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != (uiBlocks + 1) * sizeof(mifare_classic_block)) { printf("Could not read dump file: %s\n", argv[3]); fclose(pfDump); exit(EXIT_FAILURE); } fclose(pfDump); } // printf("Successfully opened required files\n"); if (atAction == ACTION_READ) { if (read_card(unlock)) { printf("Writing data to file: %s ...", argv[3]); fflush(stdout); FILE *pfDump = fopen(argv[3], "wb"); if (pfDump == NULL) { printf("Could not open dump file: %s\n", argv[3]); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (fwrite(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != ((uiBlocks + 1) * sizeof(mifare_classic_block))) { printf("\nCould not write to file: %s\n", argv[3]); fclose(pfDump); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("Done.\n"); fclose(pfDump); } } else if (atAction == ACTION_WRITE) { write_card(unlock); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-mfultralight.1000066400000000000000000000027541230265671100174600ustar00rootroot00000000000000.TH nfc-mfultralight 1 "Nov 02, 2009" "libnfc" "NFC Utilities" .SH NAME nfc-mfultralight \- MIFARE Ultralight command line tool .SH SYNOPSIS .B nfc-mfultralight .RI \fR\fBr\fR|\fBw\fR .IR DUMP .SH DESCRIPTION .B nfc-mfultralight is a MIFARE Ultralight tool that allows one to read or write a tag data to/from a .IR DUMP file. MIFARE Ultralight tag is one of the most widely used RFID tags for ticketing application. It uses a binary Mifare Dump file (MFD) to store data for all sectors. Be cautious that some parts of a Ultralight memory can be written only once and some parts are used as lock bits, so please read the tag documentation before experimenting too much! To set the UID of a special writeable UID card, edit the first 7 bytes of a dump file and then write it back, answering 'Y' to the question 'Write UID bytes?'. .SH OPTIONS .BR r " | " w Perform read from ( .B r ) or write to ( .B w ) card. .TP .IR DUMP MiFare Dump (MFD) used to write (card to MFD) or (MFD to card) .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult , .br Romuald Conty . .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/utils/nfc-mfultralight.c000066400000000000000000000210241230265671100175310ustar00rootroot00000000000000/*- * 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: * Copyright (C) 2013 Adam Laurie * * 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-mfultralight.c * @brief MIFARE Ultralight dump/restore tool */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include "nfc-utils.h" #include "mifare.h" static nfc_device *pnd; static nfc_target nt; static mifare_param mp; static mifareul_tag mtDump; static uint32_t uiBlocks = 0xF; static const nfc_modulation nmMifare = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; static void print_success_or_failure(bool bFailure, uint32_t *uiCounter) { printf("%c", (bFailure) ? 'x' : '.'); if (uiCounter) *uiCounter += (bFailure) ? 0 : 1; } static bool read_card(void) { uint32_t page; bool bFailure = false; uint32_t uiReadedPages = 0; printf("Reading %d pages |", uiBlocks + 1); for (page = 0; page <= uiBlocks; page += 4) { // Try to read out the data block if (nfc_initiator_mifare_cmd(pnd, MC_READ, page, &mp)) { memcpy(mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16); } else { bFailure = true; break; } print_success_or_failure(bFailure, &uiReadedPages); print_success_or_failure(bFailure, &uiReadedPages); print_success_or_failure(bFailure, &uiReadedPages); print_success_or_failure(bFailure, &uiReadedPages); } printf("|\n"); printf("Done, %d of %d pages readed.\n", uiReadedPages, uiBlocks + 1); fflush(stdout); return (!bFailure); } static bool write_card(void) { uint32_t uiBlock = 0; bool bFailure = false; uint32_t uiWritenPages = 0; uint32_t uiSkippedPages = 0; char buffer[BUFSIZ]; bool write_otp; bool write_lock; bool write_uid; printf("Write OTP bytes ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); } write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y')); printf("Write Lock bytes ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); } write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y')); printf("Write UID bytes (only for special writeable UID cards) ? [yN] "); if (!fgets(buffer, BUFSIZ, stdin)) { ERR("Unable to read standard input."); } write_uid = ((buffer[0] == 'y') || (buffer[0] == 'Y')); printf("Writing %d pages |", uiBlocks + 1); /* We may need to skip 2 first pages. */ if (!write_uid) { printf("ss"); uiSkippedPages = 2; } for (int page = uiSkippedPages; page <= 0xF; page++) { if ((page == 0x2) && (!write_lock)) { printf("s"); uiSkippedPages++; continue; } if ((page == 0x3) && (!write_otp)) { printf("s"); uiSkippedPages++; continue; } // 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; } // For the Mifare Ultralight, this write command can be used // in compatibility mode, which only actually writes the first // page (4 bytes). The Ultralight-specific Write command only // writes one page at a time. uiBlock = page / 4; memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 16); if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp)) bFailure = true; print_success_or_failure(bFailure, &uiWritenPages); } printf("|\n"); printf("Done, %d of %d pages written (%d pages skipped).\n", uiWritenPages, uiBlocks + 1, uiSkippedPages); return true; } int main(int argc, const char *argv[]) { bool bReadAction; FILE *pfDump; if (argc < 3) { printf("\n"); printf("%s r|w \n", argv[0]); printf("\n"); printf("r|w - Perform read from or write to card\n"); printf(" - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); printf("\n"); exit(EXIT_FAILURE); } DBG("\nChecking arguments and settings\n"); bReadAction = tolower((int)((unsigned char) * (argv[1])) == 'r'); if (bReadAction) { memset(&mtDump, 0x00, sizeof(mtDump)); } else { pfDump = fopen(argv[2], "rb"); if (pfDump == NULL) { ERR("Could not open dump file: %s\n", argv[2]); exit(EXIT_FAILURE); } if (fread(&mtDump, 1, sizeof(mtDump), pfDump) != sizeof(mtDump)) { ERR("Could not read from dump file: %s\n", argv[2]); fclose(pfDump); exit(EXIT_FAILURE); } fclose(pfDump); } DBG("Successfully opened the dump file\n"); nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } // Try to open the NFC device pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Error opening NFC device"); nfc_exit(context); exit(EXIT_FAILURE); } if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Let the device 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"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); // Try to find a MIFARE Ultralight tag if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { ERR("no tag was found\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Test if we are dealing with a MIFARE compatible tag if (nt.nti.nai.abtAtqa[1] != 0x44) { ERR("tag is not a MIFARE Ultralight card\n"); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Get the info from the current tag printf("Found MIFARE Ultralight card with UID: "); size_t szPos; for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) { printf("%02x", nt.nti.nai.abtUid[szPos]); } printf("\n"); if (bReadAction) { if (read_card()) { printf("Writing data to file: %s ... ", argv[2]); fflush(stdout); pfDump = fopen(argv[2], "wb"); if (pfDump == NULL) { printf("Could not open file: %s\n", argv[2]); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (fwrite(&mtDump, 1, sizeof(mtDump), pfDump) != sizeof(mtDump)) { printf("Could not write to file: %s\n", argv[2]); fclose(pfDump); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } fclose(pfDump); printf("Done.\n"); } } else { write_card(); } nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-read-forum-tag3.1000066400000000000000000000021641230265671100176460ustar00rootroot00000000000000.TH nfc-read-forum-tag3 1 "November 22, 2011" "libnfc" "NFC Utilities" .SH NAME nfc-read-forum-tag3 \- Extract NDEF Message from a NFC Forum Tag Type 3 .SH SYNOPSIS .B nfc-read-forum-tag3 .RI [ .RI \fR\fB\-q\fR .RI ] .RI \fR\fB\-o\fR .IR FILE .SH DESCRIPTION .B nfc-read-forum-tag3 This utility extracts (if available) NDEF Messages contained in a NFC Forum Tag Type 3 to .IR FILE . .SH OPTIONS \fR\fB\-o\fR .IR FILE : output extracted NDEF Message to .IR FILE (use \fR\fB\-o \-\fR to output to stdout) \fR\fB\-q\fR : be quiet, don't display Attribute Block parsing info .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult , .br Romain Tartière , .br Romuald Conty . .PP This manual page was written by Audrey Diacre . It is licensed under the terms of the GNU GPL (version 2 or later).libnfc-1.7.1/utils/nfc-read-forum-tag3.c000066400000000000000000000304501230265671100177270ustar00rootroot00000000000000/*- * 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-read-forum-tag3.c * @brief Extract NDEF Message from a NFC Forum Tag Type 3 * This utility extract (if available) the NDEF Message contained in an NFC Forum Tag Type 3. */ /* * This implementation was written based on information provided by the * following documents: * * NFC Forum Type 3 Tag Operation Specification * Technical Specification * NFCForum-TS-Type-3-Tag_1.1 - 2011-06-28 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include "nfc-utils.h" #if defined(WIN32) && defined(__GNUC__) /* mingw compiler */ #include #endif static nfc_device *pnd; static nfc_context *context; static void print_usage(char *progname) { fprintf(stderr, "usage: %s [-q] -o FILE\n", progname); fprintf(stderr, "\nOptions:\n"); fprintf(stderr, " -o FILE Extract NDEF message if available in FILE\n"); fprintf(stderr, " -o - Extract NDEF message if available to stdout\n"); fprintf(stderr, " -q Be quiet, don't display Attribute Block parsing info\n"); } static void stop_select(int sig) { (void) sig; if (pnd != NULL) { nfc_abort_command(pnd); } else { nfc_exit(context); exit(EXIT_FAILURE); } } static void build_felica_frame(const nfc_felica_info nfi, const uint8_t command, const uint8_t *payload, const size_t payload_len, uint8_t *frame, size_t *frame_len) { frame[0] = 1 + 1 + 8 + payload_len; *frame_len = frame[0]; frame[1] = command; memcpy(frame + 2, nfi.abtId, 8); memcpy(frame + 10, payload, payload_len); } #define CHECK 0x06 static int nfc_forum_tag_type3_check(nfc_device *dev, const nfc_target *nt, const uint16_t block, const uint8_t block_count, uint8_t *data, size_t *data_len) { uint8_t payload[1024] = { 1, // Services 0x0B, 0x00, // NFC Forum Tag Type 3's Service code block_count, 0x80, block, // block 0 }; size_t payload_len = 1 + 2 + 1; for (uint8_t b = 0; b < block_count; b++) { if (block < 0x100) { payload[payload_len++] = 0x80; payload[payload_len++] = block + b; } else { payload[payload_len++] = 0x00; payload[payload_len++] = (block + b) >> 8; payload[payload_len++] = (block + b) & 0xff; } } uint8_t frame[1024]; size_t frame_len = sizeof(frame); build_felica_frame(nt->nti.nfi, CHECK, payload, payload_len, frame, &frame_len); uint8_t rx[1024]; int res; if ((res = nfc_initiator_transceive_bytes(dev, frame, frame_len, rx, sizeof(rx), 0)) < 0) { return res; } const int res_overhead = 1 + 1 + 8 + 2; // 1+1+8+2: LEN + CMD + NFCID2 + STATUS if (res < res_overhead) { // Not enough data return -1; } uint8_t felica_res_len = rx[0]; if (res != felica_res_len) { // Error while receiving felica frame return -1; } if ((CHECK + 1) != rx[1]) { // Command return does not match return -1; } if (0 != memcmp(&rx[2], nt->nti.nfi.abtId, 8)) { // NFCID2 does not match return -1; } const uint8_t status_flag1 = rx[10]; const uint8_t status_flag2 = rx[11]; if ((status_flag1) || (status_flag2)) { // Felica card's error fprintf(stderr, "Status bytes: %02x, %02x\n", status_flag1, status_flag2); return -1; } // const uint8_t res_block_count = res[12]; *data_len = res - res_overhead + 1; // +1 => block count is stored on 1 byte memcpy(data, &rx[res_overhead + 1], *data_len); return *data_len; } int main(int argc, char *argv[]) { (void)argc; (void)argv; int ch; bool quiet = false; char *ndef_output = NULL; while ((ch = getopt(argc, argv, "hqo:")) != -1) { switch (ch) { case 'h': print_usage(argv[0]); exit(EXIT_SUCCESS); break; case 'q': quiet = true; break; case 'o': ndef_output = optarg; break; default: print_usage(argv[0]); exit(EXIT_FAILURE); } } if (ndef_output == NULL) { print_usage(argv[0]); exit(EXIT_FAILURE); } FILE *message_stream = NULL; FILE *ndef_stream = NULL; if ((strlen(ndef_output) == 1) && (ndef_output[0] == '-')) { message_stream = stderr; ndef_stream = stdout; } else { message_stream = stdout; ndef_stream = fopen(ndef_output, "wb"); if (!ndef_stream) { fprintf(stderr, "Could not open file %s.\n", ndef_output); exit(EXIT_FAILURE); } } nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)\n"); exit(EXIT_FAILURE); } pnd = nfc_open(context, NULL); if (pnd == NULL) { ERR("Unable to open NFC device"); fclose(ndef_stream); nfc_exit(context); exit(EXIT_FAILURE); } if (!quiet) { fprintf(message_stream, "NFC device: %s opened\n", nfc_device_get_name(pnd)); } nfc_modulation nm = { .nmt = NMT_FELICA, .nbr = NBR_212, }; signal(SIGINT, stop_select); nfc_target nt; if (nfc_initiator_init(pnd) < 0) { nfc_perror(pnd, "nfc_initiator_init"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (!quiet) { fprintf(message_stream, "Place your NFC Forum Tag Type 3 in the field...\n"); } // Polling payload (SENSF_REQ) must be present (see NFC Digital Protol) const uint8_t *pbtSensfReq = (uint8_t *)"\x00\xff\xff\x01\x00"; if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReq, 5, &nt) <= 0) { nfc_perror(pnd, "nfc_initiator_select_passive_target"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Check if System Code equals 0x12fc const uint8_t abtNfcForumSysCode[] = { 0x12, 0xfc }; if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) { // Retry with special polling const uint8_t *pbtSensfReqNfcForum = (uint8_t *)"\x00\x12\xfc\x01\x00"; if (nfc_initiator_select_passive_target(pnd, nm, pbtSensfReqNfcForum, 5, &nt) <= 0) { nfc_perror(pnd, "nfc_initiator_select_passive_target"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } // Check again if System Code equals 0x12fc if (0 != memcmp(nt.nti.nfi.abtSysCode, abtNfcForumSysCode, 2)) { fprintf(stderr, "Tag is not NFC Forum Tag Type 3 compliant.\n"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } } //print_nfc_felica_info(nt.nti.nfi, true); if ((nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) || (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0)) { nfc_perror(pnd, "nfc_device_set_property_bool"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } uint8_t data[1024]; size_t data_len = sizeof(data); if (nfc_forum_tag_type3_check(pnd, &nt, 0, 1, data, &data_len) <= 0) { nfc_perror(pnd, "nfc_forum_tag_type3_check"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } const int ndef_major_version = (data[0] & 0xf0) >> 4; const int ndef_minor_version = (data[0] & 0x0f); const int ndef_nbr = data[1]; const int ndef_nbw = data[2]; const int ndef_nmaxb = (data[3] << 8) + data[4]; const int ndef_writeflag = data[9]; const int ndef_rwflag = data[10]; uint32_t ndef_data_len = (data[11] << 16) + (data[12] << 8) + data[13]; uint16_t ndef_calculated_checksum = 0; for (size_t n = 0; n < 14; n++) ndef_calculated_checksum += data[n]; const uint16_t ndef_checksum = (data[14] << 8) + data[15]; if (!quiet) { fprintf(message_stream, "NDEF Attribute Block:\n"); fprintf(message_stream, "* Mapping version: %d.%d\n", ndef_major_version, ndef_minor_version); fprintf(message_stream, "* Maximum nr of blocks to read by Check Command: %3d block%s\n", ndef_nbr, ndef_nbr > 1 ? "s" : ""); fprintf(message_stream, "* Maximum nr of blocks to write by Update Command: %3d block%s\n", ndef_nbw, ndef_nbw > 1 ? "s" : ""); fprintf(message_stream, "* Maximum nr of blocks available for NDEF data: %3d block%s (%d bytes)\n", ndef_nmaxb, ndef_nmaxb > 1 ? "s" : "", ndef_nmaxb * 16); fprintf(message_stream, "* NDEF writing state: "); switch (ndef_writeflag) { case 0x00: fprintf(message_stream, "finished (0x00)\n"); break; case 0x0f: fprintf(message_stream, "in progress (0x0F)\n"); break; default: fprintf(message_stream, "invalid (0x%02X)\n", ndef_writeflag); break; } fprintf(message_stream, "* NDEF Access Attribute: "); switch (ndef_rwflag) { case 0x00: fprintf(message_stream, "Read only (0x00)\n"); break; case 0x01: fprintf(message_stream, "Read/Write (0x01)\n"); break; default: fprintf(message_stream, "invalid (0x%02X)\n", ndef_rwflag); break; } fprintf(message_stream, "* NDEF message length: %d bytes\n", ndef_data_len); if (ndef_calculated_checksum != ndef_checksum) { fprintf(message_stream, "* Checksum: fail (0x%04X != 0x%04X)\n", ndef_calculated_checksum, ndef_checksum); } else { fprintf(message_stream, "* Checksum: ok (0x%04X)\n", ndef_checksum); } } if (ndef_calculated_checksum != ndef_checksum) { fprintf(stderr, "Error: Checksum failed! Exiting now.\n"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } if (!ndef_data_len) { fprintf(stderr, "Error: empty NFC Forum Tag Type 3, nothing to read!\n"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } const uint8_t block_max_per_check = data[1]; const uint16_t block_count_to_check = (ndef_data_len / 16) + 1; data_len = 0; for (uint16_t b = 0; b < ((block_count_to_check - 1) / block_max_per_check + 1); b += block_max_per_check) { size_t size = sizeof(data) - data_len; if (!nfc_forum_tag_type3_check(pnd, &nt, 1 + b, MIN(block_max_per_check, (block_count_to_check - (b * block_max_per_check))), data + data_len, &size)) { nfc_perror(pnd, "nfc_forum_tag_type3_check"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } data_len += size; } if (fwrite(data, 1, ndef_data_len, ndef_stream) != ndef_data_len) { fprintf(stderr, "Error: could not write to file.\n"); fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_FAILURE); } else { if (!quiet) { fprintf(stderr, "%i bytes written to %s\n", ndef_data_len, ndef_output); } } fclose(ndef_stream); nfc_close(pnd); nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-relay-picc.1000066400000000000000000000040671230265671100170050ustar00rootroot00000000000000.TH nfc-relay-picc 1 "October 12, 2010" "libnfc" "NFC Utilities" .SH NAME nfc-relay-picc \- Relay demonstration tool for ISO14443-4 .SH SYNOPSIS .B nfc-relay-picc .SH DESCRIPTION .B nfc-relay-picc This tool requires two NFC devices. One device (configured as target) will emulate an ISO/IEC 14443-4 type A tag, while the second device (configured as initiator) will act as a reader. The genuine tag can be placed on the second device (initiator) and the tag emulator (target) can be placed close to the original reader. All communication is now relayed and shown in the screen on real-time. tag <---> initiator (relay) <---> target (relay) <---> original reader .SH OPTIONS \fB-h\fP Help List options \fB-q\fP Quiet mode Suppress printing of relayed data (improves timing) \fB-t\fP Target mode only (to be used on reader side) Commands are sent to file descriptor 4 Responses are read from file descriptor 3 \fB-i\fP Initiator mode only (to be used on tag side) Commands are read from file descriptor 3 Responses are sent to file descriptor 4 \fB-n\fP \fIN\fP Adds a waiting time of \fIN\fP seconds (integer) in the loop .SH EXAMPLES Basic usage: \fBnfc-relay-picc\fP Remote relay over TCP/IP: \fBsocat\fP TCP-LISTEN:port,reuseaddr "EXEC:\fBnfc-relay-picc \-i\fP,fdin=3,fdout=4" \fBsocat\fP TCP:remotehost:port "EXEC:\fBnfc-relay-picc \-t\fP,fdin=3,fdout=4" .SH NOTES There are some differences with \fBnfc-relay\fP: This example only works with PN532 because it relies on its internal handling of ISO14443-4 specificities. Thanks to this internal handling & injection of WTX frames, this example works on readers very strict on timing. .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .PP This manual page is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/utils/nfc-relay-picc.c000066400000000000000000000404131230265671100170620ustar00rootroot00000000000000/*- * 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-relay-picc.c * @brief Relay example using two PN532 devices. */ // Notes & differences with nfc-relay: // - This example only works with PN532 because it relies on // its internal handling of ISO14443-4 specificities. // - Thanks to this internal handling & injection of WTX frames, // this example works on readers very strict on timing #ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "nfc-utils.h" #define MAX_FRAME_LEN 264 #define MAX_DEVICE_COUNT 2 static uint8_t abtCapdu[MAX_FRAME_LEN]; static size_t szCapduLen; static uint8_t abtRapdu[MAX_FRAME_LEN]; static size_t szRapduLen; static nfc_device *pndInitiator; static nfc_device *pndTarget; static bool quitting = false; static bool quiet_output = false; static bool initiator_only_mode = false; static bool target_only_mode = false; static bool swap_devices = false; static unsigned int waiting_time = 0; FILE *fd3; FILE *fd4; static void intr_hdlr(int sig) { (void) sig; printf("\nQuitting...\n"); printf("Please send a last command to the emulator to quit properly.\n"); quitting = true; return; } static void print_usage(char *argv[]) { printf("Usage: %s [OPTIONS]\n", argv[0]); printf("Options:\n"); printf("\t-h\tHelp. Print this message.\n"); printf("\t-q\tQuiet mode. Suppress printing of relayed data (improves timing).\n"); printf("\t-t\tTarget mode only (the one on reader side). Data expected from FD3 to FD4.\n"); printf("\t-i\tInitiator mode only (the one on tag side). Data expected from FD3 to FD4.\n"); printf("\t-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n"); } static int print_hex_fd4(const uint8_t *pbtData, const size_t szBytes, const char *pchPrefix) { size_t szPos; if (szBytes > MAX_FRAME_LEN) { return -1; } if (fprintf(fd4, "#%s %04" PRIxPTR ": ", pchPrefix, szBytes) < 0) { return -1; } for (szPos = 0; szPos < szBytes; szPos++) { if (fprintf(fd4, "%02x ", pbtData[szPos]) < 0) { return -1; } } if (fprintf(fd4, "\n") < 0) { return -1; } fflush(fd4); return 0; } static int scan_hex_fd3(uint8_t *pbtData, size_t *pszBytes, const char *pchPrefix) { size_t szPos; unsigned int uiBytes; unsigned int uiData; char pchScan[256]; int c; // Look for our next sync marker while ((c = fgetc(fd3)) != '#') { if (c == EOF) { return -1; } } strncpy(pchScan, pchPrefix, 250); pchScan[sizeof(pchScan) - 1] = '\0'; strcat(pchScan, " %04x:"); if (fscanf(fd3, pchScan, &uiBytes) < 1) { return -1; } *pszBytes = uiBytes; if (*pszBytes > MAX_FRAME_LEN) { return -1; } for (szPos = 0; szPos < *pszBytes; szPos++) { if (fscanf(fd3, "%02x", &uiData) < 1) { return -1; } pbtData[szPos] = uiData; } return 0; } int main(int argc, char *argv[]) { int arg; const char *acLibnfcVersion = nfc_version(); nfc_target ntRealTarget; // Get commandline options for (arg = 1; arg < argc; arg++) { if (0 == strcmp(argv[arg], "-h")) { print_usage(argv); exit(EXIT_SUCCESS); } else if (0 == strcmp(argv[arg], "-q")) { quiet_output = true; } else if (0 == strcmp(argv[arg], "-t")) { printf("INFO: %s\n", "Target mode only."); initiator_only_mode = false; target_only_mode = true; } else if (0 == strcmp(argv[arg], "-i")) { printf("INFO: %s\n", "Initiator mode only."); initiator_only_mode = true; target_only_mode = false; } else if (0 == strcmp(argv[arg], "-s")) { printf("INFO: %s\n", "Swapping devices."); swap_devices = true; } else if (0 == strcmp(argv[arg], "-n")) { if (++arg == argc || (sscanf(argv[arg], "%10u", &waiting_time) < 1)) { ERR("Missing or wrong waiting time value: %s.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); } printf("Waiting time: %u secs.\n", waiting_time); } else { ERR("%s is not supported option.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); } } // Display libnfc version printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); #ifdef WIN32 signal(SIGINT, (void (__cdecl *)(int)) intr_hdlr); #else signal(SIGINT, intr_hdlr); #endif nfc_context *context; nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)"); exit(EXIT_FAILURE); } nfc_connstring connstrings[MAX_DEVICE_COUNT]; // List available devices size_t szFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (initiator_only_mode || target_only_mode) { if (szFound < 1) { ERR("No device found"); nfc_exit(context); exit(EXIT_FAILURE); } if ((fd3 = fdopen(3, "r")) == NULL) { ERR("Could not open file descriptor 3"); nfc_exit(context); exit(EXIT_FAILURE); } if ((fd4 = fdopen(4, "r")) == NULL) { ERR("Could not open file descriptor 4"); nfc_exit(context); exit(EXIT_FAILURE); } } else { if (szFound < 2) { ERR("%" PRIdPTR " device found but two opened devices are needed to relay NFC.", szFound); nfc_exit(context); exit(EXIT_FAILURE); } } if (!target_only_mode) { // Try to open the NFC reader used as initiator // Little hack to allow using initiator no matter if // there is already a target used locally or not on the same machine: // if there is more than one readers opened we open the second reader // (we hope they're always detected in the same order) if ((szFound == 1) || swap_devices) { pndInitiator = nfc_open(context, connstrings[0]); } else { pndInitiator = nfc_open(context, connstrings[1]); } if (pndInitiator == NULL) { printf("Error opening NFC reader\n"); nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC reader device: %s opened\n", nfc_device_get_name(pndInitiator)); if (nfc_initiator_init(pndInitiator) < 0) { printf("Error: fail initializing initiator\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } // Try to find a ISO 14443-4A tag nfc_modulation nm = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }; if (nfc_initiator_select_passive_target(pndInitiator, nm, NULL, 0, &ntRealTarget) <= 0) { printf("Error: no tag was found\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } printf("Found tag:\n"); print_nfc_target(&ntRealTarget, false); if (initiator_only_mode) { if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen, "UID") < 0) { fprintf(stderr, "Error while printing UID to FD4\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } if (print_hex_fd4(ntRealTarget.nti.nai.abtAtqa, 2, "ATQA") < 0) { fprintf(stderr, "Error while printing ATQA to FD4\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } if (print_hex_fd4(&(ntRealTarget.nti.nai.btSak), 1, "SAK") < 0) { fprintf(stderr, "Error while printing SAK to FD4\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } if (print_hex_fd4(ntRealTarget.nti.nai.abtAts, ntRealTarget.nti.nai.szAtsLen, "ATS") < 0) { fprintf(stderr, "Error while printing ATS to FD4\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } } } if (initiator_only_mode) { printf("Hint: tag <---> *INITIATOR* (relay) <-FD3/FD4-> target (relay) <---> original reader\n\n"); } else if (target_only_mode) { printf("Hint: tag <---> initiator (relay) <-FD3/FD4-> *TARGET* (relay) <---> original reader\n\n"); } else { printf("Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n"); } if (!initiator_only_mode) { nfc_target ntEmulatedTarget = { .nm = { .nmt = NMT_ISO14443A, .nbr = NBR_106, }, }; if (target_only_mode) { size_t foo; if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtUid, &(ntEmulatedTarget.nti.nai.szUidLen), "UID") < 0) { fprintf(stderr, "Error while scanning UID from FD3\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAtqa, &foo, "ATQA") < 0) { fprintf(stderr, "Error while scanning ATQA from FD3\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } if (scan_hex_fd3(&(ntEmulatedTarget.nti.nai.btSak), &foo, "SAK") < 0) { fprintf(stderr, "Error while scanning SAK from FD3\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAts, &(ntEmulatedTarget.nti.nai.szAtsLen), "ATS") < 0) { fprintf(stderr, "Error while scanning ATS from FD3\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } } else { ntEmulatedTarget.nti = ntRealTarget.nti; } // We can only emulate a short UID, so fix length & ATQA bit: ntEmulatedTarget.nti.nai.szUidLen = 4; ntEmulatedTarget.nti.nai.abtAtqa[1] &= (0xFF - 0x40); // First byte of UID is always automatically replaced by 0x08 in this mode anyway ntEmulatedTarget.nti.nai.abtUid[0] = 0x08; // ATS is always automatically replaced by PN532, we've no control on it: // ATS = (05) 75 33 92 03 // (TL) T0 TA TB TC // | | | +-- CID supported, NAD supported // | | +----- FWI=9 SFGI=2 => FWT=154ms, SFGT=1.21ms // | +-------- DR=2,4 DS=2,4 => supports 106, 212 & 424bps in both directions // +----------- TA,TB,TC, FSCI=5 => FSC=64 // It seems hazardous to tell we support NAD if the tag doesn't support NAD but I don't know how to disable it // PC/SC pseudo-ATR = 3B 80 80 01 01 if there is no historical bytes // Creates ATS and copy max 48 bytes of Tk: uint8_t *pbtTk; size_t szTk; pbtTk = iso14443a_locate_historical_bytes(ntEmulatedTarget.nti.nai.abtAts, ntEmulatedTarget.nti.nai.szAtsLen, &szTk); szTk = (szTk > 48) ? 48 : szTk; uint8_t pbtTkt[48]; memcpy(pbtTkt, pbtTk, szTk); ntEmulatedTarget.nti.nai.abtAts[0] = 0x75; ntEmulatedTarget.nti.nai.abtAts[1] = 0x33; ntEmulatedTarget.nti.nai.abtAts[2] = 0x92; ntEmulatedTarget.nti.nai.abtAts[3] = 0x03; ntEmulatedTarget.nti.nai.szAtsLen = 4 + szTk; memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk); printf("We will emulate:\n"); print_nfc_target(&ntEmulatedTarget, false); // Try to open the NFC emulator device if (swap_devices) { pndTarget = nfc_open(context, connstrings[1]); } else { pndTarget = nfc_open(context, connstrings[0]); } if (pndTarget == NULL) { printf("Error opening NFC emulator device\n"); if (!target_only_mode) { nfc_close(pndInitiator); } nfc_exit(context); exit(EXIT_FAILURE); } printf("NFC emulator device: %s opened\n", nfc_device_get_name(pndTarget)); if (nfc_target_init(pndTarget, &ntEmulatedTarget, abtCapdu, sizeof(abtCapdu), 0) < 0) { ERR("%s", "Initialization of NFC emulator failed"); if (!target_only_mode) { nfc_close(pndInitiator); } nfc_close(pndTarget); nfc_exit(context); exit(EXIT_FAILURE); } printf("%s\n", "Done, relaying frames now!"); } while (!quitting) { bool ret; int res = 0; if (!initiator_only_mode) { // Receive external reader command through target if ((res = nfc_target_receive_bytes(pndTarget, abtCapdu, sizeof(abtCapdu), 0)) < 0) { nfc_perror(pndTarget, "nfc_target_receive_bytes"); if (!target_only_mode) { nfc_close(pndInitiator); } nfc_close(pndTarget); nfc_exit(context); exit(EXIT_FAILURE); } szCapduLen = (size_t) res; if (target_only_mode) { if (print_hex_fd4(abtCapdu, szCapduLen, "C-APDU") < 0) { fprintf(stderr, "Error while printing C-APDU to FD4\n"); nfc_close(pndTarget); nfc_exit(context); exit(EXIT_FAILURE); } } } else { if (scan_hex_fd3(abtCapdu, &szCapduLen, "C-APDU") < 0) { fprintf(stderr, "Error while scanning C-APDU from FD3\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } } // Show transmitted response if (!quiet_output) { printf("Forwarding C-APDU: "); print_hex(abtCapdu, szCapduLen); } if (!target_only_mode) { // Forward the frame to the original tag if ((res = nfc_initiator_transceive_bytes(pndInitiator, abtCapdu, szCapduLen, abtRapdu, sizeof(abtRapdu), -1)) < 0) { ret = false; } else { szRapduLen = (size_t) res; ret = true; } } else { if (scan_hex_fd3(abtRapdu, &szRapduLen, "R-APDU") < 0) { fprintf(stderr, "Error while scanning R-APDU from FD3\n"); nfc_close(pndTarget); nfc_exit(context); exit(EXIT_FAILURE); } ret = true; } if (ret) { // Redirect the answer back to the external reader if (waiting_time != 0) { if (!quiet_output) { printf("Waiting %us to simulate longer relay...\n", waiting_time); } sleep(waiting_time); } // Show transmitted response if (!quiet_output) { printf("Forwarding R-APDU: "); print_hex(abtRapdu, szRapduLen); } if (!initiator_only_mode) { // Transmit the response bytes if (nfc_target_send_bytes(pndTarget, abtRapdu, szRapduLen, 0) < 0) { nfc_perror(pndTarget, "nfc_target_send_bytes"); if (!target_only_mode) { nfc_close(pndInitiator); } if (!initiator_only_mode) { nfc_close(pndTarget); } nfc_exit(context); exit(EXIT_FAILURE); } } else { if (print_hex_fd4(abtRapdu, szRapduLen, "R-APDU") < 0) { fprintf(stderr, "Error while printing R-APDU to FD4\n"); nfc_close(pndInitiator); nfc_exit(context); exit(EXIT_FAILURE); } } } } if (!target_only_mode) { nfc_close(pndInitiator); } if (!initiator_only_mode) { nfc_close(pndTarget); } nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-scan-device.1000066400000000000000000000031251230265671100171300ustar00rootroot00000000000000.TH nfc-scan-device 1 "October 21, 2012" "libnfc" "NFC Utilities" .SH NAME nfc-scan-device \- Scan NFC devices .SH SYNOPSIS .B nfc-scan-device [ .I options ] .SH DESCRIPTION .B nfc-scan-device is a utility for listing any available device compliant with libnfc. It can optionnally display device's capabilities. .SH OPTIONS .TP .B \-v Tells .I nfc-scan-device to be verbose and display detailed information about the devices found. .TP .B \-i Tells .I nfc-scan-device to allow intrusive scan (eg. serial ports scan). This is equivalent to set environment variable LIBNFC_INTRUSIVE_SCAN to "yes". .SH EXAMPLE For a SCL3711 device (in verbose mode): - SCM Micro / SCL3711-NFC&RW: pn53x_usb:002:017 chip: PN533 v2.7 initator mode modulations: ISO/IEC 14443A (106 kbps), FeliCa (424 kbps, 212 kbps), ISO/IEC 14443-4B (847 kbps, 424 kbps, 212 kbps, 106 kbps), Innovision Jewel (106 kbps), D.E.P. (424 kbps, 212 kbps, 106 kbps) target mode modulations: ISO/IEC 14443A (106 kbps), FeliCa (424 kbps, 212 kbps), D.E.P. (424 kbps, 212 kbps, 106 kbps) .SH BUGS Please report any bugs on the .B libnfc issue tracker at: .br .BR http://code.google.com/p/libnfc/issues .SH LICENCE .B libnfc is licensed under the GNU Lesser General Public License (LGPL), version 3. .br .B libnfc-utils and .B libnfc-examples are covered by the the BSD 2-Clause license. .SH AUTHORS Roel Verdult , .br Romain Tartière , .br Romuald Conty . .PP This manual page was written by Romuald Conty . It is licensed under the terms of the GNU GPL (version 2 or later). libnfc-1.7.1/utils/nfc-scan-device.c000066400000000000000000000101151230265671100172070ustar00rootroot00000000000000/*- * 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-scan-device.c * @brief Lists each available NFC device */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "nfc-utils.h" #define MAX_DEVICE_COUNT 16 #define MAX_TARGET_COUNT 16 static nfc_device *pnd; static void print_usage(const char *argv[]) { printf("Usage: %s [OPTIONS]\n", argv[0]); printf("Options:\n"); printf("\t-h\tPrint this help message.\n"); printf("\t-v\tSet verbose display.\n"); printf("\t-i\tAllow intrusive scan.\n"); } int main(int argc, const char *argv[]) { const char *acLibnfcVersion; size_t i; bool verbose = false; nfc_context *context; // Get commandline options for (int arg = 1; arg < argc; arg++) { if (0 == strcmp(argv[arg], "-h")) { print_usage(argv); exit(EXIT_SUCCESS); } else if (0 == strcmp(argv[arg], "-v")) { verbose = true; } else if (0 == strcmp(argv[arg], "-i")) { // This has to be done before the call to nfc_init() setenv("LIBNFC_INTRUSIVE_SCAN", "yes", 1); } else { ERR("%s is not supported option.", argv[arg]); print_usage(argv); exit(EXIT_FAILURE); } } nfc_init(&context); if (context == NULL) { ERR("Unable to init libnfc (malloc)\n"); exit(EXIT_FAILURE); } // Display libnfc version acLibnfcVersion = nfc_version(); printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion); nfc_connstring connstrings[MAX_DEVICE_COUNT]; size_t szDeviceFound = nfc_list_devices(context, connstrings, MAX_DEVICE_COUNT); if (szDeviceFound == 0) { printf("No NFC device found.\n"); nfc_exit(context); exit(EXIT_FAILURE); } printf("%d NFC device(s) found:\n", (int)szDeviceFound); char *strinfo = NULL; for (i = 0; i < szDeviceFound; i++) { pnd = nfc_open(context, connstrings[i]); if (pnd != NULL) { printf("- %s:\n %s\n", nfc_device_get_name(pnd), nfc_device_get_connstring(pnd)); if (verbose) { if (nfc_device_get_information_about(pnd, &strinfo) >= 0) { printf("%s", strinfo); nfc_free(strinfo); } } nfc_close(pnd); } else { printf("nfc_open failed for %s\n", connstrings[i]); } } nfc_exit(context); exit(EXIT_SUCCESS); } libnfc-1.7.1/utils/nfc-utils.c000066400000000000000000000075051230265671100161770ustar00rootroot00000000000000/*- * 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-utils.c * @brief Provide some examples shared functions like print, parity calculation, options parsing. */ #include #include #include "nfc-utils.h" uint8_t oddparity(const uint8_t bt) { // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel return (0x9669 >> ((bt ^ (bt >> 4)) & 0xF)) & 1; } void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar) { size_t szByteNr; // Calculate the parity bits for the command for (szByteNr = 0; szByteNr < szLen; szByteNr++) { pbtPar[szByteNr] = oddparity(pbtData[szByteNr]); } } void print_hex(const uint8_t *pbtData, const size_t szBytes) { size_t szPos; for (szPos = 0; szPos < szBytes; szPos++) { printf("%02x ", pbtData[szPos]); } printf("\n"); } void print_hex_bits(const uint8_t *pbtData, const size_t szBits) { uint8_t uRemainder; size_t szPos; size_t szBytes = szBits / 8; for (szPos = 0; szPos < szBytes; szPos++) { printf("%02x ", pbtData[szPos]); } uRemainder = szBits % 8; // Print the rest bits if (uRemainder != 0) { if (uRemainder < 5) printf("%01x (%d bits)", pbtData[szBytes], uRemainder); else printf("%02x (%d bits)", pbtData[szBytes], uRemainder); } printf("\n"); } void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar) { uint8_t uRemainder; size_t szPos; size_t szBytes = szBits / 8; for (szPos = 0; szPos < szBytes; szPos++) { printf("%02x", pbtData[szPos]); if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) { printf("! "); } else { printf(" "); } } uRemainder = szBits % 8; // Print the rest bits, these cannot have parity bit if (uRemainder != 0) { if (uRemainder < 5) printf("%01x (%d bits)", pbtData[szBytes], uRemainder); else printf("%02x (%d bits)", pbtData[szBytes], uRemainder); } printf("\n"); } void print_nfc_target(const nfc_target *pnt, bool verbose) { char *s; str_nfc_target(&s, pnt, verbose); printf("%s", s); nfc_free(s); } libnfc-1.7.1/utils/nfc-utils.h000066400000000000000000000065041230265671100162020ustar00rootroot00000000000000/*- * 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-utils.h * @brief Provide some examples shared functions like print, parity calculation, options parsing. */ #ifndef _EXAMPLES_NFC_UTILS_H_ # define _EXAMPLES_NFC_UTILS_H_ # include # include # include /** * @macro DBG * @brief Print a message of standard output only in DEBUG mode */ #ifdef DEBUG # define DBG(...) do { \ warnx ("DBG %s:%d", __FILE__, __LINE__); \ warnx (" " __VA_ARGS__ ); \ } while (0) #else # define DBG(...) {} #endif /** * @macro WARN * @brief Print a warn message */ #ifdef DEBUG # define WARN(...) do { \ warnx ("WARNING %s:%d", __FILE__, __LINE__); \ warnx (" " __VA_ARGS__ ); \ } while (0) #else # define WARN(...) warnx ("WARNING: " __VA_ARGS__ ) #endif /** * @macro ERR * @brief Print a error message */ #ifdef DEBUG # define ERR(...) do { \ warnx ("ERROR %s:%d", __FILE__, __LINE__); \ warnx (" " __VA_ARGS__ ); \ } while (0) #else # define ERR(...) warnx ("ERROR: " __VA_ARGS__ ) #endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif uint8_t oddparity(const uint8_t bt); void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar); void print_hex(const uint8_t *pbtData, const size_t szLen); void print_hex_bits(const uint8_t *pbtData, const size_t szBits); void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar); void print_nfc_target(const nfc_target *pnt, bool verbose); #endif