Compare commits

..

133 Commits

Author SHA1 Message Date
28ce753431 Document environment variables in README.md 2023-06-23 07:55:29 +00:00
80ef76fdda Fixes error libnfc.driver.acr122_usb Invalid RDR_to_PC_DataBlock frame 2023-05-27 18:12:06 +00:00
Philippe Teuwen
42de50f2b7
Merge pull request #688 from gentilkiwi/master
pn53x initiator set registers for ISO14443B-2 ST SRx
2023-02-13 21:00:49 +01:00
Benjamin DELPY
5b9ae7ee51 pn53x initiator set registers for ISO14443B-2 ST SRx
Modification to set PN53X_REG_CIU_TxAuto, PN53X_REG_CIU_CWGsP & PN53X_REG_CIU_ModGsP registers values before init.
Avoids a dummy scan in B mode before
2023-02-12 19:37:04 +01:00
Romain Tartière
3df7f25f11
Merge pull request #655 from Ujjwal0501/patch-1 2021-09-19 20:28:20 -10:00
Ujjwal Kumar
16671bd0a3
fix: Typo in configuration commands 2021-09-20 11:33:57 +05:30
Romain Tartière
6d0e8a5d9b
Merge pull request #652 from xanderio/fix-freebsd
Fix builds on FreeBSD
2021-08-14 07:25:45 -10:00
Alexander Sieg
a884a45ab1 Fix builds on FreeBSD
Without this patch the cmake config assume that every UNIX system that
is not APPLE is automatically a linux system. This however causes
problems on FreeBSD and properly on other BSD systems.

We now explicitly check if the CMAKE_SYSTEM_NAME is set to Linux.
2021-08-14 12:07:59 +02:00
Philippe Teuwen
c8185c9eca
Merge pull request #639 from rstular/fix-atqa-comparison
Fix - assignment instead of comparison (PCSC driver)
2021-08-05 09:12:47 +02:00
Philippe Teuwen
56f6bd4fbb
Merge pull request #649 from linkclau/master
Include unistd.h (required because of usleep())
2021-08-05 09:12:11 +02:00
Claudius Link
1b8c244e38 Include unistd.h (required because of usleep()) 2021-08-04 23:02:32 +02:00
Philippe Teuwen
fb290be070
Merge pull request #645 from gentilkiwi/master
Add nfc-st25b example
2021-07-10 20:05:43 +02:00
Benjamin DELPY
a9cb26b28f
Fix, lib Win32 again 2021-06-13 22:24:32 +02:00
Benjamin DELPY
c924e5e00c
Fix contrib code for Win32 example 2021-06-13 22:14:52 +02:00
Benjamin DELPY
ba14d10e79
Add utils lib dep 2021-06-13 21:49:05 +02:00
Benjamin DELPY
9a94f20050
Some cast for Windows platform build 2021-06-13 21:19:57 +02:00
Benjamin DELPY
180fbabfe1
Add nfc-st25b example
This new example allows to operate on some ISO-14443-B ST25TB* and legacy SR* cards (read, write, info)
2021-06-13 20:00:52 +02:00
Dave T
1dc9dcb664
Make README.md more helpful for newcommer, remove ref to missing INSTALL (#636) 2021-06-09 14:40:25 +02:00
rstular
1f4d2fb3d4
Fix - assignment instead of comparison (PCSC driver) 2021-05-12 18:23:53 +02:00
Ludovic Rousseau
2b5ad9ce0b
README.md: fix URL of pcsc-lite
The project moved from .alioth.debian.org to .apdu.fr
2021-01-22 13:08:21 +01:00
Philippe Teuwen
7ebf9b92d6
Merge pull request #626 from aviallon/fix-typo-pcsc
Fix typo in variable name in pcsc.c
2020-11-02 13:24:33 +01:00
Antoine Viallon
3af2e14acc
Fix typo in variable name in pcsc.c 2020-11-02 12:30:59 +01:00
Adam Laurie
b5180a6a70
Merge pull request #624 from FeitianSmartcardReader/master
Modify code to add compatibility of readers
2020-10-24 15:28:25 +01:00
Feitian Technologies
0cd314c514
Modify code to add compatibility of readers
Follow the NXP  Contactless card IC rules to be compatible with Feitian new and old R502 reader.
2020-10-20 14:29:15 +08:00
Philippe Teuwen
c3f739dea3
Merge pull request #622 from timgates42/bugfix_typo_mechanism
docs: fix simple typo, mecanism -> mechanism
2020-10-11 16:33:51 +02:00
Tim Gates
126cf9c1be
docs: fix simple typo, mecanism -> mechanism
There is a small typo in contrib/win32/libnfc/buses/uart.c, libnfc/drivers/acr122_usb.c, libnfc/drivers/acr122s.c, libnfc/drivers/arygon.c, libnfc/drivers/pn532_uart.c, libnfc/drivers/pn53x_usb.c.

Should read `mechanism` rather than `mecanism`.
2020-10-11 07:43:16 +11:00
Philippe Teuwen
d9a04a54ff document RC_FILE_TYPE 2020-07-11 15:12:57 +02:00
Philippe Teuwen
cc4311acab
Merge pull request #611 from gelotus/msvc
windows compiling with native tools and clang, macos catalina compiling, added travis ci build tests
2020-07-11 15:12:13 +02:00
Unknown
e37d24e691 Merge branch 'msvc2' into msvc 2020-07-08 13:38:46 +02:00
Unknown
1077228fbd style 2020-07-08 13:26:45 +02:00
Unknown
5c09dc180a forget to add linux clang cmake 2020-07-08 13:24:26 +02:00
Unknown
d5fcd08d41 remove unused packages 2020-07-08 13:14:13 +02:00
Unknown
f56bbabf6c easy reading condition 2020-07-08 13:06:45 +02:00
Unknown
9cece8b55d add cr 2020-07-08 13:06:03 +02:00
Unknown
7ad18a2120 some cleanings 2020-07-07 19:41:07 +02:00
WangYi
e21fab3685 Example and util compile fine. 2020-07-05 00:55:23 +02:00
WangYi
82f23c411d Make it compile under MSVC2017. 2020-07-05 00:54:54 +02:00
Adam Laurie
66d3560608
Merge pull request #609 from gelotus/fix-4k
Fix 4k - [@gelotus]
(we can re-introduce support for other card types later as long as we adhere to the principal that we don't write unless requested to)
2020-07-04 18:20:34 +01:00
Philippe Teuwen
fc51c8662b
Merge pull request #610 from iceman1001/master
chg: make version printing obey verbose flag
2020-07-01 21:48:47 +02:00
iceman1001
db081ed12d chg: make version printing obey verbose flag 2020-07-01 21:28:02 +02:00
Unknown
6fb61d3c1e error handling 2020-06-30 17:19:24 +02:00
Unknown
f2677da74c too many different clone tags, let the user to chose action
too many different clone tags, let the user to chose action
2020-06-30 16:18:47 +02:00
Unknown
0bf4cec661 remove direct write check 2020-06-30 14:52:07 +02:00
Adam Laurie
0de55961c4
Merge pull request #608 from gelotus/nfc-mfclassic
Improve support for gen2 and gen3 tags
thanks @gelotus
2020-06-28 14:20:32 +01:00
Unknown
c8fcaea8ab no need to differentiate routines 2020-06-27 16:17:15 +02:00
Unknown
6921e57fb8 correct typo 2020-06-27 13:33:04 +02:00
Unknown
01bc5693d9 another hardcode value 2020-06-26 19:08:04 +02:00
Unknown
db957aabdf adds write condition check in unlock_card() 2020-06-26 18:29:01 +02:00
Unknown
f7b9b0eafa remove unused stuff for block 0 writing 2020-06-26 13:36:18 +02:00
Unknown
709ef8381f reinit for retrieving new uid after block 0 write 2020-06-26 13:34:50 +02:00
Unknown
3c55b8746b swap 0 block write and other blocks write
when writing to gen2 and possible on gen3, it writes first block 3 wich is the trailing sector before writing to block 0, so the last write to block 0 fails because authenticate to old keyset
2020-06-26 01:50:11 +02:00
Unknown
02f0f6b290 add verbose case
add verbose case
2020-06-26 01:28:57 +02:00
Unknown
7a5e654309 hardcoded values 2020-06-25 23:56:38 +02:00
Unknown
2b21d87e8e add gen2 desc to help
add gen2 desc to help
2020-06-25 23:45:17 +02:00
Unknown
4e922e8194 sends lib log to /dev/null in posix and added option (v) to reactivate
There in an error handling and messaging inside
2020-06-25 23:32:03 +02:00
Unknown
3f4b7a037a add rewrite support for gen2 tags with W command
add rewrite support for gen2 tags with W command
2020-06-25 23:10:06 +02:00
Unknown
dd96571f88 no need to loop, only one block 2020-06-25 19:49:04 +02:00
Unknown
5a87f1f3db Splitting block 0 writing and other block writing, not needed anymore 2020-06-25 19:29:38 +02:00
Adam Laurie
7b6ff73c4b only test DirectWrite write if we need to. only write block 0 if specifically requested to. 2020-06-25 17:45:20 +02:00
Adam Laurie
e560689f60 restore original block count logic and add debuggers for block0 2020-06-25 17:44:20 +02:00
Adam Laurie
a28a537610 partial fix of nfc-mfclassic which only writes first sector of each block and not sector 1,2,3 unles 'unlocked' write - debuggers still in! 2020-06-25 17:43:19 +02:00
Philippe Teuwen
4b7791f845
Merge pull request #605 from ffontaine/master
autotools: make example build optional
2020-06-24 16:18:29 +02:00
Philippe Teuwen
1f6f75af38
Merge pull request #606 from FeitianSmartcardReader/master
Add length check when work with Feitian OEM R502
2020-06-22 11:20:50 +02:00
hongbin@ftsafe.com
435e2ffc81 Add length check to have compatible with R502
improve the code, to have compatible with OEM R502 firmware.
2020-06-22 14:33:15 +08:00
Fabrice Fontaine
874d9605aa autotools: make example build optional
This patch makes example build optional for autotools build system.

In order to keep the former behavior, example build is enabled by default.

Signed-off-by: Samuel Martin <s.martin49@gmail.com>
[Retrieved (and slightly updated to remove CMakeLists.txt) from:
https://git.buildroot.net/buildroot/tree/package/libnfc/0001-build-systems-make-example-build-optional.patch]
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2020-06-21 23:38:44 +02:00
Philippe Teuwen
53eccd4be4
Merge pull request #603 from FeitianSmartcardReader/master
Update pcsc.c
2020-05-27 19:15:22 +02:00
Feitian Technologies
b02f94d7da
Update pcsc.c
1. Fix bug for Mifare card, before do authentication, need to load PIN/password first
2. Fix bug when to get card ATS
2020-05-28 00:54:20 +08:00
Philippe Teuwen
f02ff51449 Prepare 1.8.0 version 2020-05-22 12:20:17 +02:00
Philippe Teuwen
5c3c468a6a Restore nfc_modulation_type order of v1.7.1 2020-05-22 12:20:17 +02:00
Ludovic Rousseau
63cf0acb0b pcsc: remove unused function pcsc_initiator_deselect_target
pcsc.c:763:12: warning: ‘pcsc_initiator_deselect_target’ defined but not used [-Wunused-function]
 static int pcsc_initiator_deselect_target(struct nfc_device *pnd)
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2020-05-22 10:13:52 +02:00
Ludovic Rousseau
5294c0290f Fix compiler warnings: no previous prototype
Local function should be declared static.

Fix:
pcsc.c:107:1: warning: no previous prototype for ‘pcsc_get_scardcontext’ [-Wmissing-prototypes]
 pcsc_get_scardcontext(void)
 ^~~~~~~~~~~~~~~~~~~~~
pcsc.c:119:1: warning: no previous prototype for ‘pcsc_free_scardcontext’ [-Wmissing-prototypes]
 pcsc_free_scardcontext(void)
 ^~~~~~~~~~~~~~~~~~~~~~
pcsc.c:135:5: warning: no previous prototype for ‘pcsc_transmit’ [-Wmissing-prototypes]
 int pcsc_transmit(struct nfc_device *pnd, const uint8_t *tx, const size_t tx_len, uint8_t *rx, size_t *rx_len)
     ^~~~~~~~~~~~~
pcsc.c:160:5: warning: no previous prototype for ‘pcsc_get_status’ [-Wmissing-prototypes]
 int pcsc_get_status(struct nfc_device *pnd, int *target_present, uint8_t *atr, size_t *atr_len)
     ^~~~~~~~~~~~~~~
pcsc.c:178:5: warning: no previous prototype for ‘pcsc_reconnect’ [-Wmissing-prototypes]
 int pcsc_reconnect(struct nfc_device *pnd, DWORD share_mode, DWORD protocol, DWORD disposition)
     ^~~~~~~~~~~~~~
pcsc.c:194:9: warning: no previous prototype for ‘pcsc_get_icc_type’ [-Wmissing-prototypes]
 uint8_t pcsc_get_icc_type(const struct nfc_device *pnd)
         ^~~~~~~~~~~~~~~~~
pcsc.c:203:6: warning: no previous prototype for ‘is_pcsc_reader_vendor’ [-Wmissing-prototypes]
 bool is_pcsc_reader_vendor(const struct nfc_device *pnd, const char *target_vendor_name)
      ^~~~~~~~~~~~~~~~~~~~~
pcsc.c:219:5: warning: no previous prototype for ‘pcsc_get_atqa’ [-Wmissing-prototypes]
 int pcsc_get_atqa(struct nfc_device *pnd, uint8_t *atqa, size_t atqa_len)
     ^~~~~~~~~~~~~
pcsc.c:245:5: warning: no previous prototype for ‘pcsc_get_ats’ [-Wmissing-prototypes]
 int pcsc_get_ats(struct nfc_device *pnd, uint8_t *ats, size_t ats_len)
     ^~~~~~~~~~~~
[...]
2020-05-22 10:11:52 +02:00
Ludovic Rousseau
fa78e8b883 Doxygen: unset DOT_FONTNAME
Fix warning:
warning: doxygen no longer ships with the FreeSans font.
You may want to clear or change DOT_FONTNAME.
Otherwise you run the risk that the wrong font is being used for dot generated graphs.
2020-05-22 10:02:37 +02:00
Ludovic Rousseau
357ae384af Doxygen: update Doxyfile.in to version 1.8.13
Fix warnings:
warning: Tag `SYMBOL_CACHE_SIZE' at line 299 of file `./Doxyfile' has become obsolete.
         To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag `SHOW_DIRECTORIES' at line 487 of file `./Doxyfile' has become obsolete.
         To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag `HTML_ALIGN_MEMBERS' at line 823 of file `./Doxyfile' has become obsolete.
         To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag `USE_INLINE_TREES' at line 976 of file `./Doxyfile' has become obsolete.
         To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag `XML_SCHEMA' at line 1169 of file `./Doxyfile' has become obsolete.
         To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
warning: Tag `XML_DTD' at line 1175 of file `./Doxyfile' has become obsolete.
         To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u"
2020-05-22 09:58:44 +02:00
Ludovic Rousseau
c8692aa239 Fix compiler warning: no previous prototype
nfc-mfclassic.c:623:6: warning: no previous prototype for ‘is_directwrite’ [-Wmissing-prototypes]
 bool is_directwrite(void)
      ^~~~~~~~~~~~~~
2020-05-22 09:51:14 +02:00
Ludovic Rousseau
91d7c5d32f Fix compiler warning: old-style function definition
nfc-mfclassic.c:623:6: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
 bool is_directwrite()
      ^~~~~~~~~~~~~~
nfc-mfclassic.c: In function ‘is_directwrite’:
nfc-mfclassic.c:623:6: warning: old-style function definition [-Wold-style-definition]
2020-05-22 09:50:26 +02:00
Philippe Teuwen
4525cd1c32 make style 2020-05-21 15:06:17 +02:00
Philippe Teuwen
f52d04e0a7 remove warnings 2020-05-21 15:05:48 +02:00
Philippe Teuwen
5a059db901 remove warnings 2020-05-21 14:50:30 +02:00
Philippe Teuwen
730f705c0d pcsc.c: fix error and remove warnings 2020-05-21 14:42:45 +02:00
Philippe Teuwen
6b4f6249bd rework README 2020-05-21 14:27:13 +02:00
Philippe Teuwen
d29b3170d9 update changelog 2020-05-21 14:14:43 +02:00
Adam Laurie
4a2c764961 Prepare 1.7.2 version 2020-05-21 12:05:38 +01:00
Adam Laurie
020f5317a6
Merge pull request #601 from h3xx/fix-typo
Fix typo
2020-05-21 11:40:22 +01:00
Philippe Teuwen
675c30eb93
Merge pull request #600 from FeitianSmartcardReader/master
Modify pcsc.c to have support for Mifare classic and Ultralight card
2020-05-14 12:49:43 +02:00
Feitian Technologies
beb8fdd759
Update pcsc.c
Remove call pcsc_get_vendor_name, get the vendor name from struct nfc_device
2020-05-14 11:08:23 +08:00
Dan Church
6f41ea3ad3
Fix typo
Introduced in #598
2020-05-13 09:05:27 -05:00
hongbin@ftsafe.com
8352c80679 Modify pcsc.c to have support for Mifare classic and Ultralight card
Modify pcsc.c and mifare.c files.
1. add code into pcsc.c to have support Mifare classic card.
2. The PCSC reader has SW value, add response data length for PCSC
reader
2020-05-13 12:15:28 +08:00
Adam Laurie
66176016ed bring nfc-list man page up to date 2020-05-12 16:52:47 +01:00
Adam Laurie
f1bb27d1af
Merge pull request #598 from h3xx/add-check-libnfc-nci
Add check for Libnfc-NCI before enabling pn71xx
thanks @h3xx
2020-05-12 12:36:55 +01:00
Adam Laurie
c884f36b94
Merge pull request #597 from nfc-tools/iclass
Iclass from Adam
2020-05-11 20:23:24 +01:00
Dan Church
17e615e8b1
Add check for Libnfc-NCI before enabling pn71xx
If the user specifically requests the driver, throw an error if it
cannot find libnfc-nci.

Also use the value from pkg-config to determine the library name,
instead of hard-coding it.
2020-05-11 13:45:53 -05:00
Philippe Teuwen
a07d879496 rework NMT_END_ENUM 2020-05-11 20:00:04 +02:00
Philippe Teuwen
10f880374c nfc-list bitfield 2020-05-11 19:55:44 +02:00
Philippe Teuwen
96568a1023 fix nfc-list for types B 2020-05-11 19:46:46 +02:00
Adam Laurie
dcc52cd4d5 updates as per @goedox comments 2020-05-11 18:04:57 +01:00
Adam Laurie
19a51dc2bd first cut iClass support - get nfc-list to see UID 2020-05-11 11:45:28 +01:00
Adam Laurie
61e93c1cdf
Merge pull request #591 from FeitianSmartcardReader/master
Update readme and add Feitian R502 and bR500 support into pcsc driver
2020-05-05 11:27:19 +01:00
hongbin@ftsafe.com
cbc4e7b5c4 Update readme and add Feitian R502 and bR500 support into pcsc driver
1. Modify pcsc.c code, add R502 and bR500 support into PCSC driver
2. Update readme, tell user how to build with pcsc driver
3. Add FAQ for bR500 and R502 in readme
2020-04-09 11:29:11 +08:00
Adam Laurie
692038ceaf
Merge pull request #561 from jpwidera/master
Added check for USB alternate settings
2020-04-05 14:37:22 +01:00
Adam Laurie
f3f588671c
Merge pull request #559 from frankmorgner/pcsc
Added driver for contactless PC/SC readers
(tested as far as it can see my PC/SC readers but could not open - needs debugging!)
2020-04-04 19:11:56 +01:00
Adam Laurie
fbae17186b
Merge branch 'master' into pcsc 2020-04-04 18:35:27 +01:00
Adam Laurie
004eff8e96
Merge pull request #544 from kraj/kraj/musl
usbbus: Include stdint.h for uintX_t
2020-04-04 18:31:26 +01:00
Adam Laurie
7908d405dd
Merge pull request #539 from rstular/patch-2
Updated function declaration in utils/nfc-mfultralight.c
2020-04-04 18:25:39 +01:00
Adam Laurie
ff4e1efa7b
Merge branch 'master' into patch-2 2020-04-04 18:24:40 +01:00
Adam Laurie
c34c446831
Merge pull request #520 from stawiski/master
Fixed format warnings.
2020-04-04 18:16:17 +01:00
Adam Laurie
54ba7359ce
Merge branch 'master' into master 2020-04-04 18:15:56 +01:00
Adam Laurie
fba969472d
Merge pull request #469 from jgeslin/master
Adding pn71xx NXP's NFC Controllers through Linux Libnfc-nci
(note I have only tested this does not break build etc. as I do not have a reader with this chipset)
2020-04-04 18:06:13 +01:00
Adam Laurie
a85f003d91
Merge pull request #451 from hph86/3_verbose_rats_cmd
Add RATS support indicator to nfc-mfclassic
2020-04-04 17:39:46 +01:00
Adam Laurie
8a1e14901d
Merge pull request #590 from AdamLaurie/master
add debugging for high level config requests
2020-04-04 17:18:46 +01:00
Adam Laurie
2a6a8e6e29 add debugging for high level config requests 2020-04-04 15:10:02 +01:00
jpwidera
07f918283b Fixed missing whitespaces 2019-09-05 22:33:33 +02:00
jpwidera
6e035c33f3 Re-enabled claim
If there are alternative interfaces, claim interface 0. Otherwise skip this step.
2019-09-05 22:32:03 +02:00
jpwidera
a77a2a8497 Removed USB alternate setting.
Quick and dirty fix for https://github.com/nfc-tools/libnfc/issues/535
2019-09-05 21:59:46 +02:00
Frank Morgner
6f793da1c1 cleanup 2019-09-03 22:44:44 +02:00
Frank Morgner
8e7a8e1b61 cmake: fixed pcsc requirement for acr122_pcsc 2019-09-03 15:51:38 +02:00
Frank Morgner
959a992a81 added PC/SC driver to cmake 2019-09-03 15:50:28 +02:00
Frank Morgner
75e5e23c81 Added driver for contactless PC/SC readers
- only initiator mode is supported
- properties are choosen as they are available via PC/SC, the rest of
the defaults are chosen to be compatible with Mifare DESFire
- This commit allows reading Mifare DESFire via PC/SC with libfreefare
2019-09-03 14:54:13 +02:00
Philippe Teuwen
f8b28523d7
Merge pull request #554 from quantum-x/master-UL-4K-DirectWrite-OneTimeWrite
Adding extended Magic Card support
2019-08-21 19:22:24 +03:00
quantum-x
ad695d0a18
Update .travis.yml 2019-08-21 10:06:19 +02:00
Philippe Teuwen
454a8c4d70 remove libcutter from travis as it's not available anymore in the repos 2019-08-19 19:48:16 +02:00
quantum-x
fbdbe6eff3
Update nfc-mfclassic.c
Adding support for extended Magic cards:
 - DirectWrite cards
 - One Time Write cards

Direct Write cards support modification of B0 directly, without any unlock codes. When we are attempting to detect if a card is 'magic', we will attempt to modify B0 directly as an initial check.

One Time Write cards support modification of B0 directly, one time only. They do not respond to magic commands, but have a fixed UID coming out of the factory. We now detect this UID, and if so, deem the card 'magic'.
2019-08-19 19:07:18 +02:00
quantum-x
c109d37783
Update nfc-mfultralight.c
Adding support for "DirectWrite" Ultralight tags.
 - The latest generation of "Magic" Ultralight tags support DirectWrite to B0.
 - Several versions of these cards are bricked if the older 'unlock' command is issued to the card.
 - To avoid this, when detecting if a card is magic, we attempt to modify B0 directly. If this fails, we proceed with an unlock command.
2019-08-19 19:04:52 +02:00
Philippe Teuwen
141907e127
Merge pull request #549 from admo/cmake_config_h
Generate config.h into build instead source directory.
2019-07-19 14:38:47 +02:00
Adam Oleksy
48d5f6b666 Generate config.h into build instead source directory. 2019-07-19 14:34:17 +02:00
Philippe Teuwen
a4af2be66c Fix PN533 hardcoded ednpoints table 2019-07-17 22:29:09 +02:00
Khem Raj
91f7db5b4d usbbus: Include stdint.h for uintX_t
stdint.h is needed for uintX_t typedefs which are
used to replace u_intX_t in libusb API headers in the cmake files

Signed-off-by: Khem Raj <raj.khem@gmail.com>
2019-05-20 23:50:49 -07:00
rstular
ebb13d8965
Updated function declaration in utils/nfc-mfultralight.c
Updated a function declaration in utils/nfc-mfultralight.c to match the new style of C function declarations.
2019-04-29 09:49:09 +02:00
rstular
c42e2502d4 Fixed a typo in examples/nfc-emulate-uid.1 2019-04-28 13:25:43 -10:00
Mikolaj Stawiski
793d5adde6 Fixed format warnings. 2018-11-25 13:48:04 +11:00
Hanno Heinrichs
7a0a469c8a add more verbosity to RATS handling 2017-09-17 21:04:33 +02:00
jgeslin
f9f03fa7fa Debug dedicated implementation removed 2017-01-12 09:53:40 +01:00
Jeremy
4a10d0f21b Cosmetics changes 2016-10-10 17:36:55 +02:00
Jeremy
7eae55e929 Adding pn71xx NXP's NFC Controllers through Linux Libnfc-nci 2016-10-06 17:40:48 +02:00
56 changed files with 6041 additions and 1119 deletions

2
.gitignore vendored
View File

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

View File

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

View File

@ -7,8 +7,8 @@ endif ()
project (libnfc C) project (libnfc C)
SET(VERSION_MAJOR "1") SET(VERSION_MAJOR "1")
SET(VERSION_MINOR "7") SET(VERSION_MINOR "8")
SET(VERSION_PATCH "1") SET(VERSION_PATCH "0")
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
@ -18,14 +18,18 @@ SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
# config.h # config.h
IF(WIN32) IF(WIN32)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) SET(LIBNFC_SYSCONFDIR "./config" CACHE PATH "libnfc configuration directory")
SET(LIBNFC_SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/config" CACHE PATH "libnfc configuration directory") CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32)
IF(NOT MINGW)
SET(CMAKE_C_FLAGS "-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE ${CMAKE_C_FLAGS}")
ENDIF(NOT MINGW)
ELSE(WIN32) ELSE(WIN32)
SET(_XOPEN_SOURCE 600) SET(_XOPEN_SOURCE 600)
SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory") SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
ENDIF(WIN32) ENDIF(WIN32)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
ADD_DEFINITIONS("-DHAVE_CONFIG_H") ADD_DEFINITIONS("-DHAVE_CONFIG_H")
@ -137,9 +141,15 @@ IF(NOT WIN32)
IF(LIBNFC_DRIVER_PN53X_USB) IF(LIBNFC_DRIVER_PN53X_USB)
SET(PKG_REQ ${PKG_REQ} "libusb") SET(PKG_REQ ${PKG_REQ} "libusb")
ENDIF(LIBNFC_DRIVER_PN53X_USB) ENDIF(LIBNFC_DRIVER_PN53X_USB)
IF(LIBNFC_DRIVER_ACR122) IF(LIBNFC_DRIVER_ACR122_USB)
SET(PKG_REQ ${PKG_REQ} "libusb")
ENDIF(LIBNFC_DRIVER_ACR122_USB)
IF(LIBNFC_DRIVER_PCSC)
SET(PKG_REQ ${PKG_REQ} "libpcsclite") SET(PKG_REQ ${PKG_REQ} "libpcsclite")
ENDIF(LIBNFC_DRIVER_ACR122) ENDIF(LIBNFC_DRIVER_PCSC)
IF(LIBNFC_DRIVER_ACR122_PCSC)
SET(PKG_REQ ${PKG_REQ} "libpcsclite")
ENDIF(LIBNFC_DRIVER_ACR122_PCSC)
# CMake lists are separated by a semi colon, replace with colon # CMake lists are separated by a semi colon, replace with colon
STRING(REPLACE ";" "," PKG_CONFIG_REQUIRES "${PKG_REQ}") STRING(REPLACE ";" "," PKG_CONFIG_REQUIRES "${PKG_REQ}")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libnfc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libnfc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc @ONLY)
@ -148,7 +158,7 @@ ENDIF(NOT WIN32)
INCLUDE(LibnfcDrivers) INCLUDE(LibnfcDrivers)
IF(UNIX AND NOT APPLE) IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(I2C_REQUIRED) IF(I2C_REQUIRED)
# Inspired from http://cmake.3232098.n2.nabble.com/RFC-cmake-analog-to-AC-SEARCH-LIBS-td7585423.html # Inspired from http://cmake.3232098.n2.nabble.com/RFC-cmake-analog-to-AC-SEARCH-LIBS-td7585423.html
INCLUDE (CheckFunctionExists) INCLUDE (CheckFunctionExists)
@ -162,7 +172,7 @@ IF(UNIX AND NOT APPLE)
ENDIF (HAVE_CLOCK_GETTIME_IN_RT) ENDIF (HAVE_CLOCK_GETTIME_IN_RT)
ENDIF (NOT HAVE_CLOCK_GETTIME) ENDIF (NOT HAVE_CLOCK_GETTIME)
ENDIF(I2C_REQUIRED) ENDIF(I2C_REQUIRED)
ENDIF(UNIX AND NOT APPLE) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(PCSC_INCLUDE_DIRS) IF(PCSC_INCLUDE_DIRS)
INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS})
@ -197,7 +207,8 @@ IF(WIN32)
SET(RC_COMMENT "${PACKAGE_NAME} library") SET(RC_COMMENT "${PACKAGE_NAME} library")
SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}") SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}")
SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll) SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll)
SET(RC_FILE_TYPE VFT_DLL) # RC_FILE_TYPE: VFT_DLL
SET(RC_FILE_TYPE 0x00000002L)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY)
ENDIF(WIN32) ENDIF(WIN32)

View File

@ -1,5 +1,16 @@
TBD - 1.7.x May 22, 2020 - 1.8.0
----------- --------------------
Fixes:
- Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1
Changes:
- Bump revision due to changes in API introduced in v1.7.2
- Bump library version to 6.0.0
May 21, 2020 - 1.7.2 (avoid using it, incompatible with 1.7.1)
--------------------
Fixes: Fixes:
- Remove unreachable code - Remove unreachable code
- nfc_emulate_uid: cleaner exit on interrupt - nfc_emulate_uid: cleaner exit on interrupt
@ -13,6 +24,7 @@ Fixes:
- Fix improper device name initialization - Fix improper device name initialization
- Fix setenv()/unsetenv() for Windows - Fix setenv()/unsetenv() for Windows
- Fix win32/nfc.def according to nfc.h - Fix win32/nfc.def according to nfc.h
- Fix missing timeout in pn53x_initiator_select_passive_target()
- nfc-mfclassic: fix option to tolerate write errors - nfc-mfclassic: fix option to tolerate write errors
- nfc-poll: fix card removing check - nfc-poll: fix card removing check
- nfc-relay-picc: fix wrong open mode for file descriptor - nfc-relay-picc: fix wrong open mode for file descriptor
@ -27,28 +39,37 @@ Improvements:
- Drop PCRE dependency on Windows - Drop PCRE dependency on Windows
- Remove deprecated readdir_r - Remove deprecated readdir_r
- Markdown conversion of the text files - Markdown conversion of the text files
- Use hardcoded PN533 descriptors to be more robust on Windows
- Add support for SCL3712 - Add support for SCL3712
- Add support for ACR1222U-C1 - Add support for ACR1222U-C1
- Add support for NetBSD - Add support for NetBSD
- Add support for PN532 on RPi3 UART - Add support for PN532 on RPi3 UART
- Add support for cross-compilation of 32b & 64b versions of the library for Windows - Add support for cross-compilation of 32b & 64b versions of the library for Windows
- Add pn533_usb to the kernel modules blacklist - Add pn533_usb to the kernel modules blacklist
- Add support for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested)
- Add support for contactless PC/SC readers (only as initiator)
- Add support for Feitian R502 and bR500 into pcsc driver
- Add support for HID iClass (Picopass) support (nfc-iclass tool in external nfc-tools repo)
- Allows for sending empty data in nfc_initiator_transceive_bits - Allows for sending empty data in nfc_initiator_transceive_bits
- driver i2c: respect proper timing specifications - driver i2c: respect proper timing specifications
- driver i2c: add retry on error mechanism - driver i2c: add retry on error mechanism
- nfc-mfclassic: improvements fo magic cards - nfc-mfclassic: improvements fo magic cards
- nfc-mfclassic: add option to specify UID - nfc-mfclassic: add option to specify UID
- nfc-mfclassic/nfc-mfsetuid: add support for new gen (1b) of magic 4K cards - nfc-mfclassic/nfc-mfsetuid: add support for new gen (1b) of magic 4K cards
- nfc-mfclassic: Add RATS support indicator
- nfc-mfsetuid: allow to write complete Block0, instead of only UID - nfc-mfsetuid: allow to write complete Block0, instead of only UID
- nfc-mfultralight: add automatic modes and --check-magic - nfc-mfultralight: add automatic modes and --check-magic
- nfc-mfultralight: add support for magic gen2 cards - nfc-mfultralight: add support for magic gen2 cards
- nfc-mfultralight: add option to specify UID - nfc-mfultralight: add option to specify UID
- nfc-mfultralight: add support for Ultralight NTAG213/215/216
- nfc-barcode: new command to read and decode NFC Barcodes (Tag-Talks-First) - nfc-barcode: new command to read and decode NFC Barcodes (Tag-Talks-First)
Changes: Changes:
- nfc_get_supported_baud_rate() takes now a "mode" parameter - nfc_device_get_supported_baud_rate() takes now a "mode" parameter
- New nfc_get_supported_baud_rate_target_mode() - New nfc_device_get_supported_baud_rate_target_mode()
- New NFC modulation type NMT_BARCODE to support Thinfilm NFC Barcode protocol - New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol
- New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass)
- pn53x_transceive() is now part of public API
Special thanks to: Special thanks to:
- Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus, - Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus,
@ -56,7 +77,9 @@ Special thanks to:
Alexander Inyukhin, Arnaud Kapp, David Kreitschmann, Adam Laurie, Ray Lee, Alexander Inyukhin, Arnaud Kapp, David Kreitschmann, Adam Laurie, Ray Lee,
Maxim Martyanov, Paul Menzel, Boris Moiseev, Yerzhan Mukhamejan, Maxim Martyanov, Paul Menzel, Boris Moiseev, Yerzhan Mukhamejan,
Olliver Shinagl, Jairo Andres Suarez, Mati Vait, Marcos Vives Del Sol, Olliver Shinagl, Jairo Andres Suarez, Mati Vait, Marcos Vives Del Sol,
Hidde Wieringa, Simon Yorkston, timzi, usk-johnny-s, xantares Hidde Wieringa, Simon Yorkston, timzi, usk-johnny-s, xantares, Hanno
Heinrichs, jgeslin, Mikolaj Stawiski, rstular, Khem Raj, Frank Morgner, jpwidera,
Feitian Technologies
Feb 24, 2014 - 1.7.1 Feb 24, 2014 - 1.7.1
-------------------- --------------------

File diff suppressed because it is too large Load Diff

View File

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

18
NEWS.md
View File

@ -1,9 +1,23 @@
New in 1.7.x: New in 1.8.0:
API Changes:
- Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1
- Bump library version to 6.0.0
New in 1.7.2:
Drivers:
* New driver for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested)
* New driver for contactless PC/SC readers (only as initiator)
API Changes: API Changes:
* nfc_device_get_supported_baud_rate() now takes also "mode" as argument * nfc_device_get_supported_baud_rate() now takes also "mode" as argument
* New nfc_get_supported_baud_rate_target_mode() * New nfc_device_get_supported_baud_rate_target_mode()
* New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol
* New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass)
* pn53x_transceive() is now part of public API
New in 1.7.1: New in 1.7.1:

View File

@ -40,17 +40,37 @@ Some NFC drivers depend on third party software:
* acr122_pcsc: * acr122_pcsc:
- pcsc-lite http://pcsclite.alioth.debian.org/ - pcsc-lite https://pcsclite.apdu.fr/
- pcsc:
- Support build with pcsc driver, which can be using all compatible readers, Feitian R502 and bR500 already passed the test.
The regression test suite depends on the cutter framework: The regression test suite depends on the cutter framework:
http://cutter.sf.net http://cutter.sf.net
Building
========
Note: If working directly from a git clone of the repository, some of the files need to be generated first. To do this run
`autoreconf -vis`
Alternatively use a .tar.bz2 version of a packaged release (which already contains ./configure):
https://github.com/nfc-tools/libnfc/releases/
The build should be as simple as running these commands:
./configure
make
To build with specific driver(s), see option `--with-drivers=...` detailed in `./configure --help`.
Installation Installation
============ ============
See the file `INSTALL` for configure, build and install details. make install
Additionnally, you may need to grant permissions to your user to drive your device. You may need to grant permissions to your user to drive your device.
Under GNU/Linux systems, if you use udev, you could use the provided udev rules. Under GNU/Linux systems, if you use udev, you could use the provided udev rules.
e.g. under Debian, Ubuntu, etc. e.g. under Debian, Ubuntu, etc.
@ -82,6 +102,17 @@ file per device in a nfc/devices.d directory:
printf 'name = "My first device"\nconnstring = "pn532_uart:/dev/ttyACM0"\n' | sudo tee /etc/nfc/devices.d/first.conf printf 'name = "My first device"\nconnstring = "pn532_uart:/dev/ttyACM0"\n' | sudo tee /etc/nfc/devices.d/first.conf
printf 'name = "My second device"\nconnstring = "pn532_uart:/dev/ttyACM1"\n' | sudo tee /etc/nfc/devices.d/second.conf printf 'name = "My second device"\nconnstring = "pn532_uart:/dev/ttyACM1"\n' | sudo tee /etc/nfc/devices.d/second.conf
Environment Variables
=====================
You can override certain configuration options at runtime using the following environment variables:
+ `LIBNFC_DEFAULT_DEVICE=<connstring>`: `LIBNFC_DEFAULT_DEVICE=pn532_uart:/dev/ttyACM0` will use pn532 on /dev/ttyACM0 as default device
+ `LIBNFC_DEVICE=<connstring>` will ignore all devices in the config files and use only the one defined in the variable
+ `LIBNFC_AUTO_SCAN=<true|false>` overrides `allow_autoscan` option in the config file
+ `LIBNFC_INTRUSIVE_SCAN=<true|false>` overrides `allow_intrusive_scan` option in the config file
+ `LIBNFC_LOG_LEVEL=<0|1|2|3>` overrides `log_level` option in the config file
To obtain the connstring of a recognized device, you can use `nfc-scan-device`: `LIBNFC_AUTO_SCAN=true nfc-scan-device` will show the names & connstrings of all found devices.
How to report bugs How to report bugs
================== ==================
@ -116,13 +147,17 @@ Please make sure to include:
* How to reproduce the bug. * How to reproduce the bug.
Please include a short test program that exhibits the behavior. Please include a short test program that exhibits the behavior.
As a last resort, you can also provide a pointer to a larger piece As a last resort, you can also provide a pointer to a larger piece
of software that can be downloaded. of software that can be downloaded.
* If the bug was a crash, the exact text that was printed out * If the bug was a crash, the exact text that was printed out
when the crash occured. when the crash occured.
* Further information such as stack traces may be useful, but * Further information such as stack traces may be useful, but
is not necessary. is not necessary.
Patches Patches
@ -133,19 +168,12 @@ Patches can be posted to https://github.com/nfc-tools/libnfc/issues
If the patch fixes a bug, it is usually a good idea to include If the patch fixes a bug, it is usually a good idea to include
all the information described in "How to Report Bugs". all the information described in "How to Report Bugs".
Building
========
It should be as simple as running these two commands:
./configure
make
Troubleshooting Troubleshooting
=============== ===============
Touchatag/ACR122: Touchatag/ACR122:
----------------- -----------------
If your Touchatag or ACR122 device fails being detected by libnfc, make sure If your Touchatag or ACR122 device fails being detected by libnfc, make sure
that PCSC-lite daemon (`pcscd`) is installed and is running. that PCSC-lite daemon (`pcscd`) is installed and is running.
@ -158,6 +186,7 @@ pcscd daemon.
ACR122: ACR122:
------- -------
Using an ACR122 device with libnfc and without tag (e.g. to use NFCIP modes or 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 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 CCID Exchange command. To do this, edit `libccid_Info.plist` configuration file
@ -171,13 +200,16 @@ in something like: `/usr/lib/pcsc/drivers/ifd-acsccid.bundle/Contents/Info.plist
SCL3711: SCL3711:
-------- --------
Libnfc cannot be used concurrently with the PCSC proprietary driver of SCL3711. Libnfc cannot be used concurrently with the PCSC proprietary driver of SCL3711.
Two possible solutions: Two possible solutions:
* Either you don't install SCL3711 driver at all * Either you don't install SCL3711 driver at all
* Or you stop the PCSC daemon when you want to use libnfc-based tools * Or you stop the PCSC daemon when you want to use libnfc-based tools
PN533 USB device on Linux >= 3.1: PN533 USB device on Linux >= 3.1:
--------------------------------- ---------------------------------
Since Linux kernel version 3.1, a few kernel-modules must not be loaded in order Since Linux kernel version 3.1, a few kernel-modules must not be loaded in order
to use libnfc : "nfc", "pn533" and "pn533_usb". to use libnfc : "nfc", "pn533" and "pn533_usb".
To prevent kernel from loading automatically these modules, you can blacklist To prevent kernel from loading automatically these modules, you can blacklist
@ -185,9 +217,33 @@ them in a modprobe conf file. This file is provided within libnfc archive:
sudo cp contrib/linux/blacklist-libnfc.conf /etc/modprobe.d/blacklist-libnfc.conf sudo cp contrib/linux/blacklist-libnfc.conf /etc/modprobe.d/blacklist-libnfc.conf
FEITIAN bR500 and R502:
-----------------------
Libnfc can work with PCSC proprietary driver of bR500 and R502, which is already available on most Linux setups.
To activate the PCSC support: `./configure --with-drivers=pcsc`.
Readers known to work:
- Feitian bR500
- Feitian R502 Dual interface reader
- Feitian R502 CL(Contactless) reader
These readers are support by CCID since v1.4.25, make sure your CCID driver version higher or equal to 1.4.25.
On MacOS, you can check your CCID version with the following command, and if required, you can install latest CCID driver from [https://github.com/martinpaljak/osx-ccid-installer/releases](https://github.com/martinpaljak/osx-ccid-installer/releases)
```
grep -A 1 CFBundleShortVersionString /usr/local/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
```
On Linux, you can check your CCID version with the following command, and if required, you can install latest CCID driver from [https://ccid.apdu.fr/](https://ccid.apdu.fr/)
```
grep -A 1 CFBundleShortVersionString /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist
```
Proprietary Notes Proprietary Notes
================= =================
FeliCa is a registered trademark of the Sony Corporation. FeliCa is a registered trademark of the Sony Corporation.
MIFARE is a trademark of NXP Semiconductors. MIFARE is a trademark of NXP Semiconductors.
Jewel Topaz is a trademark of Innovision Research & Technology. Jewel Topaz is a trademark of Innovision Research & Technology.

View File

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

View File

@ -1,17 +1,24 @@
SET(LIBNFC_DRIVER_PCSC OFF CACHE BOOL "Enable PC/SC reader support (Depends on PC/SC)")
SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on PC/SC)") SET(LIBNFC_DRIVER_ACR122_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_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_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)")
SET(LIBNFC_DRIVER_ARYGON ON CACHE BOOL "Enable ARYGON support (Use serial port)") SET(LIBNFC_DRIVER_ARYGON ON CACHE BOOL "Enable ARYGON support (Use serial port)")
IF(WIN32) IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(LIBNFC_DRIVER_PN532_I2C OFF CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI OFF CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ELSE(WIN32)
SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)") 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)") SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ENDIF(WIN32) ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(LIBNFC_DRIVER_PN532_I2C OFF CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI OFF CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)") SET(LIBNFC_DRIVER_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)") SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)")
IF(LIBNFC_DRIVER_PCSC)
FIND_PACKAGE(PCSC REQUIRED)
ADD_DEFINITIONS("-DDRIVER_PCSC_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pcsc")
ENDIF(LIBNFC_DRIVER_PCSC)
IF(LIBNFC_DRIVER_ACR122_PCSC) IF(LIBNFC_DRIVER_ACR122_PCSC)
FIND_PACKAGE(PCSC REQUIRED) FIND_PACKAGE(PCSC REQUIRED)
ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED") ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED")
@ -61,4 +68,11 @@ IF(LIBNFC_DRIVER_PN53X_USB)
SET(USB_REQUIRED TRUE) SET(USB_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_PN53X_USB) ENDIF(LIBNFC_DRIVER_PN53X_USB)
IF(LIBNFC_DRIVER_ACR122_USB)
FIND_PACKAGE(LIBUSB REQUIRED)
ADD_DEFINITIONS("-DDRIVER_ACR122_USB_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb")
SET(USB_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_ACR122_USB)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers)

View File

@ -1,7 +1,7 @@
# General init # General init
# /!\ Don't forget to update 'CMakeLists.txt' too /!\ # /!\ Don't forget to update 'CMakeLists.txt' too /!\
AC_INIT([libnfc],[1.7.1],[nfc-tools@googlegroups.com]) AC_INIT([libnfc],[1.8.0],[nfc-tools@googlegroups.com])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
@ -47,6 +47,7 @@ AC_HEADER_STDBOOL
AC_CHECK_HEADERS([fcntl.h limits.h stdio.h stdlib.h stdint.h stddef.h stdbool.h sys/ioctl.h sys/param.h sys/time.h termios.h]) AC_CHECK_HEADERS([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/spi/spidev.h], [spi_available="yes"])
AC_CHECK_HEADERS([linux/i2c-dev.h], [i2c_available="yes"]) AC_CHECK_HEADERS([linux/i2c-dev.h], [i2c_available="yes"])
AC_CHECK_HEADERS([linux_nfc_api.h], [nfc_nci_available="yes"])
AC_CHECK_FUNCS([memmove memset select strdup strerror strstr strtol usleep], AC_CHECK_FUNCS([memmove memset select strdup strerror strstr strtol usleep],
[AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])]) [AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])])
@ -130,6 +131,16 @@ then
AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([clock_gettime], [rt])
fi fi
# Enable Libnfc-NCI if required
if test x"$nfc_nci_required" = x"yes"
then
PKG_CHECK_MODULES([LIBNFC_NCI], [libnfc-nci],
[AC_MSG_NOTICE([libnfc-nci present])],
[AC_MSG_ERROR([libnfc-nci not present but required for some drivers configuration])]
)
CFLAGS="$CFLAGS $LIBNFC_NCI_CFLAGS"
fi
# Documentation (default: no) # Documentation (default: no)
AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"]) AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"])
@ -146,6 +157,14 @@ then
fi fi
AM_CONDITIONAL(DOC_ENABLED, [test x"$enable_doc" = xyes]) AM_CONDITIONAL(DOC_ENABLED, [test x"$enable_doc" = xyes])
# Example build (default: yes)
AC_ARG_ENABLE([example],AS_HELP_STRING([--enable-example],[Enable example build.]),[enable_example=$enableval],[enable_example="yes"])
AC_MSG_CHECKING(for example build)
AC_MSG_RESULT($enable_example)
AM_CONDITIONAL(EXAMPLE_ENABLED, [test x"$enable_example" = xyes])
# Dependencies # Dependencies
PKG_CONFIG_REQUIRES="" PKG_CONFIG_REQUIRES=""
@ -164,7 +183,10 @@ if test x$ac_cv_with_cutter = xyes -a x$ac_cv_use_cutter = xno; then
fi fi
AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"]) AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"])
if test x"$enable_example" = "xyes"
then
AC_CHECK_READLINE AC_CHECK_READLINE
fi
# Help us to write great code ;-) # Help us to write great code ;-)
CFLAGS="$CFLAGS -Wall -pedantic -Wextra" CFLAGS="$CFLAGS -Wall -pedantic -Wextra"

870
contrib/win32/dirent.h Normal file
View File

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

106
contrib/win32/getopt.c Normal file
View File

@ -0,0 +1,106 @@
#include "getopt.h" // make sure you construct the header file as dictated above
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int getopt(int nargc, char * const nargv[], const char *ostr)
{
static char *place = EMSG; /* option letter processing */
const char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':')
(void)printf("illegal option -- %c\n", optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)printf("option requires an argument -- %c\n", optopt);
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}

13
contrib/win32/getopt.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ fully customized UID but only of "random" UIDs, which always start with 0x08.
The nfc-emulate-uid tool demonstrates that this can still be done using 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. transmission of raw frames, and the desired UID can be optionally specified.
This makes it a serious thread for security systems that rely only on the This makes it a serious threat for security systems that rely only on the
uniqueness of the UID. uniqueness of the UID.
Unfortunately, this example can't directly start in fully customisable Unfortunately, this example can't directly start in fully customisable

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -101,14 +102,15 @@ main(int argc, const char *argv[])
const uint8_t uiPollNr = 20; const uint8_t uiPollNr = 20;
const uint8_t uiPeriod = 2; const uint8_t uiPeriod = 2;
const nfc_modulation nmModulations[5] = { const nfc_modulation nmModulations[6] = {
{ .nmt = NMT_ISO14443A, .nbr = NBR_106 }, { .nmt = NMT_ISO14443A, .nbr = NBR_106 },
{ .nmt = NMT_ISO14443B, .nbr = NBR_106 }, { .nmt = NMT_ISO14443B, .nbr = NBR_106 },
{ .nmt = NMT_FELICA, .nbr = NBR_212 }, { .nmt = NMT_FELICA, .nbr = NBR_212 },
{ .nmt = NMT_FELICA, .nbr = NBR_424 }, { .nmt = NMT_FELICA, .nbr = NBR_424 },
{ .nmt = NMT_JEWEL, .nbr = NBR_106 }, { .nmt = NMT_JEWEL, .nbr = NBR_106 },
{ .nmt = NMT_ISO14443BICLASS, .nbr = NBR_106 },
}; };
const size_t szModulations = 5; const size_t szModulations = 6;
nfc_target nt; nfc_target nt;
int res = 0; int res = 0;

600
examples/nfc-st25tb.c Normal file
View File

@ -0,0 +1,600 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @file nfc-st25tb.c
* @brief Tool to operate on ISO-14443-B ST25TB* and legacy SR* cards
*/
/* Benjamin DELPY `gentilkiwi`
* https://blog.gentilkiwi.com
* benjamin@gentilkiwi.com
* Licence : https://creativecommons.org/licenses/by/4.0/
* Rely on : libnfc - https://github.com/nfc-tools/libnfc
*
* $ gcc -Wall -lnfc -o nfc-st25tb nfc-st25tb.c
* $ ./nfc-st25tb -h
*
* Tested with
* - ST25TB512-AC - (BE/Brussels/STIB ; AliExpress ones)
* - ST25TB512-AT - (FR/Lille/Ilevia ; FR/Reims/Citura ; FR/Dijon/Divia ; FR/Strasbourg/CTS)
* - SRT512 - legacy - (FR/Bordeaux/TBM)
* - SRI512 - legacy - (anonymous vending machine)
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <nfc/nfc.h>
#if defined(WIN32) /* mingw compiler */
#include <getopt.h>
#endif
#define ST25TB_SR_BLOCK_MAX_SIZE ((uint8_t) 4) // for static arrays
typedef void(*get_info_specific) (uint8_t * systemArea);
typedef struct _st_data {
uint8_t chipId;
bool bIsLegacy;
const char *szName;
const char *szDatasheetUrl;
uint8_t blockSize;
uint8_t nbNormalBlock;
uint8_t bnSystem;
get_info_specific pfnGetInfo;
} st_data;
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
const st_data * get_info(const nfc_target *pnt, bool bPrintIt);
void display_system_info(nfc_device *pnd, const st_data * stdata);
void print_hex(const uint8_t *pbtData, const size_t szBytes);
int main(int argc, char *argv[])
{
nfc_context *context = NULL;
nfc_device *pnd = NULL;
nfc_target nt = {0};
nfc_modulation nm = {NMT_ISO14443B2SR, NBR_106};
const st_data * stcurrent;
int opt, res;
bool bIsBlock = false, bIsRead = false, bIsWrite = false, bIsBadCli = false;
uint8_t i, blockNumber = 0, data[ST25TB_SR_BLOCK_MAX_SIZE] = {0xff, 0xff, 0xff, 0xff}; // just in case...
size_t cbData = 0;
while(!bIsBadCli && ((opt = getopt(argc, argv, ":hib:rw:")) != -1))
{
switch(opt)
{
case 'i':
break;
case 'b':
if(optarg)
{
bIsBlock = true;
blockNumber = strtoul(optarg, NULL, 0);
}
else bIsBadCli = true;
break;
case 'r':
bIsRead = true;
break;
case 'w':
if(optarg)
{
cbData = strlen(optarg);
if((cbData == (2*2)) || ((cbData == (4*2))))
{
cbData >>= 1;
if(cbData == 2) // sr176
{
res = sscanf(optarg, "%02hhx%02hhx", data, data + 1);
}
else // all others
{
res = sscanf(optarg, "%02hhx%02hhx%02hhx%02hhx", data, data + 1, data + 2, data + 3);
}
if(res == (int) cbData)
{
bIsWrite = true;
}
}
if(!bIsWrite)
{
bIsBadCli = true;
}
}
break;
default: // includes -h
bIsBadCli = true;
}
}
if(!bIsBadCli)
{
if(bIsBlock && (bIsRead || bIsWrite))
{
if(bIsRead && bIsWrite)
{
printf("|mode : read then write\n");
}
else if(bIsRead)
{
printf("|mode : read\n");
}
else if(bIsWrite)
{
printf("|mode : write\n");
}
printf("|blk num: 0x%02hhx\n", blockNumber);
if(bIsWrite)
{
printf("|data : ");
print_hex(data, cbData);
printf("\n");
}
}
else if(!bIsRead && !bIsWrite && !bIsBlock)
{
printf("|mode : info\n");
}
else bIsBadCli = true;
}
if(!bIsBadCli)
{
nfc_init(&context);
if(context)
{
pnd = nfc_open(context, NULL);
if(pnd)
{
res = nfc_initiator_init(pnd);
if(res == NFC_SUCCESS)
{
printf("Reader : %s - via %s\n ...wait for card...\n", nfc_device_get_name(pnd), nfc_device_get_connstring(pnd));
if (nfc_initiator_select_passive_target(pnd, nm, NULL, 0, &nt) > 0)
{
stcurrent = get_info(&nt, true);
if(stcurrent)
{
printf("\n");
if(bIsBlock && (bIsRead || bIsWrite))
{
if(bIsRead)
{
get_block_at(pnd, blockNumber, NULL, 0, true);
}
if(bIsWrite)
{
set_block_at_confirmed(pnd, blockNumber, data, cbData, true);
}
}
else if(!bIsRead && !bIsWrite && !bIsBlock)
{
for(i = 0; i < stcurrent->nbNormalBlock; i++)
{
get_block_at(pnd, i, NULL, 0, true);
}
display_system_info(pnd, stcurrent);
}
}
}
}
else printf("ERROR - nfc_initiator_init: %i\n", res);
nfc_close(pnd);
}
else printf("ERROR - nfc_open\n");
nfc_exit(context);
}
else printf("ERROR - nfc_init\n");
}
else
{
printf(
"Usage:\n"
" %s [-i]\n"
" %s -b N -r\n"
" %s -b N [-r] -w ABCD[EF01]\n %s -h\n"
"Options:\n"
" -i (default) information mode - will try to dump the tag content and display informations\n"
" -b N specify block number to operate on (tag dependent), needed for read (-r) and write (-w) modes\n"
" -r read mode - will try to read block (specified with -b N parameter)\n"
" -w ABCD[EF01] write mode - will try to write specicied data (2 or 4 bytes depending on tag) to block (specified with -b N parameter)\n"
" -h this help\n"
"Examples:\n"
" %s -i\n"
" Display all tag informations\n"
" %s -b 0x0e -r\n"
" Read block 0x0e (14) of the tag\n"
" %s -b 0x0d -w 0123abcd\n"
" Write block 0x0d (13) of the tag with hexadecimal value '01 23 ab cd'\n"
" %s -b 0x0c -r -w 0123abcd\n"
" Read, then write block 0x0c (12) of the tag with hexadecimal value '01 23 ab cd'\n"
"Warnings:\n"
" Be careful with: system area, counters & otp, bytes order.\n"
, argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]);
}
return 0;
}
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t tx[2] = {0x08, block}, rx[ST25TB_SR_BLOCK_MAX_SIZE]; // 4 is the maximum, SR176 (only 2) will fit
int res;
res = nfc_initiator_transceive_bytes(pnd, tx, sizeof(tx), rx, sizeof(rx), 0);
if((res == 2) || (res == 4))
{
if(data)
{
if(cbData == res)
{
memcpy(data, rx, res);
bRet = true;
}
else printf("ERROR - We got %i bytes for a %hhu buffer size?\n", res, cbData);
}
else bRet = true;
if(bPrintIt)
{
printf("[0x%02hhx] ", block);
print_hex(rx, res);
printf("\n");
}
}
else if(res > 0)
{
printf("ERROR - We got %i bytes?\n", res);
}
else printf("ERROR - nfc_initiator_transceive_bytes(get): %i\n", res);
return bRet;
}
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t tx[2 + ST25TB_SR_BLOCK_MAX_SIZE] = {0x09, block}; // 4 is the maximum, SR176 (only 2) will fit
int res;
if(cbData <= ST25TB_SR_BLOCK_MAX_SIZE)
{
memcpy(tx + 2, data, cbData);
if(bPrintIt)
{
printf(">0x%02hhx> ", block);
print_hex(data, cbData);
printf("\n");
}
res = nfc_initiator_transceive_bytes(pnd, tx, 2 + cbData, NULL, 0, 0);
if(res == NFC_ERFTRANS) // ? :')
{
bRet = true;
}
else printf("ERROR - nfc_initiator_transceive_bytes(set): %i\n", res);
}
else printf("ERROR - Wanted to write %hhu bytes, but maximum is %hhu\n", cbData, ST25TB_SR_BLOCK_MAX_SIZE);
return bRet;
}
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t buffer[ST25TB_SR_BLOCK_MAX_SIZE]; // maximum size will be checked in set_block_at
if(set_block_at(pnd, block, data, cbData, bPrintIt))
{
if(get_block_at(pnd, block, buffer, cbData, bPrintIt))
{
if(memcmp(data, buffer, cbData) == 0)
{
bRet = true;
}
else if(bPrintIt)
{
printf("WARNING - not same value readed after write\n");
}
}
}
return bRet;
}
void get_info_st25tb512(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | ST reserved : ");
for(i = 0; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
for(i = 16; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 16; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
}
}
}
void get_info_st25tb2k_4k(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | ST reserved : ");
for(i = 0; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_RegU: ", b, b ? "not " : "");
for(i = 16; i < 24; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 24; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
{
printf(" blocks 0x07 and 0x08 are write protected\n");
}
for(i = 25; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
}
}
}
void get_info_sr176_legacy(uint8_t * systemArea)
{
uint8_t i;
printf(" | Fixed Chip_ID: 0x%1x\n | ST reserved : ", systemArea[0] & 0x0f);
for(i = 4; i < 8; i++)
{
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 8; i < 16; i++)
{
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 8; i < 16; i++)
{
if(((*(uint16_t *) systemArea) >> i) & 1)
{
printf(" blocks 0x%02hhx and 0x%02hhx are write protected\n", (uint8_t) ((i - 8) * 2), (uint8_t) (((i - 8) * 2) + 1));
}
}
}
void get_info_sri_srt_512_legacy(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
for(i = 8; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
for(i = 16; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 16; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
}
}
}
void get_info_sri2k_4k_srix4k_srix512_legacy(uint8_t * systemArea)
{
uint8_t i;
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
for(i = 8; i < 24; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 24; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
{
printf(" blocks 0x07 and 0x08 are write protected\n");
}
for(i = 25; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
}
}
}
const st_data STRefs[] = {
{0x1b, false, "ST25TB512-AC", "https://www.st.com/resource/en/datasheet/st25tb512-ac.pdf", 4, 16, 255, get_info_st25tb512},
{0x33, false, "ST25TB512-AT", "https://www.st.com/resource/en/datasheet/st25tb512-at.pdf", 4, 16, 255, get_info_st25tb512},
{0x3f, false, "ST25TB02K", "https://www.st.com/resource/en/datasheet/st25tb02k.pdf", 4, 64, 255, get_info_st25tb2k_4k},
{0x1f, false, "ST25TB04K", "https://www.st.com/resource/en/datasheet/st25tb04k.pdf", 4, 128, 255, get_info_st25tb2k_4k},
};
const st_data STRefs_legacy[] = {
{ 0, true, "SRI4K(s)", NULL, 4, 128, 255, NULL},
{ 2, true, "SR176", "https://www.st.com/resource/en/datasheet/sr176.pdf", 2, 15, 15, get_info_sr176_legacy},
{ 3, true, "SRIX4K", NULL, 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{ 4, true, "SRIX512", "https://www.st.com/resource/en/datasheet/srix512.pdf", 4, 16, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{ 6, true, "SRI512", "https://www.st.com/resource/en/datasheet/sri512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
{ 7, true, "SRI4K", "https://www.st.com/resource/en/datasheet/sri4k.pdf", 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{12, true, "SRT512", "https://www.st.com/resource/en/datasheet/srt512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
{15, true, "SRI2K", "https://www.st.com/resource/en/datasheet/sri2k.pdf", 4, 64, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
};
const st_data * get_info(const nfc_target *pnt, bool bPrintIt)
{
const st_data *currentData = NULL;
const uint8_t *p;
uint8_t chipId, i;
if(pnt->nm.nmt == NMT_ISO14443B2SR)
{
printf("Target : %s (%s)\nUID : ", str_nfc_modulation_type(pnt->nm.nmt), str_nfc_baud_rate(pnt->nm.nbr));
print_hex(pnt->nti.nsi.abtUID, sizeof(pnt->nti.nsi.abtUID));
printf("\n");
p = pnt->nti.nsi.abtUID;
if(p[7] == 0xd0) // ST25TB* / SR*
{
chipId = p[5];
printf("Manuf : 0x%02hhx - %s\n", p[6], (p[6] == 0x02) ? "STMicroelectronics" : "other");
for(i = 0; i < (sizeof(STRefs) / sizeof(STRefs[0])); i++)
{
if(chipId == STRefs[i].chipId)
{
currentData = &STRefs[i];
break;
}
}
if(!currentData)
{
chipId >>= 2;
for(i = 0; i < (sizeof(STRefs_legacy) / sizeof(STRefs_legacy[0])); i++)
{
if(chipId == STRefs_legacy[i].chipId)
{
currentData = &STRefs_legacy[i];
break;
}
}
}
if(bPrintIt && currentData)
{
printf("ChipId : 0x%02hhx - %s%s\nSerial : 0x", currentData->chipId, currentData->szName, currentData->bIsLegacy ? " (legacy)" : "");
if(currentData->bIsLegacy)
{
printf("%1hhx", (uint8_t) (p[5] & 0x03));
}
printf("%02hhx%02hhx%02hhx%02hhx%02hhx\n|blk sz : %hhu bits\n|nb blks: %hhu\n|sys idx: %hhu\n", p[4], p[3], p[2], p[1], p[0], (uint8_t) (currentData->blockSize * 8), currentData->nbNormalBlock, currentData->bnSystem);
}
}
else printf("WARNI - Last byte of UID isn\'t 0xd0, but 0x%02hhx (not ST25TB / SR series?)\n", p[7]);
}
else printf("ERROR - not a NMT_ISO14443B2SR ?\n");
return currentData;
}
void display_system_info(nfc_device *pnd, const st_data * stdata)
{
uint8_t systemArea[ST25TB_SR_BLOCK_MAX_SIZE];
if(get_block_at(pnd, stdata->bnSystem, systemArea, stdata->blockSize, true))
{
if(stdata->pfnGetInfo)
{
stdata->pfnGetInfo(systemArea);
}
}
}
void print_hex(const uint8_t *pbtData, const size_t szBytes)
{
size_t szPos;
for (szPos = 0; szPos < szBytes; szPos++)
{
printf("%02hhx ", pbtData[szPos]);
}
}

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -234,6 +235,14 @@ typedef struct {
uint8_t abtAtr[33]; uint8_t abtAtr[33];
} nfc_iso14443bi_info; } nfc_iso14443bi_info;
/**
* @struct nfc_iso14443biclass_info
* @brief NFC ISO14443BiClass tag information
*/
typedef struct {
uint8_t abtUID[8];
} nfc_iso14443biclass_info;
/** /**
* @struct nfc_iso14443b2sr_info * @struct nfc_iso14443b2sr_info
* @brief NFC ISO14443-2B ST SRx tag information * @brief NFC ISO14443-2B ST SRx tag information
@ -282,8 +291,9 @@ typedef union {
nfc_iso14443b2sr_info nsi; nfc_iso14443b2sr_info nsi;
nfc_iso14443b2ct_info nci; nfc_iso14443b2ct_info nci;
nfc_jewel_info nji; nfc_jewel_info nji;
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
nfc_dep_info ndi; nfc_dep_info ndi;
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
nfc_iso14443biclass_info nhi; // hid iclass / picopass - nii already used
} nfc_target_info; } nfc_target_info;
/** /**
@ -305,13 +315,15 @@ typedef enum {
typedef enum { typedef enum {
NMT_ISO14443A = 1, NMT_ISO14443A = 1,
NMT_JEWEL, NMT_JEWEL,
NMT_BARCODE, // Thinfilm NFC Barcode
NMT_ISO14443B, NMT_ISO14443B,
NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B' NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
NMT_ISO14443B2SR, // ISO14443-2B ST SRx NMT_ISO14443B2SR, // ISO14443-2B ST SRx
NMT_ISO14443B2CT, // ISO14443-2B ASK CTx NMT_ISO14443B2CT, // ISO14443-2B ASK CTx
NMT_FELICA, NMT_FELICA,
NMT_DEP, // DEP should be kept last one as it's used as end-of-enum NMT_DEP,
NMT_BARCODE, // Thinfilm NFC Barcode
NMT_ISO14443BICLASS, // HID iClass 14443B mode
NMT_END_ENUM = NMT_ISO14443BICLASS, // dummy for sizing - always should alias last
} nfc_modulation_type; } nfc_modulation_type;
/** /**

View File

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

View File

@ -22,7 +22,7 @@ libnfc_la_SOURCES = \
nfc-internal.h \ nfc-internal.h \
target-subr.h target-subr.h
libnfc_la_LDFLAGS = -no-undefined -version-info 5:1:0 -export-symbols-regex '^nfc_|^iso14443a_|^iso14443b_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register' libnfc_la_LDFLAGS = -no-undefined -version-info 6:0:0 -export-symbols-regex '^nfc_|^iso14443a_|^iso14443b_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register'
libnfc_la_CFLAGS = @DRIVERS_CFLAGS@ libnfc_la_CFLAGS = @DRIVERS_CFLAGS@
libnfc_la_LIBADD = \ libnfc_la_LIBADD = \
$(top_builddir)/libnfc/chips/libnfcchips.la \ $(top_builddir)/libnfc/chips/libnfcchips.la \

View File

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

View File

@ -35,6 +35,7 @@
#ifndef _WIN32 #ifndef _WIN32
// Under POSIX system, we use libusb (>= 0.1.12) // Under POSIX system, we use libusb (>= 0.1.12)
#include <stdint.h>
#include <usb.h> #include <usb.h>
#define USB_TIMEDOUT ETIMEDOUT #define USB_TIMEDOUT ETIMEDOUT
#define _usb_strerror( X ) strerror(-X) #define _usb_strerror( X ) strerror(-X)

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -85,7 +86,7 @@ pn53x_init(struct nfc_device *pnd)
} }
if (!CHIP_DATA(pnd)->supported_modulation_as_initiator) { if (!CHIP_DATA(pnd)->supported_modulation_as_initiator) {
CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * (NMT_DEP + 1)); CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * (NMT_END_ENUM + 1));
if (! CHIP_DATA(pnd)->supported_modulation_as_initiator) if (! CHIP_DATA(pnd)->supported_modulation_as_initiator)
return NFC_ESOFT; return NFC_ESOFT;
int nbSupportedModulation = 0; int nbSupportedModulation = 0;
@ -104,6 +105,8 @@ pn53x_init(struct nfc_device *pnd)
nbSupportedModulation++; nbSupportedModulation++;
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B2CT; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B2CT;
nbSupportedModulation++; nbSupportedModulation++;
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443BICLASS;
nbSupportedModulation++;
} }
if (CHIP_DATA(pnd)->type != PN531) { if (CHIP_DATA(pnd)->type != PN531) {
CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL; CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL;
@ -575,6 +578,12 @@ pn53x_decode_target_data(const uint8_t *pbtRawData, size_t szRawData, pn53x_type
memcpy(pnti->nsi.abtUID, pbtRawData, 8); memcpy(pnti->nsi.abtUID, pbtRawData, 8);
break; break;
case NMT_ISO14443BICLASS:
// Store the UID
for (uint8_t i = 0 ; i < 8 ; ++i)
pnti->nhi.abtUID[7 - i] = pbtRawData[i];
break;
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
// Store UID LSB // Store UID LSB
memcpy(pnti->nci.abtUID, pbtRawData, 2); memcpy(pnti->nci.abtUID, pbtRawData, 2);
@ -1048,6 +1057,56 @@ pn53x_initiator_init(struct nfc_device *pnd)
return NFC_SUCCESS; return NFC_SUCCESS;
} }
// iclass requires special modulation settings
void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd)
{
// send a bunch of low level commands reverse engineered from a working iClass reader
// original device was using a PN512
//
// // TxModeReg - Defines the data rate and framing during transmission.
//// set bit 4 for target mode? - RxWaitRF Set to logic 1, the counter for RxWait starts only if an external RF field is detected in Target mode for NFCIP-1 or in Card Communication mode
//pn512_write_register(0x12, "\x03", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_TxMode, 0x03);
//
// // RxModeReg - Defines the data rate and framing during reception.
//pn512_write_register(0x13, "\x03", 1, false);
// addy changed to set bit 3 - RxNoErr (put data in fifo before flagging read end)
//pn512_write_register(0x13, "\x0B", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_RxMode, 0x0B);
// ManualRCVReg - Allows manual fine tuning of the internal receiver.
//pn512_write_register(0x1d, "\x10", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_ManualRCV, 0x10);
// RFCfgReg - Configures the receiver gain and RF level detector sensitivity.
//pn512_write_register(0x26, "\x70", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_RFCfg, 0x70);
// GsNOffReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched off.
//pn512_write_register(0x23, "\x88", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOFF, 0x88);
// GsNOnReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched on.
//pn512_write_register(0x27, "\xf8", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOn, 0xf8);
// CWGsPReg - Defines the conductance of the P-driver during times of no modulation.
//pn512_write_register(0x28, "\x3f", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_CWGsP, 0x3f);
// ModGsPReg - Defines the driver P-output conductance during modulation.
//pn512_write_register(0x29, "\x10", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_ModGsP, 0x10);
// TReloadReg (MSB) - Describes the MSB of the 16-bit long timer reload value.
//pn512_write_register(0x2c, "\x69", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_hi, 0x69);
// TReloadReg (LSB) - Describes the LSB of the 16-bit long timer reload value.
//pn512_write_register(0x2d, "\xf0", 1, false);
pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_lo, 0xf0);
}
int int
pn532_initiator_init_secure_element(struct nfc_device *pnd) pn532_initiator_init_secure_element(struct nfc_device *pnd)
{ {
@ -1067,7 +1126,7 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
nfc_target nttmp; nfc_target nttmp;
memset(&nttmp, 0x00, sizeof(nfc_target)); memset(&nttmp, 0x00, sizeof(nfc_target));
if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT) { if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT || nm.nmt == NMT_ISO14443BICLASS) {
if (CHIP_DATA(pnd)->type == RCS360) { 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 // TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select
pnd->last_error = NFC_ENOTIMPL; pnd->last_error = NFC_ENOTIMPL;
@ -1094,6 +1153,16 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
size_t szInitiateLen = 2; size_t szInitiateLen = 2;
uint8_t abtSelect[] = { 0x0e, 0x00 }; uint8_t abtSelect[] = { 0x0e, 0x00 };
uint8_t abtRx[1]; uint8_t abtRx[1];
uint8_t *pbtInitData = (uint8_t *) "\x0b";
size_t szInitData = 1;
if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_TxAuto, 0xef, 0x07)) < 0) // Initial RFOn, Tx2 RFAutoEn, Tx1 RFAutoEn
return res;
if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_CWGsP, 0x3f, 0x3f)) < 0) // Conductance of the P-Driver
return res;
if ((res = pn53x_write_register(pnd, PN53X_REG_CIU_ModGsP, 0x3f, 0x12)) < 0) // Driver P-output conductance for the time of modulation
return res;
// Getting random Chip_ID // Getting random Chip_ID
if ((res = pn53x_initiator_transceive_bytes(pnd, abtInitiate, szInitiateLen, abtRx, sizeof(abtRx), timeout)) < 0) { 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 if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
@ -1106,9 +1175,18 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
return res; return res;
} }
szTargetsData = (size_t)res; szTargetsData = (size_t)res;
if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) {
if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
continue;
} else
return res;
}
szTargetsData = (size_t)res;
} else if (nm.nmt == NMT_ISO14443B2CT) { } else if (nm.nmt == NMT_ISO14443B2CT) {
// Some work to do before getting the UID... // Some work to do before getting the UID...
const uint8_t abtReqt[] = { 0x10 }; const uint8_t abtReqt[] = { 0x10 };
uint8_t *pbtInitData = (uint8_t *) "\x9F\xFF\xFF";
size_t szInitData = 3;
// Getting product code / fab code & store it in output buffer after the serial nr we'll obtain later // 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 = 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 if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
@ -1117,7 +1195,53 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
return res; return res;
} }
szTargetsData = (size_t)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 (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
} else if (nm.nmt == NMT_ISO14443BICLASS) {
pn53x_initiator_init_iclass_modulation(pnd);
//
// Some work to do before getting the UID...
// send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response
uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL
uint8_t abtAnticol[11];
if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all");
//if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
// continue;
//} else
// return res;
}
// do select - returned anticol contains 'handle' for tag if present
abtReqt[0] = 0x0c; // iClass SELECT
abtAnticol[0] = 0x81; // iClass ANTICOL
if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout)) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol");
return res;
}
// write back anticol handle to get UID
if ((res = pn53x_initiator_transceive_bytes(pnd, abtAnticol, 9, abtTargetsData, 10, timeout)) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass get UID");
return res;
}
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "iClass raw UID: %02x %02x %02x %02x %02x %02x %02x %02x", abtTargetsData[0], abtTargetsData[1], abtTargetsData[2], abtTargetsData[3], abtTargetsData[4], abtTargetsData[5], abtTargetsData[6], abtTargetsData[7]);
szTargetsData = 8;
nttmp.nm = nm;
if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) {
return res;
}
} else {
if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { if ((res = 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 if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout
@ -1126,15 +1250,8 @@ pn53x_initiator_select_passive_target_ext(struct nfc_device *pnd,
return res; return res;
} }
szTargetsData = (size_t)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; nttmp.nm = nm;
if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) {
return res; return res;
@ -1955,7 +2072,7 @@ static int pn53x_ISO14443A_Barcode_is_present(struct nfc_device *pnd)
} }
uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
if ((ret = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 1) { if (nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar) < 1) {
failures++; failures++;
} else { } else {
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
@ -2138,6 +2255,29 @@ static int pn53x_ISO14443B_SR_is_present(struct nfc_device *pnd)
return ret; return ret;
} }
static int pn53x_ISO14443B_ICLASS_is_present(struct nfc_device *pnd)
{
int timeout = 300;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B iClass");
pn53x_initiator_init_iclass_modulation(pnd);
//
// Some work to do before getting the UID...
// send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response
uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL
uint8_t abtAnticol[11];
if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all");
}
// do select - returned anticol contains 'handle' for tag if present
abtReqt[0] = 0x0c; // iClass SELECT
abtAnticol[0] = 0x81; // iClass ANTICOL
if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol");
return NFC_ETGRELEASED;;
}
return NFC_SUCCESS;
}
static int pn53x_ISO14443B_CT_is_present(struct nfc_device *pnd) static int pn53x_ISO14443B_CT_is_present(struct nfc_device *pnd)
{ {
int ret; int ret;
@ -2218,6 +2358,9 @@ pn53x_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
ret = pn53x_ISO14443B_CT_is_present(pnd); ret = pn53x_ISO14443B_CT_is_present(pnd);
break; break;
case NMT_ISO14443BICLASS:
ret = pn53x_ISO14443B_ICLASS_is_present(pnd);
break;
} }
if (ret == NFC_ETGRELEASED) if (ret == NFC_ETGRELEASED)
pn53x_current_target_free(pnd); pn53x_current_target_free(pnd);
@ -2268,6 +2411,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_ISO14443BICLASS:
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE: case NMT_BARCODE:
pnd->last_error = NFC_EDEVNOTSUPP; pnd->last_error = NFC_EDEVNOTSUPP;
@ -2370,6 +2514,7 @@ pn53x_target_init(struct nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_ISO14443BICLASS:
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE: case NMT_BARCODE:
pnd->last_error = NFC_EDEVNOTSUPP; pnd->last_error = NFC_EDEVNOTSUPP;
@ -2518,13 +2663,15 @@ pn53x_target_receive_bytes(struct nfc_device *pnd, uint8_t *pbtRx, const size_t
return pnd->last_error; return pnd->last_error;
} }
} }
// NO BREAK abtCmd[0] = TgGetInitiatorCommand;
break;
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE: case NMT_BARCODE:
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_ISO14443BICLASS:
case NMT_FELICA: case NMT_FELICA:
abtCmd[0] = TgGetInitiatorCommand; abtCmd[0] = TgGetInitiatorCommand;
break; break;
@ -2624,13 +2771,15 @@ pn53x_target_send_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size
return pnd->last_error; return pnd->last_error;
} }
} }
// NO BREAK abtCmd[0] = TgResponseToInitiator;
break;
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE: case NMT_BARCODE:
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_ISO14443BICLASS:
case NMT_FELICA: case NMT_FELICA:
abtCmd[0] = TgResponseToInitiator; abtCmd[0] = TgResponseToInitiator;
break; break;
@ -3253,6 +3402,7 @@ pn53x_nm_to_pm(const nfc_modulation nm)
return PM_ISO14443A_106; return PM_ISO14443A_106;
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BICLASS:
switch (nm.nbr) { switch (nm.nbr) {
case NBR_106: case NBR_106:
return PM_ISO14443B_106; return PM_ISO14443B_106;
@ -3351,6 +3501,7 @@ pn53x_nm_to_ptt(const nfc_modulation nm)
// return PTT_ISO14443_4A_106; // return PTT_ISO14443_4A_106;
case NMT_ISO14443B: case NMT_ISO14443B:
case NMT_ISO14443BICLASS:
switch (nm.nbr) { switch (nm.nbr) {
case NBR_106: case NBR_106:
return PTT_ISO14443_4B_106; return PTT_ISO14443_4B_106;
@ -3436,6 +3587,7 @@ pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_mo
case NMT_ISO14443BI: case NMT_ISO14443BI:
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
case NMT_ISO14443BICLASS:
*supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates; *supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates;
break; break;
case NMT_JEWEL: case NMT_JEWEL:

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -322,6 +323,7 @@ int pn53x_idle(struct nfc_device *pnd);
// NFC device as Initiator functions // NFC device as Initiator functions
int pn53x_initiator_init(struct nfc_device *pnd); int pn53x_initiator_init(struct nfc_device *pnd);
void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd);
int pn532_initiator_init_secure_element(struct nfc_device *pnd); int pn532_initiator_init_secure_element(struct nfc_device *pnd);
int pn53x_initiator_select_passive_target(struct nfc_device *pnd, int pn53x_initiator_select_passive_target(struct nfc_device *pnd,
const nfc_modulation nm, const nfc_modulation nm,

View File

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

View File

@ -7,6 +7,10 @@ libnfcdrivers_la_SOURCES =
libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses
libnfcdrivers_la_LIBADD = libnfcdrivers_la_LIBADD =
if DRIVER_PCSC_ENABLED
libnfcdrivers_la_SOURCES += pcsc.c pcsc.h
endif
if DRIVER_ACR122_PCSC_ENABLED if DRIVER_ACR122_PCSC_ENABLED
libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h
endif endif
@ -39,6 +43,11 @@ if DRIVER_PN532_I2C_ENABLED
libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h
endif endif
if DRIVER_PN71XX_ENABLED
libnfcdrivers_la_LIBADD += @LIBNFC_NCI_LIBS@
libnfcdrivers_la_SOURCES += pn71xx.c pn71xx.h
endif
if PCSC_ENABLED if PCSC_ENABLED
libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@ libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@
libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@ libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@

View File

@ -93,7 +93,7 @@ const struct pn53x_io acr122_pcsc_io;
// Prototypes // Prototypes
char *acr122_pcsc_firmware(nfc_device *pnd); char *acr122_pcsc_firmware(nfc_device *pnd);
const char *supported_devices[] = { static const char *supported_devices[] = {
"ACS ACR122", // ACR122U & Touchatag, last version "ACS ACR122", // ACR122U & Touchatag, last version
"ACS ACR 38U-CCID", // Touchatag, early version "ACS ACR 38U-CCID", // Touchatag, early version
"ACS ACR38U-CCID", // Touchatag, early version, under MacOSX "ACS ACR38U-CCID", // Touchatag, early version, under MacOSX

View File

@ -60,7 +60,9 @@ Thanks to d18c7db and Okko for example code
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#ifdef _MSC_VER
#include <sys/types.h>
#endif
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include "nfc-internal.h" #include "nfc-internal.h"
@ -331,7 +333,10 @@ acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const
// acr122_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice)); // 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); 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); usb_close(udev);
snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename); if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) {
// truncation occurred, skipping that one
continue;
}
device_found++; device_found++;
// Test if we reach the maximum "wanted" devices // Test if we reach the maximum "wanted" devices
if (device_found == connstrings_len) { if (device_found == connstrings_len) {
@ -427,6 +432,8 @@ acr122_usb_open(const nfc_context *context, const nfc_connstring connstring)
goto free_mem; goto free_mem;
} }
// Check if there are more than 0 alternative interfaces and claim the first one
if (dev->config->interface->altsetting->bAlternateSetting > 0) {
res = usb_set_altinterface(data.pudh, 0); res = usb_set_altinterface(data.pudh, 0);
if (res < 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)); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set alternate setting on USB interface (%s)", _usb_strerror(res));
@ -434,6 +441,7 @@ acr122_usb_open(const nfc_context *context, const nfc_connstring connstring)
// we failed to use the specified device // we failed to use the specified device
goto free_mem; goto free_mem;
} }
}
// Allocate memory for the device info and specification, fill it and return the info // Allocate memory for the device info and specification, fill it and return the info
pnd = nfc_device_new(context, connstring); pnd = nfc_device_new(context, connstring);
@ -590,7 +598,7 @@ read:
if (timeout == USB_INFINITE_TIMEOUT) { if (timeout == USB_INFINITE_TIMEOUT) {
usb_timeout = USB_TIMEOUT_PER_PASS; usb_timeout = USB_TIMEOUT_PER_PASS;
} else { } else {
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
remaining_time -= USB_TIMEOUT_PER_PASS; remaining_time -= USB_TIMEOUT_PER_PASS;
if (remaining_time <= 0) { if (remaining_time <= 0) {
pnd->last_error = NFC_ETIMEOUT; pnd->last_error = NFC_ETIMEOUT;
@ -604,6 +612,7 @@ read:
uint8_t attempted_response = RDR_to_PC_DataBlock; uint8_t attempted_response = RDR_to_PC_DataBlock;
size_t len; size_t len;
int error, status;
if (res == NFC_ETIMEOUT) { if (res == NFC_ETIMEOUT) {
if (DRIVER_DATA(pnd)->abort_flag) { if (DRIVER_DATA(pnd)->abort_flag) {
@ -615,7 +624,7 @@ read:
goto read; goto read;
} }
} }
if (res < 12) { if (res < 10) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame");
// try to interrupt current device state // try to interrupt current device state
acr122_usb_ack(pnd); acr122_usb_ack(pnd);
@ -630,6 +639,16 @@ read:
offset++; offset++;
len = abtRxBuf[offset++]; len = abtRxBuf[offset++];
status = abtRxBuf[7];
error = abtRxBuf[8];
if (len == 0 && error == 0xFE) { // ICC_MUTE; XXX check for more errors
// Do not check status; my ACR122U seemingly has status=0 in this case,
// even though the spec says it should have had bmCommandStatus=1
// and bmICCStatus=1.
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Command timed out");
pnd->last_error = NFC_ETIMEOUT;
return pnd->last_error;
}
if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer: if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer:
if (len != 2) { if (len != 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply");
@ -658,7 +677,7 @@ read:
goto read; // FIXME May cause some trouble on Touchatag, right ? goto read; // FIXME May cause some trouble on Touchatag, right ?
} }
} }
if (res < 12) { if (res < 10) {
// try to interrupt current device state // try to interrupt current device state
acr122_usb_ack(pnd); acr122_usb_ack(pnd);
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;

View File

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

View File

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

1080
libnfc/drivers/pcsc.c Normal file

File diff suppressed because it is too large Load Diff

35
libnfc/drivers/pcsc.h Normal file
View File

@ -0,0 +1,35 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2019 Frank Morgner
* See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file:
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file pcsc.h
* @brief Driver for non-ACR122 devices (behind PC/SC daemon)
*/
#ifndef __NFC_DRIVER_PCSC_H__
#define __NFC_DRIVER_PCSC_H__
#include <nfc/nfc-types.h>
extern const struct nfc_driver pcsc_driver;
#endif // ! __NFC_DRIVER_PCSC_H__

View File

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

View File

@ -43,7 +43,9 @@ Thanks to d18c7db and Okko for example code
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#ifdef _MSC_VER
#include <sys/types.h>
#endif
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include "nfc-internal.h" #include "nfc-internal.h"
@ -132,13 +134,13 @@ struct pn53x_usb_supported_device {
}; };
const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = { const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = {
{ 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0, 0, 0 }, { 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40 },
{ 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x04, 0x84, 40 }, { 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x84, 0x04, 0x40 },
{ 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x04, 0x84, 40 }, { 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x84, 0x04, 0x40 },
{ 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 }, { 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 }, // to check on real device
{ 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0, 0, 0 }, { 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40 },
{ 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x04, 0x84, 40 }, { 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40 },
{ 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0, 0, 0 } { 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0x84, 0x04, 0x40 }
}; };
// PN533 USB descriptors backup buffers // PN533 USB descriptors backup buffers
@ -337,7 +339,10 @@ pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const s
// pn53x_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice)); // 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); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s", bus->dirname, dev->filename);
usb_close(udev); usb_close(udev);
snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename); if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) {
// truncation occurred, skipping that one
continue;
}
device_found++; device_found++;
// Test if we reach the maximum "wanted" devices // Test if we reach the maximum "wanted" devices
if (device_found == connstrings_len) { if (device_found == connstrings_len) {
@ -421,6 +426,11 @@ pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring)
// Open the USB device // Open the USB device
if ((data.pudh = usb_open(dev)) == NULL) if ((data.pudh = usb_open(dev)) == NULL)
continue; continue;
//To retrieve real USB endpoints configuration:
//pn53x_usb_get_end_points(dev, &data);
//printf("DEBUG ENDPOINTS In:0x%x Out:0x%x Size:0x%x\n", data.uiEndPointIn, data.uiEndPointOut, data.uiMaxPacketSize);
// Retrieve end points, using hardcoded defaults if available // Retrieve end points, using hardcoded defaults if available
// or using the descriptors otherwise. // or using the descriptors otherwise.
if (pn53x_usb_get_end_points_default(dev, &data) == false) { if (pn53x_usb_get_end_points_default(dev, &data) == false) {
@ -613,7 +623,7 @@ read:
if (timeout == USB_INFINITE_TIMEOUT) { if (timeout == USB_INFINITE_TIMEOUT) {
usb_timeout = USB_TIMEOUT_PER_PASS; usb_timeout = USB_TIMEOUT_PER_PASS;
} else { } else {
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
remaining_time -= USB_TIMEOUT_PER_PASS; remaining_time -= USB_TIMEOUT_PER_PASS;
if (remaining_time <= 0) { if (remaining_time <= 0) {
pnd->last_error = NFC_ETIMEOUT; pnd->last_error = NFC_ETIMEOUT;
@ -809,7 +819,7 @@ pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const
if (NP_ACTIVATE_FIELD == property) { if (NP_ACTIVATE_FIELD == property) {
/* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */ /* 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"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Switch progressive field %s", bEnable ? "On" : "Off");
if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31))) < 0) if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0)
return NFC_ECHIP; return NFC_ECHIP;
} }
break; break;

589
libnfc/drivers/pn71xx.c Normal file
View File

@ -0,0 +1,589 @@
/**
* @file pn71xx.h
* @brief Driver for PN71XX using libnfc-nci library
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include "pn71xx.h"
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <nfc/nfc.h>
#include "drivers.h"
#include "nfc-internal.h"
#include "linux_nfc_api.h"
#define PN71XX_DRIVER_NAME "pn71xx"
#define LOG_CATEGORY "libnfc.driver.pn71xx"
#define LOG_GROUP NFC_LOG_GROUP_DRIVER
const nfc_modulation_type pn71xx_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0};
const nfc_modulation_type pn71xx_supported_modulation_as_initiator[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0};
const nfc_baud_rate pn71xx_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn71xx_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 };
const nfc_baud_rate pn71xx_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn71xx_jewel_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn71xx_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
static nfcTagCallback_t TagCB;
static nfc_tag_info_t *TagInfo = NULL;
static void onTagArrival(nfc_tag_info_t *pTagInfo);
static void onTagDeparture(void);
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
/**
* @brief Initialize libnfc_nci library to verify presence of PN71xx device.
*
* @param context NFC context.
* @param connstrings array of 'nfc_connstring' buffer (allocated by caller). It is used to store the
* connection info strings of devices found.
* @param connstrings_len length of the connstrings array.
* @return number of devices found.
*/
static size_t
pn71xx_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
{
size_t device_found = 0;
if ((context == NULL) || (connstrings_len == 0)) return 0;
if (nfcManager_doInitialize() == 0) {
nfc_connstring connstring = "pn71xx";
memcpy(connstrings[device_found++], connstring, sizeof(nfc_connstring));
}
return device_found;
}
/**
* @brief Close connection to PN71xx by stopping the discovery loop and deinitializing the libnfc_nci library.
*
* @param pnd pointer on the device to close.
*/
static void
pn71xx_close(nfc_device *pnd)
{
nfcManager_disableDiscovery();
nfcManager_deregisterTagCallback();
nfcManager_doDeinitialize();
nfc_device_free(pnd);
pnd = NULL;
}
/**
* @brief Open a connection to PN71xx, starting the discovery loop for tag detection.
*
* @param context NFC context.
* @param connstring connection info to the device
* @return pointer to the device, or NULL in case of error.
*/
static nfc_device *
pn71xx_open(const nfc_context *context, const nfc_connstring connstring)
{
nfc_device *pnd;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "open: %s", connstring);
pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
return NULL;
}
pnd->driver = &pn71xx_driver;
strcpy(pnd->name, "pn71xx-device");
strcpy(pnd->connstring, connstring);
TagCB.onTagArrival = onTagArrival;
TagCB.onTagDeparture = onTagDeparture;
nfcManager_registerTagCallback(&TagCB);
nfcManager_enableDiscovery(DEFAULT_NFA_TECH_MASK, 1, 0, 0);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "wait 1 seconds for polling");
sleep(1);
return pnd;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static bool IsTechnology(nfc_tag_info_t *TagInfo, nfc_modulation_type nmt)
{
switch (nmt) {
case NMT_ISO14443A:
if (TagInfo->technology == TARGET_TYPE_ISO14443_4
|| TagInfo->technology == TARGET_TYPE_ISO14443_3A
|| TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC
|| TagInfo->technology == TARGET_TYPE_MIFARE_UL)
return true;
break;
case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT:
if (TagInfo->technology == TARGET_TYPE_ISO14443_3B)
return true;
break;
case NMT_FELICA:
if (TagInfo->technology == TARGET_TYPE_FELICA)
return true;
break;
case NMT_JEWEL:
if (TagInfo->technology == TARGET_TYPE_ISO14443_3A
&& TagInfo->protocol == NFA_PROTOCOL_T1T)
return true;
break;
default:
return false;
}
return false;
}
static void BufferPrintBytes(char *buffer, unsigned int buflen, const uint8_t *data, unsigned int datalen)
{
int cx = 0;
for (unsigned int i = 0x00; i < datalen; i++) {
cx += snprintf(buffer + cx, buflen - cx, "%02X ", data[i]);
}
}
static void PrintTagInfo(nfc_tag_info_t *TagInfo)
{
switch (TagInfo->technology) {
case TARGET_TYPE_UNKNOWN: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Unknown'");
}
break;
case TARGET_TYPE_ISO14443_3A: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3A'");
}
break;
case TARGET_TYPE_ISO14443_3B: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3B'");
}
break;
case TARGET_TYPE_ISO14443_4: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 4A'");
}
break;
case TARGET_TYPE_FELICA: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type F'");
}
break;
case TARGET_TYPE_ISO15693: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type V'");
}
break;
case TARGET_TYPE_NDEF: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type NDEF'");
}
break;
case TARGET_TYPE_NDEF_FORMATABLE: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Formatable'");
}
break;
case TARGET_TYPE_MIFARE_CLASSIC: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Classic'");
}
break;
case TARGET_TYPE_MIFARE_UL: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Ul'");
}
break;
case TARGET_TYPE_KOVIO_BARCODE: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Kovio Barcode'");
}
break;
case TARGET_TYPE_ISO14443_3A_3B: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A/B'");
}
break;
default: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type %d (Unknown or not supported)'\n", TagInfo->technology);
}
break;
}
/*32 is max UID len (Kovio tags)*/
if ((0x00 != TagInfo->uid_length) && (32 >= TagInfo->uid_length)) {
char buffer [100];
int cx = 0;
if (4 == TagInfo->uid_length || 7 == TagInfo->uid_length || 10 == TagInfo->uid_length) {
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID1 : \t'");
} else if (8 == TagInfo->uid_length) {
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID2 : \t'");
} else {
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "UID : \t'");
}
BufferPrintBytes(buffer + cx, sizeof(buffer) - cx, (unsigned char *) TagInfo->uid, TagInfo->uid_length);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s'", buffer);
}
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static void onTagArrival(nfc_tag_info_t *pTagInfo)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag found");
TagInfo = malloc(sizeof(nfc_tag_info_t));
memcpy(TagInfo, pTagInfo, sizeof(nfc_tag_info_t));
PrintTagInfo(TagInfo);
}
static void onTagDeparture(void)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag lost");
free(TagInfo);
TagInfo = NULL;
}
static int
pn71xx_initiator_init(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
return NFC_SUCCESS;
}
static int
pn71xx_initiator_select_passive_target(struct nfc_device *pnd,
const nfc_modulation nm,
const uint8_t *pbtInitData, const size_t szInitData,
nfc_target *pnt)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "select_passive_target");
if (TagInfo) {
nfc_target nttmp;
memset(&nttmp, 0x00, sizeof(nfc_target));
nttmp.nm = nm;
void *uidPtr = NULL;
unsigned int maxLen = 0;
switch (nm.nmt) {
case NMT_ISO14443A:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 10;
uidPtr = nttmp.nti.nai.abtUid;
if (TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC) {
nttmp.nti.nai.btSak = 0x08;
} else {
// make hardcoded desfire for freefare lib check
nttmp.nti.nai.btSak = 0x20;
nttmp.nti.nai.szAtsLen = 5;
memcpy(nttmp.nti.nai.abtAts, "\x75\x77\x81\x02", 4);
}
}
break;
case NMT_ISO14443B:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nbi.abtPupi;
}
break;
case NMT_ISO14443BI:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nii.abtDIV;
}
break;
case NMT_ISO14443B2SR:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 8;
uidPtr = nttmp.nti.nsi.abtUID;
}
break;
case NMT_ISO14443B2CT:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nci.abtUID;
}
break;
case NMT_FELICA:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 8;
uidPtr = nttmp.nti.nfi.abtId;
}
break;
case NMT_JEWEL:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nji.btId;
}
break;
default:
return 0;
}
if (uidPtr && TagInfo->uid_length) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "target found");
int len = TagInfo->uid_length > maxLen ? maxLen : TagInfo->uid_length;
memcpy(uidPtr, TagInfo->uid, len);
if (nm.nmt == NMT_ISO14443A)
nttmp.nti.nai.szUidLen = len;
// Is a tag info struct available
if (pnt) {
memcpy(pnt, &nttmp, sizeof(nfc_target));
}
return 1;
}
}
return 0;
}
static int
pn71xx_initiator_deselect_target(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "deselect_passive_target");
return NFC_SUCCESS;
}
static int
pn71xx_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx,
const size_t szRx, int timeout)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "transceive_bytes timeout=%d", timeout);
if (!TagInfo) return NFC_EINVARG;
char buffer[500];
BufferPrintBytes(buffer, sizeof(buffer), pbtTx, szTx);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "===> %s", buffer);
int received = nfcTag_transceive(TagInfo->handle, (uint8_t *) pbtTx, szTx, pbtRx, szRx, 500);
if (received <= 0)
return NFC_EIO;
BufferPrintBytes(buffer, sizeof(buffer), pbtRx, received);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "<=== %s", buffer);
return received;
}
static int
pn71xx_initiator_poll_target(struct nfc_device *pnd,
const nfc_modulation *pnmModulations, const size_t szModulations,
const uint8_t uiPollNr, const uint8_t uiPeriod,
nfc_target *pnt)
{
static int periodFactor = 150000;
int period = uiPeriod * periodFactor;
if (pnd == NULL) return 0;
for (int j = 0; j < uiPollNr; j++) {
for (unsigned int i = 0; i < szModulations; i++) {
const nfc_modulation nm = pnmModulations[i];
nfc_target nt;
int res = pn71xx_initiator_select_passive_target(pnd, nm, 0, 0, &nt);
if (res > 0 && pnt) {
memcpy(pnt, &nt, sizeof(nfc_target));
return res;
}
}
usleep(period);
}
return 0;
}
static int
pn71xx_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
{
if ((pnd == NULL) || (pnt == NULL)) return 1;
return !TagInfo;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static int
pn71xx_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt)
{
if (pnd == NULL) return NFC_EIO;
switch (mode) {
case N_TARGET:
*supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_target;
break;
case N_INITIATOR:
*supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_initiator;
break;
default:
return NFC_EINVARG;
}
return NFC_SUCCESS;
}
static int
pn71xx_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br)
{
if (pnd == NULL) return NFC_EIO;
if (mode) {}
switch (nmt) {
case NMT_FELICA:
*supported_br = (nfc_baud_rate *)pn71xx_felica_supported_baud_rates;
break;
case NMT_ISO14443A:
*supported_br = (nfc_baud_rate *)pn71xx_iso14443a_supported_baud_rates;
break;
case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT:
*supported_br = (nfc_baud_rate *)pn71xx_iso14443b_supported_baud_rates;
break;
case NMT_JEWEL:
*supported_br = (nfc_baud_rate *)pn71xx_jewel_supported_baud_rates;
break;
case NMT_DEP:
*supported_br = (nfc_baud_rate *)pn71xx_dep_supported_baud_rates;
break;
default:
return NFC_EINVARG;
}
return NFC_SUCCESS;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static int
pn71xx_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable)
{
if (pnd == NULL) return NFC_EIO;
return NFC_SUCCESS;
}
static int
pn71xx_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value)
{
if (pnd == NULL) return NFC_EIO;
return NFC_SUCCESS;
}
static int
pn71xx_get_information_about(nfc_device *pnd, char **pbuf)
{
static const char *info = "PN71XX nfc driver using libnfc-nci userspace library";
size_t buflen = strlen(info) + 1;
if (pnd == NULL) return NFC_EIO;
*pbuf = malloc(buflen);
memcpy(*pbuf, info, buflen);
return buflen;
}
/**
* @brief Abort any pending operation
*
* @param pnd pointer on the NFC device.
* @return NFC_SUCCESS
*/
static int
pn71xx_abort_command(nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "abort_command");
return NFC_SUCCESS;
}
static int
pn71xx_idle(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "idle");
return NFC_SUCCESS;
}
static int
pn71xx_PowerDown(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "PowerDown");
return NFC_SUCCESS;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
const struct nfc_driver pn71xx_driver = {
.name = PN71XX_DRIVER_NAME,
.scan_type = NOT_INTRUSIVE,
.scan = pn71xx_scan,
.open = pn71xx_open,
.close = pn71xx_close,
.strerror = NULL,
.initiator_init = pn71xx_initiator_init,
.initiator_init_secure_element = NULL,
.initiator_select_passive_target = pn71xx_initiator_select_passive_target,
.initiator_poll_target = pn71xx_initiator_poll_target,
.initiator_select_dep_target = NULL,
.initiator_deselect_target = pn71xx_initiator_deselect_target,
.initiator_transceive_bytes = pn71xx_initiator_transceive_bytes,
.initiator_transceive_bits = NULL,
.initiator_transceive_bytes_timed = NULL,
.initiator_transceive_bits_timed = NULL,
.initiator_target_is_present = pn71xx_initiator_target_is_present,
.target_init = NULL,
.target_send_bytes = NULL,
.target_receive_bytes = NULL,
.target_send_bits = NULL,
.target_receive_bits = NULL,
.device_set_property_bool = pn71xx_set_property_bool,
.device_set_property_int = pn71xx_set_property_int,
.get_supported_modulation = pn71xx_get_supported_modulation,
.get_supported_baud_rate = pn71xx_get_supported_baud_rate,
.device_get_information_about = pn71xx_get_information_about,
.abort_command = pn71xx_abort_command,
.idle = pn71xx_idle,
.powerdown = pn71xx_PowerDown,
};

14
libnfc/drivers/pn71xx.h Normal file
View File

@ -0,0 +1,14 @@
/**
* @file pn71xx.h
* @brief Driver for PN71XX using libnfc-nci library
*/
#ifndef __NFC_DRIVER_PN71XX_H__
#define __NFC_DRIVER_PN71XX_H__
#include <nfc/nfc-types.h>
/* Reference to the driver structure */
extern const struct nfc_driver pn71xx_driver;
#endif // ! __NFC_DRIVER_7120_H__

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -169,37 +170,25 @@ void
prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData) prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData)
{ {
switch (nm.nmt) { switch (nm.nmt) {
case NMT_ISO14443B: { case NMT_ISO14443B:
// Application Family Identifier (AFI) must equals 0x00 in order to wakeup all ISO14443-B PICCs (see ISO/IEC 14443-3) // Application Family Identifier (AFI) must equals 0x00 in order to wakeup all ISO14443-B PICCs (see ISO/IEC 14443-3)
*ppbtInitiatorData = (uint8_t *) "\x00"; *ppbtInitiatorData = (uint8_t *) "\x00";
*pszInitiatorData = 1; *pszInitiatorData = 1;
}
break; break;
case NMT_ISO14443BI: { case NMT_ISO14443BI:
// APGEN // APGEN
*ppbtInitiatorData = (uint8_t *) "\x01\x0b\x3f\x80"; *ppbtInitiatorData = (uint8_t *) "\x01\x0b\x3f\x80";
*pszInitiatorData = 4; *pszInitiatorData = 4;
}
break; break;
case NMT_ISO14443B2SR: { case NMT_FELICA:
// 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) // polling payload must be present (see ISO/IEC 18092 11.2.2.5)
*ppbtInitiatorData = (uint8_t *) "\x00\xff\xff\x01\x00"; *ppbtInitiatorData = (uint8_t *) "\x00\xff\xff\x01\x00";
*pszInitiatorData = 5; *pszInitiatorData = 5;
}
break; break;
case NMT_ISO14443A: case NMT_ISO14443A:
case NMT_ISO14443B2CT:
case NMT_ISO14443B2SR:
case NMT_ISO14443BICLASS:
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE: case NMT_BARCODE:
case NMT_DEP: case NMT_DEP:

View File

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

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -87,6 +88,10 @@
#include "target-subr.h" #include "target-subr.h"
#include "drivers.h" #include "drivers.h"
#if defined (DRIVER_PCSC_ENABLED)
# include "drivers/pcsc.h"
#endif /* DRIVER_PCSC_ENABLED */
#if defined (DRIVER_ACR122_PCSC_ENABLED) #if defined (DRIVER_ACR122_PCSC_ENABLED)
# include "drivers/acr122_pcsc.h" # include "drivers/acr122_pcsc.h"
#endif /* DRIVER_ACR122_PCSC_ENABLED */ #endif /* DRIVER_ACR122_PCSC_ENABLED */
@ -119,6 +124,10 @@
# include "drivers/pn532_i2c.h" # include "drivers/pn532_i2c.h"
#endif /* DRIVER_PN532_I2C_ENABLED */ #endif /* DRIVER_PN532_I2C_ENABLED */
#if defined (DRIVER_PN71XX_ENABLED)
# include "drivers/pn71xx.h"
#endif /* DRIVER_PN71XX_ENABLED */
#define LOG_CATEGORY "libnfc.general" #define LOG_CATEGORY "libnfc.general"
#define LOG_GROUP NFC_LOG_GROUP_GENERAL #define LOG_GROUP NFC_LOG_GROUP_GENERAL
@ -130,12 +139,34 @@ struct nfc_driver_list {
const struct nfc_driver_list *nfc_drivers = NULL; const struct nfc_driver_list *nfc_drivers = NULL;
// descritions for debugging
const char *nfc_property_name[] = {
"NP_TIMEOUT_COMMAND",
"NP_TIMEOUT_ATR",
"NP_TIMEOUT_COM",
"NP_HANDLE_CRC",
"NP_HANDLE_PARITY",
"NP_ACTIVATE_FIELD",
"NP_ACTIVATE_CRYPTO1",
"NP_INFINITE_SELECT",
"NP_ACCEPT_INVALID_FRAMES",
"NP_ACCEPT_MULTIPLE_FRAMES",
"NP_AUTO_ISO14443_4",
"NP_EASY_FRAMING",
"NP_FORCE_ISO14443_A",
"NP_FORCE_ISO14443_B",
"NP_FORCE_SPEED_106"
};
static void static void
nfc_drivers_init(void) nfc_drivers_init(void)
{ {
#if defined (DRIVER_PN53X_USB_ENABLED) #if defined (DRIVER_PN53X_USB_ENABLED)
nfc_register_driver(&pn53x_usb_driver); nfc_register_driver(&pn53x_usb_driver);
#endif /* DRIVER_PN53X_USB_ENABLED */ #endif /* DRIVER_PN53X_USB_ENABLED */
#if defined (DRIVER_PCSC_ENABLED)
nfc_register_driver(&pcsc_driver);
#endif /* DRIVER_ACR122_PCSC_ENABLED */
#if defined (DRIVER_ACR122_PCSC_ENABLED) #if defined (DRIVER_ACR122_PCSC_ENABLED)
nfc_register_driver(&acr122_pcsc_driver); nfc_register_driver(&acr122_pcsc_driver);
#endif /* DRIVER_ACR122_PCSC_ENABLED */ #endif /* DRIVER_ACR122_PCSC_ENABLED */
@ -157,6 +188,9 @@ nfc_drivers_init(void)
#if defined (DRIVER_ARYGON_ENABLED) #if defined (DRIVER_ARYGON_ENABLED)
nfc_register_driver(&arygon_driver); nfc_register_driver(&arygon_driver);
#endif /* DRIVER_ARYGON_ENABLED */ #endif /* DRIVER_ARYGON_ENABLED */
#if defined (DRIVER_PN71XX_ENABLED)
nfc_register_driver(&pn71xx_driver);
#endif /* DRIVER_PN71XX_ENABLED */
} }
static int static int
@ -172,8 +206,10 @@ nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_m
int int
nfc_register_driver(const struct nfc_driver *ndr) nfc_register_driver(const struct nfc_driver *ndr)
{ {
if (!ndr) if (!ndr) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_register_driver returning NFC_EINVARG");
return NFC_EINVARG; return NFC_EINVARG;
}
struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list)); struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list));
if (!pndl) if (!pndl)
@ -409,6 +445,7 @@ nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_
int int
nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value) nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value)
{ {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_int %s %s", nfc_property_name[property], value ? "True" : "False");
HAL(device_set_property_int, pnd, property, value); HAL(device_set_property_int, pnd, property, value);
} }
@ -428,6 +465,7 @@ nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const
int int
nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable)
{ {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_bool %s %s", nfc_property_name[property], bEnable ? "True" : "False");
HAL(device_set_property_bool, pnd, property, bEnable); HAL(device_set_property_bool, pnd, property, bEnable);
} }
@ -527,24 +565,30 @@ nfc_initiator_select_passive_target(nfc_device *pnd,
nfc_target *pnt) nfc_target *pnt)
{ {
uint8_t *abtInit = NULL; uint8_t *abtInit = NULL;
uint8_t abtTmpInit[MAX(12, szInitData)]; uint8_t maxAbt = MAX(12, szInitData);
uint8_t *abtTmpInit = malloc(sizeof(uint8_t) * maxAbt);
size_t szInit = 0; size_t szInit = 0;
int res; int res;
if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) {
free(abtTmpInit);
return res; return res;
}
if (szInitData == 0) { if (szInitData == 0) {
// Provide default values, if any // Provide default values, if any
prepare_initiator_data(nm, &abtInit, &szInit); prepare_initiator_data(nm, &abtInit, &szInit);
free(abtTmpInit);
} else if (nm.nmt == NMT_ISO14443A) { } else if (nm.nmt == NMT_ISO14443A) {
abtInit = abtTmpInit; abtInit = abtTmpInit;
iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit); iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit);
} else { } else {
abtInit = abtTmpInit; abtInit = abtTmpInit;
memcpy(abtInit, pbtInitData, szInitData); memcpy(abtInit, pbtInitData, szInitData);
free(abtTmpInit);
szInit = szInitData; szInit = szInitData;
} }
HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt); HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
free(abtTmpInit);
} }
/** @ingroup initiator /** @ingroup initiator
@ -1261,9 +1305,11 @@ nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_m
if (nbr[j] == nm->nbr) if (nbr[j] == nm->nbr)
return NFC_SUCCESS; return NFC_SUCCESS;
} }
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG");
return NFC_EINVARG; return NFC_EINVARG;
} }
} }
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG");
return NFC_EINVARG; return NFC_EINVARG;
} }
@ -1349,6 +1395,8 @@ str_nfc_modulation_type(const nfc_modulation_type nmt)
return "ISO/IEC 14443-4B"; return "ISO/IEC 14443-4B";
case NMT_ISO14443BI: case NMT_ISO14443BI:
return "ISO/IEC 14443-4B'"; return "ISO/IEC 14443-4B'";
case NMT_ISO14443BICLASS:
return "ISO/IEC 14443-2B-3B iClass (Picopass)";
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
return "ISO/IEC 14443-2B ASK CTx"; return "ISO/IEC 14443-2B ASK CTx";
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -503,7 +504,7 @@ snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, b
{ {
(void) verbose; (void) verbose;
int off = 0; int off = 0;
off += snprintf(dst + off, size - off, " Size (bits): %lu\n", pnti->szDataLen * 8); off += snprintf(dst + off, size - off, " Size (bits): %lu\n", (unsigned long)(pnti->szDataLen * 8));
off += snprintf(dst + off, size - off, " Content: "); off += snprintf(dst + off, size - off, " Content: ");
for (uint8_t i = 0; i < pnti->szDataLen; i++) { for (uint8_t i = 0; i < pnti->szDataLen; i++) {
off += snprintf(dst + off, size - off, "%02X", pnti->abtData[i]); off += snprintf(dst + off, size - off, "%02X", pnti->abtData[i]);
@ -609,6 +610,15 @@ snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_inf
snprint_hex(dst + off, size - off, pnsi->abtUID, 8); snprint_hex(dst + off, size - off, pnsi->abtUID, 8);
} }
void
snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose)
{
(void) verbose;
int off = 0;
off += snprintf(dst + off, size - off, " UID: ");
snprint_hex(dst + off, size - off, pnic->abtUID, 8);
}
void void
snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose) snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose)
{ {
@ -668,6 +678,9 @@ snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose)
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
snprint_nfc_iso14443b2sr_info(dst + off, size - off, &pnt->nti.nsi, verbose); snprint_nfc_iso14443b2sr_info(dst + off, size - off, &pnt->nti.nsi, verbose);
break; break;
case NMT_ISO14443BICLASS:
snprint_nfc_iso14443biclass_info(dst + off, size - off, &pnt->nti.nhi, verbose);
break;
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
snprint_nfc_iso14443b2ct_info(dst + off, size - off, &pnt->nti.nci, verbose); snprint_nfc_iso14443b2ct_info(dst + off, size - off, &pnt->nti.nci, verbose);
break; break;

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -37,6 +38,7 @@ void snprint_nfc_iso14443a_info(char *dst, size_t size, const nfc_iso14443a_i
void snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info *pnbi, bool verbose); void snprint_nfc_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_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_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info *pnsi, bool verbose);
void snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose);
void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose); void snprint_nfc_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_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_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose);

View File

@ -4,7 +4,8 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
[ [
AC_MSG_CHECKING(which drivers to build) AC_MSG_CHECKING(which drivers to build)
AC_ARG_WITH(drivers, AC_ARG_WITH(drivers,
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_i2c', 'pn532_spi', 'pn532_uart' and 'pn53x_usb'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]), AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pcsc', 'pn532_i2c', 'pn532_spi', 'pn532_uart', 'pn53x_usb' and 'pn71xx'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]),
[ case "${withval}" in [ case "${withval}" in
yes | no) yes | no)
dnl ignore calls without any arguments dnl ignore calls without any arguments
@ -36,7 +37,8 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
fi fi
;; ;;
all) all)
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart" DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart pcsc"
if test x"$spi_available" = x"yes" if test x"$spi_available" = x"yes"
then then
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi" DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi"
@ -45,11 +47,16 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
then then
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c" DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c"
fi fi
if test x"$nfc_nci_available" = x"yes"
then
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn71xx"
fi
;; ;;
esac esac
DRIVERS_CFLAGS="" DRIVERS_CFLAGS=""
driver_pcsc_enabled="no"
driver_acr122_pcsc_enabled="no" driver_acr122_pcsc_enabled="no"
driver_acr122_usb_enabled="no" driver_acr122_usb_enabled="no"
driver_acr122s_enabled="no" driver_acr122s_enabled="no"
@ -58,10 +65,16 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
driver_pn532_uart_enabled="no" driver_pn532_uart_enabled="no"
driver_pn532_spi_enabled="no" driver_pn532_spi_enabled="no"
driver_pn532_i2c_enabled="no" driver_pn532_i2c_enabled="no"
driver_pn71xx_enabled="no"
for driver in ${DRIVER_BUILD_LIST} for driver in ${DRIVER_BUILD_LIST}
do do
case "${driver}" in case "${driver}" in
pcsc)
pcsc_required="yes"
driver_pcsc_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PCSC_ENABLED"
;;
acr122_pcsc) acr122_pcsc)
pcsc_required="yes" pcsc_required="yes"
driver_acr122_pcsc_enabled="yes" driver_acr122_pcsc_enabled="yes"
@ -102,6 +115,11 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
driver_pn532_i2c_enabled="yes" driver_pn532_i2c_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED"
;; ;;
pn71xx)
nfc_nci_required="yes"
driver_pn71xx_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN71XX_ENABLED"
;;
*) *)
AC_MSG_ERROR([Unknow driver: $driver]) AC_MSG_ERROR([Unknow driver: $driver])
;; ;;
@ -109,6 +127,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
done done
AC_SUBST(DRIVERS_CFLAGS) AC_SUBST(DRIVERS_CFLAGS)
AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_pcsc_enabled" = xyes]) AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_pcsc_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PCSC_ENABLED, [test x"$driver_pcsc_enabled" = xyes])
AM_CONDITIONAL(DRIVER_ACR122_USB_ENABLED, [test x"$driver_acr122_usb_enabled" = xyes]) AM_CONDITIONAL(DRIVER_ACR122_USB_ENABLED, [test x"$driver_acr122_usb_enabled" = xyes])
AM_CONDITIONAL(DRIVER_ACR122S_ENABLED, [test x"$driver_acr122s_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_PN53X_USB_ENABLED, [test x"$driver_pn53x_usb_enabled" = xyes])
@ -116,11 +135,13 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN532_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_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN71XX_ENABLED, [test x"$driver_pn71xx_enabled" = xyes])
]) ])
AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[ AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[
echo echo
echo "Selected drivers:" echo "Selected drivers:"
echo " pcsc............. $driver_pcsc_enabled"
echo " acr122_pcsc...... $driver_acr122_pcsc_enabled" echo " acr122_pcsc...... $driver_acr122_pcsc_enabled"
echo " acr122_usb....... $driver_acr122_usb_enabled" echo " acr122_usb....... $driver_acr122_usb_enabled"
echo " acr122s.......... $driver_acr122s_enabled" echo " acr122s.......... $driver_acr122s_enabled"
@ -129,4 +150,5 @@ echo " pn53x_usb........ $driver_pn53x_usb_enabled"
echo " pn532_uart....... $driver_pn532_uart_enabled" echo " pn532_uart....... $driver_pn532_uart_enabled"
echo " pn532_spi....... $driver_pn532_spi_enabled" echo " pn532_spi....... $driver_pn532_spi_enabled"
echo " pn532_i2c........ $driver_pn532_i2c_enabled" echo " pn532_i2c........ $driver_pn532_i2c_enabled"
echo " pn71xx........... $driver_pn71xx_enabled"
]) ])

View File

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

View File

@ -130,7 +130,9 @@ nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8
// When we have executed a read command, copy the received bytes into the param // When we have executed a read command, copy the received bytes into the param
if (mc == MC_READ) { if (mc == MC_READ) {
if (res == 16) {
//Check the length of response data, with PCSC reader, there have 2 bytes for SW value
if (res == 16 || res == (16 + 2)) {
memcpy(pmp->mpd.abtData, abtRx, 16); memcpy(pmp->mpd.abtData, abtRx, 16);
} else { } else {
return false; return false;

View File

@ -27,6 +27,7 @@ This includes SAK decoding and fingerprinting is available.
.TP .TP
\fB-t\fP \fIX\fP \fB-t\fP \fIX\fP
Polls only for types according to bitfield value of \fIX\fP: Polls only for types according to bitfield value of \fIX\fP:
1: ISO14443A 1: ISO14443A
2: Felica (212 kbps) 2: Felica (212 kbps)
4: Felica (424 kbps) 4: Felica (424 kbps)
@ -34,11 +35,12 @@ Polls only for types according to bitfield value of \fIX\fP:
16: ISO14443B' 16: ISO14443B'
32: ISO14443B-2 ST SRx 32: ISO14443B-2 ST SRx
64: ISO14443B-2 ASK CTx 64: ISO14443B-2 ASK CTx
128: Jewel 128: ISO14443B iClass
256: ISO14443A-3 Jewel
512: ISO14443A-2 NFC Barcode
So 255 (default) polls for all types. So 1023 (default) polls for all types.
Note that if 16, 32, 64 or 128 then 8 is selected too.
Note that if 16, 32 or 64 then 8 is selected too.
.SH EXAMPLE .SH EXAMPLE
For an ISO/IEC 14443-A tag (i.e.Mifare DESFire): For an ISO/IEC 14443-A tag (i.e.Mifare DESFire):

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -71,10 +72,11 @@ print_usage(const char *progname)
printf("\t 16: ISO14443B'\n"); printf("\t 16: ISO14443B'\n");
printf("\t 32: ISO14443B-2 ST SRx\n"); printf("\t 32: ISO14443B-2 ST SRx\n");
printf("\t 64: ISO14443B-2 ASK CTx\n"); printf("\t 64: ISO14443B-2 ASK CTx\n");
printf("\t 128: ISO14443A-3 Jewel\n"); printf("\t 128: ISO14443B iClass\n");
printf("\t 256: ISO14443A-2 NFC Barcode\n"); printf("\t 256: ISO14443A-3 Jewel\n");
printf("\tSo 511 (default) polls for all types.\n"); printf("\t 512: ISO14443A-2 NFC Barcode\n");
printf("\tNote that if 16, 32 or 64 then 8 is selected too.\n"); printf("\tSo 1023 (default) polls for all types.\n");
printf("\tNote that if 16, 32, 64 or 128 then 8 is selected too.\n");
} }
int int
@ -85,7 +87,7 @@ main(int argc, const char *argv[])
size_t i; size_t i;
bool verbose = false; bool verbose = false;
int res = 0; int res = 0;
int mask = 0x1ff; int mask = 0x3ff;
int arg; int arg;
nfc_context *context; nfc_context *context;
@ -95,10 +97,6 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Display libnfc version
acLibnfcVersion = nfc_version();
printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
// Get commandline options // Get commandline options
for (arg = 1; arg < argc; arg++) { for (arg = 1; arg < argc; arg++) {
if (0 == strcmp(argv[arg], "-h")) { if (0 == strcmp(argv[arg], "-h")) {
@ -109,13 +107,13 @@ main(int argc, const char *argv[])
} else if ((0 == strcmp(argv[arg], "-t")) && (arg + 1 < argc)) { } else if ((0 == strcmp(argv[arg], "-t")) && (arg + 1 < argc)) {
arg++; arg++;
mask = atoi(argv[arg]); mask = atoi(argv[arg]);
if ((mask < 1) || (mask > 0x1ff)) { if ((mask < 1) || (mask > 0x3ff)) {
ERR("%i is invalid value for type bitfield.", mask); ERR("%i is invalid value for type bitfield.", mask);
print_usage(argv[0]); print_usage(argv[0]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Force TypeB for all derivatives of B // Force TypeB for all derivatives of B
if (mask & 0x70) if (mask & 0xd0)
mask |= 0x08; mask |= 0x08;
} else { } else {
ERR("%s is not supported option.", argv[arg]); ERR("%s is not supported option.", argv[arg]);
@ -124,6 +122,13 @@ main(int argc, const char *argv[])
} }
} }
// Display libnfc version
if (verbose) {
acLibnfcVersion = nfc_version();
printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
}
/* Lazy way to open an NFC device */ /* Lazy way to open an NFC device */
#if 0 #if 0
pnd = nfc_open(context, NULL); pnd = nfc_open(context, NULL);
@ -272,6 +277,22 @@ main(int argc, const char *argv[])
} }
if (mask & 0x80) { if (mask & 0x80) {
nm.nmt = NMT_ISO14443BICLASS;
nm.nbr = NBR_106;
// List ISO14443B iClass targets
if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) {
int n;
if (verbose || (res > 0)) {
printf("%d ISO14443B iClass passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
}
for (n = 0; n < res; n++) {
print_nfc_target(&ant[n], verbose);
printf("\n");
}
}
}
if (mask & 0x100) {
nm.nmt = NMT_JEWEL; nm.nmt = NMT_JEWEL;
nm.nbr = NBR_106; nm.nbr = NBR_106;
// List Jewel targets // List Jewel targets
@ -287,7 +308,7 @@ main(int argc, const char *argv[])
} }
} }
if (mask & 0x100) { if (mask & 0x200) {
nm.nmt = NMT_BARCODE; nm.nmt = NMT_BARCODE;
nm.nbr = NBR_106; nm.nbr = NBR_106;
// List NFC Barcode targets // List NFC Barcode targets
@ -302,6 +323,7 @@ main(int argc, const char *argv[])
} }
} }
} }
nfc_close(pnd); nfc_close(pnd);
} }

View File

@ -10,6 +10,7 @@
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2011-2013 Adam Laurie * Copyright (C) 2011-2013 Adam Laurie
* Copyright (C) 2018-2019 Danielle Bruneo
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -53,6 +54,12 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#ifndef _WIN32
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include "mifare.h" #include "mifare.h"
@ -69,7 +76,7 @@ static bool bUseKeyFile;
static bool bForceKeyFile; static bool bForceKeyFile;
static bool bTolerateFailures; static bool bTolerateFailures;
static bool bFormatCard; static bool bFormatCard;
static bool magic2 = false; static bool dWrite = false;
static bool unlocked = false; static bool unlocked = false;
static uint8_t uiBlocks; static uint8_t uiBlocks;
static uint8_t keys[] = { static uint8_t keys[] = {
@ -208,10 +215,9 @@ authenticate(uint32_t uiBlock)
// Try to authenticate for the current sector // Try to authenticate for the current sector
if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp))
return true; return true;
}
// If formatting or not using key file, try to guess the right key // If formatting or not using key file, try to guess the right key
if (bFormatCard || !bUseKeyFile) { } else if (bFormatCard || !bUseKeyFile) {
for (size_t key_index = 0; key_index < num_keys; key_index++) { for (size_t key_index = 0; key_index < num_keys; key_index++) {
memcpy(mp.mpa.abtKey, keys + (key_index * 6), 6); memcpy(mp.mpa.abtKey, keys + (key_index * 6), 6);
if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) { if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) {
@ -232,7 +238,7 @@ authenticate(uint32_t uiBlock)
} }
static bool static bool
unlock_card(void) unlock_card(bool write)
{ {
// Configure the CRC // Configure the CRC
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) {
@ -250,6 +256,10 @@ unlock_card(void)
// now send unlock // now send unlock
if (!transmit_bits(abtUnlock1, 7)) { if (!transmit_bits(abtUnlock1, 7)) {
printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n"); printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n");
dWrite = true;
if (write) {
printf("Trying to rewrite block 0 on a direct write tag.\n");
}
} else { } else {
if (transmit_bytes(abtUnlock2, 1)) { if (transmit_bytes(abtUnlock2, 1)) {
printf("Card unlocked\n"); printf("Card unlocked\n");
@ -260,6 +270,15 @@ unlock_card(void)
} }
// reset reader // reset reader
if (!unlocked) {
if (nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL) <= 0) {
printf("Error: tag was removed\n");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
return true;
}
// Configure the CRC // Configure the CRC
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) { if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_perror(pnd, "nfc_device_set_property_bool");
@ -306,23 +325,19 @@ get_rats(void)
} }
static bool static bool
read_card(int read_unlocked) read_card(bool read_unlocked)
{ {
int32_t iBlock; int32_t iBlock;
bool bFailure = false; bool bFailure = false;
uint32_t uiReadBlocks = 0; uint32_t uiReadBlocks = 0;
if (read_unlocked) { if (read_unlocked) {
unlock_card(false);
//If the user is attempting an unlocked read, but has a direct-write type magic card, they don't //If the user is attempting an unlocked read, but has a direct-write type magic card, they don't
//need to use the R mode. We'll trigger a warning and let them proceed. //need to use the R mode. We'll trigger a warning and let them proceed.
if (magic2) { if (dWrite) {
printf("Note: This card does not require an unlocked read (R) \n"); printf("Note: This card can't do an unlocked read (R) \n");
read_unlocked = 0; read_unlocked = 0;
} else {
//If User has requested an unlocked read, but we're unable to unlock the card, we'll error out.
if (!unlock_card()) {
return false;
}
} }
} }
@ -386,31 +401,26 @@ read_card(int read_unlocked)
} }
static bool static bool
write_card(int write_block_zero) write_card(bool write_block_zero)
{ {
uint32_t uiBlock; uint32_t uiBlock;
bool bFailure = false; bool bFailure = false;
uint32_t uiWriteBlocks = 0; uint32_t uiWriteBlocks = 0;
//Determine if we have to unlock the card
if (write_block_zero) { if (write_block_zero) {
//If the user is attempting an unlocked write, but has a direct-write type magic card, they don't unlock_card(true);
//need to use the W mode. We'll trigger a warning and let them proceed.
if (magic2) {
printf("Note: This card does not require an unlocked write (W) \n");
write_block_zero = 0;
} else {
//If User has requested an unlocked write, but we're unable to unlock the card, we'll error out.
if (!unlock_card()) {
return false;
}
}
} }
printf("Writing %d blocks |", uiBlocks + 1); printf("Writing %d blocks |", uiBlocks + write_block_zero);
// Write the card from begin to end; // Completely write the card, but skipping block 0 if we don't need to write on it
for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
//Determine if we have to write block 0
if (!write_block_zero && uiBlock == 0) {
continue;
}
// Authenticate everytime we reach the first sector of a new block // Authenticate everytime we reach the first sector of a new block
if (is_first_block(uiBlock)) { if (uiBlock == 1 || is_first_block(uiBlock)) {
if (bFailure) { if (bFailure) {
// When a failure occured we need to redo the anti-collision // When a failure occured we need to redo the anti-collision
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
@ -423,11 +433,16 @@ write_card(int write_block_zero)
fflush(stdout); fflush(stdout);
// Try to authenticate for the current sector // Try to authenticate for the current sector
if (!write_block_zero && !authenticate(uiBlock) && !bTolerateFailures) { // If we are are writing to a chinese magic card, we've already unlocked
// If we're writing to a direct write card, we need to authenticate
// If we're writing something else, we'll need to authenticate
if ((write_block_zero && dWrite) || !write_block_zero) {
if (!authenticate(uiBlock) && !bTolerateFailures) {
printf("!\nError: authentication failed for block %02x\n", uiBlock); printf("!\nError: authentication failed for block %02x\n", uiBlock);
return false; return false;
} }
} }
}
if (is_trailer_block(uiBlock)) { if (is_trailer_block(uiBlock)) {
if (bFormatCard) { if (bFormatCard) {
@ -448,35 +463,49 @@ write_card(int write_block_zero)
bFailure = true; bFailure = true;
} }
} else { } 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 // Make sure a earlier write did not fail
if (!bFailure) { if (!bFailure) {
// Try to write the data block // Try to write the data block
if (bFormatCard && uiBlock) if (bFormatCard && uiBlock)
memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData)); memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData));
else else
memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData)); memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData));
// do not write a block 0 with incorrect BCC - card will be made invalid! // do not write a block 0 with incorrect BCC - card will be made invalid!
if (uiBlock == 0) { if (uiBlock == 0) {
if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00) {
printf("!\nError: incorrect BCC in MFD file!\n"); printf("!\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]); printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]);
return false; return false;
} }
} }
if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) {
bFailure = true; bFailure = true;
printf("Failure to write to data block %i\n", uiBlock);
}
if (uiBlock == 0 && dWrite) {
if (nfc_initiator_init(pnd) < 0) {
nfc_perror(pnd, "nfc_initiator_init");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
};
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
printf("!\nError: tag was removed\n");
return false;
} }
} }
} else {
printf("Failure during write process.\n");
}
}
//}
// Show if the write went well for each block // Show if the write went well for each block
print_success_or_failure(bFailure, &uiWriteBlocks); print_success_or_failure(bFailure, &uiWriteBlocks);
if ((! bTolerateFailures) && bFailure) if ((! bTolerateFailures) && bFailure)
return false; return false;
} }
printf("|\n"); printf("|\n");
printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1); printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
fflush(stdout); fflush(stdout);
@ -494,17 +523,24 @@ static void
print_usage(const char *pcProgramName) print_usage(const char *pcProgramName)
{ {
printf("Usage: "); printf("Usage: ");
#ifndef _WIN32
printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f] [v]]\n", pcProgramName);
#else
printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName); printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName);
printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n"); #endif
printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or block 0 write to (W) card\n");
printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n"); printf(" *** 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(" *** 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(" *** note that block 0 write will attempt to overwrite block 0 including UID\n");
printf(" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n"); printf(" *** block 0 write only works with special Mifare cards (Chinese clones)\n");
printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n"); printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n");
printf(" u|U - Use any (u) uid or supply a uid specifically as U01ab23cd.\n"); printf(" u|U - Use any (u) uid or supply a uid specifically as U01ab23cd.\n");
printf(" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); printf(" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
printf(" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n"); printf(" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
printf(" f - Force using the keyfile even if UID does not match (optional)\n"); printf(" f - Force using the keyfile even if UID does not match (optional)\n");
#ifndef _WIN32
printf(" v - Sends libnfc log output to console (optional)\n");
#endif
printf("Examples: \n\n"); printf("Examples: \n\n");
printf(" Read card to file, using key A:\n\n"); printf(" Read card to file, using key A:\n\n");
printf(" %s r a u mycard.mfd\n\n", pcProgramName); printf(" %s r a u mycard.mfd\n\n", pcProgramName);
@ -519,6 +555,7 @@ print_usage(const char *pcProgramName)
printf(" %s r a U01ab23cd mycard.mfd\n\n", pcProgramName); printf(" %s r a U01ab23cd mycard.mfd\n\n", pcProgramName);
} }
int int
main(int argc, const char *argv[]) main(int argc, const char *argv[])
{ {
@ -527,7 +564,7 @@ main(int argc, const char *argv[])
uint8_t _tag_uid[4]; uint8_t _tag_uid[4];
uint8_t *tag_uid = _tag_uid; uint8_t *tag_uid = _tag_uid;
int unlock = 0; bool unlock = false;
if (argc < 2) { if (argc < 2) {
print_usage(argv[0]); print_usage(argv[0]);
@ -542,19 +579,19 @@ main(int argc, const char *argv[])
if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) { if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) {
atAction = ACTION_READ; atAction = ACTION_READ;
if (strcmp(command, "R") == 0) if (strcmp(command, "R") == 0)
unlock = 1; unlock = true;
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
bUseKeyFile = (argc > 5); bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0)); bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
} else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) { } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) {
atAction = ACTION_WRITE; atAction = ACTION_WRITE;
if (strcmp(command, "W") == 0) if (strcmp(command, "W") == 0)
unlock = 1; unlock = true;
bFormatCard = (strcmp(command, "f") == 0); bFormatCard = (strcmp(command, "f") == 0);
bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
bUseKeyFile = (argc > 5); bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0)); bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
} }
if (argv[3][0] == 'U') { if (argv[3][0] == 'U') {
@ -576,6 +613,21 @@ main(int argc, const char *argv[])
tag_uid = NULL; tag_uid = NULL;
} }
#ifndef _WIN32
// Send noise from lib to /dev/null
bool verbose = false;
if (argv[7]) {
if (strcmp(argv[7], "v") == 0) verbose = true;
} else {
if ((strcmp(argv[6], "v")) || (strcmp(argv[5], "v")) == 0) verbose = true;
}
if (!verbose) {
int fd = open("/dev/null", O_WRONLY);
dup2(fd, 2);
close(fd);
}
#endif
if (atAction == ACTION_USAGE) { if (atAction == ACTION_USAGE) {
print_usage(argv[0]); print_usage(argv[0]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -615,6 +667,14 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}; };
// Drop the field for a while, so can be reset
if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool activate field");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
// Let the reader only try once to find a tag // Let the reader only try once to find a tag
if (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0) { if (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_perror(pnd, "nfc_device_set_property_bool");
@ -630,11 +690,24 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Configure the CRC and Parity settings
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool crc");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
if (nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool parity");
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
// Try to find a MIFARE Classic tag // Try to find a MIFARE Classic tag
int tags; int tags;
tags = nfc_initiator_select_passive_target(pnd, nmMifare, tag_uid, tag_uid == NULL ? 0 : 4, &nt); tags = nfc_initiator_select_passive_target(pnd, nmMifare, tag_uid, tag_uid == NULL ? 0 : 4, &nt);
if (tags <= 0) { if (tags <= 0) {
printf("Error: no tag was found\n"); printf("Error: no tag was found\n");
@ -643,7 +716,8 @@ main(int argc, const char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Test if we are dealing with a MIFARE compatible tag // Test if we are dealing with a MIFARE compatible tag
if ((nt.nti.nai.btSak & 0x08) == 0) { if (((nt.nti.nai.btSak & 0x08) == 0) && (nt.nti.nai.btSak != 0x01)) {
// if ((nt.nti.nai.btSak & 0x08) == 0) {
printf("Warning: tag is probably not a MFC!\n"); printf("Warning: tag is probably not a MFC!\n");
} }
@ -683,19 +757,16 @@ main(int argc, const char *argv[])
// Testing RATS // Testing RATS
int res; int res;
if ((res = get_rats()) > 0) { if ((res = get_rats()) > 0) {
printf("RATS support: yes\n");
if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05) if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05)
&& (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f) && (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f)
&& ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) { && ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) {
// MIFARE Plus 2K // MIFARE Plus 2K
uiBlocks = 0x7f; uiBlocks = 0x7f;
} }
// Chinese magic emulation card, ATS=0978009102:dabc1910 } else
if ((res == 9) && (abtRx[5] == 0xda) && (abtRx[6] == 0xbc) printf("RATS support: no\n");
&& (abtRx[7] == 0x19) && (abtRx[8] == 0x10)) { printf("Guessing size: seems to be a %lu-byte card\n", (unsigned long)((uiBlocks + 1) * sizeof(mifare_classic_block)));
magic2 = true;
}
}
printf("Guessing size: seems to be a %lu-byte card\n", (uiBlocks + 1) * sizeof(mifare_classic_block));
if (bUseKeyFile) { if (bUseKeyFile) {
FILE *pfKeys = fopen(argv[5], "rb"); FILE *pfKeys = fopen(argv[5], "rb");
@ -751,9 +822,17 @@ main(int argc, const char *argv[])
} }
printf("Done.\n"); printf("Done.\n");
fclose(pfDump); fclose(pfDump);
} else {
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
} }
} else if (atAction == ACTION_WRITE) { } else if (atAction == ACTION_WRITE) {
write_card(unlock); if (!write_card(unlock)) {
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_FAILURE);
}
} }
nfc_close(pnd); nfc_close(pnd);

View File

@ -10,6 +10,7 @@
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2013-2018 Adam Laurie * Copyright (C) 2013-2018 Adam Laurie
* Copyright (C) 2018-2019 Daniele Bruneo
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -290,50 +291,46 @@ unlock_card(void)
return true; return true;
} }
static bool check_magic() static bool check_magic(void)
{ {
bool bFailure = false; bool directWrite = true;
int uid_data; // Try to read pages 0, 1, 2
uint8_t original_b0[12];
for (uint32_t page = 0; page <= 1; page++) { printf("Checking if UL badge is DirectWrite...\n");
// Show if the readout went well
if (bFailure) {
// When a failure occured we need to redo the anti-collision
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
ERR("tag was removed");
return false;
}
bFailure = false;
}
uid_data = 0x00000000;
memcpy(mp.mpd.abtData, &uid_data, sizeof uid_data);
memset(mp.mpd.abtData + 4, 0, 12);
//Force the write without checking for errors - otherwise the writes to the sector 0 seem to complain
nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp);
}
//Check that the ID is now set to 0x000000000000
if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) { if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) {
//printf("%u", mp.mpd.abtData); memcpy(original_b0, mp.mpd.abtData, 12);
bool result = true; printf(" Original Block 0 (Pages 0-2): ");
for (int i = 0; i <= 7; i++) { for (int i = 0; i < 12; i++) {
if (mp.mpd.abtData[i] != 0x00) result = false; printf("%02x", original_b0[i]);
} }
printf("\n");
if (result) { printf(" Original UID: %02x%02x%02x%02x%02x%02x%02x\n",
return true; original_b0[0], original_b0[1], original_b0[2], original_b0[4], original_b0[5], original_b0[6], original_b0[7]);
} else {
printf("!\nError: unable to read block 0x%02x\n", 0);
directWrite = false;
} }
printf(" Attempt to write Block 0 (pages 0-2) ...\n");
for (uint32_t page = 0; page <= 2; page++) {
printf(" Writing Page %i:", page);
memcpy(mp.mpd.abtData, original_b0 + page * 4, 4);
for (int i = 0; i < 4; i++) {
printf(" %02x", mp.mpd.abtData[i]);
} }
printf("\n");
//Initially check if we can unlock via the MF method if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp)) {
if (unlock_card()) { printf(" Failure writing Page %i\n", page);
directWrite = false;
break;
}
}
if (directWrite) {
printf(" Block 0 written successfully\n");
printf("Card is DirectWrite\n");
return true; return true;
} else { } else {
return false; printf("Card is not DirectWrite\n");
return unlock_card();
} }
} }
@ -383,9 +380,9 @@ write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid)
write_uid = ((buffer[0] == 'y') || (buffer[0] == 'Y')); write_uid = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
} }
printf("Writing %d pages |", uiBlocks);
/* We may need to skip 2 first pages. */ /* We may need to skip 2 first pages. */
if (!write_uid) { if (!write_uid) {
printf("Writing %d pages |", uiBlocks);
printf("ss"); printf("ss");
uiSkippedPages = 2; uiSkippedPages = 2;
} else { } else {
@ -393,6 +390,7 @@ write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid)
printf("\nUnable to unlock card - are you sure the card is magic?\n"); printf("\nUnable to unlock card - are you sure the card is magic?\n");
return false; return false;
} }
printf("Writing %d pages |", uiBlocks);
} }
for (uint32_t page = uiSkippedPages; page < uiBlocks; page++) { for (uint32_t page = uiSkippedPages; page < uiBlocks; page++) {
@ -527,7 +525,7 @@ main(int argc, const char *argv[])
bool bFilename = false; bool bFilename = false;
FILE *pfDump; FILE *pfDump;
if (argc < 3) { if (argc == 0) {
print_usage(argv); print_usage(argv);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -580,7 +578,7 @@ main(int argc, const char *argv[])
} }
} }
} }
if (! bFilename) { if (iAction != 3 && !bFilename) {
ERR("Please supply a Mifare Dump filename"); ERR("Please supply a Mifare Dump filename");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -650,7 +648,7 @@ main(int argc, const char *argv[])
if (get_ev1_version()) { if (get_ev1_version()) {
if (!bPWD) if (!bPWD)
printf("WARNING: Tag is EV1 or NTAG - PASSWORD may be required\n"); printf("WARNING: Tag is EV1 or NTAG - PASSWORD may be required\n");
if (abtRx[6] == 0x0b) { if (abtRx[6] == 0x0b || abtRx[6] == 0x00) {
printf("EV1 type: MF0UL11 (48 bytes)\n"); printf("EV1 type: MF0UL11 (48 bytes)\n");
uiBlocks = 20; // total number of 4 byte 'pages' uiBlocks = 20; // total number of 4 byte 'pages'
iDumpSize = uiBlocks * 4; iDumpSize = uiBlocks * 4;
@ -714,7 +712,7 @@ main(int argc, const char *argv[])
size_t szDump; size_t szDump;
if (((szDump = fread(&mtDump, 1, sizeof(mtDump), pfDump)) != iDumpSize && !bPart) || szDump <= 0) { if (((szDump = fread(&mtDump, 1, sizeof(mtDump), pfDump)) != iDumpSize && !bPart) || szDump <= 0) {
ERR("Could not read from dump file or size mismatch: %s (read %lu, expected %lu)\n", argv[2], szDump, iDumpSize); ERR("Could not read from dump file or size mismatch: %s (read %lu, expected %lu)\n", argv[2], (unsigned long)szDump, (unsigned long)iDumpSize);
fclose(pfDump); fclose(pfDump);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

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