diff --git a/examples/mifare.c b/examples/mifare.c index 75dafcb..d436812 100644 --- a/examples/mifare.c +++ b/examples/mifare.c @@ -69,7 +69,13 @@ bool nfc_initiator_mifare_cmd(nfc_device_t* pnd, const mifare_cmd mc, const uint if (!nfc_initiator_transceive_dep_bytes(pnd,abtCmd,2+szParamLen,abtRx,&szRxLen)) return false; // When we have executed a read command, copy the received bytes into the param - if (mc == MC_READ && szRxLen == 17) memcpy(pmp->mpd.abtData,abtRx+1,16); + if (mc == MC_READ) { + if(szRxLen == 16) { + memcpy(pmp->mpd.abtData,abtRx,16); + } else { + return false; + } + } // Command succesfully executed return true; diff --git a/examples/nfc-list.c b/examples/nfc-list.c index 3e00620..b6249d0 100644 --- a/examples/nfc-list.c +++ b/examples/nfc-list.c @@ -47,7 +47,6 @@ #define MAX_TARGET_COUNT 16 static nfc_device_t* pnd; -static byte_t abtFelica[5] = { 0x00, 0xff, 0xff, 0x00, 0x00 }; int main(int argc, const char* argv[]) { @@ -55,7 +54,6 @@ int main(int argc, const char* argv[]) size_t szDeviceFound; size_t szTargetFound; size_t i; - nfc_target_info_t nti; nfc_device_desc_t *pnddDevices; // Display libnfc version @@ -133,45 +131,54 @@ int main(int argc, const char* argv[]) printf("Connected to NFC reader: %s\n",pnd->acName); + // List ISO14443A targets if (nfc_initiator_list_passive_targets(pnd, NM_ISO14443A_106, anti, MAX_TARGET_COUNT, &szTargetFound )) { size_t n; - printf("%zu ISO14443A passive targets was found:\n", szTargetFound); + printf("%zu ISO14443A passive target(s) was found%s\n", szTargetFound, (szTargetFound==0)?".\n":":"); for(n=0; n0) - { - printf(" INF: "); print_hex(nti.nbi.abtInf,nti.nbi.szInfLen); + // List Felica tags + if (nfc_initiator_list_passive_targets(pnd, NM_FELICA_212, anti, MAX_TARGET_COUNT, &szTargetFound )) { + size_t n; + printf("%zu Felica (212 kbps) passive target(s) was found%s\n", szTargetFound, (szTargetFound==0)?".\n":":"); + for(n=0; nacName); -// NOTE we can't use pn53x_transceive() because rx[0] is not status byte (0x00 != status OK) -// XXX: as of r491, this is no longer the case. Unfortunately I can't be sure that these comments can be removed. -// bool pn53x_transceive(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen); -// bool res = pn53x_transceive(pnd, abtTx, szTxLen, abtRx, &szRxLen); - -// bool (*transceive)(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen); - if (pnd->nc == NC_PN531) { // PN531 doesn't support hardware polling (InAutoPoll) + // TODO find a way to handle this in higher level (i.e. libnfc) WARN ("%s", "PN531 doesn't support hardware polling."); continue; } diff --git a/examples/nfc-utils.c b/examples/nfc-utils.c index 95b01e1..2626760 100644 --- a/examples/nfc-utils.c +++ b/examples/nfc-utils.c @@ -84,6 +84,9 @@ void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbt printf("\n"); } +#define SAK_ISO14443_4_COMPLIANT 0x20 +#define SAK_ISO18092_COMPLIANT 0x40 + void print_nfc_iso14443a_info(const nfc_iso14443a_info_t nai) { printf(" ATQA (SENS_RES): "); print_hex(nai.abtAtqa,2); @@ -93,6 +96,28 @@ void print_nfc_iso14443a_info(const nfc_iso14443a_info_t nai) printf(" ATS (ATR): "); print_hex(nai.abtAts, nai.szAtsLen); } + if ( (nai.btSak & SAK_ISO14443_4_COMPLIANT) || (nai.btSak & SAK_ISO18092_COMPLIANT) ) { + printf(" Compliant with: "); + if (nai.btSak & SAK_ISO14443_4_COMPLIANT) printf("ISO/IEC 14443-4 "); + if (nai.btSak & SAK_ISO18092_COMPLIANT) printf("ISO/IEC 18092"); + printf("\n"); + } +} +void print_nfc_felica_info(const nfc_felica_info_t nfi) +{ + printf(" ID (NFCID2): "); print_hex(nfi.abtId,8); + printf(" Parameter (PAD): "); print_hex(nfi.abtPad,8); +} + +void print_nfc_iso14443b_info(const nfc_iso14443b_info_t nbi) +{ + printf(" ATQB: "); print_hex(nbi.abtAtqb,12); + printf(" ID: "); print_hex(nbi.abtId,4); + printf(" CID: %02x\n",nbi.btCid); + if (nbi.szInfLen>0) { + printf(" INF: "); print_hex(nbi.abtInf,nbi.szInfLen); + } + printf(" PARAMS: %02x %02x %02x %02x\n",nbi.btParam1,nbi.btParam2,nbi.btParam3,nbi.btParam4); } /** diff --git a/examples/nfc-utils.h b/examples/nfc-utils.h index c672efd..aaacf93 100644 --- a/examples/nfc-utils.h +++ b/examples/nfc-utils.h @@ -31,7 +31,11 @@ void print_hex(const byte_t* pbtData, const size_t szLen); void print_hex_bits(const byte_t* pbtData, const size_t szBits); void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbtDataPar); + void print_nfc_iso14443a_info(const nfc_iso14443a_info_t nai); +void print_nfc_iso14443b_info(const nfc_iso14443b_info_t nbi); +void print_nfc_felica_info(const nfc_felica_info_t nfi); + nfc_device_desc_t* parse_device_desc(int argc, const char *argv[], size_t* szFound); #endif diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index b602381..d7c25fa 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -51,10 +51,10 @@ typedef struct { term_info tiNew; // Terminal info during the transaction } serial_port_unix; -// Set time-out on 30 miliseconds +// timeval struct that define timeout delay for serial port const struct timeval timeout = { .tv_sec = 0, // 0 second - .tv_usec = 50000 // 50 ms + .tv_usec = 60000 // 60 ms }; // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct diff --git a/libnfc/buses/uart.h b/libnfc/buses/uart.h index 995afcc..483e7a3 100644 --- a/libnfc/buses/uart.h +++ b/libnfc/buses/uart.h @@ -59,16 +59,16 @@ // Try to guess what we should use. // // XXX: Some review from users cross-compiling is welcome! -#if defined(_WIN32) - #define SERIAL_STRING "COM" -//#elif defined(__APPLE__) -// TODO: find UART connection string for PN53X device on Mac OS X -// #define SERIAL_STRING "" +#if defined (_WIN32) + #define DEFAULT_SERIAL_PORTS { "COM1", "COM2", "COM3", "COM4", NULL } +#elif defined(__APPLE__) + // XXX: find UART connection string for PN53X device on Mac OS X when multiples devices are used + #define DEFAULT_SERIAL_PORTS { "/dev/tty.SLAB_USBtoUART", NULL } #elif defined (__FreeBSD__) || defined (__OpenBSD__) // XXX: Not tested - #define SERIAL_STRING "/dev/cuau" + #define DEFAULT_SERIAL_PORTS { "/dev/cuau0", "/dev/cuau1", "/dev/cuau2", "/dev/cuau3", NULL } #elif defined (__linux__) - #define SERIAL_STRING "/dev/ttyUSB" + #define DEFAULT_SERIAL_PORTS { "/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2", "/dev/ttyUSB3", "/dev/tty0", "/dev/tty1", "/dev/tty2", "/dev/tty3", NULL } #else #error "Can't determine serial string for your system" #endif diff --git a/libnfc/chips/pn53x.c b/libnfc/chips/pn53x.c index 3570bcd..e1b4555 100644 --- a/libnfc/chips/pn53x.c +++ b/libnfc/chips/pn53x.c @@ -29,6 +29,7 @@ #include #include #include +#include #include // FIXME: WTF are doing debug macros in this file? @@ -289,8 +290,8 @@ pn53x_decode_target_data(const byte_t* pbtRawData, size_t szDataLen, nfc_chip_t case NTT_MIFARE: case NTT_GENERIC_PASSIVE_106: // We skip the first byte: its the target number (Tg) - pbtRawData++; + // Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset if (nc == NC_PN531) { pnti->nai.abtAtqa[1] = *(pbtRawData++); @@ -312,6 +313,76 @@ pn53x_decode_target_data(const byte_t* pbtRawData, size_t szDataLen, nfc_chip_t } else { pnti->nai.szAtsLen = 0; } + + // Strip CT (Cascade Tag) to retrieve and store the _real_ UID + // (e.g. 0x8801020304050607 is in fact 0x01020304050607) + if ((pnti->nai.szUidLen == 8) && (pnti->nai.abtUid[0] == 0x88)) { + pnti->nai.szUidLen = 7; + memmove (pnti->nai.abtUid, pnti->nai.abtUid + 1, 7); + } else if ((pnti->nai.szUidLen == 12) && (pnti->nai.abtUid[0] == 0x88) && (pnti->nai.abtUid[4] == 0x88)) { + pnti->nai.szUidLen = 10; + memmove (pnti->nai.abtUid, pnti->nai.abtUid + 1, 3); + memmove (pnti->nai.abtUid + 3, pnti->nai.abtUid + 5, 7); + } + break; + + case NTT_ISO14443B_106: + // We skip the first byte: its the target number (Tg) + pbtRawData++; + + // Store the mandatory info + memcpy(pnti->nbi.abtAtqb, pbtRawData, 12); + pbtRawData += 12; + + // Store temporarily the ATTRIB_RES length + uint8_t ui8AttribResLen = *(pbtRawData++); + + // Store the 4 bytes ID + memcpy(pnti->nbi.abtId, pbtRawData,4); + pbtRawData += 4; + + pnti->nbi.btParam1 = *(pbtRawData++); + pnti->nbi.btParam2 = *(pbtRawData++); + pnti->nbi.btParam3 = *(pbtRawData++); + pnti->nbi.btParam4 = *(pbtRawData++); + + // Test if the Higher layer (INF) is available + if (ui8AttribResLen > 8) { + pnti->nbi.szInfLen = *(pbtRawData++); + memcpy(pnti->nbi.abtInf, pbtRawData, pnti->nbi.szInfLen); + } else { + pnti->nbi.szInfLen = 0; + } + break; + + case NTT_FELICA_212: + case NTT_FELICA_424: + // We skip the first byte: its the target number (Tg) + pbtRawData++; + + // Store the mandatory info + pnti->nfi.szLen = *(pbtRawData++); + pnti->nfi.btResCode = *(pbtRawData++); + // Copy the NFCID2t + memcpy(pnti->nfi.abtId, pbtRawData, 8); + pbtRawData += 8; + // Copy the felica padding + memcpy(pnti->nfi.abtPad, pbtRawData, 8); + pbtRawData += 8; + // Test if the System code (SYST_CODE) is available + if (pnti->nfi.szLen > 18) + { + memcpy(pnti->nfi.abtSysCode, pbtRawData, 2); + } + break; + case NTT_JEWEL_106: + // We skip the first byte: its the target number (Tg) + pbtRawData++; + + // Store the mandatory info + memcpy(pnti->nji.btSensRes, pbtRawData, 2); + pbtRawData += 2; + memcpy(pnti->nji.btId, pbtRawData, 4); break; default: return false; @@ -381,6 +452,66 @@ pn53x_InRelease(nfc_device_t* pnd, const uint8_t ui8Target) return(pn53x_transceive(pnd,abtCmd,sizeof(abtCmd),NULL,NULL)); } +bool +pn53x_InAutoPoll(nfc_device_t* pnd, + const nfc_target_type_t* pnttTargetTypes, const size_t szTargetTypes, + const byte_t btPollNr, const byte_t btPeriod, + nfc_target_t* pntTargets, size_t* pszTargetFound) +{ + size_t szTxInAutoPoll, n, szRxLen; + byte_t abtRx[256]; + bool res; + byte_t *pbtTxInAutoPoll; + + pnd->iLastError = 0; + + if(pnd->nc == NC_PN531) { + // TODO This function is not supported by pn531 (set errno = ENOSUPP or similar) + return false; + } + + // InAutoPoll frame looks like this { 0xd4, 0x60, 0x0f, 0x01, 0x00 } => { direction, command, pollnr, period, types... } + szTxInAutoPoll = 4 + szTargetTypes; + pbtTxInAutoPoll = malloc( szTxInAutoPoll ); + pbtTxInAutoPoll[0] = 0xd4; + pbtTxInAutoPoll[1] = 0x60; + pbtTxInAutoPoll[2] = btPollNr; + pbtTxInAutoPoll[3] = btPeriod; + for(n=0; npdc->transceive(pnd->nds, pbtTxInAutoPoll, szTxInAutoPoll, abtRx, &szRxLen); + + if((szRxLen == 0)||(res == false)) { + return false; + } else { + *pszTargetFound = abtRx[0]; + if( *pszTargetFound ) { + uint8_t ln; + byte_t* pbt = abtRx + 1; + /* 1st target */ + // Target type + pntTargets[0].ntt = *(pbt++); + // AutoPollTargetData length + ln = *(pbt++); + pn53x_decode_target_data(pbt, ln, pnd->nc, pntTargets[0].ntt, &(pntTargets[0].nti)); + pbt += ln; + + if(abtRx[0] > 1) { + /* 2nd target */ + // Target type + pntTargets[1].ntt = *(pbt++); + // AutoPollTargetData length + ln = *(pbt++); + pn53x_decode_target_data(pbt, ln, pnd->nc, pntTargets[1].ntt, &(pntTargets[1].nti)); + } + } + } + return true; +} + static struct sErrorMessage { int iErrorCode; const char *pcErrorMsg; diff --git a/libnfc/chips/pn53x.h b/libnfc/chips/pn53x.h index 0b2bea3..8dea5e8 100644 --- a/libnfc/chips/pn53x.h +++ b/libnfc/chips/pn53x.h @@ -87,6 +87,7 @@ bool pn53x_decode_target_data(const byte_t* pbtRawData, size_t szDataLen, nfc_ch bool pn53x_InListPassiveTarget(nfc_device_t* pnd, const nfc_modulation_t nmInitModulation, const byte_t szMaxTargets, const byte_t* pbtInitiatorData, const size_t szInitiatorDataLen, byte_t* pbtTargetsData, size_t* pszTargetsData); bool pn53x_InDeselect(nfc_device_t* pnd, const uint8_t ui8Target); bool pn53x_InRelease(nfc_device_t* pnd, const uint8_t ui8Target); +bool pn53x_InAutoPoll(nfc_device_t* pnd, const nfc_target_type_t* pnttTargetTypes, const size_t szTargetTypes, const byte_t btPollNr, const byte_t btPeriod, nfc_target_t* pntTargets, size_t* pszTargetFound); const char *pn53x_strerror (const nfc_device_t *pnd); diff --git a/libnfc/drivers/acr122.c b/libnfc/drivers/acr122.c index c41f99e..ca41234 100644 --- a/libnfc/drivers/acr122.c +++ b/libnfc/drivers/acr122.c @@ -205,8 +205,6 @@ nfc_device_t* acr122_connect(const nfc_device_desc_t* pndd) SCARDCONTEXT *pscc; DBG("Attempt to connect to %s",pndd->acDevice); - // We no longer support connecting with a NULL - if(pndd == NULL) return NULL; // Test if context succeeded if (!(pscc = acr122_get_scardcontext ())) return NULL; // Test if we were able to connect to the "emulator" card diff --git a/libnfc/drivers/arygon.c b/libnfc/drivers/arygon.c index a64f219..4b5ffa6 100644 --- a/libnfc/drivers/arygon.c +++ b/libnfc/drivers/arygon.c @@ -109,21 +109,13 @@ arygon_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *p *pszDeviceFound = 0; serial_port sp; - char acPort[BUFFER_LENGTH]; - int iDevice; + const char* pcPorts[] = DEFAULT_SERIAL_PORTS; + const char* pcPort; + int iDevice = 0; - // I have no idea how MAC OS X deals with multiple devices, so a quick workaround - for (iDevice=0; iDevice= szDevices) break; } #ifdef DEBUG - if (sp == INVALID_SERIAL_PORT) DBG("Invalid serial port: %s",acPort); - if (sp == CLAIMED_SERIAL_PORT) DBG("Serial port already claimed: %s",acPort); + if (sp == INVALID_SERIAL_PORT) DBG("Invalid serial port: %s", pcPort); + if (sp == CLAIMED_SERIAL_PORT) DBG("Serial port already claimed: %s", pcPort); #endif /* DEBUG */ } #endif /* SERIAL_AUTOPROBE_ENABLED */ @@ -157,19 +149,14 @@ nfc_device_t* arygon_connect(const nfc_device_desc_t* pndd) serial_port sp; nfc_device_t* pnd = NULL; - if( pndd == NULL ) { - DBG("%s", "arygon_connect() need an nfc_device_desc_t struct."); - return NULL; - } else { - DBG("Attempt to connect to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed); - sp = uart_open(pndd->pcPort); + DBG("Attempt to connect to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed); + sp = uart_open(pndd->pcPort); - if (sp == INVALID_SERIAL_PORT) ERR("Invalid serial port: %s",pndd->pcPort); - if (sp == CLAIMED_SERIAL_PORT) ERR("Serial port already claimed: %s",pndd->pcPort); - if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL; + if (sp == INVALID_SERIAL_PORT) ERR("Invalid serial port: %s",pndd->pcPort); + if (sp == CLAIMED_SERIAL_PORT) ERR("Serial port already claimed: %s",pndd->pcPort); + if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL; - uart_set_speed(sp, pndd->uiSpeed); - } + uart_set_speed(sp, pndd->uiSpeed); DBG("Successfully connected to: %s",pndd->pcPort); diff --git a/libnfc/drivers/pn532_uart.c b/libnfc/drivers/pn532_uart.c index 4664191..ac34129 100644 --- a/libnfc/drivers/pn532_uart.c +++ b/libnfc/drivers/pn532_uart.c @@ -84,21 +84,13 @@ pn532_uart_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_ *pszDeviceFound = 0; serial_port sp; - char acPort[BUFFER_LENGTH]; - int iDevice; - - // I have no idea how MAC OS X deals with multiple devices, so a quick workaround - for (iDevice=0; iDevice= szDevices) break; } #ifdef DEBUG - if (sp == INVALID_SERIAL_PORT) DBG("Invalid serial port: %s",acPort); - if (sp == CLAIMED_SERIAL_PORT) DBG("Serial port already claimed: %s",acPort); + if (sp == INVALID_SERIAL_PORT) DBG("Invalid serial port: %s", pcPort); + if (sp == CLAIMED_SERIAL_PORT) DBG("Serial port already claimed: %s", pcPort); #endif /* DEBUG */ } #endif /* SERIAL_AUTOPROBE_ENABLED */ @@ -141,19 +132,15 @@ nfc_device_t* pn532_uart_connect(const nfc_device_desc_t* pndd) nfc_device_t* pnd = NULL; bool bComOk; - if( pndd == NULL ) { - DBG("%s", "pn532_uart_connect() need an nfc_device_desc_t struct."); - return NULL; - } else { - DBG("Attempt to connect to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed); - sp = uart_open(pndd->pcPort); + DBG("Attempt to connect to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed); + sp = uart_open(pndd->pcPort); - if (sp == INVALID_SERIAL_PORT) ERR("Invalid serial port: %s",pndd->pcPort); - if (sp == CLAIMED_SERIAL_PORT) ERR("Serial port already claimed: %s",pndd->pcPort); - if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL; + if (sp == INVALID_SERIAL_PORT) ERR("Invalid serial port: %s",pndd->pcPort); + if (sp == CLAIMED_SERIAL_PORT) ERR("Serial port already claimed: %s",pndd->pcPort); + if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL; - uart_set_speed(sp, pndd->uiSpeed); - } + uart_set_speed(sp, pndd->uiSpeed); + // PN532 could be powered down, we need to wake it up before line testing. pn532_uart_wakeup((nfc_device_spec_t)sp); // Check communication using "Diagnose" command, with "Comunication test" (0x00) @@ -240,7 +227,7 @@ bool pn532_uart_transceive(nfc_device_t* pnd, const byte_t* pbtTx, const size_t } #ifdef DEBUG - PRINT_HEX("RX", abtRxBuf,szRxBufLen); + PRINT_HEX("RX", abtRxBuf,szRxBufLen); #endif // When the answer should be ignored, just return a successful result diff --git a/libnfc/drivers/pn53x_usb.c b/libnfc/drivers/pn53x_usb.c index 18d9224..0316719 100644 --- a/libnfc/drivers/pn53x_usb.c +++ b/libnfc/drivers/pn53x_usb.c @@ -162,9 +162,6 @@ nfc_device_t* pn53x_usb_connect(const nfc_device_desc_t* pndd,const char * targe us.uiEndPointOut = 0; us.pudh = NULL; - // must specify device to connect to - if(pndd == NULL) return NULL; - DBG("Attempt to connect to %s device", target_name); usb_init(); diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 61bda75..53368c6 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -447,7 +447,7 @@ nfc_initiator_select_passive_target(nfc_device_t* pnd, // Make sure we are dealing with a active device if (!pnd->bActive) return false; - + // TODO Put this in a function switch(nmInitModulation) { case NM_ISO14443A_106: @@ -493,60 +493,33 @@ nfc_initiator_select_passive_target(nfc_device_t* pnd, switch(nmInitModulation) { case NM_ISO14443A_106: - if(!pn53x_decode_target_data(abtTargetsData+1, szTargetsData-1, pnd->nc, NTT_GENERIC_PASSIVE_106, pnti)) return false; - - // Strip CT (Cascade Tag) to retrieve and store the _real_ UID - // (e.g. 0x8801020304050607 is in fact 0x01020304050607) - if ((pnti->nai.szUidLen == 8) && (pnti->nai.abtUid[0] == 0x88)) { - pnti->nai.szUidLen = 7; - memmove (pnti->nai.abtUid, pnti->nai.abtUid + 1, 7); - } else if ((pnti->nai.szUidLen == 12) && (pnti->nai.abtUid[0] == 0x88) && (pnti->nai.abtUid[4] == 0x88)) { - pnti->nai.szUidLen = 10; - memmove (pnti->nai.abtUid, pnti->nai.abtUid + 1, 3); - memmove (pnti->nai.abtUid + 3, pnti->nai.abtUid + 5, 7); - } + if(!pn53x_decode_target_data(abtTargetsData+1, szTargetsData-1, pnd->nc, NTT_GENERIC_PASSIVE_106, pnti)) { + return false; + } break; case NM_FELICA_212: - case NM_FELICA_424: - // Store the mandatory info - pnti->nfi.szLen = abtTargetsData[2]; - pnti->nfi.btResCode = abtTargetsData[3]; - // Copy the NFCID2t - memcpy(pnti->nfi.abtId,abtTargetsData+4,8); - // Copy the felica padding - memcpy(pnti->nfi.abtPad,abtTargetsData+12,8); - // Test if the System code (SYST_CODE) is available - if (szTargetsData > 20) - { - memcpy(pnti->nfi.abtSysCode,abtTargetsData+20,2); + if(!pn53x_decode_target_data(abtTargetsData+1, szTargetsData-1, pnd->nc, NTT_FELICA_212, pnti)) { + return false; } - break; + break; + case NM_FELICA_424: + if(!pn53x_decode_target_data(abtTargetsData+1, szTargetsData-1, pnd->nc, NTT_FELICA_424, pnti)) { + return false; + } + break; case NM_ISO14443B_106: - // Store the mandatory info - memcpy(pnti->nbi.abtAtqb,abtTargetsData+2,12); - // Ignore the 0x1D byte, and just store the 4 byte id - memcpy(pnti->nbi.abtId,abtTargetsData+15,4); - pnti->nbi.btParam1 = abtTargetsData[19]; - pnti->nbi.btParam2 = abtTargetsData[20]; - pnti->nbi.btParam3 = abtTargetsData[21]; - pnti->nbi.btParam4 = abtTargetsData[22]; - // Test if the Higher layer (INF) is available - if (szTargetsData > 22) - { - pnti->nbi.szInfLen = abtTargetsData[23]; - memcpy(pnti->nbi.abtInf,abtTargetsData+24,pnti->nbi.szInfLen); - } else { - pnti->nbi.szInfLen = 0; + if(!pn53x_decode_target_data(abtTargetsData+1, szTargetsData-1, pnd->nc, NTT_ISO14443B_106, pnti)) { + return false; } - break; + break; case NM_JEWEL_106: - // Store the mandatory info - memcpy(pnti->nji.btSensRes,abtTargetsData+2,2); - memcpy(pnti->nji.btId,abtTargetsData+4,4); - break; + if(!pn53x_decode_target_data(abtTargetsData+1, szTargetsData-1, pnd->nc, NTT_JEWEL_106, pnti)) { + return false; + } + break; default: // Should not be possible, so whatever... @@ -556,11 +529,10 @@ nfc_initiator_select_passive_target(nfc_device_t* pnd, return true; } -bool nfc_initiator_list_passive_targets(nfc_device_t* pnd, const nfc_modulation_t nmInitModulation, nfc_target_info_t anti[], const size_t szTargets, size_t *pszTargetFound ) +bool +nfc_initiator_list_passive_targets(nfc_device_t* pnd, const nfc_modulation_t nmInitModulation, nfc_target_info_t anti[], const size_t szTargets, size_t *pszTargetFound) { nfc_target_info_t nti; - - bool bCollisionDetected = false; size_t szTargetFound = 0; pnd->iLastError = 0; @@ -568,16 +540,17 @@ bool nfc_initiator_list_passive_targets(nfc_device_t* pnd, const nfc_modulation_ // Let the reader only try once to find a target nfc_configure (pnd, NDO_INFINITE_SELECT, false); - - while (nfc_initiator_select_passive_target (pnd, nmInitModulation, NULL, 0, &nti)) { + byte_t* pbtInitData = NULL; + size_t szInitDataLen = 0; + + if(nmInitModulation == NM_ISO14443B_106) { + // Application Family Identifier (AFI) must equals 0x00 in order to wakeup all ISO14443-B PICCs (see ISO/IEC 14443-3) + pbtInitData = (byte_t*)"\x00"; + szInitDataLen = 1; + } + while (nfc_initiator_select_passive_target (pnd, nmInitModulation, pbtInitData, szInitDataLen, &nti)) { nfc_initiator_deselect_target(pnd); - if(nmInitModulation == NM_ISO14443A_106) { - if((nti.nai.abtAtqa[0] == 0x00) && (nti.nai.abtAtqa[1] == 0x00)) { - bCollisionDetected = true; - } - } - if(szTargets > szTargetFound) { memcpy( &(anti[szTargetFound]), &nti, sizeof(nfc_target_info_t) ); } @@ -585,56 +558,10 @@ bool nfc_initiator_list_passive_targets(nfc_device_t* pnd, const nfc_modulation_ } *pszTargetFound = szTargetFound; - DBG("%zu targets was found%s.", *pszTargetFound, bCollisionDetected?" (with SENS_RES collision)":""); - -/* - // TODO This chunk of code attempt to retrieve SENS_RES (ATQA) for ISO14443A which collide previously. - // XXX Unfortunately at this stage, I'm not able to REQA each tag correctly to retrieve this SENS_REQ. - - - // Drop the field for a while - nfc_configure(pnd,NDO_ACTIVATE_FIELD,false); - // Let the reader only try once to find a tag - nfc_configure(pnd,NDO_INFINITE_SELECT,false); - - // Configure the CRC and Parity settings - nfc_configure(pnd,NDO_HANDLE_CRC,true); - nfc_configure(pnd,NDO_HANDLE_PARITY,true); - - // Enable field so more power consuming cards can power themselves up - nfc_configure(pnd,NDO_ACTIVATE_FIELD,true); - - if(bCollisionDetected && (nmInitModulation == NM_ISO14443A_106)) { - // nfc_initiator_select_passive_target(pnd, NM_ISO14443A_106, anti[0].nai.abtUid, anti[0].nai.szUidLen, NULL); - - for( size_t n = 0; n < szTargetFound; n++ ) { - size_t szTargetsData; - byte_t abtTargetsData[MAX_FRAME_LEN]; - if(!pn53x_InListPassiveTarget(pnd, NM_ISO14443A_106, 2, NULL, 0, abtTargetsData, &szTargetsData)) return false; - DBG("pn53x_InListPassiveTarget(): %d selected target(s)", abtTargetsData[0]); - if(szTargetsData && (abtTargetsData[0] > 0)) { - byte_t* pbtTargetData = abtTargetsData+1; - size_t szTargetData = 5 + *(pbtTargetData + 4); // Tg, SENS_RES (2), SEL_RES, NFCIDLength, NFCID1 (NFCIDLength) - - if( (*(pbtTargetData + 3) & 0x40) && ((~(*(pbtTargetData + 3))) & 0x04) ) { // Check if SAK looks like 0bxx1xx0xx, which means compliant with ISO/IEC 14443-4 (= ATS available) (See ISO14443-3 document) - szTargetData += 1 + *(pbtTargetData + szTargetData); // Add ATS length - } - if(!pn53x_decode_target_data(pbtTargetData, szTargetData, pnd->nc, NTT_GENERIC_PASSIVE_106, &nti)) return false; - #ifdef DEBUG - for(size_t n=0;niLastError = 0; - - if(pnd->nc == NC_PN531) { - // errno = ENOSUPP - return false; - } -// byte_t abtInAutoPoll[] = { 0xd4, 0x60, 0x0f, 0x01, 0x00 }; - szTxInAutoPoll = 4 + szTargetTypes; - pbtTxInAutoPoll = malloc( szTxInAutoPoll ); - pbtTxInAutoPoll[0] = 0xd4; - pbtTxInAutoPoll[1] = 0x60; - pbtTxInAutoPoll[2] = btPollNr; - pbtTxInAutoPoll[3] = btPeriod; - for(n=0; nnc, pntTargets[0].ntt, &(pntTargets[0].nti)); - pbt += ln; - - if(abtRx[0] > 1) { - /* 2nd target */ - // Target type - pntTargets[1].ntt = *(pbt++); - // AutoPollTargetData length - ln = *(pbt++); - pn53x_decode_target_data(pbt, ln, pnd->nc, pntTargets[1].ntt, &(pntTargets[1].nti)); - } - } - } - return true; + return pn53x_InAutoPoll(pnd, pnttTargetTypes, szTargetTypes, btPollNr, btPeriod, pntTargets, pszTargetFound); } /** - * @fn nfc_initiator_transceive_bits(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxBits, const byte_t* pbtTxPar, byte_t* pbtRx, size_t* pszRxBits, byte_t* pbtRxPar) * @brief Transceive raw bit-frames * @return Returns true if action was successfully performed; otherwise returns false. * @param pbtTx contains a byte array of the frame that needs to be transmitted. @@ -821,7 +696,7 @@ bool nfc_initiator_transceive_dep_bytes(nfc_device_t* pnd, const byte_t* pbtTx, if (!pn53x_set_tx_bits(pnd,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) + // We have to give the amount of bytes + (the two command bytes 0xD4, 0x40) if (!pn53x_transceive(pnd,abtCmd,szTxLen+3,abtRx,&szRxLen)) return false; // Save the received byte count @@ -835,10 +710,10 @@ bool nfc_initiator_transceive_dep_bytes(nfc_device_t* pnd, const byte_t* pbtTx, } /** - * @brief Transceive byte and APDU frames + * @brief Send raw data to target then retrieve raw data from target * @return Returns true if action was successfully performed; otherwise returns false. * - * The reader will transmit the supplied bytes in pbtTx to the target (tag). + * The reader will transmit the supplied bytes (\a pbtTx) to the target in raw mode: PN53x will not handle input neither output data. * It waits for the response and stores the received bytes in the pbtRx byte array. * The parity bits are handled by the PN53X chip. The CRC can be generated automatically or handled manually. * Using this function, frames can be communicated very fast via the NFC reader to the tag. @@ -1168,7 +1043,7 @@ void nfc_perror (const nfc_device_t *pnd, const char *pcString) /** * @brief Returns the device name - * @return Returns a string with the device name ( MUST be freed with free() ) + * @return Returns a string with the device name */ const char* nfc_device_name(nfc_device_t* pnd) { diff --git a/m4/libnfc_drivers.m4 b/m4/libnfc_drivers.m4 index 0c7296f..2ed6aef 100644 --- a/m4/libnfc_drivers.m4 +++ b/m4/libnfc_drivers.m4 @@ -4,7 +4,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS], [ AC_MSG_CHECKING(which drivers to build) AC_ARG_WITH(drivers, - AC_HELP_STRING([--with-drivers=driver@<:@[[[,]]]driver...@:>@], [Only use specific drivers (default set)]), + AC_HELP_STRING([--with-drivers=driver@<:@[[[,]]]driver...@:>@], [Only use specific drivers (available drivers: acr122,arygon,pn531_usb,pn533_usb,pn532_uart)]), [ case "${withval}" in yes | no) dnl ignore calls without any arguments