NfcCx: Fix NCI 2 behavior when connecting to a T2T tag.

Currently there is code in the NFC CX that triggers NFC-A's SLP_REQ
command (NFC Forum, Digital Protocol, Version 2.1, Section 6.9.1) when
connecting to a T2T (e.g. Mifare) NFC tag when in NCI 2 mode.

However there are two problems:

1. The NCI specs (both versions 1 and 2) explictly call out that the
SLP_REQ command should be handled by the NFC Controller not the driver.
(NFC Forum, NCI, Version 2.0, Section 8.2.4.2, Table 94.)

2. The wrong command code is being used. Specifically, '05 00' instead
of '50 00'. So even if the SLP_REQ command was required, it would be
broken.

This change removes the code that invokes the SLP_REQ command.

In addition, tests are added for reading a T2T tag in NCI 2 mode. Also,
some code duplication was removed from the `TagTests` class.
This commit is contained in:
Chris Gunn 2018-12-31 13:54:40 -08:00
Родитель 511ce9b2a6
Коммит 026f987edb
2 изменённых файлов: 95 добавлений и 147 удалений

Просмотреть файл

@ -21,10 +21,14 @@
class TagTests
{
public:
TEST_CLASS(TagTests);
// Tests reading a NDEF NFC tag using a proximity subscription.
BEGIN_TEST_METHOD(SimpleNdefSubscriptionTest)
BEGIN_TEST_METHOD(SimpleNdefSubscriptionNci1Test)
TEST_METHOD_PROPERTY(L"Category", L"GoldenPath")
END_TEST_METHOD()
BEGIN_TEST_METHOD(SimpleNdefSubscriptionNci2Test)
TEST_METHOD_PROPERTY(L"Category", L"GoldenPath")
END_TEST_METHOD()
// Ensures NfcCxRf/NfcCxState will properly defer processing the tag arrivial event while an existing operation
@ -37,32 +41,31 @@ class TagTests
BEGIN_TEST_METHOD(SimpleNdefSubscriptionTestWithSlowIO)
TEST_METHOD_PROPERTY(L"Category", L"Reliability")
END_TEST_METHOD()
private:
void SimpleNdefSubscriptionTest(bool isNci2);
UniqueHandle OpenSubscription(NciSimConnector& simConnector, bool isNci2);
void CloseSubscription(NciSimConnector& simConnector, bool isNci2, UniqueHandle&& nfpSubInterface);
std::shared_ptr<IoOperation> StartGetSubscriptionMessage(HANDLE nfpSubInterface);
void VerifySubscriptionMessage(const std::shared_ptr<IoOperation>& ioGetMessage);
};
void
TagTests::SimpleNdefSubscriptionTest()
TagTests::SimpleNdefSubscriptionTest(bool isNci2)
{
LOG_COMMENT(L"# Open connection to NCI Simulator Driver.");
NciSimConnector simConnector;
// Start NFC Controller.
LOG_COMMENT(L"# Start NFC Controller.");
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
// Startup.
UniqueHandle nfpSubInterface = OpenSubscription(simConnector, isNci2);
// Verify NCI is initialized.
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1);
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
// Open handle for NDEF subscription.
UniqueHandle nfpSubInterface = DriverHandleFactory::OpenSubscriptionHandle(simConnector.DeviceId().c_str(), L"NDEF");
// Start an I/O request for the next message,
constexpr DWORD messageBufferSize = 2048;
std::shared_ptr<IoOperation> ioGetMessage = IoOperation::DeviceIoControl(nfpSubInterface.Get(), IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE, nullptr, 0, messageBufferSize);
// Start get next message request.
std::shared_ptr<IoOperation> ioGetMessage = StartGetSubscriptionMessage(nfpSubInterface.Get());
// Verify discovery mode is started.
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Entry);
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence_Nci1);
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence(isNci2));
// Provide a tag for the subscription to read.
SimSequenceRunner::Run(simConnector, TagSequences::Ntag216Activated::Sequence);
@ -70,32 +73,25 @@ TagTests::SimpleNdefSubscriptionTest()
// The driver has finished with the tag. So it will restart discovery to look for new tags.
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStop::Sequence);
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence_Nci1);
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence(isNci2));
// Ensure subscription receives the tag's message.
VERIFY_IS_TRUE(ioGetMessage->Wait(/*wait (ms)*/ 1'000));
// Verify message.
VerifySubscriptionMessage(ioGetMessage);
IoOperationResult ioGetMessageResult = ioGetMessage->Get();
VERIFY_WIN32_SUCCEEDED(ioGetMessageResult.ErrorCode);
// Shutdown.
CloseSubscription(simConnector, isNci2, std::move(nfpSubInterface));
}
// Verify message is correct.
VerifyProximitySubscribeMessage(ioGetMessageResult.Output.data(), ioGetMessageResult.BytesTransferred, TagPayloads::NdefBingUri, std::size(TagPayloads::NdefBingUri));
void
TagTests::SimpleNdefSubscriptionNci1Test()
{
SimpleNdefSubscriptionTest(false);
}
// Close proximity subscription handle.
// This should drop the last power reference, which should cause discovery to stop and NCI to be uninitialized.
nfpSubInterface.Reset();
// Verify discovery mode is stopped.
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStop::Sequence);
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Exit);
// Stop NFC Controller.
LOG_COMMENT(L"# Stop NFC Controller.");
std::shared_ptr<IoOperation> ioStopHost = simConnector.StopHostAsync();
// Verify NCI is uninitialized.
SimSequenceRunner::Run(simConnector, InitSequences::Uninitialize::Sequence_Nci1);
VERIFY_IS_TRUE(ioStopHost->Wait(/*timeout(ms)*/ 1'000));
void
TagTests::SimpleNdefSubscriptionNci2Test()
{
SimpleNdefSubscriptionTest(true);
}
void
@ -104,20 +100,11 @@ TagTests::NdefSubscriptionWithEarlyTagArrivalTest()
LOG_COMMENT(L"# Open connection to NCI Simulator Driver.");
NciSimConnector simConnector;
// Start NFC Controller.
LOG_COMMENT(L"# Start NFC Controller.");
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
// Startup.
UniqueHandle nfpSubInterface = OpenSubscription(simConnector, false);
// Verify NCI is initialized.
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1);
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
// Open handle for NDEF subscription.
UniqueHandle nfpSubInterface = DriverHandleFactory::OpenSubscriptionHandle(simConnector.DeviceId().c_str(), L"NDEF");
// Start an I/O request for the next message,
constexpr DWORD messageBufferSize = 2048;
std::shared_ptr<IoOperation> ioGetMessage = IoOperation::DeviceIoControl(nfpSubInterface.Get(), IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE, nullptr, 0, messageBufferSize);
// Start get next message request.
std::shared_ptr<IoOperation> ioGetMessage = StartGetSubscriptionMessage(nfpSubInterface.Get());
// Verify discovery mode is started. But don't complete the SequenceRfDiscStartComplete sequence handler yet.
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Entry);
@ -140,30 +127,11 @@ TagTests::NdefSubscriptionWithEarlyTagArrivalTest()
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStop::Sequence);
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence_Nci1);
// Ensure subscription receives the tag's message.
VERIFY_IS_TRUE(ioGetMessage->Wait(/*wait (ms)*/ 1'000));
// Verify message.
VerifySubscriptionMessage(ioGetMessage);
IoOperationResult ioGetMessageResult = ioGetMessage->Get();
VERIFY_WIN32_SUCCEEDED(ioGetMessageResult.ErrorCode);
// Verify message is correct.
VerifyProximitySubscribeMessage(ioGetMessageResult.Output.data(), ioGetMessageResult.BytesTransferred, TagPayloads::NdefBingUri, std::size(TagPayloads::NdefBingUri));
// Close proximity subscription handle.
// This should drop the last power reference, which should cause discovery to stop and NCI to be uninitialized.
nfpSubInterface.Reset();
// Verify discovery mode is stopped.
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStop::Sequence);
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Exit);
// Stop NFC Controller.
LOG_COMMENT(L"# Stop NFC Controller.");
std::shared_ptr<IoOperation> ioStopHost = simConnector.StopHostAsync();
// Verify NCI is uninitialized.
SimSequenceRunner::Run(simConnector, InitSequences::Uninitialize::Sequence_Nci1);
VERIFY_IS_TRUE(ioStopHost->Wait(/*timeout(ms)*/ 1'000));
// Shutdown.
CloseSubscription(simConnector, false, std::move(nfpSubInterface));
}
void
@ -172,20 +140,11 @@ TagTests::SimpleNdefSubscriptionTestWithSlowIO()
LOG_COMMENT(L"# Open connection to NCI Simulator Driver.");
NciSimConnector simConnector;
// Start NFC Controller.
LOG_COMMENT(L"# Start NFC Controller.");
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
// Startup.
UniqueHandle nfpSubInterface = OpenSubscription(simConnector, false);
// Verify NCI is initialized.
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence_Nci1);
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
// Open handle for NDEF subscription.
UniqueHandle nfpSubInterface = DriverHandleFactory::OpenSubscriptionHandle(simConnector.DeviceId().c_str(), L"NDEF");
// Start an I/O request for the next message,
constexpr DWORD messageBufferSize = 2048;
std::shared_ptr<IoOperation> ioGetMessage = IoOperation::DeviceIoControl(nfpSubInterface.Get(), IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE, nullptr, 0, messageBufferSize);
// Start get next message request.
std::shared_ptr<IoOperation> ioGetMessage = StartGetSubscriptionMessage(nfpSubInterface.Get());
// Verify discovery mode is started.
SimSequenceRunner::Run(simConnector, InitSequences::Power::D0Entry);
@ -211,17 +170,35 @@ TagTests::SimpleNdefSubscriptionTestWithSlowIO()
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStop::Sequence);
SimSequenceRunner::Run(simConnector, RfDiscoverySequences::DiscoveryStart::Sequence_Nci1);
// Ensure subscription receives the tag's message.
VERIFY_IS_TRUE(ioGetMessage->Wait(/*wait (ms)*/ 1'000));
// Verify message.
VerifySubscriptionMessage(ioGetMessage);
IoOperationResult ioGetMessageResult = ioGetMessage->Get();
VERIFY_WIN32_SUCCEEDED(ioGetMessageResult.ErrorCode);
// Shutdown.
CloseSubscription(simConnector, false, std::move(nfpSubInterface));
}
// Verify message is correct.
VerifyProximitySubscribeMessage(ioGetMessageResult.Output.data(), ioGetMessageResult.BytesTransferred, TagPayloads::NdefBingUri, std::size(TagPayloads::NdefBingUri));
UniqueHandle
TagTests::OpenSubscription(NciSimConnector& simConnector, bool isNci2)
{
// Start NFC Controller.
LOG_COMMENT(L"# Start NFC Controller.");
std::shared_ptr<IoOperation> ioStartHost = simConnector.StartHostAsync();
// Verify NCI is initialized.
SimSequenceRunner::Run(simConnector, InitSequences::Initialize::NoSEsSequence(isNci2));
VERIFY_IS_TRUE(ioStartHost->Wait(/*timeout(ms)*/ 1'000));
// Open handle for NDEF subscription.
UniqueHandle nfpSubInterface = DriverHandleFactory::OpenSubscriptionHandle(simConnector.DeviceId().c_str(), L"NDEF");
return std::move(nfpSubInterface);
}
void
TagTests::CloseSubscription(NciSimConnector& simConnector, bool isNci2, UniqueHandle&& nfpSubInterface)
{
// Close proximity subscription handle.
// This should drop the last power reference, which should cause discovery to stop.
// This should drop the last power reference, which should cause discovery to stop and NCI to be uninitialized.
nfpSubInterface.Reset();
// Verify discovery mode is stopped.
@ -233,6 +210,29 @@ TagTests::SimpleNdefSubscriptionTestWithSlowIO()
std::shared_ptr<IoOperation> ioStopHost = simConnector.StopHostAsync();
// Verify NCI is uninitialized.
SimSequenceRunner::Run(simConnector, InitSequences::Uninitialize::Sequence_Nci1);
SimSequenceRunner::Run(simConnector, InitSequences::Uninitialize::Sequence(isNci2));
VERIFY_IS_TRUE(ioStopHost->Wait(/*timeout(ms)*/ 1'000));
}
std::shared_ptr<IoOperation>
TagTests::StartGetSubscriptionMessage(HANDLE nfpSubInterface)
{
// Start an I/O request for the next message,
constexpr DWORD messageBufferSize = 2048;
std::shared_ptr<IoOperation> ioGetMessage = IoOperation::DeviceIoControl(nfpSubInterface, IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE, nullptr, 0, messageBufferSize);
return std::move(ioGetMessage);
}
void
TagTests::VerifySubscriptionMessage(const std::shared_ptr<IoOperation>& ioGetMessage)
{
// Ensure subscription receives the tag's message.
VERIFY_IS_TRUE(ioGetMessage->Wait(/*wait (ms)*/ 1'000));
IoOperationResult ioGetMessageResult = ioGetMessage->Get();
VERIFY_WIN32_SUCCEEDED(ioGetMessageResult.ErrorCode);
// Verify message is correct.
VerifyProximitySubscribeMessage(ioGetMessageResult.Output.data(), ioGetMessageResult.BytesTransferred, TagPayloads::NdefBingUri, std::size(TagPayloads::NdefBingUri));
}

Просмотреть файл

@ -25,7 +25,6 @@
#define PHLIBNFC_FELICA_REQRES_RESP_LEN (0x0BU) /**< Payload length for response of RequestResp command */
static NFCSTATUS phLibNfc_MifareULSendGetVersionCmd(void *pContext, NFCSTATUS status, void *pInfo);
static NFCSTATUS phLibNfc_T2TSendSleepCmd(void *pContext, NFCSTATUS status, void *pInfo);
static NFCSTATUS phLibNfc_MifareULProcessGetVersionResp(void *pContext, NFCSTATUS status, void *pInfo);
static NFCSTATUS phLibNfc_MifareULSendAuthenticateCmd(void *pContext, NFCSTATUS status, void *pInfo);
static NFCSTATUS phLibNfc_MifareULProcessAuthenticateResp(void *pContext, NFCSTATUS status, void *pInfo);
@ -126,12 +125,10 @@ static phLibNfc_Sequence_t gphLibNfc_ReActivate_MFCSeqSelect[] = {
/* Distinguish Mifare Ultralight card between Ultralight, Ultralight C, and Ultralight EV1*/
static phLibNfc_Sequence_t gphLibNfc_DistinguishMifareUL[] = {
{&phLibNfc_T2TSendSleepCmd,NULL },
{&phLibNfc_MifareULSendGetVersionCmd, &phLibNfc_MifareULProcessGetVersionResp},
{&phLibNfc_MifareULDeactivateCard, &phLibNfc_MifareULProcessDeactivateCard},
{&phLibNfc_MifareULConnectCard, &phLibNfc_MifareULProcessConnectCard},
{&phLibNfc_MifareULSendAuthenticateCmd, &phLibNfc_MifareULProcessAuthenticateResp},
{&phLibNfc_T2TSendSleepCmd, NULL },
{&phLibNfc_MifareULDeactivateCard, &phLibNfc_MifareULProcessDeactivateCard},
{&phLibNfc_MifareULConnectCard, &phLibNfc_MifareULProcessConnectCard},
{NULL, &phLibNfc_ReqInfoComplete}
@ -4964,55 +4961,6 @@ static NFCSTATUS phLibNfc_MifareULSendGetVersionCmd(void *pContext, NFCSTATUS st
return wStatus;
}
static NFCSTATUS phLibNfc_T2TSendSleepCmd(void *pContext, NFCSTATUS status, void *pInfo)
{
const uint8_t t2t_sendSleepCmd[] = {0x05,0x00};
const uint16_t timeoutMillis = 50;
NFCSTATUS wStatus = status;
pphLibNfc_Context_t pCtx = (pphLibNfc_Context_t)pContext;
phNciNfc_TransceiveInfo_t transceiveInfo = { 0 };
phNciNfc_DeviceInfo_t* pDeviceInfo = NULL;
UNUSED(pInfo);
PH_LOG_LIBNFC_FUNC_ENTRY();
if (NULL != pCtx)
{
PH_LOG_LIBNFC_INFO_STR("Nci Version = %x", pCtx->tNfccFeatures.NciVer);
if(phNciNfc_IsVersion2x(phNciNfc_GetContext()))
{
/* NCI 2.0 -DH is responsible for sending deactivation command to tag */
phOsalNfc_MemCopy(pCtx->aSendBuff, t2t_sendSleepCmd, sizeof(t2t_sendSleepCmd));
transceiveInfo.uCmd.T2TCmd = phNciNfc_eT2TRaw;
transceiveInfo.tSendData.pBuff = pCtx->aSendBuff;
transceiveInfo.tSendData.wLen = sizeof(t2t_sendSleepCmd);
transceiveInfo.tRecvData.pBuff = pCtx->aRecvBuff;
transceiveInfo.tRecvData.wLen = sizeof(pCtx->aRecvBuff);
transceiveInfo.wTimeout = timeoutMillis;
pDeviceInfo = (phNciNfc_DeviceInfo_t*)pCtx->pInfo;
wStatus = phNciNfc_Transceive(pCtx->sHwReference.pNciHandle,
pDeviceInfo->pRemDevList[0],
&transceiveInfo,
&phLibNfc_MifareULDistinguishSequence,
pCtx);
}
else
{
PH_LOG_LIBNFC_INFO_STR("Stack is booted in Nci Version = %x", pCtx->tNfccFeatures.NciVer);
wStatus = NFCSTATUS_SUCCESS;
}
}
else
{
wStatus = NFCSTATUS_INVALID_PARAMETER;
}
PH_LOG_LIBNFC_FUNC_EXIT();
return wStatus;
}
static NFCSTATUS phLibNfc_MifareULProcessGetVersionResp(void *pContext, NFCSTATUS status, void *pInfo)
{
static const uint16_t c_expectedGetVersionResponseLength = 8;