New str_nfc_target() function in API.
This allow to convert a nfc_target struct into allocated string.
This commit is contained in:
parent
82e3416619
commit
310d7eba07
13 changed files with 726 additions and 622 deletions
1
NEWS
1
NEWS
|
@ -9,6 +9,7 @@ API Changes:
|
|||
* Functions
|
||||
- New enum-to-string converter functions str_nfc_modulation_type() and
|
||||
str_nfc_baud_rate()
|
||||
- New str_nfc_target() to convert nfc_target struct into allocated string
|
||||
- New nfc_device_get_information_about() function to retreive some device's
|
||||
information
|
||||
- No more in/out function parameter: nfc_initiator_transceive_bytes() now
|
||||
|
|
|
@ -259,7 +259,7 @@ main(int argc, char *argv[])
|
|||
*/
|
||||
|
||||
printf("%s will emulate this ISO14443-A tag:\n", argv[0]);
|
||||
print_nfc_iso14443a_info(nt.nti.nai, true);
|
||||
print_nfc_target(nt, true);
|
||||
|
||||
// Switch off NP_EASY_FRAMING if target is not ISO14443-4
|
||||
nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, (nt.nti.nai.btSak & SAK_ISO14443_4_COMPLIANT));
|
||||
|
|
|
@ -159,7 +159,7 @@ main(int argc, const char *argv[])
|
|||
goto error;
|
||||
} else if (res == 1) {
|
||||
printf("The following ISO14443A tag (SAM) was found:\n");
|
||||
print_nfc_iso14443a_info(nt.nti.nai, true);
|
||||
print_nfc_target(nt, true);
|
||||
} else {
|
||||
ERR("%s", "More than one ISO14442 tag found as SAM.");
|
||||
goto error;
|
||||
|
|
|
@ -123,7 +123,7 @@ extern "C" {
|
|||
/* String converter functions */
|
||||
NFC_EXPORT const char *str_nfc_modulation_type(const nfc_modulation_type nmt);
|
||||
NFC_EXPORT const char *str_nfc_baud_rate(const nfc_baud_rate nbr);
|
||||
|
||||
NFC_EXPORT int str_nfc_target(char **buf, const nfc_target nt, bool verbose);
|
||||
|
||||
/* Error codes */
|
||||
/** @ingroup error
|
||||
|
|
|
@ -8,7 +8,9 @@ noinst_HEADERS = \
|
|||
iso7816.h \
|
||||
log.h \
|
||||
mirror-subr.h \
|
||||
nfc-internal.h
|
||||
nfc-internal.h \
|
||||
target-subr.h
|
||||
|
||||
lib_LTLIBRARIES = libnfc.la
|
||||
libnfc_la_SOURCES = \
|
||||
iso14443-subr.c \
|
||||
|
@ -16,7 +18,8 @@ libnfc_la_SOURCES = \
|
|||
nfc.c \
|
||||
nfc-device.c \
|
||||
nfc-emulation.c \
|
||||
nfc-internal.c
|
||||
nfc-internal.c \
|
||||
target-subr.c
|
||||
|
||||
libnfc_la_LDFLAGS = -no-undefined -version-info 3:0:0 -export-symbols-regex '^nfc_|^iso14443a_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration'
|
||||
libnfc_la_CFLAGS = @DRIVERS_CFLAGS@
|
||||
|
|
18
libnfc/nfc.c
18
libnfc/nfc.c
|
@ -78,6 +78,7 @@
|
|||
#include <nfc/nfc.h>
|
||||
|
||||
#include "nfc-internal.h"
|
||||
#include "target-subr.h"
|
||||
#include "drivers.h"
|
||||
|
||||
#define LOG_CATEGORY "libnfc.general"
|
||||
|
@ -1152,3 +1153,20 @@ str_nfc_modulation_type(const nfc_modulation_type nmt)
|
|||
// Should never go there..
|
||||
return "";
|
||||
}
|
||||
|
||||
/** @ingroup string-converter
|
||||
* @brief Convert \a nfc_modulation_type value to string
|
||||
* @return Upon successful return, this function returns the number of characters printed (excluding the null byte used to end output to strings), otherwise returns libnfc's error code (negative value)
|
||||
* @param nt \a nfc_target struct to print
|
||||
* @param buf pointer where string will be allocated, then nfc target information printed
|
||||
*
|
||||
* @warning *buf must be freed.
|
||||
*/
|
||||
int
|
||||
str_nfc_target(char **buf, const nfc_target nt, bool verbose)
|
||||
{
|
||||
*buf = malloc(4096);
|
||||
(*buf)[0] = '\0';
|
||||
sprint_nfc_target(*buf, nt, verbose);
|
||||
return strlen(*buf);
|
||||
}
|
||||
|
|
643
libnfc/target-subr.c
Normal file
643
libnfc/target-subr.c
Normal file
|
@ -0,0 +1,643 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010-2011, Romain Tartière
|
||||
* Copyright (C) 2009-2012, Romuald Conty
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file target-subr.c
|
||||
* @brief Target-related subroutines. (ie. determine target type, print target, etc.)
|
||||
*/
|
||||
#include <nfc/nfc.h>
|
||||
|
||||
#include "target-subr.h"
|
||||
|
||||
struct card_atqa {
|
||||
uint16_t atqa;
|
||||
uint16_t mask;
|
||||
char type[128];
|
||||
// list of up to 8 SAK values compatible with this ATQA
|
||||
int saklist[8];
|
||||
};
|
||||
|
||||
struct card_sak {
|
||||
uint8_t sak;
|
||||
uint8_t mask;
|
||||
char type[128];
|
||||
};
|
||||
|
||||
struct card_atqa const_ca[] = {
|
||||
{
|
||||
0x0044, 0xffff, "MIFARE Ultralight",
|
||||
{0, -1}
|
||||
},
|
||||
{
|
||||
0x0044, 0xffff, "MIFARE Ultralight C",
|
||||
{0, -1}
|
||||
},
|
||||
{
|
||||
0x0004, 0xff0f, "MIFARE Mini 0.3K",
|
||||
{1, -1}
|
||||
},
|
||||
{
|
||||
0x0004, 0xff0f, "MIFARE Classic 1K",
|
||||
{2, -1}
|
||||
},
|
||||
{
|
||||
0x0002, 0xff0f, "MIFARE Classic 4K",
|
||||
{3, -1}
|
||||
},
|
||||
{
|
||||
0x0004, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0002, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0044, 0xffff, "MIFARE Plus (7 Byte UID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0042, 0xffff, "MIFARE Plus (7 Byte UID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0344, 0xffff, "MIFARE DESFire",
|
||||
{10, 11, -1}
|
||||
},
|
||||
{
|
||||
0x0044, 0xffff, "P3SR008",
|
||||
{ -1}
|
||||
}, // TODO we need SAK info
|
||||
{
|
||||
0x0004, 0xf0ff, "SmartMX with MIFARE 1K emulation",
|
||||
{12, -1}
|
||||
},
|
||||
{
|
||||
0x0002, 0xf0ff, "SmartMX with MIFARE 4K emulation",
|
||||
{12, -1}
|
||||
},
|
||||
{
|
||||
0x0048, 0xf0ff, "SmartMX with 7 Byte UID",
|
||||
{12, -1}
|
||||
}
|
||||
};
|
||||
|
||||
struct card_sak const_cs[] = {
|
||||
{0x00, 0xff, "" }, // 00 MIFARE Ultralight / Ultralight C
|
||||
{0x09, 0xff, "" }, // 01 MIFARE Mini 0.3K
|
||||
{0x08, 0xff, "" }, // 02 MIFARE Classic 1K
|
||||
{0x18, 0xff, "" }, // 03 MIFARE Classik 4K
|
||||
{0x08, 0xff, " 2K, Security level 1" }, // 04 MIFARE Plus
|
||||
{0x18, 0xff, " 4K, Security level 1" }, // 05 MIFARE Plus
|
||||
{0x10, 0xff, " 2K, Security level 2" }, // 06 MIFARE Plus
|
||||
{0x11, 0xff, " 4K, Security level 2" }, // 07 MIFARE Plus
|
||||
{0x20, 0xff, " 2K, Security level 3" }, // 08 MIFARE Plus
|
||||
{0x20, 0xff, " 4K, Security level 3" }, // 09 MIFARE Plus
|
||||
{0x20, 0xff, " 4K" }, // 10 MIFARE DESFire
|
||||
{0x20, 0xff, " EV1 2K/4K/8K" }, // 11 MIFARE DESFire
|
||||
{0x00, 0x00, "" }, // 12 SmartMX
|
||||
};
|
||||
|
||||
int
|
||||
sprint_hex(char *dst, const uint8_t *pbtData, const size_t szBytes)
|
||||
{
|
||||
size_t szPos;
|
||||
|
||||
int res = 0;
|
||||
for (szPos = 0; szPos < szBytes; szPos++) {
|
||||
res += sprintf(dst + res, "%02x ", pbtData[szPos]);
|
||||
}
|
||||
res += sprintf(dst + res, "\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SAK_UID_NOT_COMPLETE 0x04
|
||||
#define SAK_ISO14443_4_COMPLIANT 0x20
|
||||
#define SAK_ISO18092_COMPLIANT 0x40
|
||||
|
||||
void
|
||||
sprint_nfc_iso14443a_info(char *dst, const nfc_iso14443a_info nai, bool verbose)
|
||||
{
|
||||
dst += sprintf(dst, " ATQA (SENS_RES): ");
|
||||
dst += sprint_hex(dst, nai.abtAtqa, 2);
|
||||
if (verbose) {
|
||||
dst += sprintf(dst, "* UID size: ");
|
||||
switch ((nai.abtAtqa[1] & 0xc0) >> 6) {
|
||||
case 0:
|
||||
dst += sprintf(dst, "single\n");
|
||||
break;
|
||||
case 1:
|
||||
dst += sprintf(dst, "double\n");
|
||||
break;
|
||||
case 2:
|
||||
dst += sprintf(dst, "triple\n");
|
||||
break;
|
||||
case 3:
|
||||
dst += sprintf(dst, "RFU\n");
|
||||
break;
|
||||
}
|
||||
dst += sprintf(dst, "* bit frame anticollision ");
|
||||
switch (nai.abtAtqa[1] & 0x1f) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x04:
|
||||
case 0x08:
|
||||
case 0x10:
|
||||
dst += sprintf(dst, "supported\n");
|
||||
break;
|
||||
default:
|
||||
dst += sprintf(dst, "not supported\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
dst += sprintf(dst, " UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
|
||||
dst += sprint_hex(dst, nai.abtUid, nai.szUidLen);
|
||||
if (verbose) {
|
||||
if (nai.abtUid[0] == 0x08) {
|
||||
dst += sprintf(dst, "* Random UID\n");
|
||||
}
|
||||
}
|
||||
dst += sprintf(dst, " SAK (SEL_RES): ");
|
||||
dst += sprint_hex(dst, &nai.btSak, 1);
|
||||
if (verbose) {
|
||||
if (nai.btSak & SAK_UID_NOT_COMPLETE) {
|
||||
dst += sprintf(dst, "* Warning! Cascade bit set: UID not complete\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
|
||||
dst += sprintf(dst, "* Compliant with ISO/IEC 14443-4\n");
|
||||
} else {
|
||||
dst += sprintf(dst, "* Not compliant with ISO/IEC 14443-4\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO18092_COMPLIANT) {
|
||||
dst += sprintf(dst, "* Compliant with ISO/IEC 18092\n");
|
||||
} else {
|
||||
dst += sprintf(dst, "* Not compliant with ISO/IEC 18092\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen) {
|
||||
dst += sprintf(dst, " ATS: ");
|
||||
dst += sprint_hex(dst, nai.abtAts, nai.szAtsLen);
|
||||
}
|
||||
if (nai.szAtsLen && verbose) {
|
||||
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
dst += sprintf(dst, "* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
|
||||
|
||||
size_t offset = 1;
|
||||
if (nai.abtAts[0] & 0x10) { // TA(1) present
|
||||
uint8_t TA = nai.abtAts[offset];
|
||||
offset++;
|
||||
dst += sprintf(dst, "* Bit Rate Capability:\n");
|
||||
if (TA == 0) {
|
||||
dst += sprintf(dst, " * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (TA & 1 << 7) {
|
||||
dst += sprintf(dst, " * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (TA & 1 << 4) {
|
||||
dst += sprintf(dst, " * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 5) {
|
||||
dst += sprintf(dst, " * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 6) {
|
||||
dst += sprintf(dst, " * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 0) {
|
||||
dst += sprintf(dst, " * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 1) {
|
||||
dst += sprintf(dst, " * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 2) {
|
||||
dst += sprintf(dst, " * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 3) {
|
||||
dst += sprintf(dst, " * ERROR unknown value\n");
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x20) { // TB(1) present
|
||||
uint8_t TB = nai.abtAts[offset];
|
||||
offset++;
|
||||
dst += sprintf(dst, "* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((TB & 0xf0) >> 4)) / 13560.0);
|
||||
if ((TB & 0x0f) == 0) {
|
||||
dst += sprintf(dst, "* No Start-up Frame Guard Time required\n");
|
||||
} else {
|
||||
dst += sprintf(dst, "* Start-up Frame Guard Time: %.4g ms\n", 256.0 * 16.0 * (1 << (TB & 0x0f)) / 13560.0);
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x40) { // TC(1) present
|
||||
uint8_t TC = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (TC & 0x1) {
|
||||
dst += sprintf(dst, "* Node ADdress supported\n");
|
||||
} else {
|
||||
dst += sprintf(dst, "* Node ADdress not supported\n");
|
||||
}
|
||||
if (TC & 0x2) {
|
||||
dst += sprintf(dst, "* Card IDentifier supported\n");
|
||||
} else {
|
||||
dst += sprintf(dst, "* Card IDentifier not supported\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen > offset) {
|
||||
dst += sprintf(dst, "* Historical bytes Tk: ");
|
||||
dst += sprint_hex(dst, nai.abtAts + offset, (nai.szAtsLen - offset));
|
||||
uint8_t CIB = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
|
||||
dst += sprintf(dst, " * Proprietary format\n");
|
||||
if (CIB == 0xc1) {
|
||||
dst += sprintf(dst, " * Tag byte: Mifare or virtual cards of various types\n");
|
||||
uint8_t L = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (L != (nai.szAtsLen - offset)) {
|
||||
dst += sprintf(dst, " * Warning: Type Identification Coding length (%i)", L);
|
||||
dst += sprintf(dst, " not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
|
||||
}
|
||||
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
|
||||
uint8_t CTC = nai.abtAts[offset];
|
||||
offset++;
|
||||
dst += sprintf(dst, " * Chip Type: ");
|
||||
switch (CTC & 0xf0) {
|
||||
case 0x00:
|
||||
dst += sprintf(dst, "(Multiple) Virtual Cards\n");
|
||||
break;
|
||||
case 0x10:
|
||||
dst += sprintf(dst, "Mifare DESFire\n");
|
||||
break;
|
||||
case 0x20:
|
||||
dst += sprintf(dst, "Mifare Plus\n");
|
||||
break;
|
||||
default:
|
||||
dst += sprintf(dst, "RFU\n");
|
||||
break;
|
||||
}
|
||||
dst += sprintf(dst, " * Memory size: ");
|
||||
switch (CTC & 0x0f) {
|
||||
case 0x00:
|
||||
dst += sprintf(dst, "<1 kbyte\n");
|
||||
break;
|
||||
case 0x01:
|
||||
dst += sprintf(dst, "1 kbyte\n");
|
||||
break;
|
||||
case 0x02:
|
||||
dst += sprintf(dst, "2 kbyte\n");
|
||||
break;
|
||||
case 0x03:
|
||||
dst += sprintf(dst, "4 kbyte\n");
|
||||
break;
|
||||
case 0x04:
|
||||
dst += sprintf(dst, "8 kbyte\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
dst += sprintf(dst, "Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
dst += sprintf(dst, "RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
uint8_t CVC = nai.abtAts[offset];
|
||||
offset++;
|
||||
dst += sprintf(dst, " * Chip Status: ");
|
||||
switch (CVC & 0xf0) {
|
||||
case 0x00:
|
||||
dst += sprintf(dst, "Engineering sample\n");
|
||||
break;
|
||||
case 0x20:
|
||||
dst += sprintf(dst, "Released\n");
|
||||
break;
|
||||
default:
|
||||
dst += sprintf(dst, "RFU\n");
|
||||
break;
|
||||
}
|
||||
dst += sprintf(dst, " * Chip Generation: ");
|
||||
switch (CVC & 0x0f) {
|
||||
case 0x00:
|
||||
dst += sprintf(dst, "Generation 1\n");
|
||||
break;
|
||||
case 0x01:
|
||||
dst += sprintf(dst, "Generation 2\n");
|
||||
break;
|
||||
case 0x02:
|
||||
dst += sprintf(dst, "Generation 3\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
dst += sprintf(dst, "Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
dst += sprintf(dst, "RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
uint8_t VCS = nai.abtAts[offset];
|
||||
offset++;
|
||||
dst += sprintf(dst, " * Specifics (Virtual Card Selection):\n");
|
||||
if ((VCS & 0x09) == 0x00) {
|
||||
dst += sprintf(dst, " * Only VCSL supported\n");
|
||||
} else if ((VCS & 0x09) == 0x01) {
|
||||
dst += sprintf(dst, " * VCS, VCSL and SVC supported\n");
|
||||
}
|
||||
if ((VCS & 0x0e) == 0x00) {
|
||||
dst += sprintf(dst, " * SL1, SL2(?), SL3 supported\n");
|
||||
} else if ((VCS & 0x0e) == 0x02) {
|
||||
dst += sprintf(dst, " * SL3 only card\n");
|
||||
} else if ((VCS & 0x0f) == 0x0e) {
|
||||
dst += sprintf(dst, " * No VCS command supported\n");
|
||||
} else if ((VCS & 0x0f) == 0x0f) {
|
||||
dst += sprintf(dst, " * Unspecified\n");
|
||||
} else {
|
||||
dst += sprintf(dst, " * RFU\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (CIB == 0x00) {
|
||||
dst += sprintf(dst, " * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
|
||||
dst += sprintf(dst, " followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
|
||||
dst += sprintf(dst, " See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
if (CIB == 0x10) {
|
||||
dst += sprintf(dst, " * DIR data reference: %02x\n", nai.abtAts[offset]);
|
||||
}
|
||||
if (CIB == 0x80) {
|
||||
if (nai.szAtsLen == offset) {
|
||||
dst += sprintf(dst, " * No COMPACT-TLV objects found, no status found\n");
|
||||
} else {
|
||||
dst += sprintf(dst, " * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
|
||||
dst += sprintf(dst, " the last data object may carry a status indicator of one, two or three bytes.\n");
|
||||
dst += sprintf(dst, " See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
dst += sprintf(dst, "\nFingerprinting based on MIFARE type Identification Procedure:\n"); // AN10833
|
||||
uint16_t atqa = 0;
|
||||
uint8_t sak = 0;
|
||||
uint8_t i, j;
|
||||
bool found_possible_match = false;
|
||||
|
||||
atqa = (((uint16_t)nai.abtAtqa[0] & 0xff) << 8);
|
||||
atqa += (((uint16_t)nai.abtAtqa[1] & 0xff));
|
||||
sak = ((uint8_t)nai.btSak & 0xff);
|
||||
|
||||
for (i = 0; i < sizeof(const_ca) / sizeof(const_ca[0]); i++) {
|
||||
if ((atqa & const_ca[i].mask) == const_ca[i].atqa) {
|
||||
for (j = 0; (j < sizeof(const_ca[i].saklist)) && (const_ca[i].saklist[j] >= 0); j++) {
|
||||
int sakindex = const_ca[i].saklist[j];
|
||||
if ((sak & const_cs[sakindex].mask) == const_cs[sakindex].sak) {
|
||||
dst += sprintf(dst, "* %s%s\n", const_ca[i].type, const_cs[sakindex].type);
|
||||
found_possible_match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Other matches not described in
|
||||
// AN10833 MIFARE Type Identification Procedure
|
||||
// but seen in the field:
|
||||
dst += sprintf(dst, "Other possible matches based on ATQA & SAK values:\n");
|
||||
uint32_t atqasak = 0;
|
||||
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff) << 16);
|
||||
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff) << 8);
|
||||
atqasak += ((uint32_t)nai.btSak & 0xff);
|
||||
switch (atqasak) {
|
||||
case 0x000488:
|
||||
dst += sprintf(dst, "* Mifare Classic 1K Infineon\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000298:
|
||||
dst += sprintf(dst, "* Gemplus MPCOS\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x030428:
|
||||
dst += sprintf(dst, "* JCOP31\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004820:
|
||||
dst += sprintf(dst, "* JCOP31 v2.4.1\n");
|
||||
dst += sprintf(dst, "* JCOP31 v2.2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000428:
|
||||
dst += sprintf(dst, "* JCOP31 v2.3.1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000453:
|
||||
dst += sprintf(dst, "* Fudan FM1208SH01\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000820:
|
||||
dst += sprintf(dst, "* Fudan FM1208\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000238:
|
||||
dst += sprintf(dst, "* MFC 4K emulated by Nokia 6212 Classic\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000838:
|
||||
dst += sprintf(dst, "* MFC 4K emulated by Nokia 6131 NFC\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
if (! found_possible_match) {
|
||||
dst += sprintf(dst, "* Unknown card, sorry\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sprint_nfc_felica_info(char *dst, const nfc_felica_info nfi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
dst += sprintf(dst, " ID (NFCID2): ");
|
||||
dst += sprint_hex(dst, nfi.abtId, 8);
|
||||
dst += sprintf(dst, " Parameter (PAD): ");
|
||||
dst += sprint_hex(dst, nfi.abtPad, 8);
|
||||
dst += sprintf(dst, " System Code (SC): ");
|
||||
dst += sprint_hex(dst, nfi.abtSysCode, 2);
|
||||
}
|
||||
|
||||
void
|
||||
sprint_nfc_jewel_info(char *dst, const nfc_jewel_info nji, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
dst += sprintf(dst, " ATQA (SENS_RES): ");
|
||||
dst += sprint_hex(dst, nji.btSensRes, 2);
|
||||
dst += sprintf(dst, " 4-LSB JEWELID: ");
|
||||
dst += sprint_hex(dst, nji.btId, 4);
|
||||
}
|
||||
|
||||
#define PI_ISO14443_4_SUPPORTED 0x01
|
||||
#define PI_NAD_SUPPORTED 0x01
|
||||
#define PI_CID_SUPPORTED 0x02
|
||||
void
|
||||
sprint_nfc_iso14443b_info(char *dst, const nfc_iso14443b_info nbi, bool verbose)
|
||||
{
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
dst += sprintf(dst, " PUPI: ");
|
||||
dst += sprint_hex(dst, nbi.abtPupi, 4);
|
||||
dst += sprintf(dst, " Application Data: ");
|
||||
dst += sprint_hex(dst, nbi.abtApplicationData, 4);
|
||||
dst += sprintf(dst, " Protocol Info: ");
|
||||
dst += sprint_hex(dst, nbi.abtProtocolInfo, 3);
|
||||
if (verbose) {
|
||||
dst += sprintf(dst, "* Bit Rate Capability:\n");
|
||||
if (nbi.abtProtocolInfo[0] == 0) {
|
||||
dst += sprintf(dst, " * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 7) {
|
||||
dst += sprintf(dst, " * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 4) {
|
||||
dst += sprintf(dst, " * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 5) {
|
||||
dst += sprintf(dst, " * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 6) {
|
||||
dst += sprintf(dst, " * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 0) {
|
||||
dst += sprintf(dst, " * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 1) {
|
||||
dst += sprintf(dst, " * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 2) {
|
||||
dst += sprintf(dst, " * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 3) {
|
||||
dst += sprintf(dst, " * ERROR unknown value\n");
|
||||
}
|
||||
if ((nbi.abtProtocolInfo[1] & 0xf0) <= 0x80) {
|
||||
dst += sprintf(dst, "* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
|
||||
}
|
||||
if ((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
|
||||
dst += sprintf(dst, "* Protocol types supported: ISO/IEC 14443-4\n");
|
||||
}
|
||||
dst += sprintf(dst, "* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((nbi.abtProtocolInfo[2] & 0xf0) >> 4)) / 13560.0);
|
||||
if ((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED | PI_CID_SUPPORTED)) != 0) {
|
||||
dst += sprintf(dst, "* Frame options supported: ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) dst += sprintf(dst, "NAD ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) dst += sprintf(dst, "CID ");
|
||||
dst += sprintf(dst, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sprint_nfc_iso14443bi_info(char *dst, const nfc_iso14443bi_info nii, bool verbose)
|
||||
{
|
||||
dst += sprintf(dst, " DIV: ");
|
||||
dst += sprint_hex(dst, nii.abtDIV, 4);
|
||||
if (verbose) {
|
||||
int version = (nii.btVerLog & 0x1e) >> 1;
|
||||
dst += sprintf(dst, " Software Version: ");
|
||||
if (version == 15) {
|
||||
dst += sprintf(dst, "Undefined\n");
|
||||
} else {
|
||||
dst += sprintf(dst, "%i\n", version);
|
||||
}
|
||||
|
||||
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)) {
|
||||
dst += sprintf(dst, " Wait Enable: yes");
|
||||
}
|
||||
}
|
||||
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) {
|
||||
dst += sprintf(dst, " ATS: ");
|
||||
dst += sprint_hex(dst, nii.abtAtr, nii.szAtrLen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sprint_nfc_iso14443b2sr_info(char *dst, const nfc_iso14443b2sr_info nsi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
dst += sprintf(dst, " UID: ");
|
||||
dst += sprint_hex(dst, nsi.abtUID, 8);
|
||||
}
|
||||
|
||||
void
|
||||
sprint_nfc_iso14443b2ct_info(char *dst, const nfc_iso14443b2ct_info nci, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
uint32_t uid;
|
||||
uid = (nci.abtUID[3] << 24) + (nci.abtUID[2] << 16) + (nci.abtUID[1] << 8) + nci.abtUID[0];
|
||||
dst += sprintf(dst, " UID: ");
|
||||
dst += sprint_hex(dst, nci.abtUID, sizeof(nci.abtUID));
|
||||
dst += sprintf(dst, " UID (decimal): %010u\n", uid);
|
||||
dst += sprintf(dst, " Product Code: %02X\n", nci.btProdCode);
|
||||
dst += sprintf(dst, " Fab Code: %02X\n", nci.btFabCode);
|
||||
}
|
||||
|
||||
void
|
||||
sprint_nfc_dep_info(char *dst, const nfc_dep_info ndi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
dst += sprintf(dst, " NFCID3: ");
|
||||
dst += sprint_hex(dst, ndi.abtNFCID3, 10);
|
||||
dst += sprintf(dst, " BS: %02x\n", ndi.btBS);
|
||||
dst += sprintf(dst, " BR: %02x\n", ndi.btBR);
|
||||
dst += sprintf(dst, " TO: %02x\n", ndi.btTO);
|
||||
dst += sprintf(dst, " PP: %02x\n", ndi.btPP);
|
||||
if (ndi.szGB) {
|
||||
dst += sprintf(dst, "General Bytes: ");
|
||||
dst += sprint_hex(dst, ndi.abtGB, ndi.szGB);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sprint_nfc_target(char *dst, const nfc_target nt, bool verbose)
|
||||
{
|
||||
dst += sprintf(dst, "%s (%s%s) target:\n", str_nfc_modulation_type(nt.nm.nmt), str_nfc_baud_rate(nt.nm.nbr), (nt.nm.nmt != NMT_DEP) ? "" : (nt.nti.ndi.ndm == NDM_ACTIVE) ? "active mode" : "passive mode");
|
||||
switch (nt.nm.nmt) {
|
||||
case NMT_ISO14443A:
|
||||
sprint_nfc_iso14443a_info(dst, nt.nti.nai, verbose);
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
sprint_nfc_jewel_info(dst, nt.nti.nji, verbose);
|
||||
break;
|
||||
case NMT_FELICA:
|
||||
sprint_nfc_felica_info(dst, nt.nti.nfi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B:
|
||||
sprint_nfc_iso14443b_info(dst, nt.nti.nbi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443BI:
|
||||
sprint_nfc_iso14443bi_info(dst, nt.nti.nii, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B2SR:
|
||||
sprint_nfc_iso14443b2sr_info(dst, nt.nti.nsi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B2CT:
|
||||
sprint_nfc_iso14443b2ct_info(dst, nt.nti.nci, verbose);
|
||||
break;
|
||||
case NMT_DEP:
|
||||
sprint_nfc_dep_info(dst, nt.nti.ndi, verbose);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
41
libnfc/target-subr.h
Normal file
41
libnfc/target-subr.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010-2011, Romain Tartière
|
||||
* Copyright (C) 2009-2012, Romuald Conty
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file target-subr.c
|
||||
* @brief Target-related subroutines. (ie. determine target type, print target, etc.)
|
||||
*/
|
||||
|
||||
#ifndef _TARGET_SUBR_H_
|
||||
#define _TARGET_SUBR_H_
|
||||
|
||||
int sprint_hex(char *dst, const uint8_t *pbtData, const size_t szLen);
|
||||
void sprint_nfc_iso14443a_info(char *dst, const nfc_iso14443a_info nai, bool verbose);
|
||||
void sprint_nfc_iso14443b_info(char *dst, const nfc_iso14443b_info nbi, bool verbose);
|
||||
void sprint_nfc_iso14443bi_info(char *dst, const nfc_iso14443bi_info nii, bool verbose);
|
||||
void sprint_nfc_iso14443b2sr_info(char *dst, const nfc_iso14443b2sr_info nsi, bool verbose);
|
||||
void sprint_nfc_iso14443b2ct_info(char *dst, const nfc_iso14443b2ct_info nci, bool verbose);
|
||||
void sprint_nfc_felica_info(char *dst, const nfc_felica_info nfi, bool verbose);
|
||||
void sprint_nfc_jewel_info(char *dst, const nfc_jewel_info nji, bool verbose);
|
||||
void sprint_nfc_dep_info(char *dst, const nfc_dep_info ndi, bool verbose);
|
||||
void sprint_nfc_target(char *dst, const nfc_target nt, bool verbose);
|
||||
|
||||
#endif
|
|
@ -148,7 +148,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d ISO14443A passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_iso14443a_info(ant[n].nti.nai, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d Felica (212 kbps) passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_felica_info(ant[n].nti.nfi, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d Felica (424 kbps) passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_felica_info(ant[n].nti.nfi, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d ISO14443B passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_iso14443b_info(ant[n].nti.nbi, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d ISO14443B' passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_iso14443bi_info(ant[n].nti.nii, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d ISO14443B-2 ST SRx passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_iso14443b2sr_info(ant[n].nti.nsi, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d ISO14443B-2 ASK CTx passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_iso14443b2ct_info(ant[n].nti.nci, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ main(int argc, const char *argv[])
|
|||
printf("%d Jewel passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":");
|
||||
}
|
||||
for (n = 0; n < res; n++) {
|
||||
print_nfc_jewel_info(ant[n].nti.nji, verbose);
|
||||
print_nfc_target(ant[n], verbose);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -556,7 +556,7 @@ main(int argc, const char *argv[])
|
|||
}
|
||||
}
|
||||
printf("Found MIFARE Classic card:\n");
|
||||
print_nfc_iso14443a_info(nt.nti.nai, false);
|
||||
print_nfc_target(nt, false);
|
||||
|
||||
// Guessing size
|
||||
if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02)
|
||||
|
|
|
@ -250,7 +250,7 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
printf("Found tag:\n");
|
||||
print_nfc_iso14443a_info(ntRealTarget.nti.nai, false);
|
||||
print_nfc_target(ntRealTarget, false);
|
||||
if (initiator_only_mode) {
|
||||
if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen, "UID") != EXIT_SUCCESS) {
|
||||
fprintf(stderr, "Error while printing UID to FD4\n");
|
||||
|
@ -350,7 +350,7 @@ main(int argc, char *argv[])
|
|||
memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk);
|
||||
|
||||
printf("We will emulate:\n");
|
||||
print_nfc_iso14443a_info(ntEmulatedTarget.nti.nai, false);
|
||||
print_nfc_target(ntEmulatedTarget, false);
|
||||
|
||||
// Try to open the NFC emulator device
|
||||
pndTarget = nfc_open(NULL, connstrings[0]);
|
||||
|
|
|
@ -37,95 +37,6 @@
|
|||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
struct card_atqa {
|
||||
uint16_t atqa;
|
||||
uint16_t mask;
|
||||
char type[128];
|
||||
// list of up to 8 SAK values compatible with this ATQA
|
||||
int saklist[8];
|
||||
};
|
||||
|
||||
struct card_sak {
|
||||
uint8_t sak;
|
||||
uint8_t mask;
|
||||
char type[128];
|
||||
};
|
||||
|
||||
struct card_atqa const_ca[] = {
|
||||
{
|
||||
0x0044, 0xffff, "MIFARE Ultralight",
|
||||
{0, -1}
|
||||
},
|
||||
{
|
||||
0x0044, 0xffff, "MIFARE Ultralight C",
|
||||
{0, -1}
|
||||
},
|
||||
{
|
||||
0x0004, 0xff0f, "MIFARE Mini 0.3K",
|
||||
{1, -1}
|
||||
},
|
||||
{
|
||||
0x0004, 0xff0f, "MIFARE Classic 1K",
|
||||
{2, -1}
|
||||
},
|
||||
{
|
||||
0x0002, 0xff0f, "MIFARE Classic 4K",
|
||||
{3, -1}
|
||||
},
|
||||
{
|
||||
0x0004, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0002, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0044, 0xffff, "MIFARE Plus (7 Byte UID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0042, 0xffff, "MIFARE Plus (7 Byte UID)",
|
||||
{4, 5, 6, 7, 8, 9, -1}
|
||||
},
|
||||
{
|
||||
0x0344, 0xffff, "MIFARE DESFire",
|
||||
{10, 11, -1}
|
||||
},
|
||||
{
|
||||
0x0044, 0xffff, "P3SR008",
|
||||
{ -1}
|
||||
}, // TODO we need SAK info
|
||||
{
|
||||
0x0004, 0xf0ff, "SmartMX with MIFARE 1K emulation",
|
||||
{12, -1}
|
||||
},
|
||||
{
|
||||
0x0002, 0xf0ff, "SmartMX with MIFARE 4K emulation",
|
||||
{12, -1}
|
||||
},
|
||||
{
|
||||
0x0048, 0xf0ff, "SmartMX with 7 Byte UID",
|
||||
{12, -1}
|
||||
}
|
||||
};
|
||||
|
||||
struct card_sak const_cs[] = {
|
||||
{0x00, 0xff, "" }, // 00 MIFARE Ultralight / Ultralight C
|
||||
{0x09, 0xff, "" }, // 01 MIFARE Mini 0.3K
|
||||
{0x08, 0xff, "" }, // 02 MIFARE Classic 1K
|
||||
{0x18, 0xff, "" }, // 03 MIFARE Classik 4K
|
||||
{0x08, 0xff, " 2K, Security level 1" }, // 04 MIFARE Plus
|
||||
{0x18, 0xff, " 4K, Security level 1" }, // 05 MIFARE Plus
|
||||
{0x10, 0xff, " 2K, Security level 2" }, // 06 MIFARE Plus
|
||||
{0x11, 0xff, " 4K, Security level 2" }, // 07 MIFARE Plus
|
||||
{0x20, 0xff, " 2K, Security level 3" }, // 08 MIFARE Plus
|
||||
{0x20, 0xff, " 4K, Security level 3" }, // 09 MIFARE Plus
|
||||
{0x20, 0xff, " 4K" }, // 10 MIFARE DESFire
|
||||
{0x20, 0xff, " EV1 2K/4K/8K" }, // 11 MIFARE DESFire
|
||||
{0x00, 0x00, "" }, // 12 SmartMX
|
||||
};
|
||||
|
||||
uint8_t
|
||||
oddparity(const uint8_t bt)
|
||||
{
|
||||
|
@ -203,515 +114,11 @@ print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDat
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
#define SAK_UID_NOT_COMPLETE 0x04
|
||||
#define SAK_ISO14443_4_COMPLIANT 0x20
|
||||
#define SAK_ISO18092_COMPLIANT 0x40
|
||||
|
||||
void
|
||||
print_nfc_iso14443a_info(const nfc_iso14443a_info nai, bool verbose)
|
||||
{
|
||||
printf(" ATQA (SENS_RES): ");
|
||||
print_hex(nai.abtAtqa, 2);
|
||||
if (verbose) {
|
||||
printf("* UID size: ");
|
||||
switch ((nai.abtAtqa[1] & 0xc0) >> 6) {
|
||||
case 0:
|
||||
printf("single\n");
|
||||
break;
|
||||
case 1:
|
||||
printf("double\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("triple\n");
|
||||
break;
|
||||
case 3:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf("* bit frame anticollision ");
|
||||
switch (nai.abtAtqa[1] & 0x1f) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x04:
|
||||
case 0x08:
|
||||
case 0x10:
|
||||
printf("supported\n");
|
||||
break;
|
||||
default:
|
||||
printf("not supported\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf(" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
|
||||
print_hex(nai.abtUid, nai.szUidLen);
|
||||
if (verbose) {
|
||||
if (nai.abtUid[0] == 0x08) {
|
||||
printf("* Random UID\n");
|
||||
}
|
||||
}
|
||||
printf(" SAK (SEL_RES): ");
|
||||
print_hex(&nai.btSak, 1);
|
||||
if (verbose) {
|
||||
if (nai.btSak & SAK_UID_NOT_COMPLETE) {
|
||||
printf("* Warning! Cascade bit set: UID not complete\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
|
||||
printf("* Compliant with ISO/IEC 14443-4\n");
|
||||
} else {
|
||||
printf("* Not compliant with ISO/IEC 14443-4\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO18092_COMPLIANT) {
|
||||
printf("* Compliant with ISO/IEC 18092\n");
|
||||
} else {
|
||||
printf("* Not compliant with ISO/IEC 18092\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen) {
|
||||
printf(" ATS: ");
|
||||
print_hex(nai.abtAts, nai.szAtsLen);
|
||||
}
|
||||
if (nai.szAtsLen && verbose) {
|
||||
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
printf("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
|
||||
|
||||
size_t offset = 1;
|
||||
if (nai.abtAts[0] & 0x10) { // TA(1) present
|
||||
uint8_t TA = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf("* Bit Rate Capability:\n");
|
||||
if (TA == 0) {
|
||||
printf(" * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (TA & 1 << 7) {
|
||||
printf(" * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (TA & 1 << 4) {
|
||||
printf(" * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 5) {
|
||||
printf(" * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 6) {
|
||||
printf(" * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 0) {
|
||||
printf(" * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 1) {
|
||||
printf(" * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 2) {
|
||||
printf(" * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1 << 3) {
|
||||
printf(" * ERROR unknown value\n");
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x20) { // TB(1) present
|
||||
uint8_t TB = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf("* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((TB & 0xf0) >> 4)) / 13560.0);
|
||||
if ((TB & 0x0f) == 0) {
|
||||
printf("* No Start-up Frame Guard Time required\n");
|
||||
} else {
|
||||
printf("* Start-up Frame Guard Time: %.4g ms\n", 256.0 * 16.0 * (1 << (TB & 0x0f)) / 13560.0);
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x40) { // TC(1) present
|
||||
uint8_t TC = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (TC & 0x1) {
|
||||
printf("* Node ADdress supported\n");
|
||||
} else {
|
||||
printf("* Node ADdress not supported\n");
|
||||
}
|
||||
if (TC & 0x2) {
|
||||
printf("* Card IDentifier supported\n");
|
||||
} else {
|
||||
printf("* Card IDentifier not supported\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen > offset) {
|
||||
printf("* Historical bytes Tk: ");
|
||||
print_hex(nai.abtAts + offset, (nai.szAtsLen - offset));
|
||||
uint8_t CIB = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
|
||||
printf(" * Proprietary format\n");
|
||||
if (CIB == 0xc1) {
|
||||
printf(" * Tag byte: Mifare or virtual cards of various types\n");
|
||||
uint8_t L = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (L != (nai.szAtsLen - offset)) {
|
||||
printf(" * Warning: Type Identification Coding length (%i)", L);
|
||||
printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
|
||||
}
|
||||
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
|
||||
uint8_t CTC = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Chip Type: ");
|
||||
switch (CTC & 0xf0) {
|
||||
case 0x00:
|
||||
printf("(Multiple) Virtual Cards\n");
|
||||
break;
|
||||
case 0x10:
|
||||
printf("Mifare DESFire\n");
|
||||
break;
|
||||
case 0x20:
|
||||
printf("Mifare Plus\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf(" * Memory size: ");
|
||||
switch (CTC & 0x0f) {
|
||||
case 0x00:
|
||||
printf("<1 kbyte\n");
|
||||
break;
|
||||
case 0x01:
|
||||
printf("1 kbyte\n");
|
||||
break;
|
||||
case 0x02:
|
||||
printf("2 kbyte\n");
|
||||
break;
|
||||
case 0x03:
|
||||
printf("4 kbyte\n");
|
||||
break;
|
||||
case 0x04:
|
||||
printf("8 kbyte\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
printf("Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
uint8_t CVC = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Chip Status: ");
|
||||
switch (CVC & 0xf0) {
|
||||
case 0x00:
|
||||
printf("Engineering sample\n");
|
||||
break;
|
||||
case 0x20:
|
||||
printf("Released\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf(" * Chip Generation: ");
|
||||
switch (CVC & 0x0f) {
|
||||
case 0x00:
|
||||
printf("Generation 1\n");
|
||||
break;
|
||||
case 0x01:
|
||||
printf("Generation 2\n");
|
||||
break;
|
||||
case 0x02:
|
||||
printf("Generation 3\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
printf("Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
uint8_t VCS = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Specifics (Virtual Card Selection):\n");
|
||||
if ((VCS & 0x09) == 0x00) {
|
||||
printf(" * Only VCSL supported\n");
|
||||
} else if ((VCS & 0x09) == 0x01) {
|
||||
printf(" * VCS, VCSL and SVC supported\n");
|
||||
}
|
||||
if ((VCS & 0x0e) == 0x00) {
|
||||
printf(" * SL1, SL2(?), SL3 supported\n");
|
||||
} else if ((VCS & 0x0e) == 0x02) {
|
||||
printf(" * SL3 only card\n");
|
||||
} else if ((VCS & 0x0f) == 0x0e) {
|
||||
printf(" * No VCS command supported\n");
|
||||
} else if ((VCS & 0x0f) == 0x0f) {
|
||||
printf(" * Unspecified\n");
|
||||
} else {
|
||||
printf(" * RFU\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (CIB == 0x00) {
|
||||
printf(" * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
|
||||
printf(" followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
|
||||
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
if (CIB == 0x10) {
|
||||
printf(" * DIR data reference: %02x\n", nai.abtAts[offset]);
|
||||
}
|
||||
if (CIB == 0x80) {
|
||||
if (nai.szAtsLen == offset) {
|
||||
printf(" * No COMPACT-TLV objects found, no status found\n");
|
||||
} else {
|
||||
printf(" * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
|
||||
printf(" the last data object may carry a status indicator of one, two or three bytes.\n");
|
||||
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
printf("\nFingerprinting based on MIFARE type Identification Procedure:\n"); // AN10833
|
||||
uint16_t atqa = 0;
|
||||
uint8_t sak = 0;
|
||||
uint8_t i, j;
|
||||
bool found_possible_match = false;
|
||||
|
||||
atqa = (((uint16_t)nai.abtAtqa[0] & 0xff) << 8);
|
||||
atqa += (((uint16_t)nai.abtAtqa[1] & 0xff));
|
||||
sak = ((uint8_t)nai.btSak & 0xff);
|
||||
|
||||
for (i = 0; i < sizeof(const_ca) / sizeof(const_ca[0]); i++) {
|
||||
if ((atqa & const_ca[i].mask) == const_ca[i].atqa) {
|
||||
for (j = 0; (j < sizeof(const_ca[i].saklist)) && (const_ca[i].saklist[j] >= 0); j++) {
|
||||
int sakindex = const_ca[i].saklist[j];
|
||||
if ((sak & const_cs[sakindex].mask) == const_cs[sakindex].sak) {
|
||||
printf("* %s%s\n", const_ca[i].type, const_cs[sakindex].type);
|
||||
found_possible_match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Other matches not described in
|
||||
// AN10833 MIFARE Type Identification Procedure
|
||||
// but seen in the field:
|
||||
printf("Other possible matches based on ATQA & SAK values:\n");
|
||||
uint32_t atqasak = 0;
|
||||
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff) << 16);
|
||||
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff) << 8);
|
||||
atqasak += ((uint32_t)nai.btSak & 0xff);
|
||||
switch (atqasak) {
|
||||
case 0x000488:
|
||||
printf("* Mifare Classic 1K Infineon\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000298:
|
||||
printf("* Gemplus MPCOS\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x030428:
|
||||
printf("* JCOP31\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004820:
|
||||
printf("* JCOP31 v2.4.1\n");
|
||||
printf("* JCOP31 v2.2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000428:
|
||||
printf("* JCOP31 v2.3.1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000453:
|
||||
printf("* Fudan FM1208SH01\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000820:
|
||||
printf("* Fudan FM1208\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000238:
|
||||
printf("* MFC 4K emulated by Nokia 6212 Classic\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000838:
|
||||
printf("* MFC 4K emulated by Nokia 6131 NFC\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
if (! found_possible_match) {
|
||||
printf("* Unknown card, sorry\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_felica_info(const nfc_felica_info nfi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf(" ID (NFCID2): ");
|
||||
print_hex(nfi.abtId, 8);
|
||||
printf(" Parameter (PAD): ");
|
||||
print_hex(nfi.abtPad, 8);
|
||||
printf(" System Code (SC): ");
|
||||
print_hex(nfi.abtSysCode, 2);
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_jewel_info(const nfc_jewel_info nji, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf(" ATQA (SENS_RES): ");
|
||||
print_hex(nji.btSensRes, 2);
|
||||
printf(" 4-LSB JEWELID: ");
|
||||
print_hex(nji.btId, 4);
|
||||
}
|
||||
|
||||
#define PI_ISO14443_4_SUPPORTED 0x01
|
||||
#define PI_NAD_SUPPORTED 0x01
|
||||
#define PI_CID_SUPPORTED 0x02
|
||||
void
|
||||
print_nfc_iso14443b_info(const nfc_iso14443b_info nbi, bool verbose)
|
||||
{
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
printf(" PUPI: ");
|
||||
print_hex(nbi.abtPupi, 4);
|
||||
printf(" Application Data: ");
|
||||
print_hex(nbi.abtApplicationData, 4);
|
||||
printf(" Protocol Info: ");
|
||||
print_hex(nbi.abtProtocolInfo, 3);
|
||||
if (verbose) {
|
||||
printf("* Bit Rate Capability:\n");
|
||||
if (nbi.abtProtocolInfo[0] == 0) {
|
||||
printf(" * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 7) {
|
||||
printf(" * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 4) {
|
||||
printf(" * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 5) {
|
||||
printf(" * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 6) {
|
||||
printf(" * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 0) {
|
||||
printf(" * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 1) {
|
||||
printf(" * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 2) {
|
||||
printf(" * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1 << 3) {
|
||||
printf(" * ERROR unknown value\n");
|
||||
}
|
||||
if ((nbi.abtProtocolInfo[1] & 0xf0) <= 0x80) {
|
||||
printf("* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
|
||||
}
|
||||
if ((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
|
||||
printf("* Protocol types supported: ISO/IEC 14443-4\n");
|
||||
}
|
||||
printf("* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((nbi.abtProtocolInfo[2] & 0xf0) >> 4)) / 13560.0);
|
||||
if ((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED | PI_CID_SUPPORTED)) != 0) {
|
||||
printf("* Frame options supported: ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) printf("NAD ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) printf("CID ");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_iso14443bi_info(const nfc_iso14443bi_info nii, bool verbose)
|
||||
{
|
||||
printf(" DIV: ");
|
||||
print_hex(nii.abtDIV, 4);
|
||||
if (verbose) {
|
||||
int version = (nii.btVerLog & 0x1e) >> 1;
|
||||
printf(" Software Version: ");
|
||||
if (version == 15) {
|
||||
printf("Undefined\n");
|
||||
} else {
|
||||
printf("%i\n", version);
|
||||
}
|
||||
|
||||
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)) {
|
||||
printf(" Wait Enable: yes");
|
||||
}
|
||||
}
|
||||
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) {
|
||||
printf(" ATS: ");
|
||||
print_hex(nii.abtAtr, nii.szAtrLen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_iso14443b2sr_info(const nfc_iso14443b2sr_info nsi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf(" UID: ");
|
||||
print_hex(nsi.abtUID, 8);
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_iso14443b2ct_info(const nfc_iso14443b2ct_info nci, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
uint32_t uid;
|
||||
uid = (nci.abtUID[3] << 24) + (nci.abtUID[2] << 16) + (nci.abtUID[1] << 8) + nci.abtUID[0];
|
||||
printf(" UID: ");
|
||||
print_hex(nci.abtUID, sizeof(nci.abtUID));
|
||||
printf(" UID (decimal): %010u\n", uid);
|
||||
printf(" Product Code: %02X\n", nci.btProdCode);
|
||||
printf(" Fab Code: %02X\n", nci.btFabCode);
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_dep_info(const nfc_dep_info ndi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf(" NFCID3: ");
|
||||
print_hex(ndi.abtNFCID3, 10);
|
||||
printf(" BS: %02x\n", ndi.btBS);
|
||||
printf(" BR: %02x\n", ndi.btBR);
|
||||
printf(" TO: %02x\n", ndi.btTO);
|
||||
printf(" PP: %02x\n", ndi.btPP);
|
||||
if (ndi.szGB) {
|
||||
printf("General Bytes: ");
|
||||
print_hex(ndi.abtGB, ndi.szGB);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_target(const nfc_target nt, bool verbose)
|
||||
{
|
||||
printf("%s (%s%s) target:\n", str_nfc_modulation_type(nt.nm.nmt), str_nfc_baud_rate(nt.nm.nbr), (nt.nm.nmt != NMT_DEP) ? "" : (nt.nti.ndi.ndm == NDM_ACTIVE) ? "active mode" : "passive mode");
|
||||
switch (nt.nm.nmt) {
|
||||
case NMT_ISO14443A:
|
||||
print_nfc_iso14443a_info(nt.nti.nai, verbose);
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
print_nfc_jewel_info(nt.nti.nji, verbose);
|
||||
break;
|
||||
case NMT_FELICA:
|
||||
print_nfc_felica_info(nt.nti.nfi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B:
|
||||
print_nfc_iso14443b_info(nt.nti.nbi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443BI:
|
||||
print_nfc_iso14443bi_info(nt.nti.nii, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B2SR:
|
||||
print_nfc_iso14443b2sr_info(nt.nti.nsi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B2CT:
|
||||
print_nfc_iso14443b2ct_info(nt.nti.nci, verbose);
|
||||
break;
|
||||
case NMT_DEP:
|
||||
print_nfc_dep_info(nt.nti.ndi, verbose);
|
||||
break;
|
||||
}
|
||||
char *s;
|
||||
str_nfc_target(&s, nt, verbose);
|
||||
printf("%s", s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -93,15 +93,6 @@ void print_hex(const uint8_t *pbtData, const size_t szLen);
|
|||
void print_hex_bits(const uint8_t *pbtData, const size_t szBits);
|
||||
void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar);
|
||||
|
||||
void print_nfc_iso14443a_info(const nfc_iso14443a_info nai, bool verbose);
|
||||
void print_nfc_iso14443b_info(const nfc_iso14443b_info nbi, bool verbose);
|
||||
void print_nfc_iso14443bi_info(const nfc_iso14443bi_info nii, bool verbose);
|
||||
void print_nfc_iso14443b2sr_info(const nfc_iso14443b2sr_info nsi, bool verbose);
|
||||
void print_nfc_iso14443b2ct_info(const nfc_iso14443b2ct_info nci, bool verbose);
|
||||
void print_nfc_felica_info(const nfc_felica_info nfi, bool verbose);
|
||||
void print_nfc_jewel_info(const nfc_jewel_info nji, bool verbose);
|
||||
void print_nfc_dep_info(const nfc_dep_info ndi, bool verbose);
|
||||
|
||||
void print_nfc_target(const nfc_target nt, bool verbose);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue