Many command return 1 byte, and my documentation does not tell what it's
supposed to be. However, this byte is always 0 when running the regression test
suite. It's likely to be an error code with value 0 being a no-error code.
Assume this and check that the returned byte is always 0.
For the regression test-suite test_mifare_desfire, it's a ~11% performance
boost, with 206 cache hits out of 488 calls to
mifare_desfire_get_file_settings().
The check is already done by the PICC and we may not have access to the
required information to do the check from the library. Additionally, the
mifare_desfire_change_key() would require different keys to operate if we
detected an error, so no recovery of any kind is possible.
Currently, when the libfreefare finds a NFC target, it checks whether it's a
supported one looking at it's ATQA.
If the target's ATQA is not in the supported ATQA list, the target was not
deselected. While this is buggy, it allowed to detect 2 tags with colliding
ATQA on a single NFC device and still have the ATQA of each tag (on ATQA
collision, the ATQA is set to 0x0000 by the NFC chip, but as the tag is not
deselected, it will have a second chance to tell it's ATQA when it will be idle
again):
computer PCD PICC1 PICC2
| | ATQA: 0x1234 0x6789
| | | |
|- InListTargets ->| | |
| |------ REQA ----->(===============)
| |<---- ATQA 1234 ------| | } Both reply
| |<---- ATQA 6789 --------------| } simultaneously
| | S |
| | // Collision detected PICC1 only is selected because
| | // only a single tag was wanted. It's ATQA is set
| | // to 0x0000.
|<-- ATQA 0x0000 --| S |
| // Unsuported ATQA, skipped S |
| | S |
| // DESELECT IS MISSING HERE! S |
| | S |
|- InListTargets ->| S |
| |------ REQA ----->(===============)
| |<---- ATQA 6789 --------------S // PICC1 won't reply
|<-- ATQA 0x6789 --| | S // it is still selected
| // Supported, deselect it | S
|--- InDeselect -->| | S
| |-------- HALT --------------->X
| | | X
|- InListTargets ->| | X
| |------ REQA ----->(===============)
| |<---- ATQA 1234 ------S X // PICC2 won't reply
|<-- ATQA 0x1234 --| S X // it is deselected
| // Supported, deselect it S X
|--- InDeselect -->| S X
| |-------- HALT ------->X X
| | X X
|--- InDeselect -->| X X
| |------ REQA ----->(===============)
| | X X // No reply
| | X X
Tag timeline legend:
| - Target idle
S - Target selected
X - Target deselected
Since PN53x devices can only known about 2 tags simultaneously, presenting 3
targets to the NFC device caused an infinite loop.
This commit prevents this infinite loop to occur, and will be completed later
by another commit for not relying on the ATQA to determine targets type.
Instead of uting nfc_initiator_transceive_dep_bytes() to transmit commands,
prepend an ISO-14443-4 header to it and send it using
nfc_initiator_transceive_bytes(). In case of WTX reply, handle it, and then
extract relevant information from the data returned by the PICC.
This prevents failure that happen with ISO-14443-4 compliant targets when using
a PN531-based NFC-device, and allows using the libfreefare with Mifare DESFire
targets on such devices.
Not a hack this time:
- Use the hexdump(3) function of the system if it exists;
- Build the subpart of FreeBSD's libutil if not (contrib);
- Do this only if configured --with-debug.
The Mifare Classic / Ultralight code will be eventually changed to also provide this functionality.
This should avoid failure in some advanced use cases and when the example will be able to add user-provided data without data-loss.
Suggested by: Romuald Conty <rconty@il4p.fr>
The code can work with virtually any size of DESFire (since the operating
system embedded in the card handle almost everything), so there is no need for
us to distinguish cards of different sizes.