Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add protocol awareness to NFC card transceivers #2045

Merged
merged 3 commits into from
Mar 11, 2023

Conversation

jdbruner
Copy link
Contributor

@jdbruner jdbruner commented Feb 21, 2023

NFC is a complex ecosystem with multiple protocols at different layers of the stack. NFC chipsets support varying combinations of these, including special handling for some protocol-specific commands. As an example, ISO/IEC 14443 is one set of RF standards, for which 14443-3 defines initialization and anticollision (of two types, A and B), and 14443-4 defines a transmission protocol atop 14443-3. However, some protocols, notably Mifare Classic and Mifare Ultralight, use a proprietary command set atop 14443-3. Mifare Classic uses a proprietary authentication scheme, so NFC chipsets implement this authentication protocol. (Alas, security by obscurity was not successful at preventing Mifare Classic authentication from being broken, particularly because it uses a relatively short 64-bit key.)

Some Mifare Classic commands require multiple RF exchanges - these include Write16Bytes, and counter operations. The PN532 provides direct support for these commands, but this must be handled in software for other transceivers.

The PN532 also provides direct support for other protocols, such as chaining and retransmission for 14443-4.

In .NET IoT, all card transceivers derive from the CardTransceiver abstract base class and override a specific implementation of the abstract Transceive method. This creates a common interface between the different NFC card types (MifareCard, Ultralight, CreditCard) and the NFC transceiver

public abstract int Transceive(byte targetNumber, ReadOnlySpan<byte> dataToSend, Span<byte> dataFromCard);

However, the diversity of protocols and transceiver support creates challenges to implement this interface. The various implementations must deduce the type of data exchange that is being performed and handle the special cases (such as Mifare authentication and Mifare writes) appropriately. However, this is difficult to do in general, because there are multiple commands, and the commands used by different protocols overlap. For example, Mifare Classic's AuthenticationA command uses the same command byte as Ultralight's GetVersion command. For transceivers that support other protocols as well (such as Innovision Jewel or FeliCa) there is an even greater risk that commands will overlap.

Therefore, this CR redefines the transceiver interface with a breaking change. A new enum, Iot.Device.Card.NfcProtocol defines protocols that may be understood specially by NFC transceivers. A new abstract property SupportedProtocols is added to CardTransceiver and overridden by each transceiver to indicate the protocols it supports, including:

  • ISO/IEC 14443-3
  • ISO/IEC 14443-4
  • Mifare (Classic)
  • Innovision Jewel
  • JIS X 6319-4 (FeliCa)
  • ISO/IEC 15693 (ICODE SLIX)

The Transceive method has an additional parameter that specifies the protocol that the caller intends to use for this transaction:

public abstract int Transceive(byte targetNumber, ReadOnlySpan<byte> dataToSend, Span<byte> dataFromCard, NfcProtocol protocol);

Each transceiver handles the protocols according to its specific implementation:

  • Mfrc522 uses this as an indication that it should handle a request as Mifare Classic (including authentiation and two-stage write operations) or 14443-3 (such as for Ultralight). [In theory the Mfrc522 could also be used for 14443-4, but its small FIFO is a significant obstacle.]
  • Pn532 uses this to determine whether it should invoke its special handlers for various protocols (Mifare, Jewel, FeliCa, 14443-4) or simply pass through the request (14443-3, notably for Ultralight)
  • Pn5180 uses this to recognize when it should perform special handling for Mifare Classic

MifareCard always requests Mifare protocol. Ultralight requests 14443-3 except for the "compatibility write" command, which has the same command code as Mifare Classic's write command, and requires a two-step operation. CreditCard requests 14443-4.

In addition, two additional abstract properties are defined in CardTransceiver:

public abstract uint MaximumWriteSize { get; }
public abstract uint MaximumWriteSize { get; }

so that callers can determine whether their requests are appropriately sized.

This also includes some miscellaneous fixes:

  • added support for Mifare 2-step writes to PN5180
  • changed the timeout for Type A transceive in the PN5180
  • fixed a PN532 issue with commands that returned no data (e.g., Ultralight write was actually successful, but it was reported as a failure)

Tested on a Raspberry Pi 4B with MFRC522, PN532, and PN5180 using Mifare Classic and Ultralight cards. This change didn't impact the code path in PN5180 for CreditCard, but I was not able to verify that there are no regressions here.

Microsoft Reviewers: Open in CodeFlow

@ghost ghost added the area-device-bindings Device Bindings for audio, sensor, motor, and display hardware that can used with System.Device.Gpio label Feb 21, 2023
Copy link
Member

@Ellerbach Ellerbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for the proposal and the PR. We've been discussing this on Discord and I agree this is needed.
I'm fine all up with the implementation. It will make things much easier when we'll have to deal with even more protocols.
In the mean time, few comments.


/// <summary>
/// Mifare Classic
/// (proprietary commands on top of ISO/IEC 14443-3 Type A)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// (proprietary commands on top of ISO/IEC 14443-3 Type A)
/// Proprietary commands on top of ISO/IEC 14443-3 Type A

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure; I'll change this (and the same pattern in the other cases also).

Jewel = (1 << 3),

/// <summary>
/// JIS X 6319-4 (compatible with FeliCa)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// JIS X 6319-4 (compatible with FeliCa)
/// JIS X 6319-4. Compatible with FeliCa.

JisX6319_4 = (1 << 4),

/// <summary>
/// JIS X 6319-4 (compatible with FeliCa)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// JIS X 6319-4 (compatible with FeliCa)
/// JIS X 6319-4. Compatible with FeliCa.

/// <summary>
/// JIS X 6319-4 (compatible with FeliCa)
/// </summary>
FeliCa = JisX6319_4,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why defining this one equal to the previous one? Isn't 1 enough for both?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In retrospect, I don't have a strong reason, so I'll remove the duplicate.

src/devices/Mfrc522/Mfrc522.cs Show resolved Hide resolved
src/devices/Pn5180/Pn5180.cs Show resolved Hide resolved
Copy link
Member

@Ellerbach Ellerbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the improvement. This will indeed help a lot.

@Ellerbach Ellerbach merged commit 82a5abd into dotnet:main Mar 11, 2023
@minbaby
Copy link

minbaby commented Mar 14, 2023

@Ellerbach @jdbruner after merge this mr, piplines failed. some one can resolve it.

@github-actions github-actions bot locked and limited conversation to collaborators Dec 8, 2023
This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-device-bindings Device Bindings for audio, sensor, motor, and display hardware that can used with System.Device.Gpio
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants