sprint_nfc_target() => snprint_nfc_target()

And all sub-functions in target_subr.c
This commit is contained in:
Philippe Teuwen 2013-03-06 12:17:33 +01:00
parent 658ec4585a
commit a3facbdc7d
3 changed files with 197 additions and 189 deletions

View file

@ -1292,6 +1292,6 @@ str_nfc_target(char **buf, const nfc_target nt, bool verbose)
if (! *buf) if (! *buf)
return NFC_ESOFT; return NFC_ESOFT;
(*buf)[0] = '\0'; (*buf)[0] = '\0';
sprint_nfc_target(*buf, nt, verbose); snprint_nfc_target(*buf, 4096, nt, verbose);
return strlen(*buf); return strlen(*buf);
} }

View file

@ -117,15 +117,14 @@ struct card_sak const_cs[] = {
}; };
int int
sprint_hex(char *dst, const uint8_t *pbtData, const size_t szBytes) snprint_hex(char *dst, size_t size, const uint8_t *pbtData, const size_t szBytes)
{ {
size_t szPos; size_t szPos;
size_t res = 0;
int res = 0;
for (szPos = 0; szPos < szBytes; szPos++) { for (szPos = 0; szPos < szBytes; szPos++) {
res += sprintf(dst + res, "%02x ", pbtData[szPos]); res += snprintf(dst + res, size - res, "%02x ", pbtData[szPos]);
} }
res += sprintf(dst + res, "\n"); res += snprintf(dst + res, size - res, "\n");
return res; return res;
} }
@ -134,267 +133,268 @@ sprint_hex(char *dst, const uint8_t *pbtData, const size_t szBytes)
#define SAK_ISO18092_COMPLIANT 0x40 #define SAK_ISO18092_COMPLIANT 0x40
void void
sprint_nfc_iso14443a_info(char *dst, const nfc_iso14443a_info nai, bool verbose) snprint_nfc_iso14443a_info(char *dst, size_t size, const nfc_iso14443a_info nai, bool verbose)
{ {
dst += sprintf(dst, " ATQA (SENS_RES): "); int off = 0;
dst += sprint_hex(dst, nai.abtAtqa, 2); off += snprintf(dst + off, size - off, " ATQA (SENS_RES): ");
off += snprint_hex(dst + off, size - off, nai.abtAtqa, 2);
if (verbose) { if (verbose) {
dst += sprintf(dst, "* UID size: "); off += snprintf(dst + off, size - off, "* UID size: ");
switch ((nai.abtAtqa[1] & 0xc0) >> 6) { switch ((nai.abtAtqa[1] & 0xc0) >> 6) {
case 0: case 0:
dst += sprintf(dst, "single\n"); off += snprintf(dst + off, size - off, "single\n");
break; break;
case 1: case 1:
dst += sprintf(dst, "double\n"); off += snprintf(dst + off, size - off, "double\n");
break; break;
case 2: case 2:
dst += sprintf(dst, "triple\n"); off += snprintf(dst + off, size - off, "triple\n");
break; break;
case 3: case 3:
dst += sprintf(dst, "RFU\n"); off += snprintf(dst + off, size - off, "RFU\n");
break; break;
} }
dst += sprintf(dst, "* bit frame anticollision "); off += snprintf(dst + off, size - off, "* bit frame anticollision ");
switch (nai.abtAtqa[1] & 0x1f) { switch (nai.abtAtqa[1] & 0x1f) {
case 0x01: case 0x01:
case 0x02: case 0x02:
case 0x04: case 0x04:
case 0x08: case 0x08:
case 0x10: case 0x10:
dst += sprintf(dst, "supported\n"); off += snprintf(dst + off, size - off, "supported\n");
break; break;
default: default:
dst += sprintf(dst, "not supported\n"); off += snprintf(dst + off, size - off, "not supported\n");
break; break;
} }
} }
dst += sprintf(dst, " UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1')); off += snprintf(dst + off, size - off, " UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
dst += sprint_hex(dst, nai.abtUid, nai.szUidLen); off += snprint_hex(dst + off, size - off, nai.abtUid, nai.szUidLen);
if (verbose) { if (verbose) {
if (nai.abtUid[0] == 0x08) { if (nai.abtUid[0] == 0x08) {
dst += sprintf(dst, "* Random UID\n"); off += snprintf(dst + off, size - off, "* Random UID\n");
} }
} }
dst += sprintf(dst, " SAK (SEL_RES): "); off += snprintf(dst + off, size - off, " SAK (SEL_RES): ");
dst += sprint_hex(dst, &nai.btSak, 1); off += snprint_hex(dst + off, size - off, &nai.btSak, 1);
if (verbose) { if (verbose) {
if (nai.btSak & SAK_UID_NOT_COMPLETE) { if (nai.btSak & SAK_UID_NOT_COMPLETE) {
dst += sprintf(dst, "* Warning! Cascade bit set: UID not complete\n"); off += snprintf(dst + off, size - off, "* Warning! Cascade bit set: UID not complete\n");
} }
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) { if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
dst += sprintf(dst, "* Compliant with ISO/IEC 14443-4\n"); off += snprintf(dst + off, size - off, "* Compliant with ISO/IEC 14443-4\n");
} else { } else {
dst += sprintf(dst, "* Not compliant with ISO/IEC 14443-4\n"); off += snprintf(dst + off, size - off, "* Not compliant with ISO/IEC 14443-4\n");
} }
if (nai.btSak & SAK_ISO18092_COMPLIANT) { if (nai.btSak & SAK_ISO18092_COMPLIANT) {
dst += sprintf(dst, "* Compliant with ISO/IEC 18092\n"); off += snprintf(dst + off, size - off, "* Compliant with ISO/IEC 18092\n");
} else { } else {
dst += sprintf(dst, "* Not compliant with ISO/IEC 18092\n"); off += snprintf(dst + off, size - off, "* Not compliant with ISO/IEC 18092\n");
} }
} }
if (nai.szAtsLen) { if (nai.szAtsLen) {
dst += sprintf(dst, " ATS: "); off += snprintf(dst + off, size - off, " ATS: ");
dst += sprint_hex(dst, nai.abtAts, nai.szAtsLen); off += snprint_hex(dst + off, size - off, nai.abtAts, nai.szAtsLen);
} }
if (nai.szAtsLen && verbose) { if (nai.szAtsLen && verbose) {
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select) // 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 }; 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]); off += snprintf(dst + off, size - off, "* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
size_t offset = 1; size_t offset = 1;
if (nai.abtAts[0] & 0x10) { // TA(1) present if (nai.abtAts[0] & 0x10) { // TA(1) present
uint8_t TA = nai.abtAts[offset]; uint8_t TA = nai.abtAts[offset];
offset++; offset++;
dst += sprintf(dst, "* Bit Rate Capability:\n"); off += snprintf(dst + off, size - off, "* Bit Rate Capability:\n");
if (TA == 0) { if (TA == 0) {
dst += sprintf(dst, " * PICC supports only 106 kbits/s in both directions\n"); off += snprintf(dst + off, size - off, " * PICC supports only 106 kbits/s in both directions\n");
} }
if (TA & 1 << 7) { if (TA & 1 << 7) {
dst += sprintf(dst, " * Same bitrate in both directions mandatory\n"); off += snprintf(dst + off, size - off, " * Same bitrate in both directions mandatory\n");
} }
if (TA & 1 << 4) { if (TA & 1 << 4) {
dst += sprintf(dst, " * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
} }
if (TA & 1 << 5) { if (TA & 1 << 5) {
dst += sprintf(dst, " * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
} }
if (TA & 1 << 6) { if (TA & 1 << 6) {
dst += sprintf(dst, " * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
} }
if (TA & 1 << 0) { if (TA & 1 << 0) {
dst += sprintf(dst, " * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
} }
if (TA & 1 << 1) { if (TA & 1 << 1) {
dst += sprintf(dst, " * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
} }
if (TA & 1 << 2) { if (TA & 1 << 2) {
dst += sprintf(dst, " * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
} }
if (TA & 1 << 3) { if (TA & 1 << 3) {
dst += sprintf(dst, " * ERROR unknown value\n"); off += snprintf(dst + off, size - off, " * ERROR unknown value\n");
} }
} }
if (nai.abtAts[0] & 0x20) { // TB(1) present if (nai.abtAts[0] & 0x20) { // TB(1) present
uint8_t TB = nai.abtAts[offset]; uint8_t TB = nai.abtAts[offset];
offset++; offset++;
dst += sprintf(dst, "* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((TB & 0xf0) >> 4)) / 13560.0); off += snprintf(dst + off, size - off, "* Frame Waiting Time: %.4g ms\n", 256.0 * 16.0 * (1 << ((TB & 0xf0) >> 4)) / 13560.0);
if ((TB & 0x0f) == 0) { if ((TB & 0x0f) == 0) {
dst += sprintf(dst, "* No Start-up Frame Guard Time required\n"); off += snprintf(dst + off, size - off, "* No Start-up Frame Guard Time required\n");
} else { } else {
dst += sprintf(dst, "* Start-up Frame Guard Time: %.4g ms\n", 256.0 * 16.0 * (1 << (TB & 0x0f)) / 13560.0); off += snprintf(dst + off, size - off, "* 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 if (nai.abtAts[0] & 0x40) { // TC(1) present
uint8_t TC = nai.abtAts[offset]; uint8_t TC = nai.abtAts[offset];
offset++; offset++;
if (TC & 0x1) { if (TC & 0x1) {
dst += sprintf(dst, "* Node ADdress supported\n"); off += snprintf(dst + off, size - off, "* Node ADdress supported\n");
} else { } else {
dst += sprintf(dst, "* Node ADdress not supported\n"); off += snprintf(dst + off, size - off, "* Node ADdress not supported\n");
} }
if (TC & 0x2) { if (TC & 0x2) {
dst += sprintf(dst, "* Card IDentifier supported\n"); off += snprintf(dst + off, size - off, "* Card IDentifier supported\n");
} else { } else {
dst += sprintf(dst, "* Card IDentifier not supported\n"); off += snprintf(dst + off, size - off, "* Card IDentifier not supported\n");
} }
} }
if (nai.szAtsLen > offset) { if (nai.szAtsLen > offset) {
dst += sprintf(dst, "* Historical bytes Tk: "); off += snprintf(dst + off, size - off, "* Historical bytes Tk: ");
dst += sprint_hex(dst, nai.abtAts + offset, (nai.szAtsLen - offset)); off += snprint_hex(dst + off, size - off, nai.abtAts + offset, (nai.szAtsLen - offset));
uint8_t CIB = nai.abtAts[offset]; uint8_t CIB = nai.abtAts[offset];
offset++; offset++;
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) { if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
dst += sprintf(dst, " * Proprietary format\n"); off += snprintf(dst + off, size - off, " * Proprietary format\n");
if (CIB == 0xc1) { if (CIB == 0xc1) {
dst += sprintf(dst, " * Tag byte: Mifare or virtual cards of various types\n"); off += snprintf(dst + off, size - off, " * Tag byte: Mifare or virtual cards of various types\n");
uint8_t L = nai.abtAts[offset]; uint8_t L = nai.abtAts[offset];
offset++; offset++;
if (L != (nai.szAtsLen - offset)) { if (L != (nai.szAtsLen - offset)) {
dst += sprintf(dst, " * Warning: Type Identification Coding length (%i)", L); off += snprintf(dst + off, size - off, " * Warning: Type Identification Coding length (%i)", L);
dst += sprintf(dst, " not matching Tk length (%zi)\n", (nai.szAtsLen - offset)); off += snprintf(dst + off, size - off, " not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
} }
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
uint8_t CTC = nai.abtAts[offset]; uint8_t CTC = nai.abtAts[offset];
offset++; offset++;
dst += sprintf(dst, " * Chip Type: "); off += snprintf(dst + off, size - off, " * Chip Type: ");
switch (CTC & 0xf0) { switch (CTC & 0xf0) {
case 0x00: case 0x00:
dst += sprintf(dst, "(Multiple) Virtual Cards\n"); off += snprintf(dst + off, size - off, "(Multiple) Virtual Cards\n");
break; break;
case 0x10: case 0x10:
dst += sprintf(dst, "Mifare DESFire\n"); off += snprintf(dst + off, size - off, "Mifare DESFire\n");
break; break;
case 0x20: case 0x20:
dst += sprintf(dst, "Mifare Plus\n"); off += snprintf(dst + off, size - off, "Mifare Plus\n");
break; break;
default: default:
dst += sprintf(dst, "RFU\n"); off += snprintf(dst + off, size - off, "RFU\n");
break; break;
} }
dst += sprintf(dst, " * Memory size: "); off += snprintf(dst + off, size - off, " * Memory size: ");
switch (CTC & 0x0f) { switch (CTC & 0x0f) {
case 0x00: case 0x00:
dst += sprintf(dst, "<1 kbyte\n"); off += snprintf(dst + off, size - off, "<1 kbyte\n");
break; break;
case 0x01: case 0x01:
dst += sprintf(dst, "1 kbyte\n"); off += snprintf(dst + off, size - off, "1 kbyte\n");
break; break;
case 0x02: case 0x02:
dst += sprintf(dst, "2 kbyte\n"); off += snprintf(dst + off, size - off, "2 kbyte\n");
break; break;
case 0x03: case 0x03:
dst += sprintf(dst, "4 kbyte\n"); off += snprintf(dst + off, size - off, "4 kbyte\n");
break; break;
case 0x04: case 0x04:
dst += sprintf(dst, "8 kbyte\n"); off += snprintf(dst + off, size - off, "8 kbyte\n");
break; break;
case 0x0f: case 0x0f:
dst += sprintf(dst, "Unspecified\n"); off += snprintf(dst + off, size - off, "Unspecified\n");
break; break;
default: default:
dst += sprintf(dst, "RFU\n"); off += snprintf(dst + off, size - off, "RFU\n");
break; break;
} }
} }
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
uint8_t CVC = nai.abtAts[offset]; uint8_t CVC = nai.abtAts[offset];
offset++; offset++;
dst += sprintf(dst, " * Chip Status: "); off += snprintf(dst + off, size - off, " * Chip Status: ");
switch (CVC & 0xf0) { switch (CVC & 0xf0) {
case 0x00: case 0x00:
dst += sprintf(dst, "Engineering sample\n"); off += snprintf(dst + off, size - off, "Engineering sample\n");
break; break;
case 0x20: case 0x20:
dst += sprintf(dst, "Released\n"); off += snprintf(dst + off, size - off, "Released\n");
break; break;
default: default:
dst += sprintf(dst, "RFU\n"); off += snprintf(dst + off, size - off, "RFU\n");
break; break;
} }
dst += sprintf(dst, " * Chip Generation: "); off += snprintf(dst + off, size - off, " * Chip Generation: ");
switch (CVC & 0x0f) { switch (CVC & 0x0f) {
case 0x00: case 0x00:
dst += sprintf(dst, "Generation 1\n"); off += snprintf(dst + off, size - off, "Generation 1\n");
break; break;
case 0x01: case 0x01:
dst += sprintf(dst, "Generation 2\n"); off += snprintf(dst + off, size - off, "Generation 2\n");
break; break;
case 0x02: case 0x02:
dst += sprintf(dst, "Generation 3\n"); off += snprintf(dst + off, size - off, "Generation 3\n");
break; break;
case 0x0f: case 0x0f:
dst += sprintf(dst, "Unspecified\n"); off += snprintf(dst + off, size - off, "Unspecified\n");
break; break;
default: default:
dst += sprintf(dst, "RFU\n"); off += snprintf(dst + off, size - off, "RFU\n");
break; break;
} }
} }
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
uint8_t VCS = nai.abtAts[offset]; uint8_t VCS = nai.abtAts[offset];
offset++; offset++;
dst += sprintf(dst, " * Specifics (Virtual Card Selection):\n"); off += snprintf(dst + off, size - off, " * Specifics (Virtual Card Selection):\n");
if ((VCS & 0x09) == 0x00) { if ((VCS & 0x09) == 0x00) {
dst += sprintf(dst, " * Only VCSL supported\n"); off += snprintf(dst + off, size - off, " * Only VCSL supported\n");
} else if ((VCS & 0x09) == 0x01) { } else if ((VCS & 0x09) == 0x01) {
dst += sprintf(dst, " * VCS, VCSL and SVC supported\n"); off += snprintf(dst + off, size - off, " * VCS, VCSL and SVC supported\n");
} }
if ((VCS & 0x0e) == 0x00) { if ((VCS & 0x0e) == 0x00) {
dst += sprintf(dst, " * SL1, SL2(?), SL3 supported\n"); off += snprintf(dst + off, size - off, " * SL1, SL2(?), SL3 supported\n");
} else if ((VCS & 0x0e) == 0x02) { } else if ((VCS & 0x0e) == 0x02) {
dst += sprintf(dst, " * SL3 only card\n"); off += snprintf(dst + off, size - off, " * SL3 only card\n");
} else if ((VCS & 0x0f) == 0x0e) { } else if ((VCS & 0x0f) == 0x0e) {
dst += sprintf(dst, " * No VCS command supported\n"); off += snprintf(dst + off, size - off, " * No VCS command supported\n");
} else if ((VCS & 0x0f) == 0x0f) { } else if ((VCS & 0x0f) == 0x0f) {
dst += sprintf(dst, " * Unspecified\n"); off += snprintf(dst + off, size - off, " * Unspecified\n");
} else { } else {
dst += sprintf(dst, " * RFU\n"); off += snprintf(dst + off, size - off, " * RFU\n");
} }
} }
} }
} else { } else {
if (CIB == 0x00) { if (CIB == 0x00) {
dst += sprintf(dst, " * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n"); off += snprintf(dst + off, size - off, " * 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"); off += snprintf(dst + off, size - off, " 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"); off += snprintf(dst + off, size - off, " See ISO/IEC 7816-4 8.1.1.3 for more info\n");
} }
if (CIB == 0x10) { if (CIB == 0x10) {
dst += sprintf(dst, " * DIR data reference: %02x\n", nai.abtAts[offset]); off += snprintf(dst + off, size - off, " * DIR data reference: %02x\n", nai.abtAts[offset]);
} }
if (CIB == 0x80) { if (CIB == 0x80) {
if (nai.szAtsLen == offset) { if (nai.szAtsLen == offset) {
dst += sprintf(dst, " * No COMPACT-TLV objects found, no status found\n"); off += snprintf(dst + off, size - off, " * No COMPACT-TLV objects found, no status found\n");
} else { } else {
dst += sprintf(dst, " * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n"); off += snprintf(dst + off, size - off, " * 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"); off += snprintf(dst + off, size - off, " 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"); off += snprintf(dst + off, size - off, " See ISO/IEC 7816-4 8.1.1.3 for more info\n");
} }
} }
} }
} }
} }
if (verbose) { if (verbose) {
dst += sprintf(dst, "\nFingerprinting based on MIFARE type Identification Procedure:\n"); // AN10833 off += snprintf(dst + off, size - off, "\nFingerprinting based on MIFARE type Identification Procedure:\n"); // AN10833
uint16_t atqa = 0; uint16_t atqa = 0;
uint8_t sak = 0; uint8_t sak = 0;
uint8_t i, j; uint8_t i, j;
@ -409,7 +409,7 @@ sprint_nfc_iso14443a_info(char *dst, const nfc_iso14443a_info nai, bool verbose)
for (j = 0; (j < sizeof(const_ca[i].saklist)) && (const_ca[i].saklist[j] >= 0); j++) { for (j = 0; (j < sizeof(const_ca[i].saklist)) && (const_ca[i].saklist[j] >= 0); j++) {
int sakindex = const_ca[i].saklist[j]; int sakindex = const_ca[i].saklist[j];
if ((sak & const_cs[sakindex].mask) == const_cs[sakindex].sak) { if ((sak & const_cs[sakindex].mask) == const_cs[sakindex].sak) {
dst += sprintf(dst, "* %s%s\n", const_ca[i].type, const_cs[sakindex].type); off += snprintf(dst + off, size - off, "* %s%s\n", const_ca[i].type, const_cs[sakindex].type);
found_possible_match = true; found_possible_match = true;
} }
} }
@ -418,225 +418,233 @@ sprint_nfc_iso14443a_info(char *dst, const nfc_iso14443a_info nai, bool verbose)
// Other matches not described in // Other matches not described in
// AN10833 MIFARE Type Identification Procedure // AN10833 MIFARE Type Identification Procedure
// but seen in the field: // but seen in the field:
dst += sprintf(dst, "Other possible matches based on ATQA & SAK values:\n"); off += snprintf(dst + off, size - off, "Other possible matches based on ATQA & SAK values:\n");
uint32_t atqasak = 0; uint32_t atqasak = 0;
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff) << 16); atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff) << 16);
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff) << 8); atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff) << 8);
atqasak += ((uint32_t)nai.btSak & 0xff); atqasak += ((uint32_t)nai.btSak & 0xff);
switch (atqasak) { switch (atqasak) {
case 0x000488: case 0x000488:
dst += sprintf(dst, "* Mifare Classic 1K Infineon\n"); off += snprintf(dst + off, size - off, "* Mifare Classic 1K Infineon\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x000298: case 0x000298:
dst += sprintf(dst, "* Gemplus MPCOS\n"); off += snprintf(dst + off, size - off, "* Gemplus MPCOS\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x030428: case 0x030428:
dst += sprintf(dst, "* JCOP31\n"); off += snprintf(dst + off, size - off, "* JCOP31\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x004820: case 0x004820:
dst += sprintf(dst, "* JCOP31 v2.4.1\n"); off += snprintf(dst + off, size - off, "* JCOP31 v2.4.1\n");
dst += sprintf(dst, "* JCOP31 v2.2\n"); off += snprintf(dst + off, size - off, "* JCOP31 v2.2\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x000428: case 0x000428:
dst += sprintf(dst, "* JCOP31 v2.3.1\n"); off += snprintf(dst + off, size - off, "* JCOP31 v2.3.1\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x000453: case 0x000453:
dst += sprintf(dst, "* Fudan FM1208SH01\n"); off += snprintf(dst + off, size - off, "* Fudan FM1208SH01\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x000820: case 0x000820:
dst += sprintf(dst, "* Fudan FM1208\n"); off += snprintf(dst + off, size - off, "* Fudan FM1208\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x000238: case 0x000238:
dst += sprintf(dst, "* MFC 4K emulated by Nokia 6212 Classic\n"); off += snprintf(dst + off, size - off, "* MFC 4K emulated by Nokia 6212 Classic\n");
found_possible_match = true; found_possible_match = true;
break; break;
case 0x000838: case 0x000838:
dst += sprintf(dst, "* MFC 4K emulated by Nokia 6131 NFC\n"); off += snprintf(dst + off, size - off, "* MFC 4K emulated by Nokia 6131 NFC\n");
found_possible_match = true; found_possible_match = true;
break; break;
} }
if (! found_possible_match) { if (! found_possible_match) {
sprintf(dst, "* Unknown card, sorry\n"); snprintf(dst + off, size - off, "* Unknown card, sorry\n");
} }
} }
} }
void void
sprint_nfc_felica_info(char *dst, const nfc_felica_info nfi, bool verbose) snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info nfi, bool verbose)
{ {
(void) verbose; (void) verbose;
dst += sprintf(dst, " ID (NFCID2): "); int off = 0;
dst += sprint_hex(dst, nfi.abtId, 8); off += snprintf(dst + off, size - off, " ID (NFCID2): ");
dst += sprintf(dst, " Parameter (PAD): "); off += snprint_hex(dst + off, size - off, nfi.abtId, 8);
dst += sprint_hex(dst, nfi.abtPad, 8); off += snprintf(dst + off, size - off, " Parameter (PAD): ");
dst += sprintf(dst, " System Code (SC): "); off += snprint_hex(dst + off, size - off, nfi.abtPad, 8);
sprint_hex(dst, nfi.abtSysCode, 2); off += snprintf(dst + off, size - off, " System Code (SC): ");
snprint_hex(dst + off, size - off, nfi.abtSysCode, 2);
} }
void void
sprint_nfc_jewel_info(char *dst, const nfc_jewel_info nji, bool verbose) snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info nji, bool verbose)
{ {
(void) verbose; (void) verbose;
dst += sprintf(dst, " ATQA (SENS_RES): "); int off = 0;
dst += sprint_hex(dst, nji.btSensRes, 2); off += snprintf(dst + off, size - off, " ATQA (SENS_RES): ");
dst += sprintf(dst, " 4-LSB JEWELID: "); off += snprint_hex(dst + off, size - off, nji.btSensRes, 2);
sprint_hex(dst, nji.btId, 4); off += snprintf(dst + off, size - off, " 4-LSB JEWELID: ");
snprint_hex(dst + off, size - off, nji.btId, 4);
} }
#define PI_ISO14443_4_SUPPORTED 0x01 #define PI_ISO14443_4_SUPPORTED 0x01
#define PI_NAD_SUPPORTED 0x01 #define PI_NAD_SUPPORTED 0x01
#define PI_CID_SUPPORTED 0x02 #define PI_CID_SUPPORTED 0x02
void void
sprint_nfc_iso14443b_info(char *dst, const nfc_iso14443b_info nbi, bool verbose) snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info nbi, bool verbose)
{ {
dst += sprintf(dst, " PUPI: "); int off = 0;
dst += sprint_hex(dst, nbi.abtPupi, 4); off += snprintf(dst + off, size - off, " PUPI: ");
dst += sprintf(dst, " Application Data: "); off += snprint_hex(dst + off, size - off, nbi.abtPupi, 4);
dst += sprint_hex(dst, nbi.abtApplicationData, 4); off += snprintf(dst + off, size - off, " Application Data: ");
dst += sprintf(dst, " Protocol Info: "); off += snprint_hex(dst + off, size - off, nbi.abtApplicationData, 4);
dst += sprint_hex(dst, nbi.abtProtocolInfo, 3); off += snprintf(dst + off, size - off, " Protocol Info: ");
off += snprint_hex(dst + off, size - off, nbi.abtProtocolInfo, 3);
if (verbose) { if (verbose) {
dst += sprintf(dst, "* Bit Rate Capability:\n"); off += snprintf(dst + off, size - off, "* Bit Rate Capability:\n");
if (nbi.abtProtocolInfo[0] == 0) { if (nbi.abtProtocolInfo[0] == 0) {
dst += sprintf(dst, " * PICC supports only 106 kbits/s in both directions\n"); off += snprintf(dst + off, size - off, " * PICC supports only 106 kbits/s in both directions\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 7) { if (nbi.abtProtocolInfo[0] & 1 << 7) {
dst += sprintf(dst, " * Same bitrate in both directions mandatory\n"); off += snprintf(dst + off, size - off, " * Same bitrate in both directions mandatory\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 4) { if (nbi.abtProtocolInfo[0] & 1 << 4) {
dst += sprintf(dst, " * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 5) { if (nbi.abtProtocolInfo[0] & 1 << 5) {
dst += sprintf(dst, " * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 6) { if (nbi.abtProtocolInfo[0] & 1 << 6) {
dst += sprintf(dst, " * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 0) { if (nbi.abtProtocolInfo[0] & 1 << 0) {
dst += sprintf(dst, " * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 1) { if (nbi.abtProtocolInfo[0] & 1 << 1) {
dst += sprintf(dst, " * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 2) { if (nbi.abtProtocolInfo[0] & 1 << 2) {
dst += sprintf(dst, " * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n"); off += snprintf(dst + off, size - off, " * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
} }
if (nbi.abtProtocolInfo[0] & 1 << 3) { if (nbi.abtProtocolInfo[0] & 1 << 3) {
dst += sprintf(dst, " * ERROR unknown value\n"); off += snprintf(dst + off, size - off, " * ERROR unknown value\n");
} }
if ((nbi.abtProtocolInfo[1] & 0xf0) <= 0x80) { if ((nbi.abtProtocolInfo[1] & 0xf0) <= 0x80) {
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 }; const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
dst += sprintf(dst, "* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]); off += snprintf(dst + off, size - off, "* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
} }
if ((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) { if ((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
dst += sprintf(dst, "* Protocol types supported: ISO/IEC 14443-4\n"); off += snprintf(dst + off, size - off, "* 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); off += snprintf(dst + off, size - off, "* 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) { if ((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED | PI_CID_SUPPORTED)) != 0) {
dst += sprintf(dst, "* Frame options supported: "); off += snprintf(dst + off, size - off, "* Frame options supported: ");
if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) dst += sprintf(dst, "NAD "); if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) off += snprintf(dst + off, size - off, "NAD ");
if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) dst += sprintf(dst, "CID "); if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) off += snprintf(dst + off, size - off, "CID ");
sprintf(dst, "\n"); snprintf(dst + off, size - off, "\n");
} }
} }
} }
void void
sprint_nfc_iso14443bi_info(char *dst, const nfc_iso14443bi_info nii, bool verbose) snprint_nfc_iso14443bi_info(char *dst, size_t size, const nfc_iso14443bi_info nii, bool verbose)
{ {
dst += sprintf(dst, " DIV: "); int off = 0;
dst += sprint_hex(dst, nii.abtDIV, 4); off += snprintf(dst + off, size - off, " DIV: ");
off += snprint_hex(dst + off, size - off, nii.abtDIV, 4);
if (verbose) { if (verbose) {
int version = (nii.btVerLog & 0x1e) >> 1; int version = (nii.btVerLog & 0x1e) >> 1;
dst += sprintf(dst, " Software Version: "); off += snprintf(dst + off, size - off, " Software Version: ");
if (version == 15) { if (version == 15) {
dst += sprintf(dst, "Undefined\n"); off += snprintf(dst + off, size - off, "Undefined\n");
} else { } else {
dst += sprintf(dst, "%i\n", version); off += snprintf(dst + off, size - off, "%i\n", version);
} }
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)) { if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)) {
dst += sprintf(dst, " Wait Enable: yes"); off += snprintf(dst + off, size - off, " Wait Enable: yes");
} }
} }
if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) { if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) {
dst += sprintf(dst, " ATS: "); off += snprintf(dst + off, size - off, " ATS: ");
sprint_hex(dst, nii.abtAtr, nii.szAtrLen); snprint_hex(dst + off, size - off, nii.abtAtr, nii.szAtrLen);
} }
} }
void void
sprint_nfc_iso14443b2sr_info(char *dst, const nfc_iso14443b2sr_info nsi, bool verbose) snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info nsi, bool verbose)
{ {
(void) verbose; (void) verbose;
dst += sprintf(dst, " UID: "); int off = 0;
sprint_hex(dst, nsi.abtUID, 8); off += snprintf(dst + off, size - off, " UID: ");
snprint_hex(dst + off, size - off, nsi.abtUID, 8);
} }
void void
sprint_nfc_iso14443b2ct_info(char *dst, const nfc_iso14443b2ct_info nci, bool verbose) snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info nci, bool verbose)
{ {
(void) verbose; (void) verbose;
int off = 0;
uint32_t uid; uint32_t uid;
uid = (nci.abtUID[3] << 24) + (nci.abtUID[2] << 16) + (nci.abtUID[1] << 8) + nci.abtUID[0]; uid = (nci.abtUID[3] << 24) + (nci.abtUID[2] << 16) + (nci.abtUID[1] << 8) + nci.abtUID[0];
dst += sprintf(dst, " UID: "); off += snprintf(dst + off, size - off, " UID: ");
dst += sprint_hex(dst, nci.abtUID, sizeof(nci.abtUID)); off += snprint_hex(dst + off, size - off, nci.abtUID, sizeof(nci.abtUID));
dst += sprintf(dst, " UID (decimal): %010u\n", uid); off += snprintf(dst + off, size - off, " UID (decimal): %010u\n", uid);
dst += sprintf(dst, " Product Code: %02X\n", nci.btProdCode); off += snprintf(dst + off, size - off, " Product Code: %02X\n", nci.btProdCode);
sprintf(dst, " Fab Code: %02X\n", nci.btFabCode); snprintf(dst + off, size - off, " Fab Code: %02X\n", nci.btFabCode);
} }
void void
sprint_nfc_dep_info(char *dst, const nfc_dep_info ndi, bool verbose) snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info ndi, bool verbose)
{ {
(void) verbose; (void) verbose;
dst += sprintf(dst, " NFCID3: "); int off = 0;
dst += sprint_hex(dst, ndi.abtNFCID3, 10); off += snprintf(dst + off, size - off, " NFCID3: ");
dst += sprintf(dst, " BS: %02x\n", ndi.btBS); off += snprint_hex(dst + off, size - off, ndi.abtNFCID3, 10);
dst += sprintf(dst, " BR: %02x\n", ndi.btBR); off += snprintf(dst + off, size - off, " BS: %02x\n", ndi.btBS);
dst += sprintf(dst, " TO: %02x\n", ndi.btTO); off += snprintf(dst + off, size - off, " BR: %02x\n", ndi.btBR);
dst += sprintf(dst, " PP: %02x\n", ndi.btPP); off += snprintf(dst + off, size - off, " TO: %02x\n", ndi.btTO);
off += snprintf(dst + off, size - off, " PP: %02x\n", ndi.btPP);
if (ndi.szGB) { if (ndi.szGB) {
dst += sprintf(dst, "General Bytes: "); off += snprintf(dst + off, size - off, "General Bytes: ");
sprint_hex(dst, ndi.abtGB, ndi.szGB); snprint_hex(dst + off, size - off, ndi.abtGB, ndi.szGB);
} }
} }
void void
sprint_nfc_target(char *dst, const nfc_target nt, bool verbose) snprint_nfc_target(char *dst, size_t size, 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"); int off = 0;
off += snprintf(dst + off, size - off, "%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) { switch (nt.nm.nmt) {
case NMT_ISO14443A: case NMT_ISO14443A:
sprint_nfc_iso14443a_info(dst, nt.nti.nai, verbose); snprint_nfc_iso14443a_info(dst + off, size - off, nt.nti.nai, verbose);
break; break;
case NMT_JEWEL: case NMT_JEWEL:
sprint_nfc_jewel_info(dst, nt.nti.nji, verbose); snprint_nfc_jewel_info(dst + off, size - off, nt.nti.nji, verbose);
break; break;
case NMT_FELICA: case NMT_FELICA:
sprint_nfc_felica_info(dst, nt.nti.nfi, verbose); snprint_nfc_felica_info(dst + off, size - off, nt.nti.nfi, verbose);
break; break;
case NMT_ISO14443B: case NMT_ISO14443B:
sprint_nfc_iso14443b_info(dst, nt.nti.nbi, verbose); snprint_nfc_iso14443b_info(dst + off, size - off, nt.nti.nbi, verbose);
break; break;
case NMT_ISO14443BI: case NMT_ISO14443BI:
sprint_nfc_iso14443bi_info(dst, nt.nti.nii, verbose); snprint_nfc_iso14443bi_info(dst + off, size - off, nt.nti.nii, verbose);
break; break;
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
sprint_nfc_iso14443b2sr_info(dst, nt.nti.nsi, verbose); snprint_nfc_iso14443b2sr_info(dst + off, size - off, nt.nti.nsi, verbose);
break; break;
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
sprint_nfc_iso14443b2ct_info(dst, nt.nti.nci, verbose); snprint_nfc_iso14443b2ct_info(dst + off, size - off, nt.nti.nci, verbose);
break; break;
case NMT_DEP: case NMT_DEP:
sprint_nfc_dep_info(dst, nt.nti.ndi, verbose); snprint_nfc_dep_info(dst + off, size - off, nt.nti.ndi, verbose);
break; break;
} }
} }

View file

@ -27,15 +27,15 @@
#ifndef _TARGET_SUBR_H_ #ifndef _TARGET_SUBR_H_
#define _TARGET_SUBR_H_ #define _TARGET_SUBR_H_
int sprint_hex(char *dst, const uint8_t *pbtData, const size_t szLen); int snprint_hex(char *dst, size_t size, const uint8_t *pbtData, const size_t szLen);
void sprint_nfc_iso14443a_info(char *dst, const nfc_iso14443a_info nai, bool verbose); void snprint_nfc_iso14443a_info(char *dst, size_t size, const nfc_iso14443a_info nai, bool verbose);
void sprint_nfc_iso14443b_info(char *dst, const nfc_iso14443b_info nbi, bool verbose); void snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info nbi, bool verbose);
void sprint_nfc_iso14443bi_info(char *dst, const nfc_iso14443bi_info nii, bool verbose); void snprint_nfc_iso14443bi_info(char *dst, size_t size, const nfc_iso14443bi_info nii, bool verbose);
void sprint_nfc_iso14443b2sr_info(char *dst, const nfc_iso14443b2sr_info nsi, bool verbose); void snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info nsi, bool verbose);
void sprint_nfc_iso14443b2ct_info(char *dst, const nfc_iso14443b2ct_info nci, bool verbose); void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info nci, bool verbose);
void sprint_nfc_felica_info(char *dst, const nfc_felica_info nfi, bool verbose); void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info nfi, bool verbose);
void sprint_nfc_jewel_info(char *dst, const nfc_jewel_info nji, bool verbose); void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info nji, bool verbose);
void sprint_nfc_dep_info(char *dst, const nfc_dep_info ndi, bool verbose); void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info ndi, bool verbose);
void sprint_nfc_target(char *dst, const nfc_target nt, bool verbose); void snprint_nfc_target(char *dst, size_t size, const nfc_target nt, bool verbose);
#endif #endif