Moving sources into src/ directory.

This commit is contained in:
Romuald Conty 2009-05-04 13:02:29 +00:00
parent 0b979eaee2
commit f5acfd7af3
20 changed files with 30 additions and 27 deletions

28
src/Makefile.am Normal file
View file

@ -0,0 +1,28 @@
bin_PROGRAMS = anticol list mftool relay emulate
# set the include path found by configure
INCLUDES= $(all_includes)
nfcinclude_HEADERS = libnfc.h bitutils.h defines.h dev_acr122.h dev_pn531.h types.h mifaretag.h devices.h
nfcincludedir = $(includedir)/libnfc
lib_LTLIBRARIES = libnfc.la
libnfc_la_CFLAGS = @LIBUSB_CFLAGS@ @LIBPCSCLITE_CFLAGS@
libnfc_la_SOURCES = dev_pn531.c dev_acr122.c bitutils.c libnfc.c
libnfc_la_LIBADD = @LIBUSB_LIBS@ @LIBPCSCLITE_LIBS@
anticol_SOURCES = anticol.c
anticol_LDADD = libnfc.la
list_SOURCES = list.c
list_LDADD = libnfc.la
mftool_SOURCES = mftool.c
mftool_LDADD = libnfc.la
relay_SOURCES = relay.c
relay_LDADD = libnfc.la
emulate_SOURCES = emulate.c
emulate_LDADD = libnfc.la

150
src/anticol.c Normal file
View file

@ -0,0 +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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

186
src/bitutils.c Normal file
View file

@ -0,0 +1,186 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "bitutils.h"
const static byte OddParity[256] = {
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
};
const static byte ByteMirror[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30,
0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98,
0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64,
0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc,
0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02,
0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2,
0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a,
0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e,
0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81,
0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71,
0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15,
0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad,
0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43,
0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b,
0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97,
0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f,
0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};
byte oddparity(const byte bt)
{
return OddParity[bt];
}
void oddparity_bytes(const byte* pbtData, const ui32 uiLen, byte* pbtPar)
{
ui32 uiByteNr;
// Calculate the parity bits for the command
for (uiByteNr=0; uiByteNr<uiLen; uiByteNr++)
{
pbtPar[uiByteNr] = OddParity[pbtData[uiByteNr]];
}
}
byte mirror(byte bt)
{
return ByteMirror[bt];
}
ui32 mirror32(ui32 ui32Bits)
{
mirror_bytes((byte*)&ui32Bits,4);
return ui32Bits;
}
ui64 mirror64(ui64 ui64Bits)
{
mirror_bytes((byte*)&ui64Bits,8);
return ui64Bits;
}
void mirror_bytes(byte *pbts, ui32 uiLen)
{
ui32 btNr;
for (btNr=0; btNr<uiLen; btNr++)
{
*pbts = ByteMirror[*pbts];
pbts++;
}
}
ui32 swap_endian32(const void* pui32)
{
ui32 ui32N = *((ui32*)pui32);
return (((ui32N&0xFF)<<24)+((ui32N&0xFF00)<<8)+((ui32N&0xFF0000)>>8)+((ui32N&0xFF000000)>>24));
}
ui64 swap_endian64(const void* pui64)
{
ui64 ui64N = *((ui64*)pui64);
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)
{
byte bt;
ui32 wCrc = 0x6363;
do {
bt = *pbtData++;
bt = (bt^(byte)(wCrc & 0x00FF));
bt = (bt^(bt<<4));
wCrc = (wCrc >> 8)^((ui32)bt << 8)^((ui32)bt<<3)^((ui32)bt>>4);
} while (--uiLen);
*pbtData++ = (byte) (wCrc & 0xFF);
*pbtData = (byte) ((wCrc >> 8) & 0xFF);
}
void print_hex(const byte* pbtData, const ui32 uiBytes)
{
ui32 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;
ui32 uiBytes = uiBits/8;
for (uiPos=0; uiPos < uiBytes; uiPos++)
{
printf("%02x",pbtData[uiPos]);
if (OddParity[pbtData[uiPos]] != pbtDataPar[uiPos])
{
printf("! ");
} else {
printf(" ");
}
}
// Print the rest bits, these cannot have no parity bit
if (uiBits%8 != 0) printf("%02x",pbtData[uiBytes]);
printf("\n");
}

44
src/bitutils.h Normal file
View file

@ -0,0 +1,44 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_BITUTILS_H_
#define _LIBNFC_BITUTILS_H_
#include "defines.h"
byte oddparity(const byte bt);
void oddparity_bytes(const byte* pbtData, const ui32 uiLen, byte* pbtPar);
byte mirror(byte bt);
ui32 mirror32(ui32 ui32Bits);
ui64 mirror64(ui64 ui64Bits);
void mirror_bytes(byte *pbts, ui32 uiLen);
ui32 swap_endian32(const void* pui32);
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_

50
src/defines.h Normal file
View file

@ -0,0 +1,50 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_DEFINES_H_
#define _LIBNFC_DEFINES_H_
// #define _LIBNFC_VERBOSE_
typedef unsigned char byte;
typedef unsigned char ui8;
typedef unsigned short ui16;
typedef unsigned int ui32;
typedef unsigned long long ui64;
typedef unsigned long ulong;
typedef char i8;
typedef short i16;
typedef int i32;
#define null 0
typedef void* dev_spec; // Device connection specification
#define INVALID_DEVICE_INFO null
#define MAX_FRAME_LEN 264
#define DEVICE_NAME_LENGTH 256
// 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_

269
src/dev_acr122.c Normal file
View file

@ -0,0 +1,269 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include "defines.h"
#include <winscard.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dev_acr122.h"
#include "bitutils.h"
// WINDOWS: #define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
#define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
#define SCARD_OPERATION_SUCCESS 0x61
#define SCARD_OPERATION_ERROR 0x63
#ifndef SCARD_PROTOCOL_UNDEFINED
#define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET
#endif
#define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS)
#define ACR122_WRAP_LEN 5
#define ACR122_COMMAND_LEN 266
#define ACR122_RESPONSE_LEN 268
#define MAX_READERS 16
typedef struct {
SCARDCONTEXT hCtx;
SCARDHANDLE hCard;
SCARD_IO_REQUEST ioCard;
} dev_spec_acr122;
static byte abtTxBuf[ACR122_WRAP_LEN+ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
static byte abtRxCmd[5] = { 0xFF,0xC0,0x00,0x00 };
static byte uiRxCmdLen = sizeof(abtRxCmd);
static byte abtRxBuf[ACR122_RESPONSE_LEN];
static ulong ulRxBufLen;
static byte abtGetFw[5] = { 0xFF,0x00,0x48,0x00,0x00 };
static byte abtLed[9] = { 0xFF,0x00,0x40,0x05,0x04,0x00,0x00,0x00,0x00 };
dev_info* dev_acr122_connect(const ui32 uiIndex)
{
char* pacReaders[MAX_READERS];
char acList[256+64*MAX_READERS];
ulong ulListLen = sizeof(acList);
ui32 uiPos;
ui32 uiReaderCount;
ui32 uiReader;
ui32 uiDevIndex;
dev_info* pdi;
dev_spec_acr122* pdsa;
dev_spec_acr122 dsa;
char* pcFirmware;
// Clear the reader list
memset(acList,0x00,ulListLen);
// Test if context succeeded
if (SCardEstablishContext(SCARD_SCOPE_USER,null,null,&(dsa.hCtx)) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
// Retrieve the string array of all available pcsc readers
if (SCardListReaders(dsa.hCtx,null,acList,(void*)&ulListLen) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
#ifdef _LIBNFC_VERBOSE_
printf("Found the following PCSC device(s)\n");
printf("- %s\n",acList);
#endif
pacReaders[0] = acList;
uiReaderCount = 1;
for (uiPos=0; uiPos<ulListLen; uiPos++)
{
// Make sure don't break out of our reader array
if (uiReaderCount == MAX_READERS) break;
// Test if there is a next reader available
if (acList[uiPos] == 0x00)
{
// Test if we are at the end of the list
if (acList[uiPos+1] == 0x00)
{
break;
}
// Store the position of the next reader and search for more readers
pacReaders[uiReaderCount] = acList+uiPos+1;
uiReaderCount++;
// Debug info
#ifdef _LIBNFC_VERBOSE_
printf("- %s\n",acList+uiPos+1);
#endif
}
}
// Initialize the device index we are seaching for
uiDevIndex = uiIndex;
// Iterate through all readers and try to find the ACR122 on requested index
for (uiReader=0; uiReader<uiReaderCount; uiReader++)
{
// Test if we were able to connect to the "emulator" card
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_EXCLUSIVE,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
{
// Connect to ACR122 firmware version >2.0
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_DIRECT,0,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
{
// We can not connect to this device, we will just ignore it
continue;
}
}
// Configure I/O settings for card communication
dsa.ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST);
// Retrieve the current firmware version
pcFirmware = dev_acr122_firmware((dev_info*)&dsa);
if (strstr(pcFirmware,FIRMWARE_TEXT) != null)
{
// We found a occurence, test if it has the right index
if (uiDevIndex != 0)
{
// Let's look for the next reader
uiDevIndex--;
continue;
}
// Allocate memory and store the device specification
pdsa = malloc(sizeof(dev_spec_acr122));
*pdsa = dsa;
// Done, we found the reader we are looking for
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,pcFirmware);
pdi->ct = CT_PN532;
pdi->ds = (dev_spec)pdsa;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
}
// Too bad, the reader could not be located;
return INVALID_DEVICE_INFO;
}
void dev_acr122_disconnect(dev_info* pdi)
{
dev_spec_acr122* pdsa = (dev_spec_acr122*)pdi->ds;
SCardDisconnect(pdsa->hCard,SCARD_LEAVE_CARD);
SCardReleaseContext(pdsa->hCtx);
free(pdsa);
free(pdi);
}
bool dev_acr122_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
{
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
// Make sure the command does not overflow the send buffer
if (uiTxLen > ACR122_COMMAND_LEN) return false;
// Store the length of the command we are going to send
abtTxBuf[4] = uiTxLen;
// Prepare and transmit the send buffer
memcpy(abtTxBuf+5,pbtTx,uiTxLen);
ulRxBufLen = sizeof(abtRxBuf);
#ifdef _LIBNFC_VERBOSE_
printf("Tx: ");
print_hex(abtTxBuf,uiTxLen+5);
#endif
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
if (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtTxBuf,uiTxLen+5,abtRxBuf,ulRxBufLen,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
} else {
if (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtTxBuf,uiTxLen+5,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
}
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_T0)
{
// Make sure we received the byte-count we expected
if (ulRxBufLen != 2) return false;
// Check if the operation was successful, so an answer is available
if (*abtRxBuf == SCARD_OPERATION_ERROR) return false;
// Retrieve the response bytes
abtRxCmd[4] = abtRxBuf[1];
ulRxBufLen = sizeof(abtRxBuf);
if (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtRxCmd,uiRxCmdLen,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
}
#ifdef _LIBNFC_VERBOSE_
printf("Rx: ");
print_hex(abtRxBuf,ulRxBufLen);
#endif
// When the answer should be ignored, just return a succesful result
if (pbtRx == null || puiRxLen == null) return true;
// Make sure we have an emulated answer that fits the return buffer
if (ulRxBufLen < 4 || (ulRxBufLen-4) > *puiRxLen) return false;
// Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
*puiRxLen = ulRxBufLen-4;
memcpy(pbtRx,abtRxBuf+2,*puiRxLen);
// Transmission went successful
return true;
}
char* dev_acr122_firmware(const dev_spec ds)
{
ui32 uiResult;
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
static char abtFw[11];
ulong ulFwLen = sizeof(abtFw);
memset(abtFw,0x00,ulFwLen);
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
uiResult = SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtGetFw,sizeof(abtGetFw),abtFw,ulFwLen,(void*)&ulFwLen);
} else {
uiResult = SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtGetFw,sizeof(abtGetFw),null,(byte*)abtFw,(void*)&ulFwLen);
}
#ifdef _LIBNFC_VERBOSE_
if (uiResult != SCARD_S_SUCCESS)
{
printf("No ACR122 firmware received, Error: %08x\n",uiResult);
}
#endif
return abtFw;
}
bool dev_acr122_led_red(const dev_spec ds, bool bOn)
{
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
byte abtBuf[2];
ulong ulBufLen = sizeof(abtBuf);
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
return (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtLed,sizeof(abtLed),abtBuf,ulBufLen,(void*)&ulBufLen) == SCARD_S_SUCCESS);
} else {
return (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtLed,sizeof(abtLed),null,(byte*)abtBuf,(void*)&ulBufLen) == SCARD_S_SUCCESS);
}
}

39
src/dev_acr122.h Normal file
View file

@ -0,0 +1,39 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_DEV_ACR122_H_
#define _LIBNFC_DEV_ACR122_H_
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_acr122_connect(const ui32 uiIndex);
void dev_acr122_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_acr122_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
// Various additional features this device supports
char* dev_acr122_firmware(const dev_spec ds);
bool dev_acr122_led_red(const dev_spec ds, bool bOn);
#endif // _LIBNFC_DEV_ACR122_H_

247
src/dev_pn531.c Normal file
View file

@ -0,0 +1,247 @@
/*
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 <http://www.gnu.org/licenses/>.
Thanks to d18c7db and Okko for example code
*/
#include "defines.h"
#include <usb.h>
#include <stdio.h>
#include <string.h>
#include "dev_pn531.h"
#include "bitutils.h"
#define BUFFER_LENGTH 256
#define USB_TIMEOUT 30000
static char buffer[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
typedef struct {
usb_dev_handle* pudh;
ui32 uiEndPointIn;
ui32 uiEndPointOut;
} dev_spec_pn531;
// Find transfer endpoints for bulk transfers
void get_end_points(struct usb_device *dev, dev_spec_pn531* pdsp)
{
ui32 uiIndex;
ui32 uiEndPoint;
struct usb_interface_descriptor* puid = dev->config->interface->altsetting;
// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
for(uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++)
{
// Only accept bulk transfer endpoints (ignore interrupt endpoints)
if(puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue;
// Copy the endpoint to a local var, makes it more readable code
uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress;
// Test if we dealing with a bulk IN endpoint
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN)
{
#ifdef _LIBNFC_VERBOSE_
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointIn = uiEndPoint;
}
// Test if we dealing with a bulk OUT endpoint
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
{
#ifdef _LIBNFC_VERBOSE_
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointOut = uiEndPoint;
}
}
}
dev_info* dev_pn531_connect(const ui32 uiIndex)
{
int idvendor = 0x04CC;
int idproduct = 0x0531;
struct usb_bus *bus;
struct usb_device *dev;
dev_info* pdi = INVALID_DEVICE_INFO;
dev_spec_pn531* pdsp;
dev_spec_pn531 dsp;
ui32 uiDevIndex;
dsp.uiEndPointIn = 0;
dsp.uiEndPointOut = 0;
dsp.pudh = null;
usb_init();
if (usb_find_busses() < 0) return INVALID_DEVICE_INFO;
if (usb_find_devices() < 0) return INVALID_DEVICE_INFO;
// Initialize the device index we are seaching for
uiDevIndex = uiIndex;
for (bus = usb_get_busses(); bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if (idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct)
{
// Make sure there are 2 endpoints available
if (dev->config->interface->altsetting->bNumEndpoints < 2) return pdi;
// Test if we are looking for this device according to the current index
if (uiDevIndex != 0)
{
// Nope, we maybe want the next one, let's try to find another
uiDevIndex--;
continue;
}
#ifdef _LIBNFC_VERBOSE_
printf("Found PN531 device\n");
#endif
// Open the PN531 USB device
dsp.pudh = usb_open(dev);
get_end_points(dev,&dsp);
if(usb_set_configuration(dsp.pudh,1) < 0)
{
#ifdef _LIBNFC_VERBOSE_
printf("Setting config failed\n");
#endif
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
if(usb_claim_interface(dsp.pudh,0) < 0)
{
#ifdef _LIBNFC_VERBOSE_
printf("Can't claim interface\n");
#endif
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
// Allocate memory for the device info and specification, fill it and return the info
pdsp = malloc(sizeof(dev_spec_pn531));
*pdsp = dsp;
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,"PN531USB");
pdi->ct = CT_PN531;
pdi->ds = (dev_spec)pdsp;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
}
}
return pdi;
}
void dev_pn531_disconnect(dev_info* pdi)
{
dev_spec_pn531* pdsp = (dev_spec_pn531*)pdi->ds;
usb_release_interface(pdsp->pudh,0);
usb_close(pdsp->pudh);
free(pdi->ds);
free(pdi);
}
bool dev_pn531_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
{
ui32 uiPos = 0;
int ret = 0;
char buf[BUFFER_LENGTH];
dev_spec_pn531* pdsp = (dev_spec_pn531*)ds;
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
buffer[3] = uiTxLen;
// Packet length checksum
buffer[4] = BUFFER_LENGTH - buffer[3];
// Copy the PN53X command into the packet buffer
memmove(buffer+5,pbtTx,uiTxLen);
// Calculate data payload checksum
buffer[uiTxLen+5] = 0;
for(uiPos=0; uiPos < uiTxLen; uiPos++)
{
buffer[uiTxLen+5] -= buffer[uiPos+5];
}
// End of stream marker
buffer[uiTxLen+6] = 0;
#ifdef _LIBNFC_VERBOSE_
printf("Tx: ");
print_hex((byte*)buffer,uiTxLen+7);
#endif
ret = usb_bulk_write(pdsp->pudh, pdsp->uiEndPointOut, buffer, uiTxLen+7, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef _LIBNFC_VERBOSE_
printf("usb_bulk_write failed with error %d\n", ret);
#endif
return false;
}
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, buf, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef _LIBNFC_VERBOSE_
printf( "usb_bulk_read failed with error %d\n", ret);
#endif
return false;
}
#ifdef _LIBNFC_VERBOSE_
printf("Rx: ");
print_hex((byte*)buf,ret);
#endif
if( ret == 6 )
{
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, buf, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef _LIBNFC_VERBOSE_
printf("usb_bulk_read failed with error %d\n", ret);
#endif
return false;
}
#ifdef _LIBNFC_VERBOSE_
printf("Rx: ");
print_hex((byte*)buf,ret);
#endif
}
// When the answer should be ignored, just return a succesful result
if(pbtRx == null || puiRxLen == null) return true;
// Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
if(ret < 9) return false;
// Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
*puiRxLen = ret - 7 - 2;
memcpy( pbtRx, buf + 7, *puiRxLen);
return true;
}

35
src/dev_pn531.h Normal file
View file

@ -0,0 +1,35 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_DEV_PN531_H_
#define _LIBNFC_DEV_PN531_H_
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_pn531_connect(const ui32 uiIndex);
void dev_pn531_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_pn531_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
#endif // _LIBNFC_DEV_PN531_H_

36
src/devices.h Normal file
View file

@ -0,0 +1,36 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_DEVICES_H_
#define _LIBNFC_DEVICES_H_
#include "defines.h"
#include "types.h"
#include "dev_acr122.h"
#include "dev_pn531.h"
const static struct dev_callbacks dev_callbacks_list[] = {
// Driver Name Connect Transceive Disconect
{ "ACR122", dev_acr122_connect, dev_acr122_transceive, dev_acr122_disconnect },
{ "PN531USB", dev_pn531_connect, dev_pn531_transceive, dev_pn531_disconnect }
};
#endif // _LIBNFC_DEVICES_H_

112
src/emulate.c Normal file
View file

@ -0,0 +1,112 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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-emulation, this requires a second reader!\n");
printf("[+] To do this, please send any command after the anti-collision\n");
printf("[+] For example, send a RATS command or use the \"anticol\" tool\n");
if (!nfc_target_init(pdi,abtRecv,&uiRecvBits))
{
printf("Error: Could not come out of auto-emulation, 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 emulated 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);
}

761
src/libnfc.c Normal file
View file

@ -0,0 +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 <http://www.gnu.org/licenses/>.
*/
#include "libnfc.h"
#include "bitutils.h"
#include <stdio.h>
#include <string.h>
// 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; uiDev<sizeof(dev_callbacks_list)/sizeof(dev_callbacks_list[0]); uiDev++)
{
// Try to claim the device
pdi = dev_callbacks_list[uiDev].connect(0);
// Test if the connection was successful
if (pdi != INVALID_DEVICE_INFO)
{
// Great we have claimed a device
pdi->pdc = &(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;
}

47
src/libnfc.h Normal file
View file

@ -0,0 +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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_H_
#define _LIBNFC_H_
#include "defines.h"
#include "types.h"
#include "bitutils.h"
#include "devices.h"
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_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_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_

96
src/list.c Normal file
View file

@ -0,0 +1,96 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libnfc.h"
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
pdi = nfc_connect();
if (pdi == INVALID_DEVICE_INFO)
{
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);
// Let the reader only try once to find a tag
nfc_configure(pdi,DCO_INFINITE_SELECT,false);
// Configure the CRC and Parity settings
nfc_configure(pdi,DCO_HANDLE_CRC,true);
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);
// Poll for a ISO14443A (MIFARE) tag
if (nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
printf("The following (NFC) ISO14443A tag was found:\n\n");
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(" ATS (ATR): ");
print_hex(ti.tia.abtAts,ti.tia.uiAtsLen);
}
}
// 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);
}
// 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;
}

374
src/mftool.c Normal file
View file

@ -0,0 +1,374 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "libnfc.h"
#include "mifaretag.h"
static dev_info* pdi;
static tag_info ti;
static mifare_param mp;
static mifare_tag mtKeys;
static mifare_tag mtDump;
static bool bUseKeyA;
static ui32 uiBlocks;
bool is_first_block(ui32 uiBlock)
{
// Test if we are in the small or big sectors
if (uiBlock < 128) return ((uiBlock)%4 == 0); else return ((uiBlock)%16 == 0);
}
bool is_trailer_block(ui32 uiBlock)
{
// Test if we are in the small or big sectors
if (uiBlock < 128) return ((uiBlock+1)%4 == 0); else return ((uiBlock+1)%16 == 0);
}
ui32 get_trailer_block(ui32 uiFirstBlock)
{
// Test if we are in the small or big sectors
if (uiFirstBlock<128) return uiFirstBlock+3; else return uiFirstBlock+15;
}
bool read_card()
{
i32 iBlock;
mifare_cmd mc;
bool bFailure = false;
printf("Reading out %d blocks |",uiBlocks+1);
// Read the card from end to begin
for (iBlock=uiBlocks; iBlock>=0; iBlock--)
{
// Authenticate everytime we reach a trailer block
if (is_trailer_block(iBlock))
{
// Show if the readout went well
if (bFailure)
{
printf("x");
// When a failure occured we need to redo the anti-collision
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
printf("!\nError: tag was removed\n");
return 1;
}
bFailure = false;
} else {
// Skip this the first time, bFailure it means nothing (yet)
if (iBlock != uiBlocks)
{
printf(".");
}
}
fflush(stdout);
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,ti.tia.abtUid,4);
// Determin if we should use the a or the b key
if (bUseKeyA)
{
mc = MC_AUTH_A;
memcpy(mp.mpa.abtKey,mtKeys.amb[iBlock].mbt.abtKeyA,6);
} else {
mc = MC_AUTH_B;
memcpy(mp.mpa.abtKey,mtKeys.amb[iBlock].mbt.abtKeyB,6);
}
// Try to authenticate for the current sector
if (!nfc_reader_mifare_cmd(pdi,MC_AUTH_A,iBlock,&mp))
{
printf("!\nError: authentication failed for block %02x\n",iBlock);
return false;
}
// Try to read out the trailer
if (nfc_reader_mifare_cmd(pdi,MC_READ,iBlock,&mp))
{
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mtDump.amb[iBlock].mbt.abtKeyA,mtKeys.amb[iBlock].mbt.abtKeyA,6);
memcpy(mtDump.amb[iBlock].mbt.abtAccessBits,mp.mpd.abtData+6,4);
memcpy(mtDump.amb[iBlock].mbt.abtKeyB,mtKeys.amb[iBlock].mbt.abtKeyB,6);
}
} else {
// Make sure a earlier readout did not fail
if (!bFailure)
{
// Try to read out the data block
if (nfc_reader_mifare_cmd(pdi,MC_READ,iBlock,&mp))
{
memcpy(mtDump.amb[iBlock].mbd.abtData,mp.mpd.abtData,16);
} else {
bFailure = true;
}
}
}
}
printf("%c|\n",(bFailure)?'x':'.');
fflush(stdout);
return true;
}
bool write_card()
{
ui32 uiBlock;
ui32 uiTrailerBlock;
bool bFailure = false;
mifare_cmd mc;
printf("Writing %d blocks |",uiBlocks+1);
// Write the card from begin to end;
for (uiBlock=0; uiBlock<=uiBlocks; uiBlock++)
{
// Authenticate everytime we reach the first sector of a new block
if (is_first_block(uiBlock))
{
// Show if the readout went well
if (bFailure)
{
printf("x");
// When a failure occured we need to redo the anti-collision
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
printf("!\nError: tag was removed\n");
return false;
}
bFailure = false;
} else {
// Skip this the first time, bFailure it means nothing (yet)
if (uiBlock != 0)
{
printf(".");
}
}
fflush(stdout);
// Locate the trailer (with the keys) used for this sector
uiTrailerBlock = get_trailer_block(uiBlock);
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,ti.tia.abtUid,4);
// Determin if we should use the a or the b key
if (bUseKeyA)
{
mc = MC_AUTH_A;
memcpy(mp.mpa.abtKey,mtKeys.amb[uiTrailerBlock].mbt.abtKeyA,6);
} else {
mc = MC_AUTH_B;
memcpy(mp.mpa.abtKey,mtKeys.amb[uiTrailerBlock].mbt.abtKeyB,6);
}
// Try to authenticate for the current sector
if (!nfc_reader_mifare_cmd(pdi,mc,uiBlock,&mp))
{
printf("!\nError: authentication failed for block %02x\n",uiBlock);
return false;
}
}
if (is_trailer_block(uiBlock))
{
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mp.mpd.abtData,mtDump.amb[uiBlock].mbt.abtKeyA,6);
memcpy(mp.mpd.abtData+6,mtDump.amb[uiBlock].mbt.abtAccessBits,4);
memcpy(mp.mpd.abtData+10,mtDump.amb[uiBlock].mbt.abtKeyB,6);
// Try to write the trailer
nfc_reader_mifare_cmd(pdi,MC_WRITE,uiBlock,&mp);
} else {
// The first block 0x00 is read only, skip this
if (uiBlock == 0) continue;
// Make sure a earlier write did not fail
if (!bFailure)
{
// Try to write the data block
memcpy(mp.mpd.abtData,mtDump.amb[uiBlock].mbd.abtData,16);
if (!nfc_reader_mifare_cmd(pdi,MC_WRITE,uiBlock,&mp)) bFailure = true;
}
}
}
printf("%c|\n",(bFailure)?'x':'.');
fflush(stdout);
return true;
}
int main(int argc, const char* argv[])
{
bool b4K;
bool bReadAction;
byte* pbtUID;
FILE* pfKeys;
FILE* pfDump;
if (argc < 5)
{
printf("\n");
printf("mftool <r|w> <a|b> <keys.mfd> <dump.mfd>\n");
printf("\n");
printf("<r|w> - Perform (read from) or (write to) card\n");
printf("<a|b> - Use A or B keys to for action\n");
printf("<keys.mfd> - Mifare-dump that contain the keys\n");
printf("<dump.mfd> - Used to write (card to file) or (file to card)\n");
printf("\n");
return 1;
}
printf("\nChecking arguments and settings\n");
bReadAction = (tolower(*(argv[1])) == 'r');
bUseKeyA = (tolower(*(argv[2])) == 'a');
pfKeys = fopen(argv[3],"rb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[3]);
return 1;
}
if (fread(&mtKeys,1,sizeof(mtKeys),pfKeys) != sizeof(mtKeys))
{
printf("Could not read from keys file: %s\n",argv[3]);
fclose(pfKeys);
return 1;
}
fclose(pfKeys);
if (bReadAction)
{
memset(&mtDump,0x00,sizeof(mtDump));
} else {
pfDump = fopen(argv[4],"rb");
if (pfDump == null)
{
printf("Could not open dump file: %s\n",argv[4]);
return 1;
}
if (fread(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
{
printf("Could not read from dump file: %s\n",argv[4]);
fclose(pfDump);
return 1;
}
fclose(pfDump);
}
printf("Succesful opened MIFARE the required files\n");
// Try to open the NFC reader
pdi = nfc_connect();
if (pdi == INVALID_DEVICE_INFO)
{
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);
// Let the reader only try once to find a tag
nfc_configure(pdi,DCO_INFINITE_SELECT,false);
nfc_configure(pdi,DCO_HANDLE_CRC,true);
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("Connected to NFC reader: %s\n",pdi->acName);
// Try to find a MIFARE Classic tag
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
printf("Error: no tag was found\n");
nfc_disconnect(pdi);
return 1;
}
// Test if we are dealing with a MIFARE compatible tag
if ((ti.tia.btSak & 0x08) == 0)
{
printf("Error: tag is not a MIFARE Classic card\n");
nfc_disconnect(pdi);
return 1;
}
// Get the info from the key dump
b4K = (mtKeys.amb[0].mbm.abtATQA[1] == 0x02);
pbtUID = mtKeys.amb[0].mbm.abtUID;
// Compare if key dump UID is the same as the current tag UID
if (memcmp(ti.tia.abtUid,pbtUID,4) != 0)
{
printf("Expected MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
}
// Get the info from the current tag
pbtUID = ti.tia.abtUid;
b4K = (ti.tia.abtAtqa[1] == 0x02);
printf("Found MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
uiBlocks = (b4K)?0xff:0x3f;
if (bReadAction)
{
if (read_card())
{
printf("Writing data to file: %s\n",argv[4]);
fflush(stdout);
pfDump = fopen(argv[4],"wb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[4]);
return 1;
}
if (fwrite(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
{
printf("Could not write to file: %s\n",argv[4]);
return 1;
}
fclose(pfDump);
printf("Done, all bytes dumped to file!\n");
}
} else {
if (write_card())
{
printf("Done, all data is written to the card!\n");
}
}
nfc_disconnect(pdi);
return 0;
}

54
src/mifaretag.h Normal file
View file

@ -0,0 +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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_MIFARE_TAG_H_
#define _LIBNFC_MIFARE_TAG_H_
#include "defines.h"
typedef struct {
byte abtUID[4];
byte btBCC;
byte btUnknown;
byte abtATQA[2];
byte abtUnknown[8];
} mifare_block_manufacturer;
typedef struct {
byte abtData[16];
} mifare_block_data;
typedef struct {
byte abtKeyA[6];
byte abtAccessBits[4];
byte abtKeyB[6];
} mifare_block_trailer;
typedef union {
mifare_block_manufacturer mbm;
mifare_block_data mbd;
mifare_block_trailer mbt;
} mifare_block;
typedef struct {
mifare_block amb[256];
} mifare_tag;
#endif // _LIBNFC_MIFARE_TAG_H_

99
src/relay.c Normal file
View file

@ -0,0 +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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}

159
src/types.h Normal file
View file

@ -0,0 +1,159 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_TYPES_H_
#define _LIBNFC_TYPES_H_
#include "defines.h"
// Compiler directive, set struct alignment to 1 byte for compatibility
#pragma pack(1)
typedef enum {
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,
MC_AUTH_B = 0x61,
MC_READ = 0x30,
MC_WRITE = 0xA0,
MC_TRANSFER = 0xB0,
MC_DECREMENT = 0xC0,
MC_INCREMENT = 0xC1,
MC_STORE = 0xC2,
}mifare_cmd;
// MIFARE Classic command params
typedef struct {
byte abtKey[6];
byte abtUid[4];
}mifare_param_auth;
typedef struct {
byte abtData[16];
}mifare_param_data;
typedef struct {
byte abtValue[4];
}mifare_param_value;
typedef union {
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_