diff --git a/README.TXT b/README.TXT index 22c3e77..01ce245 100644 --- a/README.TXT +++ b/README.TXT @@ -2,145 +2,23 @@ Public platform independent Near Field Communication (NFC) library Copyright (C) 2009, Roel Verdult -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +------------------------------------------------------------------------ +Welcome to the developers community of libnfc. -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. +Since it is hard to keep all information up to date +we decided to only maintain the online documentation. +Please visit the official website for more info: +http://www.libnfc.org -You should have received a copy of the GNU General Public License -along with this program. If not, see . +If you have questions, remarks, bug-reports, we encourage you to +post this in the developers community: +http://www.libnfc.org/community ------------------------------------------------------------------------ -Welcome to the community of libnfc (website: http://www.libnfc.org). +Proprietary Notes: -libnfc version 1.0.0 - -Index: -1. Introduction -2. Hardware -3. Compilation -4. Examples -5. Todo -6. Contact - ------------------------------------------------------------------------- -1. Introduction - -Since the RFID market is spoiled by proprietary hard and software -we want to contribute constructively by distributing a free library -which can be used in RFID/NFC applications. - ------------------------------------------------------------------------- -2. Hardware - -To communicate with NFC targets/tags you need a USB device which is -called a "RFID Reader". The cheapest hardware around that can carries -a fully NFC complied chip is the ACR122 from the company ACS, Advanced -Card Systems Limited (website: http://www.acs.com.hk/acr122.php). -This reader uses the PN532 chipset from NXP Semiconductors. The reader -costs around the €60 and is available in different webshops all over -the world. The NFC reader used in the "tikitag" project is exactly the -same reader as the ACR122 but with a different logo. This reader is -available for only €35,- (website: http://www.tikitag.com). We would -recommend to use one of these readers, since we tested both of them. - -Other NFC readers, like the SCL3710 from SCM Microsystems (website: -http://www.scmmicro.com/scl3710/) are not supported yet. They use the -same chipset, so the instruction set is completely the same. This means -that with little effort these readers could be added to be part of the -NFC library. We would be very pleased if someone is willing to add this -support to libnfc. - ------------------------------------------------------------------------- -3. Compilation - -If you use linux, please make sure you have libpcsc-lite installed. -For Ubuntu this means you have to install the following packages: -$sudo apt-get install pcscd -$sudo apt-get install libpcsclite-dev -When these are installed, just run "make" and you are ready to go. - -MacOSX users have to edit the "Makefile" file in the main directory. -Uncomment the following lines: -#LIB_TYPE=... -#LIB_FLAGS=... -#PCSC_HEADERS=... -#PCSC_LIB=... -Run "make" and you it should work like a charm. - -Windows users can use the binairy files located in the "win32bin" -directory. Or they can open the VS2005 solution which can be found -in the "win32" directory. Compilation should work "out of the box". - ------------------------------------------------------------------------- -4. Examples - -There are 6 example tools coming with this library. They can be used -as a reference during development of your software. All tools try to -demonstrate a different feature. Below there is short description of -the tools and their purpose. - -anticol - Anti-collision demonstration tool for ISO14443A tags using - self constructed REQA/WUPA and SELECT frames. - -list - List passive tags tool for ISO14443A tags using the commands - available in the instruction set of the hardware chip. - -simulate - With this example you can turn your reader into a NFC target. - For testing purposes it simulates a ISO14443A tag with a UID - that consists of 0xDEADBEAF. The frames are delayed because - of the USB communication, so not all readers will recognize - the tag. The "Omnikey 5121" though has no problems with this - small delay. - -relay - This tool allows the user to use 2 readers. One will similate - a ISO14443A tag, while the 2nd reader will stay a reader. - The original tag can be placed on the 2nd reader and the - simulated tag can be placed on top of the original reader. - All communication is relayed now and showed on the screen. - NOTE: relaying frames is time-consuming, not all readers - allow slow responds from the (simulated) tag. Though, one of - the most used RFID readers, the "Omnikey 5121" has no problem - and can perfectly be used for demonstrating this features. - -mfread - With this tool a complete MIFARE card can be readout and stored - in a MIFARE dump file (*.mfd). - -mfwrite - With this tool a complete MIFARE card can be restored from a - a MIFARE dump file (*.mfd) back to the tag. - -A MIFARE dump file (*.mfd) is a plain 4KB image of a mifare tag. This -image should contain the data, keys and access bits on their usual position. -A Dump file is always 4KB, even when a 1KB tag is dumped. From the first -block, the manufacturer data, can be determined if you are dealing with -a 1KB or a 4KB tag. This is stored in the ATQA part of block0 (byte 6/7). -More info can be found in the MIFARE functional specification from NXP. -(Website: http://www.nxp.com/products/identification/mifare/classic) - ------------------------------------------------------------------------- -5. Todo - -Support more communication protocols. Sony Felica, ISO14443B and Innovision -Jewel Topaz tags are supported by the chipset, but they are not used by -this library. It would be very useful if we could add support for these -tags in this library. - ------------------------------------------------------------------------- -6. Contact - -Please visit the website (http://www.libnfc.org) and place your questions -in the community forum there. We are sure a member of the community will -help you out. - ------------------------------------------------------------------------- -Proprietary notes: - -Note: FeliCa is s registered trademark of Sony Corporation. MIFARE is a +FeliCa is s registered trademark of Sony Corporation. MIFARE is a trademark of NXP Semiconductors. Jewel Topaz is a trademark of Innovision Research & Technology. All other trademarks are the property of their respective owners. + diff --git a/anticol.c b/anticol.c index 876d0a9..e4e4e34 100644 --- a/anticol.c +++ b/anticol.c @@ -1,142 +1,150 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - -#include -#include -#include -#include "libnfc.h" - -static byte abtRecv[MAX_FRAME_LEN]; -static ui32 uiRecvLen; -static byte abtUid[10]; -static ui32 uiUidLen = 4; -static dev_id di; - -// ISO14443A Anti-Collision Commands -byte abtWupa [1] = { 0x52 }; -byte abtSelectAll [2] = { 0x93,0x20 }; -byte abtSelectTag [9] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; -byte abtRats [4] = { 0xe0,0x50,0xbc,0xa5 }; -byte abtHalt [4] = { 0x50,0x00,0x57,0xcd }; - -bool transmit_7bits(const byte btTx) -{ - bool bResult; - printf("R: %02x\n",btTx); - uiRecvLen = MAX_FRAME_LEN; - bResult = nfc_reader_transceive_7bits(di,btTx,abtRecv,&uiRecvLen); - if (bResult) - { - printf("T: "); - print_hex(abtRecv,uiRecvLen); - } - return bResult; -} - -bool transmit_bytes(const byte* pbtTx, const ui32 uiTxLen) -{ - bool bResult; - printf("R: "); - print_hex(pbtTx,uiTxLen); - uiRecvLen = MAX_FRAME_LEN; - bResult = nfc_reader_transceive_bytes(di,pbtTx,uiTxLen,abtRecv,&uiRecvLen); - if (bResult) - { - printf("T: "); - print_hex(abtRecv,uiRecvLen); - } - return bResult; -} - -int main(int argc, const char* argv[]) -{ - // Try to open the NFC reader - di = acr122_connect(0); - - if (di == INVALID_DEVICE_ID) - { - printf("Error connecting NFC reader\n"); - return 1; - } - nfc_reader_init(di); - - // Let the reader only try once to find a tag - nfc_configure_list_passive_infinite(di,false); - - // Drop the field so the tag will be reset - nfc_configure_field(di,false); - - // Configure the communication channel, we use our own CRC - nfc_configure_handle_crc(di,false); - nfc_configure_handle_parity(di,true); - - // Enable the field so the more power consuming tags will respond - nfc_configure_field(di,true); - - printf("\nConnected to NFC reader\n\n"); - - if (!transmit_7bits(*abtWupa)) - { - printf("Error: No tag available\n"); - return 1; - } - // Anti-collision - transmit_bytes(abtSelectAll,2); - - // Save the UID - memcpy(abtUid,abtRecv,4); - memcpy(abtSelectTag+2,abtRecv,5); - append_iso14443a_crc(abtSelectTag,7); - transmit_bytes(abtSelectTag,9); - - if (abtUid[0] == 0x88) - { - abtSelectAll[0] = 0x95; - abtSelectTag[0] = 0x95; - - // Anti-collision - transmit_bytes(abtSelectAll,2); - - // Save the UID - memcpy(abtUid+4,abtRecv,4); - memcpy(abtSelectTag+2,abtRecv,5); - append_iso14443a_crc(abtSelectTag,7); - transmit_bytes(abtSelectTag,9); - uiUidLen = 7; - } - - // Request ATS, this only applies to tags that support ISO 14443A-4 - if (abtRecv[0] & 0x20) - { - transmit_bytes(abtRats,4); - } - - // Done, halt the tag now - transmit_bytes(abtHalt,4); - - printf("\nFound tag with UID: "); - if (uiUidLen == 4) - { - printf("%08x\n",swap_endian32(abtUid)); - } else { - printf("%014llx\n",swap_endian64(abtUid)&0x00ffffffffffffffull); - } - return 0; -} +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + +#include +#include +#include +#include "libnfc.h" + +#define SAK_FLAG_ATS_SUPPORTED 0x20 + +static byte abtRx[MAX_FRAME_LEN]; +static ui32 uiRxBits; +static ui32 uiRxLen; +static byte abtUid[10]; +static ui32 uiUidLen = 4; +static dev_info* pdi; + +// ISO14443A Anti-Collision Commands +byte abtReqa [1] = { 0x26 }; +byte abtSelectAll [2] = { 0x93,0x20 }; +byte abtSelectTag [9] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +byte abtRats [4] = { 0xe0,0x50,0xbc,0xa5 }; +byte abtHalt [4] = { 0x50,0x00,0x57,0xcd }; + +bool transmit_bits(const byte* pbtTx, const ui32 uiTxBits) +{ + // Show transmitted command + printf("R: "); print_hex_bits(pbtTx,uiTxBits); + + // Transmit the bit frame command, we don't use the arbitrary parity feature + if (!nfc_reader_transceive_bits(pdi,pbtTx,uiTxBits,null,abtRx,&uiRxBits,null)) return false; + + // Show received answer + printf("T: "); print_hex_bits(abtRx,uiRxBits); + + // Succesful transfer + return true; +} + + +bool transmit_bytes(const byte* pbtTx, const ui32 uiTxLen) +{ + // Show transmitted command + printf("R: "); print_hex(pbtTx,uiTxLen); + + // Transmit the command bytes + if (!nfc_reader_transceive_bytes(pdi,pbtTx,uiTxLen,abtRx,&uiRxLen)) return false; + + // Show received answer + printf("T: "); print_hex(abtRx,uiRxLen); + + // Succesful transfer + return true; +} + +int main(int argc, const char* argv[]) +{ + // Try to open the NFC reader + pdi = nfc_connect(); + + if (!pdi) + { + printf("Error connecting NFC reader\n"); + return 1; + } + nfc_reader_init(pdi); + + // Drop the field for a while + nfc_configure(pdi,DCO_ACTIVATE_FIELD,false); + + // Configure the CRC and Parity settings + nfc_configure(pdi,DCO_HANDLE_CRC,false); + nfc_configure(pdi,DCO_HANDLE_PARITY,true); + + // Enable field so more power consuming cards can power themselves up + nfc_configure(pdi,DCO_ACTIVATE_FIELD,true); + + printf("\nConnected to NFC reader: %s\n\n",pdi->acName); + + // Send the 7 bits request command specified in ISO 14443A (0x26) + if (!transmit_bits(abtReqa,7)) + { + printf("Error: No tag available\n"); + nfc_disconnect(pdi); + return 1; + } + + // Anti-collision + transmit_bytes(abtSelectAll,2); + + // Save the UID + memcpy(abtUid,abtRx,4); + memcpy(abtSelectTag+2,abtRx,5); + append_iso14443a_crc(abtSelectTag,7); + transmit_bytes(abtSelectTag,9); + + // Test if we are dealing with a 4 bytes uid + if (abtUid[0]!= 0x88) + { + uiUidLen = 4; + } else { + // We have to do the anti-collision for cascade level 2 + abtSelectAll[0] = 0x95; + abtSelectTag[0] = 0x95; + + // Anti-collision + transmit_bytes(abtSelectAll,2); + + // Save the UID + memcpy(abtUid+4,abtRx,4); + memcpy(abtSelectTag+2,abtRx,5); + append_iso14443a_crc(abtSelectTag,7); + transmit_bytes(abtSelectTag,9); + uiUidLen = 7; + } + + // Request ATS, this only applies to tags that support ISO 14443A-4 + if (abtRx[0] & SAK_FLAG_ATS_SUPPORTED) transmit_bytes(abtRats,4); + + // Done, halt the tag now + transmit_bytes(abtHalt,4); + + printf("\nFound tag with UID: "); + if (uiUidLen == 4) + { + printf("%08x\n",swap_endian32(abtUid)); + } else { + printf("%014llx\n",swap_endian64(abtUid)&0x00ffffffffffffffull); + } + + nfc_disconnect(pdi); + return 0; +} diff --git a/bitutils.c b/bitutils.c index f7f9458..5fda4b1 100644 --- a/bitutils.c +++ b/bitutils.c @@ -1,23 +1,23 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + #include #include "bitutils.h" @@ -116,7 +116,7 @@ ui32 swap_endian32(const void* pui32) ui64 swap_endian64(const void* pui64) { ui64 ui64N = *((ui64*)pui64); - return (((ui64N&0xFF)<<56)+((ui64N&0xFF00)<<40)+((ui64N&0xFF0000)<<24)+((ui64N&0xFF000000)<<8)+((ui64N&0xFF00000000)>>8)+((ui64N&0xFF0000000000)>>24)+((ui64N&0xFF000000000000)>>40)+((ui64N&0xFF00000000000000)>>56)); + return (((ui64N&0xFF)<<56)+((ui64N&0xFF00)<<40)+((ui64N&0xFF0000)<<24)+((ui64N&0xFF000000)<<8)+((ui64N&0xFF00000000ull)>>8)+((ui64N&0xFF0000000000ull)>>24)+((ui64N&0xFF000000000000ull)>>40)+((ui64N&0xFF00000000000000ull)>>56)); } void append_iso14443a_crc(byte* pbtData, ui32 uiLen) @@ -135,16 +135,33 @@ void append_iso14443a_crc(byte* pbtData, ui32 uiLen) *pbtData = (byte) ((wCrc >> 8) & 0xFF); } -void print_hex(const byte* pbtData, const ui32 uiLen) +void print_hex(const byte* pbtData, const ui32 uiBytes) { ui32 uiPos; - for (uiPos=0; uiPos < uiLen; uiPos++) + + for (uiPos=0; uiPos < uiBytes; uiPos++) { printf("%02x ",pbtData[uiPos]); } printf("\n"); } +void print_hex_bits(const byte* pbtData, const ui32 uiBits) +{ + ui32 uiPos; + ui32 uiBytes = uiBits/8; + + for (uiPos=0; uiPos < uiBytes; uiPos++) + { + printf("%02x ",pbtData[uiPos]); + } + + // Print the rest bits, these cannot have no parity bit + if (uiBits%8 != 0) printf("%02x",pbtData[uiBytes]); + + printf("\n"); +} + void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPar) { ui32 uiPos; @@ -162,10 +179,7 @@ void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPa } // Print the rest bits, these cannot have no parity bit - if (uiBits%8 != 0) - { - printf("%02x",pbtData[uiBytes]); - } + if (uiBits%8 != 0) printf("%02x",pbtData[uiBytes]); printf("\n"); } diff --git a/bitutils.h b/bitutils.h index e231678..312c968 100644 --- a/bitutils.h +++ b/bitutils.h @@ -1,46 +1,28 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + #ifndef _LIBNFC_BITUTILS_H_ #define _LIBNFC_BITUTILS_H_ #include "defines.h" -#define INNER_XOR8(n) {\ - n ^= (n >> 4); \ - n ^= (n >> 2); \ - n ^= (n >> 1); \ - n &= 0x01; \ -} - -#define INNER_XOR32(n) {\ - n ^= (n >> 16); \ - n ^= (n >> 8); \ - INNER_XOR8(n); \ -} - -#define INNER_XOR64(n) {\ - n ^= (n >> 32); \ - INNER_XOR32(n); \ -} - byte oddparity(const byte bt); void oddparity_bytes(const byte* pbtData, const ui32 uiLen, byte* pbtPar); @@ -55,6 +37,7 @@ ui64 swap_endian64(const void* pui64); void append_iso14443a_crc(byte* pbtData, ui32 uiLen); void print_hex(const byte* pbtData, const ui32 uiLen); +void print_hex_bits(const byte* pbtData, const ui32 uiBits); void print_hex_par(const byte* pbtData, const ui32 uiBits, const byte* pbtDataPar); #endif // _LIBNFC_BITUTILS_H_ diff --git a/defines.h b/defines.h index 99edc19..6ec18e2 100644 --- a/defines.h +++ b/defines.h @@ -1,26 +1,28 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + #ifndef _LIBNFC_DEFINES_H_ #define _LIBNFC_DEFINES_H_ +// #define _LIBNFC_VERBOSE_ + typedef unsigned char byte; typedef unsigned char ui8; typedef unsigned short ui16; @@ -33,13 +35,16 @@ typedef int i32; #define null 0 -typedef void* dev_id; // Device Id -#define INVALID_DEVICE_ID null +typedef void* dev_spec; // Device connection specification +#define INVALID_DEVICE_INFO null #define MAX_FRAME_LEN 264 +#define DEVICE_NAME_LENGTH 256 -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#define max(a,b) (((a) > (b)) ? (a) : (b)) - -// #define _LIBNFC_VERBOSE_ +// Useful macros +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define INNER_XOR8(n) {n ^= (n >> 4); n ^= (n >> 2); n ^= (n >> 1); n &= 0x01; } +#define INNER_XOR32(n) {n ^= (n >> 16); n ^= (n >> 8); INNER_XOR8(n); } +#define INNER_XOR64(n) {n ^= (n >> 32); INNER_XOR32(n); } #endif // _LIBNFC_DEFINES_H_ diff --git a/libnfc.c b/libnfc.c index f832b28..8d87140 100644 --- a/libnfc.c +++ b/libnfc.c @@ -1,524 +1,761 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - -#include -#include -#include "libnfc.h" -#include "acr122.h" -#include "bitutils.h" - -#define REG_CIU_TX_MODE 0x6302 -#define REG_CIU_RX_MODE 0x6303 -#define REG_CIU_TX_AUTO 0x6305 -#define REG_CIU_MANUAL_RCV 0x630D -#define REG_CIU_CONTROL 0x633C -#define REG_CIU_BIT_FRAMING 0x633D - -#define PARAM_NONE 0x00 -#define PARAM_NAD_USED 0x01 -#define PARAM_DID_USED 0x02 -#define PARAM_AUTO_ATR_RES 0x04 -#define PARAM_AUTO_RATS 0x10 -#define PARAM_14443_4_PICC 0x20 -#define PARAM_NO_AMBLE 0x40 - -// PN532 configuration -byte pncmd_get_firmware_version [ 2] = { 0xD4,0x02 }; -byte pncmd_get_general_status [ 2] = { 0xD4,0x04 }; -byte pncmd_get_register [ 4] = { 0xD4,0x06 }; -byte pncmd_set_register [ 5] = { 0xD4,0x08 }; -byte pncmd_set_parameters [ 3] = { 0xD4,0x12 }; - -// RF field configuration -byte pncmd_rf_configure_field [ 4] = { 0xD4,0x32,0x01 }; -byte pncmd_rf_configure_timing [ 4] = { 0xD4,0x32,0x02 }; -byte pncmd_rf_configure_retry_data [ 4] = { 0xD4,0x32,0x04 }; -byte pncmd_rf_configure_retry_select [ 6] = { 0xD4,0x32,0x05 }; - -// Reader -byte pncmd_reader_list_passive [264] = { 0xD4,0x4A }; -byte pncmd_reader_select [ 3] = { 0xD4,0x54 }; -byte pncmd_reader_deselect [ 3] = { 0xD4,0x44 }; -byte pncmd_reader_release [ 3] = { 0xD4,0x52 }; -byte pncmd_reader_set_baud_rate [ 5] = { 0xD4,0x4E }; -byte pncmd_reader_exchange_data [265] = { 0xD4,0x40 }; -byte pncmd_reader_auto_poll [ 5] = { 0xD4,0x60 }; - -// Target -byte pncmd_target_get_data [ 2] = { 0xD4,0x86 }; -byte pncmd_target_init [ 39] = { 0xD4,0x8C }; -byte pncmd_target_virtual_card [ 4] = { 0xD4,0x14 }; -byte pncmd_target_receive [ 2] = { 0xD4,0x88 }; -byte pncmd_target_send [264] = { 0xD4,0x90 }; -byte pncmd_target_get_status [ 2] = { 0xD4,0x8A }; - -// Exchange raw data frames -byte pncmd_exchange_raw_data [266] = { 0xD4,0x42 }; - -// Global buffers used for communication with the PN532 chip -#define MAX_FRAME_LEN 264 -static byte abtRx[MAX_FRAME_LEN]; -static ui32 uiRxLen; -static ui8 ui8Value; -static ui32 ui32Len = 1; - -bool pn532_transceive(const dev_id di, const byte* pbtTx, const ui32 uiTxLen) -{ - uiRxLen = MAX_FRAME_LEN; - return acr122_transceive(di,pbtTx,uiTxLen,abtRx,&uiRxLen); -} - -bool pn532_set_reg(const dev_id di, ui16 ui16Reg, ui8 ui8Value) -{ - pncmd_set_register[2] = ui16Reg >> 8; - pncmd_set_register[3] = ui16Reg & 0xff; - pncmd_set_register[4] = ui8Value; - return acr122_transceive(di,pncmd_set_register,5,null,null); -} - -byte pn532_get_reg(const dev_id di, ui16 ui16Reg) -{ - pncmd_get_register[2] = ui16Reg >> 8; - pncmd_get_register[3] = ui16Reg & 0xff; - acr122_transceive(di,pncmd_get_register,4,&ui8Value,&ui32Len); - return ui8Value; -} - -bool pn532_set_parameters(const dev_id di, ui8 ui8Value) -{ - pncmd_set_parameters[2] = ui8Value; - return acr122_transceive(di,pncmd_set_parameters,3,null,null); -} - -bool pn532_wrap_frame(const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtFrame, ui32* puiFrameBits) -{ - byte btFrame; - byte btData; - ui32 uiBitPos; - ui32 uiDataPos = 0; - ui32 uiBitsLeft = uiTxBits; - - // Make sure we should frame at least something - if (uiBitsLeft == 0) return false; - - // Handle a short response (1byte) as a special case - if (uiBitsLeft < 9) - { - *pbtFrame = *pbtTx; - *puiFrameBits = uiTxBits; - return true; - } - - // We start by calculating the frame length in bits - *puiFrameBits = uiTxBits + (uiTxBits/8); - - // Parse the data bytes and add the parity bits - // This is really a sensitive process, mirror the frame bytes and append parity bits - // buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ... - // split "buffer" up in segments of 8 bits again and mirror them - // air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + .. - while(true) - { - // Reset the temporary frame byte; - btFrame = 0; - - for (uiBitPos=0; uiBitPos<8; uiBitPos++) - { - // Copy as much data that fits in the frame byte - btData = mirror(pbtTx[uiDataPos]); - btFrame |= (btData >> uiBitPos); - // Save this frame byte - *pbtFrame = mirror(btFrame); - // Set the remaining bits of the date in the new frame byte and append the parity bit - btFrame = (btData << (8-uiBitPos)); - btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7-uiBitPos)); - // Backup the frame bits we have so far - pbtFrame++; - *pbtFrame = mirror(btFrame); - // Increase the data (without parity bit) position - uiDataPos++; - // Test if we are done - if (uiBitsLeft < 9) return true; - uiBitsLeft -= 8; - } - // Every 8 data bytes we lose one frame byte to the parities - pbtFrame++; - } -} - -bool pn532_unwrap_frame(const byte* pbtFrame, const ui32 uiFrameBits, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar) -{ - byte btFrame; - byte btData; - ui8 uiBitPos; - ui32 uiDataPos = 0; - byte* pbtFramePos = (byte*) pbtFrame; - ui32 uiBitsLeft = uiFrameBits; - - // Make sure we should frame at least something - if (uiBitsLeft == 0) return false; - - // Handle a short response (1byte) as a special case - if (uiBitsLeft < 9) - { - *pbtRx = *pbtFrame; - *puiRxBits = uiFrameBits; - return true; - } - - // Calculate the data length in bits - *puiRxBits = uiFrameBits - (uiFrameBits/9); - - // Parse the frame bytes, remove the parity bits and store them in the parity array - // This process is the reverse of WrapFrame(), look there for more info - while(true) - { - for (uiBitPos=0; uiBitPos<8; uiBitPos++) - { - btFrame = mirror(pbtFramePos[uiDataPos]); - btData = (btFrame << uiBitPos); - btFrame = mirror(pbtFramePos[uiDataPos+1]); - btData |= (btFrame >> (8-uiBitPos)); - pbtRx[uiDataPos] = mirror(btData); - if(pbtRxPar != null) pbtRxPar[uiDataPos] = ((btFrame >> (7-uiBitPos)) & 0x01); - // Increase the data (without parity bit) position - uiDataPos++; - // Test if we are done - if (uiBitsLeft < 9) return true; - uiBitsLeft -= 9; - } - // Every 8 data bytes we lose one frame byte to the parities - pbtFramePos++; - } -} - -bool nfc_configure_handle_crc(const dev_id di, const bool bEnable) -{ - if (bEnable) - { - // Enable automatic receiving/sending of CRC bytes - if (!pn532_set_reg(di,REG_CIU_TX_MODE,pn532_get_reg(di,REG_CIU_TX_MODE) | 0x80)) return false; - if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0x80)) return false; - } else { - // Disable automatic receiving/sending of CRC bytes - if (!pn532_set_reg(di,REG_CIU_TX_MODE,pn532_get_reg(di,REG_CIU_TX_MODE) & 0x7f)) return false; - if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) & 0x7f)) return false; - } - return true; -} - -bool nfc_configure_handle_parity(const dev_id di, const bool bEnable) -{ - if (bEnable) - { - // Handle parity by chip - if (!pn532_set_reg(di,REG_CIU_MANUAL_RCV,pn532_get_reg(di,REG_CIU_MANUAL_RCV) & 0xef)) return false; - - } else { - // Parse parity as data bit - if (!pn532_set_reg(di,REG_CIU_MANUAL_RCV,pn532_get_reg(di,REG_CIU_MANUAL_RCV) | 0x10)) return false; - } - return true; -} - -bool nfc_configure_field(const dev_id di, const bool bEnable) -{ - pncmd_rf_configure_field[3] = (bEnable) ? 1 : 0; - return acr122_transceive(di,pncmd_rf_configure_field,4,null,null); -} - -bool nfc_configure_list_passive_infinite(const dev_id di, const bool bEnable) -{ - // Retry format: 0x00 means only 1 try, 0xff means infinite - pncmd_rf_configure_retry_select[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02 - pncmd_rf_configure_retry_select[4] = (bEnable) ? 0xff : 0x00; // MxRtyPSL, default: 0x01 - pncmd_rf_configure_retry_select[5] = (bEnable) ? 0xff : 0x00; // MxRtyPassiveActivation, default: 0xff - return acr122_transceive(di,pncmd_rf_configure_retry_select,6,null,null); -} - -bool nfc_configure_accept_invalid_frames(const dev_id di, const bool bEnable) -{ - if (bEnable) - { - // Handle parity by chip - if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0x08)) return false; - - } else { - // Parse parity as data bit - if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0xf7)) return false; - } - return true; -} - -bool nfc_configure_accept_multiple_frames(const dev_id di, const bool bEnable) -{ - if (bEnable) - { - // Handle parity by chip - if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0x04)) return false; - - } else { - // Parse parity as data bit - if (!pn532_set_reg(di,REG_CIU_RX_MODE,pn532_get_reg(di,REG_CIU_RX_MODE) | 0xfb)) return false; - } - return true; -} - -bool nfc_reader_init(const dev_id di) -{ - // Try to connect to the NFC reader - if (di == INVALID_DEVICE_ID) return INVALID_DEVICE_ID; - - // Let the PN5XX automatically be activated by the RF level detector - if (!pn532_set_reg(di,REG_CIU_TX_AUTO,pn532_get_reg(di,REG_CIU_TX_AUTO) | 0x40)) return false; - - // Configure the PN532 to be an Initiator or Reader/Writer - if (!pn532_set_reg(di,REG_CIU_CONTROL,pn532_get_reg(di,REG_CIU_CONTROL) | 0x10)) return false; - - return true; -} - -bool nfc_reader_list_passive(const dev_id di, const ModulationType mt, const byte* pbtInitData, const ui32 uiInitDataLen, byte* pbtTag, ui32* puiTagLen) -{ - pncmd_reader_list_passive[2] = 1; // MaxTg, we only want to select 1 tag at the time - pncmd_reader_list_passive[3] = mt; // BrTy, the type of modulation used for polling a passive tag - - // Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or selecting a specific UID). - if (pbtInitData) memcpy(pncmd_reader_list_passive+4,pbtInitData,uiInitDataLen); - - // Try to find the available tags - if (!acr122_transceive(di,pncmd_reader_list_passive,4+uiInitDataLen,pbtTag,puiTagLen)) return false; - - // Return true only if at least one tag has been found, the PN532 returns 0x00 if none was available - return (pbtTag[0] != 0x00); -} - -bool nfc_reader_transceive_7bits(const dev_id di, const byte btTx, byte* pbtRx, ui32* puiRxLen) -{ - // Set transmission bits to 7 - if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,7)) return false; - - pncmd_exchange_raw_data[2] = btTx; - if (!pn532_transceive(di,pncmd_exchange_raw_data,3)) return false; - - if (uiRxLen == 1 || abtRx[0] != 0) return false; - *puiRxLen = uiRxLen-1; - memcpy(pbtRx,abtRx+1,*puiRxLen); - - // Reset transmission bits count - if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,0)) return false; - - return true; -} - -bool nfc_reader_transceive_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen) -{ - memcpy(pncmd_exchange_raw_data+2,pbtTx,uiTxLen); - - if (!pn532_transceive(di,pncmd_exchange_raw_data,2+uiTxLen)) return false; - - if (uiRxLen == 1 || abtRx[0] != 0) return false; - *puiRxLen = uiRxLen-1; - memcpy(pbtRx,abtRx+1,*puiRxLen); - - return true; -} - -bool nfc_reader_transceive_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar) -{ - ui32 uiFrameBits = 0; - ui8 ui8Bits = 0; - - // Convert data to a frame - pn532_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_exchange_raw_data+2,&uiFrameBits); - - // Retrieve the resting bits - ui8Bits = uiFrameBits%8; - - // Set the amount of transmission bits in the pn532 chip register - if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,ui8Bits)) return false; - - // Send the frame to the pn532 chip and get the answer - // We have to give the amount of bytes + 1 byte if there are leading bits + the two 0xD4,0x42 - if (!pn532_transceive(di,pncmd_exchange_raw_data,(uiFrameBits/8)+((ui8Bits==0)?0:1)+2)) return false; - - // Make sure there was no failure reported by the PN532 chip (0 == OK) - // TODO: is this ACR122 specific? - if (uiRxLen == 1 || abtRx[0] != 0) return false; - - // Get the last bit-count that is stored in the received byte - ui8Bits = pn532_get_reg(di,REG_CIU_CONTROL) & 0x07; - - // Unwrap the response frame - pn532_unwrap_frame(abtRx+1,((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits,pbtRx,puiRxBits,pbtRxPar); - - // Everything went successful - return true; -} - -bool nfc_reader_mifare_cmd(const dev_id di, const MifareCmd mc, const ui8 ui8Block, MifareParam* pmp) -{ - ui32 uiParamLen; - pncmd_reader_exchange_data[2] = 0x01; // Use first target/card - pncmd_reader_exchange_data[3] = mc; // The MIFARE Classic command - pncmd_reader_exchange_data[4] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff) - - switch (mc) - { - // Read and store command have no parameter - case MC_READ: - case MC_STORE: - uiParamLen = 0; - break; - - // Authenticate command - case MC_AUTH_A: - case MC_AUTH_B: - uiParamLen = sizeof(MifareParamAuth); - break; - - // Data command - case MC_WRITE: - uiParamLen = sizeof(MifareParamData); - break; - - // Value command - case MC_DECREMENT: - case MC_INCREMENT: - case MC_TRANSFER: - uiParamLen = sizeof(MifareParamValue); - break; - - // Please fix your code, you never should reach this statement - default: - return false; - break; - } - - // When available, copy the parameter bytes - if (uiParamLen) memcpy(pncmd_reader_exchange_data+5,(byte*)pmp,uiParamLen); - - // Fire the mifare command - if (!pn532_transceive(di,pncmd_reader_exchange_data,5+uiParamLen)) return false; - - // Make sure there was no failure reported by the PN532 chip (0 == OK) - // TODO: is this ACR122 specific? - if (abtRx[0] != 0) return false; - - // When we have executed a read command, copy the received bytes into the param - if (mc == MC_READ) memcpy(pmp->mpd.abtData,abtRx+1,16); - - // Command succesfully executed - return true; -} - -bool nfc_target_init(const dev_id di, byte* pbtRx, ui32* puiRxLen) -{ - // Clear the target init struct, reset to all zeros - memset(pncmd_target_init+2,0x00,37); - - // Set ATQA (SENS_RES) - pncmd_target_init[3] = 0x04; - pncmd_target_init[4] = 0x00; - - // Set SAK (SEL_RES) - pncmd_target_init[8] = 0x20; - - // Set UID - pncmd_target_init[5] = 0x00; - pncmd_target_init[6] = 0xb0; - pncmd_target_init[7] = 0x0b; - - // Enable CRC & parity, needed for target_init to work properly - nfc_configure_handle_crc(di,true); - nfc_configure_handle_parity(di,true); - - // Request the initialization as a target - if (!pn532_transceive(di,pncmd_target_init,39)) return false; - - if (uiRxLen == 1 || abtRx[0] != 0) return false; - *puiRxLen = uiRxLen-1; - memcpy(pbtRx,abtRx+1,*puiRxLen); - - return true; -} - -bool nfc_target_receive_bytes(const dev_id di, byte* pbtRx, ui32* puiRxLen) -{ - if (!pn532_transceive(di,pncmd_target_receive,2)) return false; - - if (uiRxLen == 1 || abtRx[0] != 0) return false; - *puiRxLen = uiRxLen-1; - memcpy(pbtRx,abtRx+1,*puiRxLen); - - return true; -} - -bool nfc_target_receive_bits(const dev_id di, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar) -{ - ui8 ui8Bits; - - // Try to gather the received frames from the reader - if (!pn532_transceive(di,pncmd_target_receive,2)) return false; - - // Make sure there was no failure reported by the PN532 chip (0 == OK) - // TODO: is this ACR122 specific? - if (uiRxLen == 1 || abtRx[0] != 0) return false; - - // Get the last bit-count that is stored in the received byte - ui8Bits = pn532_get_reg(di,REG_CIU_CONTROL) & 0x07; - - // Unwrap the response frame - pn532_unwrap_frame(abtRx+1,((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits,pbtRx,puiRxBits,pbtRxPar); - - return true; -} - -bool nfc_target_send_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen) -{ - memcpy(pncmd_target_send+2,pbtTx,uiTxLen); - return acr122_transceive(di,pncmd_target_send,2+uiTxLen,null,null); -} - -bool nfc_target_send_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar) -{ - ui32 uiFrameBits = 0; - ui8 ui8Bits = 0; - - // Convert data to a frame - pn532_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_target_send+2,&uiFrameBits); - - // Retrieve the resting bits - ui8Bits = uiFrameBits%8; - - // Set the amount of transmission bits in the pn532 chip register - if (!pn532_set_reg(di,REG_CIU_BIT_FRAMING,ui8Bits)) return false; - - // Try to send the bits to the reader - if (!pn532_transceive(di,pncmd_target_send,(uiFrameBits/8)+((ui8Bits==0)?0:1)+2)) return false; - - // Make sure there was no failure reported by the PN532 chip (0 == OK) - // TODO: is this ACR122 specific? - if (uiRxLen == 1 || abtRx[0] != 0) return false; - - // Everyting seems ok, return true - return true; -} - +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + +#include "libnfc.h" +#include "bitutils.h" +#include +#include + +// Registers and symbols masks used to covers parts within a register +#define REG_CIU_TX_MODE 0x6302 + #define SYMBOL_TX_CRC_ENABLE 0x80 +#define REG_CIU_RX_MODE 0x6303 + #define SYMBOL_RX_CRC_ENABLE 0x80 + #define SYMBOL_RX_NO_ERROR 0x08 + #define SYMBOL_RX_MULTIPLE 0x04 +#define REG_CIU_TX_AUTO 0x6305 + #define SYMBOL_FORCE_100_ASK 0x40 + #define SYMBOL_AUTO_WAKE_UP 0x20 + #define SYMBOL_INITIAL_RF_ON 0x04 +#define REG_CIU_MANUAL_RCV 0x630D + #define SYMBOL_PARITY_DISABLE 0x10 +#define REG_CIU_STATUS2 0x6338 + #define SYMBOL_MF_CRYPTO1_ON 0x08 +#define REG_CIU_CONTROL 0x633C + #define SYMBOL_INITIATOR 0x10 + #define SYMBOL_RX_LAST_BITS 0x07 +#define REG_CIU_BIT_FRAMING 0x633D + #define SYMBOL_TX_LAST_BITS 0x07 + +#define PARAM_NONE 0x00 +#define PARAM_NAD_USED 0x01 +#define PARAM_DID_USED 0x02 +#define PARAM_AUTO_ATR_RES 0x04 +#define PARAM_AUTO_RATS 0x10 +#define PARAM_14443_4_PICC 0x20 +#define PARAM_NO_AMBLE 0x40 + +// PN53X configuration +byte pncmd_get_firmware_version [ 2] = { 0xD4,0x02 }; +byte pncmd_get_general_status [ 2] = { 0xD4,0x04 }; +byte pncmd_get_register [ 4] = { 0xD4,0x06 }; +byte pncmd_set_register [ 5] = { 0xD4,0x08 }; +byte pncmd_set_parameters [ 3] = { 0xD4,0x12 }; + +// RF field configuration +byte pncmd_rf_configure_field [ 4] = { 0xD4,0x32,0x01 }; +byte pncmd_rf_configure_timing [ 4] = { 0xD4,0x32,0x02 }; +byte pncmd_rf_configure_retry_data [ 4] = { 0xD4,0x32,0x04 }; +byte pncmd_rf_configure_retry_select [ 6] = { 0xD4,0x32,0x05 }; + +// Reader +byte pncmd_reader_list_passive [264] = { 0xD4,0x4A }; +byte pncmd_reader_select [ 3] = { 0xD4,0x54 }; +byte pncmd_reader_deselect [ 3] = { 0xD4,0x44,0x00 }; +byte pncmd_reader_release [ 3] = { 0xD4,0x52,0x00 }; +byte pncmd_reader_set_baud_rate [ 5] = { 0xD4,0x4E }; +byte pncmd_reader_exchange_data [265] = { 0xD4,0x40 }; +byte pncmd_reader_auto_poll [ 5] = { 0xD4,0x60 }; + +// Target +byte pncmd_target_get_data [ 2] = { 0xD4,0x86 }; +byte pncmd_target_init [ 39] = { 0xD4,0x8C }; +byte pncmd_target_virtual_card [ 4] = { 0xD4,0x14 }; +byte pncmd_target_receive [ 2] = { 0xD4,0x88 }; +byte pncmd_target_send [264] = { 0xD4,0x90 }; +byte pncmd_target_get_status [ 2] = { 0xD4,0x8A }; + +// Exchange raw data frames +byte pncmd_exchange_raw_data [266] = { 0xD4,0x42 }; + +// Global buffers used for communication with the PN53X chip +#define MAX_FRAME_LEN 264 +static byte abtRx[MAX_FRAME_LEN]; +static ui32 uiRxLen; + +bool pn53x_transceive(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen) +{ + // Reset the receiving buffer + uiRxLen = MAX_FRAME_LEN; + + // Call the tranceive callback function of the current device + if (!pdi->pdc->transceive(pdi->ds,pbtTx,uiTxLen,abtRx,&uiRxLen)) return false; + + // Make sure there was no failure reported by the PN53X chip (0x00 == OK) + if (abtRx[0] != 0) return false; + + // Succesful transmission + return true; +} + +byte pn53x_get_reg(const dev_info* pdi, ui16 ui16Reg) +{ + ui8 ui8Value; + ui32 uiValueLen = 1; + pncmd_get_register[2] = ui16Reg >> 8; + pncmd_get_register[3] = ui16Reg & 0xff; + pdi->pdc->transceive(pdi->ds,pncmd_get_register,4,&ui8Value,&uiValueLen); + return ui8Value; +} + +bool pn53x_set_reg(const dev_info* pdi, ui16 ui16Reg, ui8 ui8SybmolMask, ui8 ui8Value) +{ + pncmd_set_register[2] = ui16Reg >> 8; + pncmd_set_register[3] = ui16Reg & 0xff; + pncmd_set_register[4] = ui8Value | (pn53x_get_reg(pdi,ui16Reg) & (~ui8SybmolMask)); + return pdi->pdc->transceive(pdi->ds,pncmd_set_register,5,null,null); +} + +bool pn53x_set_parameters(const dev_info* pdi, ui8 ui8Value) +{ + pncmd_set_parameters[2] = ui8Value; + return pdi->pdc->transceive(pdi->ds,pncmd_set_parameters,3,null,null); +} + +bool pn53x_set_tx_bits(const dev_info* pdi, ui8 ui8Bits) +{ + // Test if we need to update the transmission bits register setting + if (pdi->ui8TxBits != ui8Bits) + { + // Set the amount of transmission bits in the PN53X chip register + if (!pn53x_set_reg(pdi,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,ui8Bits)) return false; + + // Store the new setting + ((dev_info*)pdi)->ui8TxBits = ui8Bits; + } + return true; +} + +bool pn53x_wrap_frame(const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtFrame, ui32* puiFrameBits) +{ + byte btFrame; + byte btData; + ui32 uiBitPos; + ui32 uiDataPos = 0; + ui32 uiBitsLeft = uiTxBits; + + // Make sure we should frame at least something + if (uiBitsLeft == 0) return false; + + // Handle a short response (1byte) as a special case + if (uiBitsLeft < 9) + { + *pbtFrame = *pbtTx; + *puiFrameBits = uiTxBits; + return true; + } + + // We start by calculating the frame length in bits + *puiFrameBits = uiTxBits + (uiTxBits/8); + + // Parse the data bytes and add the parity bits + // This is really a sensitive process, mirror the frame bytes and append parity bits + // buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ... + // split "buffer" up in segments of 8 bits again and mirror them + // air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + .. + while(true) + { + // Reset the temporary frame byte; + btFrame = 0; + + for (uiBitPos=0; uiBitPos<8; uiBitPos++) + { + // Copy as much data that fits in the frame byte + btData = mirror(pbtTx[uiDataPos]); + btFrame |= (btData >> uiBitPos); + // Save this frame byte + *pbtFrame = mirror(btFrame); + // Set the remaining bits of the date in the new frame byte and append the parity bit + btFrame = (btData << (8-uiBitPos)); + btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7-uiBitPos)); + // Backup the frame bits we have so far + pbtFrame++; + *pbtFrame = mirror(btFrame); + // Increase the data (without parity bit) position + uiDataPos++; + // Test if we are done + if (uiBitsLeft < 9) return true; + uiBitsLeft -= 8; + } + // Every 8 data bytes we lose one frame byte to the parities + pbtFrame++; + } +} + +bool pn53x_unwrap_frame(const byte* pbtFrame, const ui32 uiFrameBits, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar) +{ + byte btFrame; + byte btData; + ui8 uiBitPos; + ui32 uiDataPos = 0; + byte* pbtFramePos = (byte*) pbtFrame; + ui32 uiBitsLeft = uiFrameBits; + + // Make sure we should frame at least something + if (uiBitsLeft == 0) return false; + + // Handle a short response (1byte) as a special case + if (uiBitsLeft < 9) + { + *pbtRx = *pbtFrame; + *puiRxBits = uiFrameBits; + return true; + } + + // Calculate the data length in bits + *puiRxBits = uiFrameBits - (uiFrameBits/9); + + // Parse the frame bytes, remove the parity bits and store them in the parity array + // This process is the reverse of WrapFrame(), look there for more info + while(true) + { + for (uiBitPos=0; uiBitPos<8; uiBitPos++) + { + btFrame = mirror(pbtFramePos[uiDataPos]); + btData = (btFrame << uiBitPos); + btFrame = mirror(pbtFramePos[uiDataPos+1]); + btData |= (btFrame >> (8-uiBitPos)); + pbtRx[uiDataPos] = mirror(btData); + if(pbtRxPar != null) pbtRxPar[uiDataPos] = ((btFrame >> (7-uiBitPos)) & 0x01); + // Increase the data (without parity bit) position + uiDataPos++; + // Test if we are done + if (uiBitsLeft < 9) return true; + uiBitsLeft -= 9; + } + // Every 8 data bytes we lose one frame byte to the parities + pbtFramePos++; + } +} + +dev_info* nfc_connect() +{ + dev_info* pdi; + ui32 uiDev; + byte abtFw[4]; + ui32 uiFwLen = sizeof(abtFw); + + // Search through the device list for an available device + for (uiDev=0; uiDevpdc = &(dev_callbacks_list[uiDev]); + pdi->pdc->transceive(pdi->ds,pncmd_get_register,4,null,null); + + // Try to retrieve PN53x chip revision + if (!pdi->pdc->transceive(pdi->ds,pncmd_get_firmware_version,2,abtFw,&uiFwLen)) + { + // Failed to get firmware revision??, whatever...let's disconnect and clean up and return err + pdi->pdc->disconnect(pdi); + return INVALID_DEVICE_INFO; + } + + // Add the firmware revision to the device name, PN531 gives 2 bytes info, but PN532 gives 4 + switch(pdi->ct) + { + case CT_PN531: sprintf(pdi->acName,"%s - PN531 v%d.%d",pdi->acName,abtFw[0],abtFw[1]); break; + case CT_PN532: sprintf(pdi->acName,"%s - PN532 v%d.%d (0x%02x)",pdi->acName,abtFw[1],abtFw[2],abtFw[3]); break; + case CT_PN533: sprintf(pdi->acName,"%s - PN533 v%d.%d (0x%02x)",pdi->acName,abtFw[1],abtFw[2],abtFw[3]); break; + } + + // Reset the ending transmission bits register, it is unknown what the last tranmission used there + if (!pn53x_set_reg(pdi,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,0x00)) return INVALID_DEVICE_INFO; + + // Make sure we reset the CRC and parity to chip handling. + if (!nfc_configure(pdi,DCO_HANDLE_CRC,true)) return INVALID_DEVICE_INFO; + if (!nfc_configure(pdi,DCO_HANDLE_PARITY,true)) return INVALID_DEVICE_INFO; + + // Deactivate the CRYPTO1 chiper, it may could cause problems when still active + if (!nfc_configure(pdi,DCO_ACTIVATE_CRYPTO1,false)) return INVALID_DEVICE_INFO; + + return pdi; + } + } + + // To bad, no reader is ready to be claimed + return INVALID_DEVICE_INFO; +} + +void nfc_disconnect(dev_info* pdi) +{ + // Disconnect, clean up and release the device + pdi->pdc->disconnect(pdi); +} + +bool nfc_configure(dev_info* pdi, const dev_config_option dco, const bool bEnable) +{ + byte btValue; + + // Make sure we are dealing with a active device + if (!pdi->bActive) return false; + + switch(dco) + { + case DCO_HANDLE_CRC: + // Enable or disable automatic receiving/sending of CRC bytes + // TX and RX are both represented by the symbol 0x80 + btValue = (bEnable) ? 0x80 : 0x00; + if (!pn53x_set_reg(pdi,REG_CIU_TX_MODE,SYMBOL_TX_CRC_ENABLE,btValue)) return false; + if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_CRC_ENABLE,btValue)) return false; + pdi->bCrc = bEnable; + break; + + case DCO_HANDLE_PARITY: + // Handle parity bit by PN53X chip or parse it as data bit + btValue = (bEnable) ? 0x00 : SYMBOL_PARITY_DISABLE; + if (!pn53x_set_reg(pdi,REG_CIU_MANUAL_RCV,SYMBOL_PARITY_DISABLE,btValue)) return false; + pdi->bPar = bEnable; + break; + + case DCO_ACTIVATE_FIELD: + pncmd_rf_configure_field[3] = (bEnable) ? 1 : 0; + if (!pdi->pdc->transceive(pdi->ds,pncmd_rf_configure_field,4,null,null)) return false; + break; + + case DCO_ACTIVATE_CRYPTO1: + btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00; + if (!pn53x_set_reg(pdi,REG_CIU_STATUS2,SYMBOL_MF_CRYPTO1_ON,btValue)) return false; + break; + + case DCO_INFINITE_SELECT: + // Retry format: 0x00 means only 1 try, 0xff means infinite + pncmd_rf_configure_retry_select[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02 + pncmd_rf_configure_retry_select[4] = (bEnable) ? 0xff : 0x00; // MxRtyPSL, default: 0x01 + pncmd_rf_configure_retry_select[5] = (bEnable) ? 0xff : 0x00; // MxRtyPassiveActivation, default: 0xff + if(!pdi->pdc->transceive(pdi->ds,pncmd_rf_configure_retry_select,6,null,null)) return false; + break; + + case DCO_ACCEPT_INVALID_FRAMES: + btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00; + if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_NO_ERROR,btValue)) return false; + break; + + case DCO_ACCEPT_MULTIPLE_FRAMES: + btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00; + if (!pn53x_set_reg(pdi,REG_CIU_RX_MODE,SYMBOL_RX_MULTIPLE,btValue)) return false; + return true; + + break; + } + + // When we reach this, the configuration is completed and succesful + return true; +} + +bool nfc_reader_init(const dev_info* pdi) +{ + // Make sure we are dealing with a active device + if (!pdi->bActive) return false; + + // Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards) + if (!pn53x_set_reg(pdi,REG_CIU_TX_AUTO,SYMBOL_FORCE_100_ASK,0x40)) return false; + + // Configure the PN53X to be an Initiator or Reader/Writer + if (!pn53x_set_reg(pdi,REG_CIU_CONTROL,SYMBOL_INITIATOR,0x10)) return false; + + return true; +} + +bool nfc_reader_select(const dev_info* pdi, const init_modulation im, const byte* pbtInitData, const ui32 uiInitDataLen, tag_info* pti) +{ + // Make sure we are dealing with a active device + if (!pdi->bActive) return false; + + pncmd_reader_list_passive[2] = 1; // MaxTg, we only want to select 1 tag at the time + pncmd_reader_list_passive[3] = im; // BrTy, the type of init modulation used for polling a passive tag + + // Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID). + if (pbtInitData) memcpy(pncmd_reader_list_passive+4,pbtInitData,uiInitDataLen); + + // Try to find a tag, call the tranceive callback function of the current device + uiRxLen = MAX_FRAME_LEN; + if (!pdi->pdc->transceive(pdi->ds,pncmd_reader_list_passive,4+uiInitDataLen,abtRx,&uiRxLen)) return false; + + // Make sure one tag has been found, the PN53X returns 0x00 if none was available + if (abtRx[0] != 1) return false; + + // Is a tag info struct available + if (pti) + { + // Fill the tag info struct with the values corresponding to this init modulation + switch(im) + { + case IM_ISO14443A_106: + // Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset + if (pdi->ct == CT_PN531) + { + pti->tia.abtAtqa[0] = abtRx[3]; + pti->tia.abtAtqa[1] = abtRx[2]; + } else { + memcpy(pti->tia.abtAtqa,abtRx+2,2); + } + pti->tia.btSak = abtRx[4]; + // Copy the NFCID1 + pti->tia.uiUidLen = abtRx[5]; + memcpy(pti->tia.abtUid,abtRx+6,pti->tia.uiUidLen); + // Did we received an optional ATS (Smardcard ATR) + if (uiRxLen > pti->tia.uiUidLen+6) + { + pti->tia.uiAtsLen = abtRx[pti->tia.uiUidLen+6]; + memcpy(pti->tia.abtAts,abtRx+pti->tia.uiUidLen+6,pti->tia.uiAtsLen); + } else { + pti->tia.uiAtsLen = 0; + } + break; + + case IM_FELICA_212: + case IM_FELICA_424: + // Store the mandatory info + pti->tif.uiLen = abtRx[2]; + pti->tif.btResCode = abtRx[3]; + // Copy the NFCID2t + memcpy(pti->tif.abtId,abtRx+4,8); + // Copy the felica padding + memcpy(pti->tif.abtPad,abtRx+12,8); + // Test if the System code (SYST_CODE) is available + if (uiRxLen > 20) + { + memcpy(pti->tif.abtSysCode,abtRx+20,2); + } + break; + + case IM_ISO14443B_106: + // Store the mandatory info + memcpy(pti->tib.abtAtqb,abtRx+2,12); + // Ignore the 0x1D byte, and just store the 4 byte id + memcpy(pti->tib.abtId,abtRx+15,4); + pti->tib.btParam1 = abtRx[19]; + pti->tib.btParam2 = abtRx[20]; + pti->tib.btParam3 = abtRx[21]; + pti->tib.btParam4 = abtRx[22]; + // Test if the Higher layer (INF) is available + if (uiRxLen > 22) + { + pti->tib.uiInfLen = abtRx[23]; + memcpy(pti->tib.abtInf,abtRx+24,pti->tib.uiInfLen); + } else { + pti->tib.uiInfLen = 0; + } + break; + + case IM_JEWEL_106: + // Store the mandatory info + memcpy(pti->tij.btSensRes,abtRx+2,2); + memcpy(pti->tij.btId,abtRx+4,4); + break; + + default: + // Should not be possible, so whatever... + break; + } + } + return true; +} + +bool nfc_reader_deselect(const dev_info* pdi) +{ + return (pdi->pdc->transceive(pdi->ds,pncmd_reader_deselect,3,null,null)); +} + +bool nfc_reader_transceive_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar) +{ + ui32 uiFrameBits = 0; + ui32 uiFrameBytes = 0; + ui8 ui8Bits = 0; + + // Check if we should prepare the parity bits ourself + if (!pdi->bPar) + { + // Convert data with parity to a frame + pn53x_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_exchange_raw_data+2,&uiFrameBits); + } else { + uiFrameBits = uiTxBits; + } + + // Retrieve the leading bits + ui8Bits = uiFrameBits%8; + + // Get the amount of frame bytes + optional (1 byte if there are leading bits) + uiFrameBytes = (uiFrameBits/8)+((ui8Bits==0)?0:1); + + // When the parity is handled before us, we just copy the data + if (pdi->bPar) memcpy(pncmd_exchange_raw_data+2,pbtTx,uiFrameBytes); + + // Set the amount of transmission bits in the PN53X chip register + if (!pn53x_set_tx_bits(pdi,ui8Bits)) return false; + + // Send the frame to the PN53X chip and get the answer + // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42) + if (!pn53x_transceive(pdi,pncmd_exchange_raw_data,uiFrameBytes+2)) return false; + + // Get the last bit-count that is stored in the received byte + ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS; + + // Recover the real frame length in bits + uiFrameBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits; + + // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive() + // Check if we should recover the parity bits ourself + if (!pdi->bPar) + { + // Unwrap the response frame + pn53x_unwrap_frame(abtRx+1,uiFrameBits,pbtRx,puiRxBits,pbtRxPar); + } else { + // Save the received bits + *puiRxBits = uiFrameBits; + // Copy the received bytes + memcpy(pbtRx,abtRx+1,uiRxLen-1); + } + + // Everything went successful + return true; +} + +bool nfc_reader_transceive_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen) +{ + // We can not just send bytes without parity if while the PN53X expects we handled them + if (!pdi->bPar) return false; + + // Copy the data into the command frame + memcpy(pncmd_exchange_raw_data+2,pbtTx,uiTxLen); + + // To transfer command frames bytes we can not have any leading bits, reset this to zero + if (!pn53x_set_tx_bits(pdi,0)) return false; + + // Send the frame to the PN53X chip and get the answer + // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42) + if (!pn53x_transceive(pdi,pncmd_exchange_raw_data,uiTxLen+2)) return false; + + // Save the received byte count + *puiRxLen = uiRxLen-1; + + // Copy the received bytes + memcpy(pbtRx,abtRx+1,*puiRxLen); + + // Everything went successful + return true; +} + +bool nfc_reader_mifare_cmd(const dev_info* pdi, const mifare_cmd mc, const ui8 ui8Block, mifare_param* pmp) +{ + ui32 uiParamLen; + + // Make sure we are dealing with a active device + if (!pdi->bActive) return false; + + pncmd_reader_exchange_data[2] = 0x01; // Use first target/card + pncmd_reader_exchange_data[3] = mc; // The MIFARE Classic command + pncmd_reader_exchange_data[4] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff) + + switch (mc) + { + // Read and store command have no parameter + case MC_READ: + case MC_STORE: + uiParamLen = 0; + break; + + // Authenticate command + case MC_AUTH_A: + case MC_AUTH_B: + uiParamLen = sizeof(mifare_param_auth); + break; + + // Data command + case MC_WRITE: + uiParamLen = sizeof(mifare_param_data); + break; + + // Value command + case MC_DECREMENT: + case MC_INCREMENT: + case MC_TRANSFER: + uiParamLen = sizeof(mifare_param_value); + break; + + // Please fix your code, you never should reach this statement + default: + return false; + break; + } + + // When available, copy the parameter bytes + if (uiParamLen) memcpy(pncmd_reader_exchange_data+5,(byte*)pmp,uiParamLen); + + // Fire the mifare command + if (!pn53x_transceive(pdi,pncmd_reader_exchange_data,5+uiParamLen)) return false; + + // When we have executed a read command, copy the received bytes into the param + if (mc == MC_READ) memcpy(pmp->mpd.abtData,abtRx+1,16); + + // Command succesfully executed + return true; +} + +bool nfc_target_init(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits) +{ + ui8 ui8Bits; + + // Save the current configuration settings + bool bCrc = pdi->bCrc; + bool bPar = pdi->bPar; + + // Clear the target init struct, reset to all zeros + memset(pncmd_target_init+2,0x00,37); + + // Set ATQA (SENS_RES) + pncmd_target_init[3] = 0x04; + pncmd_target_init[4] = 0x00; + + // Set SAK (SEL_RES) + pncmd_target_init[8] = 0x20; + + // Set UID + pncmd_target_init[5] = 0x00; + pncmd_target_init[6] = 0xb0; + pncmd_target_init[7] = 0x0b; + + // Make sure the CRC & parity are handled by the device, this is needed for target_init to work properly + if (!bCrc) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,true); + if (!bPar) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,true); + + // Let the PN53X be activated by the RF level detector from power down mode + if (!pn53x_set_reg(pdi,REG_CIU_TX_AUTO, SYMBOL_INITIAL_RF_ON,0x04)) return false; + + // Request the initialization as a target, we can not use pn53x_transceive() because + // abtRx[0] contains the emulation mode (baudrate, 14443-4?, DEP and framing type) + uiRxLen = MAX_FRAME_LEN; + if (!pdi->pdc->transceive(pdi->ds,pncmd_target_init,39,abtRx,&uiRxLen)) return false; + + // Get the last bit-count that is stored in the received byte + ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS; + + // We are sure the parity is handled by the PN53X chip, so we handle it this way + *puiRxBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits; + // Copy the received bytes + memcpy(pbtRx,abtRx+1,uiRxLen-1); + + // Restore the CRC & parity setting to the original value (if needed) + if (!bCrc) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,false); + if (!bPar) nfc_configure((dev_info*)pdi,DCO_HANDLE_CRC,false); + + return true; +} + +bool nfc_target_receive_bits(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar) +{ + ui32 uiFrameBits; + ui8 ui8Bits; + + // Try to gather a received frame from the reader + if (!pn53x_transceive(pdi,pncmd_target_receive,2)) return false; + + // Get the last bit-count that is stored in the received byte + ui8Bits = pn53x_get_reg(pdi,REG_CIU_CONTROL) & SYMBOL_RX_LAST_BITS; + + // Recover the real frame length in bits + uiFrameBits = ((uiRxLen-1-((ui8Bits==0)?0:1))*8)+ui8Bits; + + // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive() + // Check if we should recover the parity bits ourself + if (!pdi->bPar) + { + // Unwrap the response frame + pn53x_unwrap_frame(abtRx+1,uiFrameBits,pbtRx,puiRxBits,pbtRxPar); + } else { + // Save the received bits + *puiRxBits = uiFrameBits; + // Copy the received bytes + memcpy(pbtRx,abtRx+1,uiRxLen-1); + } + // Everyting seems ok, return true + return true; +} + +bool nfc_target_receive_bytes(const dev_info* pdi, byte* pbtRx, ui32* puiRxLen) +{ + // Try to gather a received frame from the reader + if (!pn53x_transceive(pdi,pncmd_target_receive,2)) return false; + + // Save the received byte count + *puiRxLen = uiRxLen-1; + + // Copy the received bytes + memcpy(pbtRx,abtRx+1,*puiRxLen); + + // Everyting seems ok, return true + return true; +} + +bool nfc_target_send_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar) +{ + ui32 uiFrameBits = 0; + ui32 uiFrameBytes = 0; + ui8 ui8Bits = 0; + + // Check if we should prepare the parity bits ourself + if (!pdi->bPar) + { + // Convert data with parity to a frame + pn53x_wrap_frame(pbtTx,uiTxBits,pbtTxPar,pncmd_target_send+2,&uiFrameBits); + } else { + uiFrameBits = uiTxBits; + } + + // Retrieve the leading bits + ui8Bits = uiFrameBits%8; + + // Get the amount of frame bytes + optional (1 byte if there are leading bits) + uiFrameBytes = (uiFrameBits/8)+((ui8Bits==0)?0:1); + + // When the parity is handled before us, we just copy the data + if (pdi->bPar) memcpy(pncmd_target_send+2,pbtTx,uiFrameBytes); + + // Set the amount of transmission bits in the PN53X chip register + if (!pn53x_set_tx_bits(pdi,ui8Bits)) return false; + + // Try to send the bits to the reader + if (!pn53x_transceive(pdi,pncmd_target_send,uiFrameBytes+2)) return false; + + // Everyting seems ok, return true + return true; +} + + +bool nfc_target_send_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen) +{ + // We can not just send bytes without parity if while the PN53X expects we handled them + if (!pdi->bPar) return false; + + // Copy the data into the command frame + memcpy(pncmd_target_send+2,pbtTx,uiTxLen); + + // Try to send the bits to the reader + if (!pn53x_transceive(pdi,pncmd_target_send,uiTxLen+2)) return false; + + // Everyting seems ok, return true + return true; +} diff --git a/libnfc.h b/libnfc.h index ba8802a..f122137 100644 --- a/libnfc.h +++ b/libnfc.h @@ -1,50 +1,47 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + #ifndef _LIBNFC_H_ #define _LIBNFC_H_ #include "defines.h" #include "types.h" #include "bitutils.h" -#include "acr122.h" +#include "devices.h" -bool nfc_configure_handle_crc(const dev_id di, const bool bEnable); -bool nfc_configure_handle_parity(const dev_id di, const bool bEnable); -bool nfc_configure_field(const dev_id di, const bool bEnable); -bool nfc_configure_list_passive_infinite(const dev_id di, const bool bEnable); -bool nfc_configure_accept_invalid_frames(const dev_id di, const bool bEnable); -bool nfc_configure_accept_multiple_frames(const dev_id di, const bool bEnable); +dev_info* nfc_connect(); +void nfc_disconnect(dev_info* pdi); +bool nfc_configure(dev_info* pdi, const dev_config_option dco, const bool bEnable); -bool nfc_reader_init(const dev_id di); -bool nfc_reader_list_passive(const dev_id di, const ModulationType mt, const byte* pbtInitData, const ui32 uiInitDataLen, byte* pbtTag, ui32* puiTagLen); -bool nfc_reader_transceive_7bits(const dev_id di, const byte btTx, byte* pbtRx, ui32* puiRxLen); -bool nfc_reader_transceive_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen); -bool nfc_reader_transceive_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar); -bool nfc_reader_mifare_cmd(const dev_id di, const MifareCmd mc, const ui8 ui8Block, MifareParam* pmp); +bool nfc_reader_init(const dev_info* pdi); +bool nfc_reader_select(const dev_info* pdi, const init_modulation im, const byte* pbtInitData, const ui32 uiInitDataLen, tag_info* pti); +bool nfc_reader_deselect(const dev_info* pdi); +bool nfc_reader_transceive_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar); +bool nfc_reader_transceive_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen); +bool nfc_reader_mifare_cmd(const dev_info* pdi, const mifare_cmd mc, const ui8 ui8Block, mifare_param* pmp); -bool nfc_target_init(const dev_id di, byte* pbtRx, ui32* puiRxLen); -bool nfc_target_receive_bytes(const dev_id di, byte* pbtRx, ui32* puiRxLen); -bool nfc_target_receive_bits(const dev_id di, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar); -bool nfc_target_send_bytes(const dev_id di, const byte* pbtTx, const ui32 uiTxLen); -bool nfc_target_send_bits(const dev_id di, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar); +bool nfc_target_init(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits); +bool nfc_target_receive_bits(const dev_info* pdi, byte* pbtRx, ui32* puiRxBits, byte* pbtRxPar); +bool nfc_target_receive_bytes(const dev_info* pdi, byte* pbtRx, ui32* puiRxLen); +bool nfc_target_send_bits(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxBits, const byte* pbtTxPar); +bool nfc_target_send_bytes(const dev_info* pdi, const byte* pbtTx, const ui32 uiTxLen); #endif // _LIBNFC_H_ diff --git a/list.c b/list.c index 7cb111b..be02e9b 100644 --- a/list.c +++ b/list.c @@ -23,61 +23,74 @@ along with this program. If not, see . #include #include "libnfc.h" -static byte abtRecv[MAX_FRAME_LEN]; -static ui32 uiRecvLen; -static dev_id di; +static dev_info* pdi; +static byte abtFelica[5] = { 0x00, 0xff, 0xff, 0x00, 0x00 }; int main(int argc, const char* argv[]) { + tag_info ti; + // Try to open the NFC reader - di = acr122_connect(0); + pdi = nfc_connect(); - if (di == INVALID_DEVICE_ID) + if (pdi == INVALID_DEVICE_INFO) { printf("Error connecting NFC reader\n"); return 1; } - nfc_reader_init(di); + nfc_reader_init(pdi); + + // Drop the field for a while + nfc_configure(pdi,DCO_ACTIVATE_FIELD,false); // Let the reader only try once to find a tag - nfc_configure_list_passive_infinite(di,false); + nfc_configure(pdi,DCO_INFINITE_SELECT,false); - // Drop the field so the tag will be reset - nfc_configure_field(di,false); + // Configure the CRC and Parity settings + nfc_configure(pdi,DCO_HANDLE_CRC,true); + nfc_configure(pdi,DCO_HANDLE_PARITY,true); - // Configure the communication channel - nfc_configure_handle_crc(di,true); - nfc_configure_handle_parity(di,true); + // Enable field so more power consuming cards can power themselves up + nfc_configure(pdi,DCO_ACTIVATE_FIELD,true); - printf("\nConnected to NFC reader\n\n"); - - uiRecvLen = MAX_FRAME_LEN; - if (nfc_reader_list_passive(di,MT_ISO14443A_106,null,null,abtRecv,&uiRecvLen)) + printf("\nConnected to NFC reader: %s\n\n",pdi->acName); + + // Poll for a ISO14443A (MIFARE) tag + if (nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti)) { - // ISO14443A tag info = ( tag_count[1], tag_nr[1], ATQA[2], SAK[1], uid_len[1], UID[uid_len], ats_len[1], ATS[ats_len-1] ) - // ATS is optional printf("The following (NFC) ISO14443A tag was found:\n\n"); - printf("%17s","ATQA (SENS_RES): "); - print_hex(abtRecv+2,2); - printf("%17s","UID (NFCID1): "); - print_hex(abtRecv+6,abtRecv[5]); - printf("%17s","SAK (SEL_RES): "); - print_hex(abtRecv+4,1); - if (uiRecvLen > 6+(ui32)abtRecv[5]) + printf(" ATQA (SENS_RES): "); print_hex(ti.tia.abtAtqa,2); + printf(" UID (NFCID%c): ",(ti.tia.abtUid[0]==0x08?'3':'1')); print_hex(ti.tia.abtUid,ti.tia.uiUidLen); + printf(" SAK (SEL_RES): "); print_hex(&ti.tia.btSak,1); + if (ti.tia.uiAtsLen) { - printf("%17s","ATS (ATR): "); - print_hex(abtRecv+6+abtRecv[5]+1,abtRecv[6+abtRecv[5]]-1); + printf(" ATS (ATR): "); + print_hex(ti.tia.abtAts,ti.tia.uiAtsLen); } - } else { - printf("Error: no tag was found\n"); } - // Todo: listing the folllowing tags types - // - // MT_FELICA_212 - // MT_FELICA_424 - // MT_ISO14443B_106 - // MT_TOPAZ_106 + // Poll for a Felica tag + if (nfc_reader_select(pdi,IM_FELICA_212,abtFelica,5,&ti) || nfc_reader_select(pdi,IM_FELICA_424,abtFelica,5,&ti)) + { + printf("The following (NFC) Felica tag was found:\n\n"); + printf("%18s","ID (NFCID2): "); print_hex(ti.tif.abtId,8); + printf("%18s","Parameter (PAD): "); print_hex(ti.tif.abtPad,8); + } - return 0; + // Poll for a ISO14443B tag + if (nfc_reader_select(pdi,IM_ISO14443B_106,null,null,&ti)) + { + // No test results yet + printf("iso14443b\n"); + } + + // Poll for a Jewel tag + if (nfc_reader_select(pdi,IM_JEWEL_106,null,null,&ti)) + { + // No test results yet + printf("jewel\n"); + } + + nfc_disconnect(pdi); + return 1; } diff --git a/mifaretag.h b/mifaretag.h index f6bc772..b07e43d 100644 --- a/mifaretag.h +++ b/mifaretag.h @@ -1,54 +1,54 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - -#ifndef _MIFARE_TAG_H_ -#define _MIFARE_TAG_H_ +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + +#ifndef _LIBNFC_MIFARE_TAG_H_ +#define _LIBNFC_MIFARE_TAG_H_ #include "defines.h" -typedef struct tagBlockManufacturer { +typedef struct { byte abtUID[4]; byte btBCC; byte btUnknown; byte abtATQA[2]; byte abtUnknown[8]; -} BlockManufacturer; +} mifare_block_manufacturer; -typedef struct tagBlockData { - byte abtContent[16]; -} BlockData; +typedef struct { + byte abtData[16]; +} mifare_block_data; -typedef struct tagBlockTrailer { +typedef struct { byte abtKeyA[6]; byte abtAccessBits[4]; byte abtKeyB[6]; -} BlockTrailer; +} mifare_block_trailer; -typedef union tagBlock { - BlockManufacturer bm; - BlockData bd; - BlockTrailer bt; -} Block; +typedef union { + mifare_block_manufacturer mbm; + mifare_block_data mbd; + mifare_block_trailer mbt; +} mifare_block; -typedef struct tagMifareTag { - Block blContent[256]; -} MifareTag; +typedef struct { + mifare_block amb[256]; +} mifare_tag; -#endif // _MIFARE_TAG_H_ +#endif // _LIBNFC_MIFARE_TAG_H_ diff --git a/relay.c b/relay.c index f6295bd..65c1566 100644 --- a/relay.c +++ b/relay.c @@ -1,107 +1,99 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - -#include -#include -#include -#include "libnfc.h" - -static byte abtReaderRecv[MAX_FRAME_LEN]; -static byte abtReaderRecvPar[MAX_FRAME_LEN]; -static ui32 uiReaderRecvBits; -static byte abtTagRecv[MAX_FRAME_LEN]; -static byte abtTagRecvPar[MAX_FRAME_LEN]; -static ui32 uiTagRecvBits; -static dev_id diReader; -static dev_id diTag; - -int main(int argc, const char* argv[]) -{ - // Try to open the NFC reader - diReader = acr122_connect(0); - if (diReader == INVALID_DEVICE_ID) - { - printf("Error connecting first NFC reader\n"); - return 1; - } - - diTag = acr122_connect(1); - if (diTag == INVALID_DEVICE_ID) - { - printf("Error connecting second NFC reader\n"); - return 1; - } - - printf("\n"); - printf("[+] Connected to the both NFC readers\n"); - acr122_led_red(diTag,true); - printf("[+] Identified simulated tag by setting the red light\n"); - printf("[+] Place both readers on top of each other\n"); - printf("[+] Please run 'anticol' tool in a different shell\n"); - nfc_target_init(diTag,abtReaderRecv,&uiReaderRecvBits); - nfc_configure_handle_crc(diTag,false); - nfc_configure_handle_parity(diTag,false); - nfc_configure_accept_invalid_frames(diTag,true); - printf("[+] Thank you, the simulated tag is initialized\n"); - - printf("[+] Attaching to first NFC reader \n"); - // Retry until it becomes ready - while (!nfc_reader_init(diReader)) - { - acr122_disconnect(diReader); - printf("error\n"); - diReader = acr122_connect(0); - } - nfc_configure_handle_crc(diReader,false); - nfc_configure_handle_parity(diReader,false); - nfc_configure_accept_invalid_frames(diReader,true); - printf("[+] Done, relaying frames now!\n\n"); - - while(true) - { - // Test if we received a frame from the reader - if (nfc_target_receive_bits(diTag,abtReaderRecv,&uiReaderRecvBits,abtReaderRecvPar)) - { - // Drop down the field before sending a REQA command and start a new session - if (uiReaderRecvBits == 7 && abtReaderRecv[0] == 0x26) - { - // Drop down field for a very short time (tag will reboot) - nfc_configure_field(diReader,false); - printf("\n"); - nfc_configure_field(diReader,true); - } - - // Print the reader frame to the screen - printf("R: "); - print_hex_par(abtReaderRecv,uiReaderRecvBits,abtReaderRecvPar); - - // Forward the frame to the original tag - if (nfc_reader_transceive_bits(diReader,abtReaderRecv,uiReaderRecvBits,abtReaderRecvPar,abtTagRecv,&uiTagRecvBits,abtTagRecvPar)) - { - // Redirect the answer back to the reader - nfc_target_send_bits(diTag,abtTagRecv,uiTagRecvBits,abtTagRecvPar); - - // Print the tag frame to the screen - printf("T: "); - print_hex_par(abtTagRecv,uiTagRecvBits,abtTagRecvPar); - } - } - } -} +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + +#include +#include +#include +#include "libnfc.h" + +static byte abtReaderRx[MAX_FRAME_LEN]; +static byte abtReaderRxPar[MAX_FRAME_LEN]; +static ui32 uiReaderRxBits; +static byte abtTagRx[MAX_FRAME_LEN]; +static byte abtTagRxPar[MAX_FRAME_LEN]; +static ui32 uiTagRxBits; +static dev_info* pdiReader; +static dev_info* pdiTag; + +int main(int argc, const char* argv[]) +{ + // Try to open the NFC emulator device + pdiTag = nfc_connect(); + if (pdiTag == INVALID_DEVICE_INFO) + { + printf("Error connecting NFC emulator device\n"); + return 1; + } + + printf("\n"); + printf("[+] Connected to the NFC emulator device\n"); + printf("[+] Try to break out the auto-simulation, this requires a second reader!\n"); + printf("[+] To do this, please send any command after the anti-collision\n"); + printf("[+] For example, send a RATS command or use the \"anticol\" tool\n"); + nfc_target_init(pdiTag,abtReaderRx,&uiReaderRxBits); + printf("[+] Configuring emulator settings\n"); + nfc_configure(pdiTag,DCO_HANDLE_CRC,false); + nfc_configure(pdiTag,DCO_HANDLE_PARITY,false); + nfc_configure(pdiTag,DCO_ACCEPT_INVALID_FRAMES,true); + printf("[+] Thank you, the emulated tag is initialized\n"); + + // Try to open the NFC reader + pdiReader = INVALID_DEVICE_INFO; + while (pdiReader == INVALID_DEVICE_INFO) pdiReader = nfc_connect(); + printf("[+] Configuring NFC reader settings\n"); + nfc_configure(pdiReader,DCO_HANDLE_CRC,false); + nfc_configure(pdiReader,DCO_HANDLE_PARITY,false); + nfc_configure(pdiReader,DCO_ACCEPT_INVALID_FRAMES,true); + printf("[+] Done, relaying frames now!\n\n"); + + while(true) + { + // Test if we received a frame from the reader + if (nfc_target_receive_bits(pdiTag,abtReaderRx,&uiReaderRxBits,abtReaderRxPar)) + { + // Drop down the field before sending a REQA command and start a new session + if (uiReaderRxBits == 7 && abtReaderRx[0] == 0x26) + { + // Drop down field for a very short time (original tag will reboot) + nfc_configure(pdiReader,DCO_ACTIVATE_FIELD,false); + printf("\n"); + nfc_configure(pdiReader,DCO_ACTIVATE_FIELD,true); + } + + // Print the reader frame to the screen + printf("R: "); + print_hex_par(abtReaderRx,uiReaderRxBits,abtReaderRxPar); + + // Forward the frame to the original tag + if (nfc_reader_transceive_bits(pdiReader,abtReaderRx,uiReaderRxBits,abtReaderRxPar,abtTagRx,&uiTagRxBits,abtTagRxPar)) + { + // Redirect the answer back to the reader + nfc_target_send_bits(pdiTag,abtTagRx,uiTagRxBits,abtTagRxPar); + + // Print the tag frame to the screen + printf("T: "); + print_hex_par(abtTagRx,uiTagRxBits,abtTagRxPar); + } + } + } + + nfc_disconnect(pdiTag); + nfc_disconnect(pdiReader); +} diff --git a/simulate.c b/simulate.c index ad522a1..d8cf0eb 100644 --- a/simulate.c +++ b/simulate.c @@ -1,108 +1,111 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - -#include -#include -#include -#include "libnfc.h" - -static byte abtRecv[MAX_FRAME_LEN]; -static ui32 uiRecvLen; -static dev_id di; - -// ISO14443A Anti-Collision response -byte abtAtqa [2] = { 0x04,0x00 }; -byte abtUidBcc [5] = { 0xDE,0xAD,0xBE,0xAF,0x62 }; -byte abtSak [9] = { 0x08,0xb6,0xdd }; - -int main(int argc, const char* argv[]) -{ - byte* pbtTx; - ui32 uiTxLen; - - // Try to open the NFC reader - di = acr122_connect(0); - - if (di == INVALID_DEVICE_ID) - { - printf("Error connecting NFC reader\n"); - return 1; - } - - printf("\n"); - printf("[+] Connected to NFC target\n"); - acr122_led_red(di,true); - printf("[+] Identified simulated tag by setting the red light\n"); - printf("[+] First we have to come out auto-simulation\n"); - printf("[+] To do this, please send any command after the\n"); - printf("[+] anti-collision, for example, the RATS command\n\n"); - nfc_target_init(di,abtRecv,&uiRecvLen); - printf("[+] Initiator command: "); - print_hex(abtRecv,uiRecvLen); - printf("[+] Configuring communication"); - nfc_configure_accept_invalid_frames(di,true); - nfc_configure_handle_crc(di,false); - printf("[+] Done, the simulated tag is initialized \n"); - - - while(true) - { - // Test if we received a frame - if (nfc_target_receive_bytes(di,abtRecv,&uiRecvLen)) - { - // Prepare the command to send back for the anti-collision request - switch(uiRecvLen) - { - case 1: // Request or Wakeup - pbtTx = abtAtqa; - uiTxLen = 2; - // New anti-collsion session started - printf("\n"); - break; - - case 2: // Select All - pbtTx = abtUidBcc; - uiTxLen = 5; - break; - - case 9: // Select Tag - pbtTx = abtSak; - uiTxLen = 3; - break; - - default: // unknown length? - uiTxLen = 0; - break; - } - - printf("R: "); - print_hex(abtRecv,uiRecvLen); - - // Test if we know how to respond - if(uiTxLen) - { - // Send and print the command to the screen - nfc_target_send_bytes(di,pbtTx,uiTxLen); - printf("T: "); - print_hex(pbtTx,uiTxLen); - } - } - } -} +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + +#include +#include +#include +#include "libnfc.h" + +static byte abtRecv[MAX_FRAME_LEN]; +static ui32 uiRecvBits; +static dev_info* pdi; + +// ISO14443A Anti-Collision response +byte abtAtqa [2] = { 0x04,0x00 }; +byte abtUidBcc [5] = { 0xDE,0xAD,0xBE,0xAF,0x62 }; +byte abtSak [9] = { 0x08,0xb6,0xdd }; + +int main(int argc, const char* argv[]) +{ + byte* pbtTx = null; + ui32 uiTxBits; + + // Try to open the NFC reader + pdi = nfc_connect(); + + if (pdi == INVALID_DEVICE_INFO) + { + printf("Error connecting NFC second reader\n"); + return 1; + } + + printf("\n"); + printf("[+] Connected to NFC reader: %s\n",pdi->acName); + printf("[+] Try to break out the auto-simulation, this requires a second reader!\n"); + printf("[+] To do this, please send any command after the anti-collision\n"); + printf("[+] For example, send a RATS command or use the \"anticol\" tool\n"); + if (!nfc_target_init(pdi,abtRecv,&uiRecvBits)) + { + printf("Error: Could not come out of auto-simulation, no command was received\n"); + return 1; + } + printf("[+] Received initiator command: "); + print_hex_bits(abtRecv,uiRecvBits); + printf("[+] Configuring communication\n"); + nfc_configure(pdi,DCO_HANDLE_CRC,false); + nfc_configure(pdi,DCO_HANDLE_PARITY,true); + printf("[+] Done, the simulated tag is initialized\n\n"); + + while(true) + { + // Test if we received a frame + if (nfc_target_receive_bits(pdi,abtRecv,&uiRecvBits,null)) + { + // Prepare the command to send back for the anti-collision request + switch(uiRecvBits) + { + case 7: // Request or Wakeup + pbtTx = abtAtqa; + uiTxBits = 16; + // New anti-collsion session started + printf("\n"); + break; + + case 16: // Select All + pbtTx = abtUidBcc; + uiTxBits = 40; + break; + + case 72: // Select Tag + pbtTx = abtSak; + uiTxBits = 24; + break; + + default: // unknown length? + uiTxBits = 0; + break; + } + + printf("R: "); + print_hex_bits(abtRecv,uiRecvBits); + + // Test if we know how to respond + if(uiTxBits) + { + // Send and print the command to the screen + nfc_target_send_bits(pdi,pbtTx,uiTxBits,null); + printf("T: "); + print_hex_bits(pbtTx,uiTxBits); + } + } + } + + nfc_disconnect(pdi); +} diff --git a/types.h b/types.h index cba978e..ab3c02d 100644 --- a/types.h +++ b/types.h @@ -1,40 +1,126 @@ -/* - -Public platform independent Near Field Communication (NFC) library -Copyright (C) 2009, Roel Verdult - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU 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 General Public License -along with this program. If not, see . - -*/ - +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License +along with this program. If not, see . + +*/ + #ifndef _LIBNFC_TYPES_H_ #define _LIBNFC_TYPES_H_ #include "defines.h" -typedef enum { - false = 0x00, - true = 0x01 -}bool; +// Compiler directive, set struct alignment to 1 byte for compatibility +#pragma pack(1) typedef enum { - MT_ISO14443A_106 = 0x00, - MT_FELICA_212 = 0x01, - MT_FELICA_424 = 0x02, - MT_ISO14443B_106 = 0x03, - MT_TOPAZ_106 = 0x04, -}ModulationType; + false = 0x00, + true = 0x01 +} bool; + +typedef enum { + CT_PN531 = 0x10, + CT_PN532 = 0x20, + CT_PN533 = 0x30, +} chip_type; + +struct dev_callbacks; // Prototype the callback struct + +typedef struct { + const struct dev_callbacks* pdc; // Callback functions for handling device specific wrapping + char acName[DEVICE_NAME_LENGTH]; // Device name string, including device wrapper firmware + chip_type ct; // PN53X chip type, this is useful for some "bug" work-arounds + dev_spec ds; // Pointer to the device connection specification + bool bActive; // This represents if the PN53X device was initialized succesful + bool bCrc; // Is the crc automaticly added, checked and removed from the frames + bool bPar; // Does the PN53x chip handles parity bits, all parities are handled as data + ui8 ui8TxBits; // The last tx bits setting, we need to reset this if it does not apply anymore +} dev_info; + +struct dev_callbacks { + const char* acDriver; // Driver description + dev_info* (*connect)(const ui32 uiIndex); + bool (*transceive)(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen); + void (*disconnect)(dev_info* pdi); +}; + +typedef enum { + DCO_HANDLE_CRC = 0x00, + DCO_HANDLE_PARITY = 0x01, + DCO_ACTIVATE_FIELD = 0x10, + DCO_ACTIVATE_CRYPTO1 = 0x11, + DCO_INFINITE_SELECT = 0x20, + DCO_ACCEPT_INVALID_FRAMES = 0x30, + DCO_ACCEPT_MULTIPLE_FRAMES = 0x31 +}dev_config_option; + +//////////////////////////////////////////////////////////////////// +// nfc_reader_list_passive - using InListPassiveTarget + +typedef enum { + IM_ISO14443A_106 = 0x00, + IM_FELICA_212 = 0x01, + IM_FELICA_424 = 0x02, + IM_ISO14443B_106 = 0x03, + IM_JEWEL_106 = 0x04 +}init_modulation; + +typedef struct { + byte abtAtqa[2]; + byte btSak; + ui32 uiUidLen; + byte abtUid[10]; + ui32 uiAtsLen; + byte abtAts[36]; +}tag_info_iso14443a; + +typedef struct { + ui32 uiLen; + byte btResCode; + byte abtId[8]; + byte abtPad[8]; + byte abtSysCode[2]; +}tag_info_felica; + +typedef struct { + byte abtAtqb[12]; + byte abtId[4]; + byte btParam1; + byte btParam2; + byte btParam3; + byte btParam4; + byte btCid; + ui32 uiInfLen; + byte abtInf[64]; +}tag_info_iso14443b; + +typedef struct { + byte btSensRes[2]; + byte btId[4]; +}tag_info_jewel; + +typedef union { + tag_info_iso14443a tia; + tag_info_felica tif; + tag_info_iso14443b tib; + tag_info_jewel tij; +}tag_info; + +//////////////////////////////////////////////////////////////////// +// InDataExchange, MIFARE Classic card typedef enum { MC_AUTH_A = 0x60, @@ -45,25 +131,29 @@ typedef enum { MC_DECREMENT = 0xC0, MC_INCREMENT = 0xC1, MC_STORE = 0xC2, -}MifareCmd; +}mifare_cmd; +// MIFARE Classic command params typedef struct { byte abtKey[6]; byte abtUid[4]; -}MifareParamAuth; +}mifare_param_auth; typedef struct { byte abtData[16]; -}MifareParamData; +}mifare_param_data; typedef struct { byte abtValue[4]; -}MifareParamValue; +}mifare_param_value; typedef union { - MifareParamAuth mpa; - MifareParamData mpd; - MifareParamValue mpv; -}MifareParam; + mifare_param_auth mpa; + mifare_param_data mpd; + mifare_param_value mpv; +}mifare_param; + +// Reset struct alignment to default +#pragma pack() #endif // _LIBNFC_TYPES_H_ diff --git a/win32/anticol.vcproj b/win32/anticol.vcproj index 3e27c8a..b96d8d3 100644 --- a/win32/anticol.vcproj +++ b/win32/anticol.vcproj @@ -1,7 +1,7 @@ - - - - @@ -195,6 +191,26 @@ RelativePath="..\defines.h" > + + + + + + + + + + diff --git a/win32/list.vcproj b/win32/list.vcproj index d329b0a..69a3dae 100644 --- a/win32/list.vcproj +++ b/win32/list.vcproj @@ -1,7 +1,7 @@