summaryrefslogtreecommitdiff
path: root/nfc/Simulator
diff options
context:
space:
mode:
Diffstat (limited to 'nfc/Simulator')
-rw-r--r--nfc/Simulator/Inc/NfcSimulatorDDI.h34
-rw-r--r--nfc/Simulator/README.md14
-rw-r--r--nfc/Simulator/Src/Connection.cpp271
-rw-r--r--nfc/Simulator/Src/Connection.h121
-rw-r--r--nfc/Simulator/Src/Constants.h102
-rw-r--r--nfc/Simulator/Src/Device.cpp245
-rw-r--r--nfc/Simulator/Src/Device.h55
-rw-r--r--nfc/Simulator/Src/Driver.cpp70
-rw-r--r--nfc/Simulator/Src/Driver.h27
-rw-r--r--nfc/Simulator/Src/FileContext.cpp640
-rw-r--r--nfc/Simulator/Src/FileContext.h268
-rw-r--r--nfc/Simulator/Src/Internal.h84
-rw-r--r--nfc/Simulator/Src/Internalsrc.cpp1
-rw-r--r--nfc/Simulator/Src/LinkList.h121
-rw-r--r--nfc/Simulator/Src/NfcDriverSim.vcxproj371
-rw-r--r--nfc/Simulator/Src/NfcDriverSim.vcxproj.Filters69
-rw-r--r--nfc/Simulator/Src/NfcSimulator.def6
-rw-r--r--nfc/Simulator/Src/NfcSimulator.inxbin0 -> 4110 bytes
-rw-r--r--nfc/Simulator/Src/NfcSimulator.rc15
-rw-r--r--nfc/Simulator/Src/Queue.cpp2420
-rw-r--r--nfc/Simulator/Src/Queue.h217
-rw-r--r--nfc/Simulator/Src/RoutingTable.cpp388
-rw-r--r--nfc/Simulator/Src/RoutingTable.h55
-rw-r--r--nfc/Simulator/Src/SecureElement.cpp52
-rw-r--r--nfc/Simulator/Src/SecureElement.h56
-rw-r--r--nfc/Simulator/Src/SmartCard.cpp312
-rw-r--r--nfc/Simulator/Src/SmartCard.h100
-rw-r--r--nfc/Simulator/Src/SmartCardReader.cpp564
-rw-r--r--nfc/Simulator/Src/SmartCardReader.h87
-rw-r--r--nfc/Simulator/Src/SocketListener.cpp185
-rw-r--r--nfc/Simulator/Src/SocketListener.h85
-rw-r--r--nfc/Simulator/Src/WppDefs.h367
32 files changed, 7402 insertions, 0 deletions
diff --git a/nfc/Simulator/Inc/NfcSimulatorDDI.h b/nfc/Simulator/Inc/NfcSimulatorDDI.h
new file mode 100644
index 00000000..0fc742df
--- /dev/null
+++ b/nfc/Simulator/Inc/NfcSimulatorDDI.h
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ NFCSimulatorDDI.h
+
+Abstract:
+
+ This header contains definitions for the NFC simulator driver
+
+Environment:
+
+ User Mode
+
+--*/
+#pragma once
+
+// {A965F47F-23E8-4897-90D1-A6C8A1BB4C59}
+const GUID GUID_DEVINTERFACE_NFCSIM =
+ {0xa965f47f, 0x23e8, 0x4897, {0x90, 0xd1, 0xa6, 0xc8, 0xa1, 0xbb, 0x4c, 0x59}};
+
+// {4D535369-6DD8-4448-4E46-4345452D4944}
+const GUID GUID_DH_SECURE_ELEMENT =
+ {0x4D535369, 0x6DD8, 0x4448, {0x4E, 0x46, 0x43, 0x45, 0x45, 0x2D, 0x49, 0x44}};
+
+#define IOCTL_NFCSIM_BEGIN_PROXIMITY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1000, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_NFCSIM_TRIGGER_SEEVENT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1001, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+struct BEGIN_PROXIMITY_ARGS
+{
+ WCHAR szName[MAX_PATH]; // Name or IP address
+};
diff --git a/nfc/Simulator/README.md b/nfc/Simulator/README.md
new file mode 100644
index 00000000..dfdeaa7c
--- /dev/null
+++ b/nfc/Simulator/README.md
@@ -0,0 +1,14 @@
+NFC Simulator Driver Sample
+===========================
+This sample demonstrates how to use User-Mode Driver Framework (UMDF) to write a Near-Field Communication (NFC) universal driver along with best practices.
+
+This sample uses a TCP/IPv6 network connection and a static configuration between two machines to allow simulation of near-field interaction.
+
+Installing the driver
+---------------------
+To install the NfcSimulator driver:
+Copy the driver binary, NfcSimulator.inf to a directory on your test machine. Change to the directory containing the inf and binaries Next run devcon.exe as follows:
+
+ devcon.exe install NfcSimulator.inf root\NfcSimulator
+
+Create a Windows Firewall rule to allow the NfcSimulator to receive proximity simulation requests over the network. For example, run WF.msc, and create a new inbound rule that opens port 9299. \ No newline at end of file
diff --git a/nfc/Simulator/Src/Connection.cpp b/nfc/Simulator/Src/Connection.cpp
new file mode 100644
index 00000000..0b1d76bb
--- /dev/null
+++ b/nfc/Simulator/Src/Connection.cpp
@@ -0,0 +1,271 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+--*/
+
+#include "Internal.h"
+#include "Connection.tmh"
+
+/* 9C7D2C68-5AD8-4A14-BE20-F8741D60D100 */
+const GUID MAGIC_PACKET_P2P =
+ {0x9C7D2C68, 0x5AD8, 0x4A14, {0xBE, 0x20, 0xF8, 0x74, 0x1D, 0x60, 0xD1, 0x00}};
+
+/* 9C7D2C68-5AD8-4A14-BE20-F8741D60D101 */
+const GUID MAGIC_PACKET_TAG =
+ {0x9C7D2C68, 0x5AD8, 0x4A14, {0xBE, 0x20, 0xF8, 0x74, 0x1D, 0x60, 0xD1, 0x01}};
+
+/* 9C7D2C68-5AD8-4A14-BE20-F8741D60D102 */
+const GUID MAGIC_PACKET_HCE =
+ {0x9C7D2C68, 0x5AD8, 0x4A14, {0xBE, 0x20, 0xF8, 0x74, 0x1D, 0x60, 0xD1, 0x02}};
+
+HRESULT SetSocketIpv6Only(_In_ SOCKET socket, _In_ BOOL Ipv6Only);
+
+HRESULT SynchronousReadSocket(_In_ SOCKET Socket, _In_reads_bytes_(cbBuffer) PVOID pBuffer, _In_ DWORD cbBuffer)
+{
+ HRESULT hr = S_OK;
+ DWORD cbBytesRead = 0;
+ OVERLAPPED Overlapped = {};
+
+ if (!ReadFile((HANDLE)Socket, pBuffer, cbBuffer, &cbBytesRead, &Overlapped)) {
+ if (GetLastError() == ERROR_IO_PENDING) {
+ if (!GetOverlappedResult((HANDLE)Socket, &Overlapped, &cbBytesRead, TRUE)) {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ else {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+ return hr;
+}
+
+BOOL CConnection::Create(_In_ IConnectionCallback* pCallback, _Outptr_result_maybenull_ CConnection** ppConnection)
+{
+ NT_ASSERT(ppConnection != nullptr);
+
+ *ppConnection = new CConnection(pCallback);
+
+ if (*ppConnection != nullptr) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void CConnection::Terminate()
+{
+ MethodEntry("void");
+
+ STATE PriorState = (STATE)(InterlockedExchange((long*)&_State, (long)TERMINATED));
+
+ if (PriorState != TERMINATED) {
+ shutdown(_Socket, SD_SEND);
+
+ if (_ThreadpoolThreadId != GetCurrentThreadId()) {
+ WaitForThreadpoolWorkCallbacks(_ThreadpoolWork, false);
+ }
+
+ SOCKET Socket = (SOCKET)InterlockedExchangePointer((PVOID*)&_Socket, (PVOID)INVALID_SOCKET);
+
+ if (Socket != INVALID_SOCKET) {
+ closesocket(Socket);
+ }
+ }
+
+ MethodReturnVoid();
+}
+
+HRESULT CConnection::InitializeAsClient(_In_ BEGIN_PROXIMITY_ARGS* pArgs)
+{
+ MethodEntry("pArgs->szName = '%S'", pArgs->szName);
+
+ HRESULT hr = S_OK;
+
+ pArgs->szName[MAX_PATH-1] = L'\0';
+
+ _Socket = socket(AF_INET6, SOCK_STREAM, 0);
+
+ if (_Socket == INVALID_SOCKET) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = SetSocketIpv6Only(_Socket, FALSE);
+ }
+
+ if (SUCCEEDED(hr)) {
+ SOCKADDR_STORAGE LocalAddress = {};
+ SOCKADDR_STORAGE RemoteAddress = {};
+ DWORD cbLocalAddress = sizeof(LocalAddress);
+ DWORD cbRemoteAddress = sizeof(RemoteAddress);
+ timeval Timeout = {8, 0};
+
+ if (!WSAConnectByName(
+ _Socket,
+ pArgs->szName,
+ L"9299",
+ &cbLocalAddress,
+ (SOCKADDR*)&LocalAddress,
+ &cbRemoteAddress,
+ (SOCKADDR*)&RemoteAddress,
+ &Timeout,
+ nullptr)) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ TraceErrorHR(hr, L"WSAConnectByName returned failure");
+ }
+ }
+
+ if (SUCCEEDED(hr)) {
+ if (setsockopt(_Socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, nullptr, 0) == SOCKET_ERROR) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+
+ if (SUCCEEDED(hr)) {
+ if (send(_Socket, (char*)&MAGIC_PACKET_P2P, sizeof(MAGIC_PACKET_P2P), 0) == SOCKET_ERROR) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+
+ if (SUCCEEDED(hr)) {
+ GUID MagicPacket = {};
+
+ hr = SynchronousReadSocket(_Socket, &MagicPacket, sizeof(MagicPacket));
+
+ if (SUCCEEDED(hr)) {
+ if (memcmp(&MagicPacket, &MAGIC_PACKET_P2P, sizeof(MAGIC_PACKET_P2P)) != 0) {
+ hr = E_FAIL;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = FinalizeEstablish(INVALID_SOCKET);
+ }
+ }
+
+ if (FAILED(hr)) {
+ if (_Socket != INVALID_SOCKET) {
+ closesocket(_Socket);
+ _Socket = INVALID_SOCKET;
+ }
+ }
+
+ MethodReturnHR(hr);
+}
+
+void CConnection::ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket)
+{
+ MethodEntry("...");
+
+ TraceASSERT(Socket != INVALID_SOCKET);
+
+ HRESULT hr = S_OK;
+
+ if (memcmp(pMagicPacket, &MAGIC_PACKET_P2P, sizeof(MAGIC_PACKET_P2P)) == 0) {
+ _ConnectionType = CONNECTION_TYPE_P2P;
+ }
+ else if (memcmp(pMagicPacket, &MAGIC_PACKET_TAG, sizeof(MAGIC_PACKET_TAG)) == 0) {
+ _ConnectionType = CONNECTION_TYPE_TAG;
+ }
+ else if (memcmp(pMagicPacket, &MAGIC_PACKET_HCE, sizeof(MAGIC_PACKET_HCE)) == 0) {
+ _ConnectionType = CONNECTION_TYPE_HCE;
+ }
+ else {
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr)) {
+ if (send(Socket, (char*)pMagicPacket, sizeof(GUID), 0) == SOCKET_ERROR) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = FinalizeEstablish(Socket);
+ }
+
+ if (FAILED(hr)) {
+ closesocket(Socket);
+ }
+
+ MethodReturnVoid();
+}
+
+HRESULT CConnection::FinalizeEstablish(_In_ SOCKET Socket)
+{
+ MethodEntry("...");
+
+ HRESULT hr = S_OK;
+
+ STATE PriorState = (STATE)(InterlockedCompareExchange((long*)&_State, (long)ESTABLISHED, (long)INITIAL));
+
+ if (PriorState != INITIAL) {
+ hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
+ }
+
+ if (SUCCEEDED(hr)) {
+ _ThreadpoolWork = CreateThreadpoolWork(s_ReceiveThreadProc, this, nullptr);
+
+ if (_ThreadpoolWork == nullptr) {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else {
+ if (Socket != INVALID_SOCKET) {
+ _Socket = Socket;
+ }
+
+ SubmitThreadpoolWork(_ThreadpoolWork);
+ _pCallback->ConnectionEstablished(this);
+ }
+ }
+
+ MethodReturnHR(hr);
+}
+
+BOOL CConnection::ReceiveThreadProc()
+{
+ MethodEntry("void");
+
+ MESSAGE* pMessage = new MESSAGE();
+
+ if (pMessage == nullptr) {
+ Terminate();
+ }
+ else
+ {
+ while (_Socket != INVALID_SOCKET) {
+ if (recv(_Socket, (char*)pMessage, sizeof(*pMessage), MSG_WAITALL) == sizeof(*pMessage)) {
+ _pCallback->HandleReceivedMessage(_ConnectionType, pMessage);
+ }
+ else {
+ Terminate();
+ break;
+ }
+ }
+ delete pMessage;
+ }
+
+ BOOL fConnectionDeleted = _pCallback->ConnectionTerminated(this);
+
+ MethodReturnBool(fConnectionDeleted);
+}
+
+HRESULT CConnection::TransmitMessage(_In_ MESSAGE* pMessage)
+{
+ MethodEntry("...");
+
+ HRESULT hr = S_OK;
+
+ if (_Socket == INVALID_SOCKET) {
+ hr = HRESULT_FROM_WIN32(WSAENOTSOCK);
+ }
+ else {
+ if (send(_Socket, (char*)pMessage, sizeof(*pMessage), 0) == SOCKET_ERROR) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ Terminate();
+ }
+ }
+
+ MethodReturnHR(hr);
+}
diff --git a/nfc/Simulator/Src/Connection.h b/nfc/Simulator/Src/Connection.h
new file mode 100644
index 00000000..ea851b58
--- /dev/null
+++ b/nfc/Simulator/Src/Connection.h
@@ -0,0 +1,121 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Abstract:
+
+ Defines a simple NFP Provider implementation using the network.
+
+--*/
+#pragma once
+
+#include "SocketListener.h"
+
+class CConnection;
+
+struct MESSAGE;
+
+enum CONNECTION_TYPE
+{
+ CONNECTION_TYPE_P2P = 0, // Peer to peer connection
+ CONNECTION_TYPE_TAG, // Tag supports NDEF read/write access
+ CONNECTION_TYPE_HCE, // HCE connection
+};
+
+class IConnectionCallback
+{
+public:
+ virtual void HandleReceivedMessage(_In_ CONNECTION_TYPE ConnType, _In_ MESSAGE* pMessage) = 0;
+ virtual void ConnectionEstablished(_In_ CConnection* pConnection) = 0;
+ virtual BOOL ConnectionTerminated(_In_ CConnection* pConnection) = 0;
+};
+
+class CConnection : public IValidateAccept
+{
+private:
+ CConnection(_In_ IConnectionCallback* pCallback) :
+ _State(INITIAL),
+ _Socket(INVALID_SOCKET),
+ _pCallback(pCallback),
+ _ThreadpoolWork(nullptr),
+ _fInboundConnection(false),
+ _ConnectionType(CONNECTION_TYPE_P2P)
+ {}
+
+public:
+ virtual ~CConnection()
+ {
+ Terminate();
+
+ if (_ThreadpoolWork != nullptr) {
+ // Don't wait for threadpool callbacks when this thread is actually the threadpool callback
+ if (_ThreadpoolThreadId != GetCurrentThreadId()) {
+ WaitForThreadpoolWorkCallbacks(_ThreadpoolWork, false);
+ }
+ CloseThreadpoolWork(_ThreadpoolWork);
+ _ThreadpoolWork = nullptr;
+ }
+ }
+
+ static BOOL Create(_In_ IConnectionCallback* pCallback, _Outptr_result_maybenull_ CConnection** ppConnection);
+
+ void SetInboundConnection() { _fInboundConnection = true; }
+ bool IsInboundConnection() { return _fInboundConnection; }
+
+ // IValidateAccept
+ void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket);
+
+ HRESULT FinalizeEstablish(_In_ SOCKET Socket);
+ HRESULT InitializeAsClient(_In_ BEGIN_PROXIMITY_ARGS* pArgs);
+ HRESULT TransmitMessage(_In_ MESSAGE* pMessage);
+
+ BOOL ReceiveThreadProc();
+
+ static VOID CALLBACK s_ReceiveThreadProc(
+ _Inout_ PTP_CALLBACK_INSTANCE Instance,
+ _Inout_ PVOID Context,
+ _Inout_ PTP_WORK /*Work*/)
+ {
+ CallbackMayRunLong(Instance);
+
+ CConnection* pConnection = (CConnection*)Context;
+ pConnection->_ThreadpoolThreadId = GetCurrentThreadId();
+ BOOL fConnectionDeleted = pConnection->ReceiveThreadProc();
+
+ if (!fConnectionDeleted) {
+ // Only clear the member variable if the connection object wasn't deleted.
+ pConnection->_ThreadpoolThreadId = 0;
+ }
+ }
+
+ LIST_ENTRY* GetListEntry() { return &_ListEntry; }
+ static CConnection* FromListEntry(LIST_ENTRY* pListEntry)
+ {
+ return (CConnection*) CONTAINING_RECORD(pListEntry, CConnection, _ListEntry);
+ }
+
+ CONNECTION_TYPE GetConnectionType()
+ {
+ return _ConnectionType;
+ }
+
+private:
+ void Terminate();
+
+private:
+ enum STATE
+ {
+ INITIAL = 0,
+ ESTABLISHED,
+ TERMINATED
+ };
+
+ volatile STATE _State;
+ SOCKET _Socket;
+ PTP_WORK _ThreadpoolWork;
+ DWORD _ThreadpoolThreadId;
+ IConnectionCallback* _pCallback;
+ bool _fInboundConnection;
+ LIST_ENTRY _ListEntry;
+ CONNECTION_TYPE _ConnectionType;
+};
diff --git a/nfc/Simulator/Src/Constants.h b/nfc/Simulator/Src/Constants.h
new file mode 100644
index 00000000..f6be14c9
--- /dev/null
+++ b/nfc/Simulator/Src/Constants.h
@@ -0,0 +1,102 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Constants.h
+
+Abstract:
+
+ This header contains definitions common for NFC drivers
+
+--*/
+
+#pragma once
+
+//
+// Message Types
+//
+#define WINDOWS_PROTOCOL L"Windows"
+#define WINDOWS_PROTOCOL_CHARS (ARRAYSIZE(WINDOWS_PROTOCOL) - 1)
+
+#define WINDOWSURI_TYPE L"Uri"
+#define WINDOWSURI_TYPE_CHARS (ARRAYSIZE(WINDOWSURI_TYPE) - 1)
+
+#define WINDOWSURI_PROTOCOL WINDOWS_PROTOCOL WINDOWSURI_TYPE
+#define WINDOWSURI_PROTOCOL_CHARS (ARRAYSIZE(WINDOWSURI_PROTOCOL) - 1)
+
+#define WINDOWSMIME_TYPE L"Mime"
+#define WINDOWSMIME_TYPE_CHARS (ARRAYSIZE(WINDOWSMIME_TYPE) - 1)
+
+#define WINDOWSMIME_PROTOCOL WINDOWS_PROTOCOL WINDOWSMIME_TYPE
+#define WINDOWSMIME_PROTOCOL_CHARS (ARRAYSIZE(WINDOWSMIME_PROTOCOL) - 1)
+
+#define NDEF_PROTOCOL L"NDEF"
+#define NDEF_PROTOCOL_CHARS (ARRAYSIZE(NDEF_PROTOCOL) - 1)
+
+#define NDEF_UNKNOWN_TYPE L"Unknown"
+#define NDEF_UNKNOWN_TYPE_CHARS (ARRAYSIZE(NDEF_UNKNOWN_TYPE) - 1)
+
+#define NDEF_EMPTY_TYPE L"Empty"
+#define NDEF_EMPTY_TYPE_CHARS (ARRAYSIZE(NDEF_EMPTY_TYPE) - 1)
+
+#define NDEF_EXT_TYPE L"ext."
+#define NDEF_EXT_TYPE_CHARS (ARRAYSIZE(NDEF_EXT_TYPE) - 1)
+
+#define NDEF_MIME_TYPE L"MIME."
+#define NDEF_MIME_TYPE_CHARS (ARRAYSIZE(NDEF_MIME_TYPE) - 1)
+
+#define NDEF_URI_TYPE L"URI."
+#define NDEF_URI_TYPE_CHARS (ARRAYSIZE(NDEF_URI_TYPE) - 1)
+
+#define NDEF_WKT_TYPE L"wkt."
+#define NDEF_WKT_TYPE_CHARS (ARRAYSIZE(NDEF_WKT_TYPE) - 1)
+
+#define WRITETAG_TYPE L"WriteTag"
+#define WRITETAG_TYPE_CHARS (ARRAYSIZE(WRITETAG_TYPE) - 1)
+
+#define DEVICE_ARRIVED L"DeviceArrived"
+#define DEVICE_DEPARTED L"DeviceDeparted"
+#define WRITEABLETAG_PROTOCOL L"WriteableTag"
+#define PAIRING_BLUETOOTH_PROTOCOL L"Pairing:Bluetooth"
+#define PAIRING_UPNP_PROTOCOL L"Pairing:UPnP"
+#define LAUNCHAPP_WRITETAG_PROTOCOL L"LaunchApp:WriteTag"
+
+//
+// Namespaces
+//
+#define NFP_NAMESPACE L"Nfp"
+#define NFP_NAMESPACE_CHARS (ARRAYSIZE(NFP_NAMESPACE) - 1)
+
+#define PUBS_NAMESPACE L"Pubs\\"
+#define PUBS_NAMESPACE_CHARS (ARRAYSIZE(PUBS_NAMESPACE) - 1)
+
+#define SUBS_NAMESPACE L"Subs\\"
+#define SUBS_NAMESPACE_CHARS (ARRAYSIZE(SUBS_NAMESPACE) - 1)
+
+#define SE_NAMESPACE L"SE"
+#define SE_NAMESPACE_CHARS (ARRAYSIZE(SE_NAMESPACE) - 1)
+
+#define SEMANAGE_NAMESPACE L"SEManage"
+#define SEMANAGE_NAMESPACE_CHARS (ARRAYSIZE(SEMANAGE_NAMESPACE) - 1)
+
+#define SEEVENTS_NAMESPACE L"SEEvents"
+#define SEEVENTS_NAMESPACE_CHARS (ARRAYSIZE(SEEVENTS_NAMESPACE) - 1)
+
+#define SMARTCARD_READER_NAMESPACE L"SCReader"
+#define SMARTCARD_READER_NAMESPACE_CHARS (ARRAYSIZE(SMARTCARD_READER_NAMESPACE) - 1)
+
+#define RM_NAMESPACE L"RadioManage"
+#define RM_NAMESPACE_CHARS (ARRAYSIZE(RM_NAMESPACE) - 1)
+
+#define MAX_MESSAGE_QUEUE_SIZE 50
+
+//
+// Macros
+//
+#define IsStringPrefixed(_STRING_, _PREFIX_) \
+ (CompareStringOrdinal(_STRING_, (_PREFIX_ ## _CHARS), _PREFIX_, (_PREFIX_ ## _CHARS), TRUE) == CSTR_EQUAL)
+
+#define IsStringEqual(_STRING1_, _STRING2_) \
+ (CompareStringOrdinal(_STRING1_, -1, _STRING2_, -1, TRUE) == CSTR_EQUAL) \ No newline at end of file
diff --git a/nfc/Simulator/Src/Device.cpp b/nfc/Simulator/Src/Device.cpp
new file mode 100644
index 00000000..cfbc57c0
--- /dev/null
+++ b/nfc/Simulator/Src/Device.cpp
@@ -0,0 +1,245 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ Device.cpp
+
+Abstract:
+
+ This module contains the implementation of the UMDF
+ driver's device callback object.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "Internal.h"
+#include "Device.tmh"
+
+NTSTATUS
+CDevice::OnDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+{
+ FunctionEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFDEVICE Device;
+ WDF_OBJECT_ATTRIBUTES DeviceAttributes;
+ WDF_OBJECT_ATTRIBUTES FileAttributes;
+ WDF_FILEOBJECT_CONFIG FileConfig;
+ WDF_PNPPOWER_EVENT_CALLBACKS PowerCallbacks;
+ CDevice* pDevice = nullptr;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PowerCallbacks);
+
+ PowerCallbacks.EvtDeviceD0Entry = CDevice::OnD0Entry;
+ PowerCallbacks.EvtDeviceD0Exit = CDevice::OnD0Exit;
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PowerCallbacks);
+
+ WDF_FILEOBJECT_CONFIG_INIT(
+ &FileConfig,
+ CDevice::OnFileCreate,
+ CDevice::OnFileClose,
+ WDF_NO_EVENT_CALLBACK);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&FileAttributes, CFileObject);
+ FileAttributes.EvtDestroyCallback = CFileObject::OnDestroy;
+
+ WdfDeviceInitSetFileObjectConfig(DeviceInit, &FileConfig, &FileAttributes);
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DeviceAttributes, CDevice);
+
+ DeviceAttributes.EvtCleanupCallback = CDevice::OnCleanup;
+ DeviceAttributes.SynchronizationScope = WdfSynchronizationScopeNone;
+ DeviceAttributes.ExecutionLevel = WdfExecutionLevelPassive;
+
+ Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &Device);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreate failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Construct device object on the preallocated buffer using placement 'new'
+ pDevice = new (GetDeviceObject(Device)) CDevice(Device);
+
+ if (pDevice == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ Status = pDevice->Initialize();
+
+Exit:
+ FunctionReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CDevice::Initialize()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDF_IO_QUEUE_CONFIG QueueConfig;
+ WDF_OBJECT_ATTRIBUTES QueueAttributes;
+ WDFQUEUE Queue = nullptr;
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, WdfIoQueueDispatchParallel);
+
+ QueueConfig.PowerManaged = WdfFalse;
+ QueueConfig.EvtIoDeviceControl = CQueue::OnIoDeviceControl;
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&QueueAttributes, CQueue);
+
+ Status = WdfIoQueueCreate(
+ m_Device,
+ &QueueConfig,
+ &QueueAttributes,
+ &Queue);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfIoQueueCreate failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Construct a queue object on the preallocated buffer using placement new operation
+ m_pQueue = new (GetQueueObject(Queue)) CQueue(Queue);
+
+ if (m_pQueue == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ Status = m_pQueue->Initialize();
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+VOID CDevice::OnCleanup(_In_ WDFOBJECT Object)
+{
+ FunctionEntry("...");
+
+ CDevice *pDevice = GetDeviceObject(Object);
+
+ NT_ASSERT(pDevice != nullptr);
+
+ if (pDevice->m_Device == Object) {
+ // Device object constructed using placement 'new' so explicitly invoke destructor
+ pDevice->Deinitialize();
+ pDevice->~CDevice();
+ }
+
+ FunctionReturnVoid();
+}
+
+NTSTATUS CDevice::Deinitialize()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (m_pQueue != nullptr) {
+ // Queue object constructed using placement new so explicitly invoke destructor
+ m_pQueue->Deinitialize();
+ m_pQueue->~CQueue();
+
+ m_pQueue = nullptr;
+ }
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CDevice::OnD0Entry(
+ _In_ WDFDEVICE Device,
+ _In_ WDF_POWER_DEVICE_STATE PreviousState
+ )
+{
+ FunctionEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ CDevice *pDevice = GetDeviceObject(Device);
+
+ NT_ASSERT(pDevice != nullptr);
+ Status = pDevice->OnD0Entry(PreviousState);
+
+ FunctionReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CDevice::OnD0Entry(
+ _In_ WDF_POWER_DEVICE_STATE PreviousState
+ )
+{
+ MethodEntry("PreviousState = %d", PreviousState);
+ NTSTATUS Status = STATUS_SUCCESS;
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CDevice::OnD0Exit(
+ _In_ WDFDEVICE Device,
+ _In_ WDF_POWER_DEVICE_STATE TargetState
+ )
+{
+ FunctionEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ CDevice *pDevice = GetDeviceObject(Device);
+
+ NT_ASSERT(pDevice != nullptr);
+ Status = pDevice->OnD0Exit(TargetState);
+
+ FunctionReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CDevice::OnD0Exit(
+ _In_ WDF_POWER_DEVICE_STATE TargetState
+ )
+{
+ MethodEntry("TargetState = %d", TargetState);
+ NTSTATUS Status = STATUS_SUCCESS;
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+VOID
+CDevice::OnFileCreate(
+ _In_ WDFDEVICE Device,
+ _In_ WDFREQUEST Request,
+ _In_ WDFFILEOBJECT FileObject
+ )
+{
+ FunctionEntry("...");
+
+ CDevice *pDevice = GetDeviceObject(Device);
+
+ NT_ASSERT(pDevice != nullptr);
+ pDevice->GetQueue()->OnFileCreate(Device, Request, FileObject);
+
+ FunctionReturnVoid();
+}
+
+VOID
+CDevice::OnFileClose(
+ _In_ WDFFILEOBJECT FileObject
+ )
+{
+ FunctionEntry("...");
+
+ CDevice *pDevice = GetDeviceObject(WdfFileObjectGetDevice(FileObject));
+
+ NT_ASSERT(pDevice != nullptr);
+ pDevice->GetQueue()->OnFileClose(FileObject);
+
+ FunctionReturnVoid();
+}
diff --git a/nfc/Simulator/Src/Device.h b/nfc/Simulator/Src/Device.h
new file mode 100644
index 00000000..41c32cf3
--- /dev/null
+++ b/nfc/Simulator/Src/Device.h
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Device.h
+
+Abstract:
+
+ This module contains the type definitions for the
+ driver's device callback class.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+#pragma once
+
+class CQueue;
+
+class CDevice
+{
+public:
+ CDevice(WDFDEVICE Device) : m_Device(Device), m_pQueue(nullptr)
+ {}
+
+public:
+ static EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd;
+ static EVT_WDF_OBJECT_CONTEXT_CLEANUP OnCleanup;
+ static EVT_WDF_DEVICE_D0_ENTRY OnD0Entry;
+ static EVT_WDF_DEVICE_D0_EXIT OnD0Exit;
+ static EVT_WDF_DEVICE_FILE_CREATE OnFileCreate;
+ static EVT_WDF_FILE_CLOSE OnFileClose;
+
+public:
+ NTSTATUS Initialize();
+ NTSTATUS Deinitialize();
+
+ NTSTATUS OnD0Entry(_In_ WDF_POWER_DEVICE_STATE PreviousState);
+ NTSTATUS OnD0Exit(_In_ WDF_POWER_DEVICE_STATE TargetState);
+
+public:
+ CQueue* GetQueue()
+ {
+ return m_pQueue;
+ }
+
+private:
+ WDFDEVICE m_Device;
+ CQueue* m_pQueue;
+};
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CDevice, GetDeviceObject); \ No newline at end of file
diff --git a/nfc/Simulator/Src/Driver.cpp b/nfc/Simulator/Src/Driver.cpp
new file mode 100644
index 00000000..5082e3b4
--- /dev/null
+++ b/nfc/Simulator/Src/Driver.cpp
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ Driver.cpp
+
+Abstract:
+
+ This module contains the implementation of the UMDF driver callback object.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "Internal.h"
+#include "Driver.tmh"
+
+DECLARE_TRACING_TLS;
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDF_DRIVER_CONFIG Config;
+
+ WPP_INIT_TRACING(DriverObject, RegistryPath);
+ TracingTlsInitialize();
+
+ FunctionEntry("...");
+
+ WDF_DRIVER_CONFIG_INIT(&Config, CDevice::OnDeviceAdd);
+ Config.EvtDriverUnload = OnDriverUnload;
+
+ Status = WdfDriverCreate(
+ DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &Config,
+ WDF_NO_HANDLE);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDriverCreate failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+Exit:
+ if (!NT_SUCCESS(Status)) {
+ TracingTlsFree();
+ WPP_CLEANUP(DriverObject);
+ }
+ FunctionReturn(Status, "Status = %!STATUS!", Status);
+}
+
+VOID
+OnDriverUnload(
+ _In_ WDFDRIVER Driver
+ )
+{
+ UNREFERENCED_PARAMETER(Driver);
+
+ TracingTlsFree();
+ WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));
+}
diff --git a/nfc/Simulator/Src/Driver.h b/nfc/Simulator/Src/Driver.h
new file mode 100644
index 00000000..2ad65992
--- /dev/null
+++ b/nfc/Simulator/Src/Driver.h
@@ -0,0 +1,27 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Driver.h
+
+Abstract:
+
+ This module contains the type definitions for the UMDF
+ driver callback class.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+WDF_EXTERN_C_START
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD OnDriverUnload;
+
+WDF_EXTERN_C_END \ No newline at end of file
diff --git a/nfc/Simulator/Src/FileContext.cpp b/nfc/Simulator/Src/FileContext.cpp
new file mode 100644
index 00000000..6e609832
--- /dev/null
+++ b/nfc/Simulator/Src/FileContext.cpp
@@ -0,0 +1,640 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ filecontext.cpp
+
+Abstract:
+
+ This file implements the class for context associated with the file object
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "Internal.h"
+#include "FileContext.tmh"
+
+CFileObject::CFileObject(
+ WDFFILEOBJECT FileObject
+ )
+ : m_FileObject(FileObject),
+ m_Role(ROLE_UNDEFINED),
+ m_pszType(nullptr),
+ m_fEnabled(TRUE),
+ m_dwQueueSize(0),
+ m_cCompleteReady(0),
+ m_pConnection(nullptr),
+ m_Request(nullptr),
+ m_SecureElementEventType(ExternalReaderArrival)
+{
+ NT_ASSERT(m_FileObject != nullptr);
+
+ InitializeListHead(&m_Queue);
+ InitializeListHead(&m_ListEntry);
+ InitializeCriticalSection(&m_RoleLock);
+
+ RtlZeroMemory(&m_SecureElementId, sizeof(GUID));
+}
+
+CFileObject::~CFileObject()
+{
+ //
+ // The object is bound to the file handle and so this happens after close and the
+ // framework guarentees all requests on the file handle are cancelled prior to close
+ //
+ EnterCriticalSection(&m_RoleLock);
+ NT_ASSERT(m_Request == nullptr);
+ LeaveCriticalSection(&m_RoleLock);
+
+ PurgeQueue();
+
+ SAFE_DELETEARRAY(m_pszType);
+ SAFE_DELETE(m_pConnection);
+
+ DeleteCriticalSection(&m_RoleLock);
+
+ m_FileObject = nullptr;
+}
+
+VOID CFileObject::OnDestroy(_In_ WDFOBJECT FileObject)
+{
+ FunctionEntry("...");
+
+ CFileObject *pFileObject = GetFileObject(FileObject);
+
+ NT_ASSERT(pFileObject != nullptr);
+
+ if (pFileObject->m_FileObject == FileObject) {
+ // File object constructed using placement 'new' so explicitly invoke destructor
+ pFileObject->~CFileObject();
+ }
+
+ FunctionReturnVoid();
+}
+
+NTSTATUS CFileObject::Enable()
+{
+ MethodEntry("void");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsPublication() || IsSubscription());
+
+ if (m_fEnabled) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ m_fEnabled = TRUE;
+
+Exit:
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CFileObject::Disable()
+{
+ MethodEntry("void");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsPublication() || IsSubscription());
+
+ if (!m_fEnabled) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ m_fEnabled = FALSE;
+ CompleteRequest(STATUS_CANCELLED, 0, true);
+ PurgeQueue();
+
+Exit:
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CFileObject::SetType(_In_ PCWSTR pszType)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ size_t cchType = wcslen(pszType) + 1;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(m_pszType == nullptr);
+
+ NT_ASSERT(IsPublication() || IsSubscription());
+
+ if ((cchType > MinCchType) && (cchType < MaxCchType)) {
+ m_pszType = new WCHAR[cchType];
+
+ if (m_pszType != nullptr) {
+ StringCchCopy(m_pszType, cchType, pszType);
+ }
+ else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CFileObject::GetNextSubscribedMessage(_In_ WDFREQUEST Request)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ CPayload* pPayload = nullptr;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsSubscription());
+
+ if (m_Request != nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ if (!m_fEnabled) {
+ Status = STATUS_CANCELLED;
+ goto Exit;
+ }
+
+ Status = WdfRequestMarkCancelableEx(Request, CFileObject::OnRequestCancel);
+
+ if (NT_SUCCESS(Status)) {
+ m_Request = Request;
+
+ if (!IsListEmpty(&m_Queue)) {
+ pPayload = CPayload::FromListEntry(m_Queue.Flink);
+
+ if (CompleteRequest(pPayload->GetSize(), pPayload->GetPayload())) {
+ m_dwQueueSize--;
+ RemoveHeadList(&m_Queue);
+ delete pPayload;
+ }
+ }
+ }
+
+Exit:
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CFileObject::SetPayload(_In_ DWORD cbPayload, _In_reads_bytes_(cbPayload) PBYTE pbPayload)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsPublication());
+
+ if (m_Payload.GetPayload() != nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ Status = m_Payload.Initialize(cbPayload, pbPayload);
+
+Exit:
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CFileObject::GetNextTransmittedMessage(_In_ WDFREQUEST Request)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsPublication());
+
+ if (m_Request != nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ if (!m_fEnabled) {
+ Status = STATUS_CANCELLED;
+ goto Exit;
+ }
+
+ Status = WdfRequestMarkCancelableEx(Request, CFileObject::OnRequestCancel);
+
+ if (NT_SUCCESS(Status)) {
+ m_Request = Request;
+
+ if (m_cCompleteReady > 0) {
+ if (CompleteRequest(STATUS_SUCCESS, 0, true)) {
+ m_cCompleteReady--;
+ }
+ }
+ }
+
+Exit:
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CFileObject::GetNextSecureElementPayload(_In_ WDFREQUEST Request)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ CPayload* pPayload = nullptr;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsSecureElementEvent() || IsSecureElementManager());
+
+ if (m_Request != nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ Status = WdfRequestMarkCancelableEx(Request, CFileObject::OnRequestCancel);
+
+ if (NT_SUCCESS(Status)) {
+ m_Request = Request;
+
+ if (!IsListEmpty(&m_Queue)) {
+ pPayload = CPayload::FromListEntry(m_Queue.Flink);
+
+ if (CompleteRequest(pPayload->GetSize(), pPayload->GetPayload())) {
+ m_dwQueueSize--;
+ RemoveHeadList(&m_Queue);
+ delete pPayload;
+ }
+ }
+ }
+
+Exit:
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CFileObject::SubscribeForEvent(_In_ GUID& SecureElementId, _In_ SECURE_ELEMENT_EVENT_TYPE SecureElementEventType)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsSecureElementEvent());
+
+ m_SecureElementId = SecureElementId;
+ m_SecureElementEventType = SecureElementEventType;
+
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CFileObject::BeginProximity(
+ _In_ BEGIN_PROXIMITY_ARGS *pArgs,
+ _In_ IConnectionCallback* pCallback
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NT_ASSERT(IsRoleSimulation());
+
+ if (CConnection::Create(pCallback, &m_pConnection)) {
+ if (SUCCEEDED(m_pConnection->InitializeAsClient(pArgs))) {
+ Status = STATUS_SUCCESS;
+ }
+ else {
+ Status = STATUS_INTERNAL_ERROR;
+ }
+ }
+ else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+void CFileObject::HandleArrivalEvent()
+{
+ MethodEntry("void");
+
+ DWORD dwFlags = 1; // payload for arrival event
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsArrivedSubscription());
+
+ if (m_fEnabled) {
+ HandleReceivedMessage(sizeof(DWORD), (PBYTE) &dwFlags);
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturnVoid();
+}
+
+void CFileObject::HandleRemovalEvent()
+{
+ MethodEntry("void");
+
+ DWORD dwFlags = 0; // payload for removal event
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsDepartedSubscription());
+
+ if (m_fEnabled) {
+ HandleReceivedMessage(sizeof(DWORD), (PBYTE) &dwFlags);
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturnVoid();
+}
+
+void CFileObject::HandleMessageTransmitted(void)
+{
+ MethodEntry("m_fEnabled=%!bool!", m_fEnabled);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsPublication());
+
+ if (m_fEnabled) {
+ if (!CompleteRequest(STATUS_SUCCESS, 0, true)) {
+ m_cCompleteReady++;
+ }
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturnVoid();
+}
+
+void
+CFileObject::HandleReceivedMessage(
+ _In_ PCWSTR pszType,
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+{
+ MethodEntry("Enabled=%!bool!", m_fEnabled);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsNormalSubscription());
+
+ if (m_fEnabled) {
+ if ((CompareStringOrdinal(m_pszType, -1, WINDOWSMIME_PROTOCOL, -1, FALSE) == CSTR_EQUAL) &&
+ (wcslen(pszType) > WINDOWSMIME_PROTOCOL_CHARS) &&
+ (CompareStringOrdinal(pszType, WINDOWSMIME_PROTOCOL_CHARS, WINDOWSMIME_PROTOCOL, -1, FALSE) == CSTR_EQUAL)) {
+
+ CHAR szMimeType[MaxCchMimeType + 1] = {};
+ BYTE* pbNewPayload = new BYTE[cbPayload + MaxCchMimeType];
+
+ if (pbNewPayload != nullptr) {
+ if (SUCCEEDED(StringCchPrintfA(szMimeType, _countof(szMimeType), "%S", pszType + WINDOWSMIME_PROTOCOL_CHARS + 1))) {
+ RtlCopyMemory(pbNewPayload, szMimeType, MaxCchMimeType);
+ RtlCopyMemory(pbNewPayload + MaxCchMimeType, pbPayload, cbPayload);
+
+ HandleReceivedMessage(cbPayload + MaxCchMimeType, pbNewPayload);
+ }
+
+ SAFE_DELETEARRAY(pbNewPayload);
+ }
+ }
+ else if (CompareStringOrdinal(pszType, -1, m_pszType, -1, FALSE) == CSTR_EQUAL) {
+ if (CompareStringOrdinal(m_pszType, -1, WINDOWSURI_PROTOCOL, -1, FALSE) == CSTR_EQUAL) {
+ // WindowsUri must be returned as NULL terminated UTF16
+ DWORD cbNewPayload = cbPayload + sizeof(WCHAR);
+ BYTE* pbNewPayload = new BYTE[cbNewPayload];
+
+ if (pbNewPayload != nullptr) {
+ RtlCopyMemory(pbNewPayload, pbPayload, cbPayload);
+ RtlZeroMemory(pbNewPayload + cbPayload, sizeof(WCHAR));
+
+ HandleReceivedMessage(cbNewPayload, pbNewPayload);
+
+ SAFE_DELETEARRAY(pbNewPayload);
+ }
+ }
+ else {
+ HandleReceivedMessage(cbPayload, pbPayload);
+ }
+ }
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturnVoid();
+}
+
+void CFileObject::HandleReceiveHcePacket(
+ _In_ USHORT uConnectionId,
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+{
+ MethodEntry("...");
+
+ size_t cbUsedBufferSize = 0;
+ DWORD cbNewPayload = cbPayload + 2 * sizeof(USHORT);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsSecureElementManager());
+
+ BYTE* pbNewPayload = new BYTE[cbNewPayload];
+
+ if (pbNewPayload != nullptr) {
+ RtlCopyMemory(pbNewPayload + cbUsedBufferSize, &uConnectionId, sizeof(USHORT));
+ cbUsedBufferSize += sizeof(USHORT);
+ USHORT cbSize = (USHORT)cbPayload;
+
+ RtlCopyMemory(pbNewPayload + cbUsedBufferSize, &cbSize, sizeof(USHORT));
+ cbUsedBufferSize += sizeof(USHORT);
+ RtlCopyMemory(pbNewPayload + cbUsedBufferSize, pbPayload, cbPayload);
+
+ HandleReceivedMessage(cbNewPayload, pbNewPayload);
+
+ SAFE_DELETEARRAY(pbNewPayload);
+ }
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturnVoid();
+}
+
+void CFileObject::HandleSecureElementEvent(SECURE_ELEMENT_EVENT_INFO* pInfo)
+{
+ MethodEntry("...");
+
+ EnterCriticalSection(&m_RoleLock);
+
+ NT_ASSERT(IsSecureElementEvent());
+
+ if ((IsEqualGUID(m_SecureElementId, pInfo->guidSecureElementId) || IsEqualGUID(m_SecureElementId, GUID_NULL)) &&
+ (m_SecureElementEventType == pInfo->eEventType)) {
+ BYTE* pbPayload = (BYTE*)pInfo;
+ DWORD cbPayload = SECURE_ELEMENT_EVENT_INFO_HEADER + pInfo->cbEventData;
+
+ HandleReceivedMessage(cbPayload, pbPayload);
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+ MethodReturnVoid();
+}
+
+VOID CFileObject::HandleReceivedMessage(
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+{
+ bool fDelivered = false;
+
+ if (m_Request != nullptr) {
+ fDelivered = CompleteRequest(cbPayload, pbPayload);
+ }
+
+ if ((!fDelivered) && (m_dwQueueSize < MAX_MESSAGE_QUEUE_SIZE)) {
+ CPayload* pPayload = new CPayload();
+
+ if (pPayload != nullptr) {
+ if (NT_SUCCESS(pPayload->Initialize(cbPayload, pbPayload))) {
+ InsertTailList(&m_Queue, pPayload->GetListEntry());
+ m_dwQueueSize++;
+ }
+ else {
+ delete pPayload;
+ }
+ }
+ }
+}
+
+VOID CFileObject::OnRequestCancel(_In_ WDFREQUEST Request)
+{
+ FunctionEntry("...");
+
+ CFileObject *pFileObject = GetFileObject(WdfRequestGetFileObject(Request));
+
+ NT_ASSERT(pFileObject != nullptr);
+ pFileObject->Cancel();
+
+ FunctionReturnVoid();
+}
+
+void CFileObject::Cancel()
+{
+ MethodEntry("...");
+
+ EnterCriticalSection(&m_RoleLock);
+ CompleteRequest(STATUS_CANCELLED, 0, false);
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnVoid();
+}
+
+bool
+CFileObject::CompleteRequest(
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_opt_(cbPayload) PBYTE pbPayload
+ )
+{
+ MethodEntry("cbPayload = %d", cbPayload);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ bool fDelivered = false;
+ WDFMEMORY OutputMemory;
+ size_t cbUsedBufferSize = 0;
+ size_t cbMaxBufferSize = 0;
+
+ NT_ASSERT(m_Request != nullptr);
+
+ Status = WdfRequestRetrieveOutputMemory(m_Request, &OutputMemory);
+
+ if (NT_SUCCESS(Status) && OutputMemory != nullptr) {
+ // Set the first 4 bytes as the size of the payload as a hint for future subscriptions.
+ Status = WdfMemoryCopyFromBuffer(OutputMemory, cbUsedBufferSize, &cbPayload, sizeof(DWORD));
+ cbUsedBufferSize += sizeof(DWORD);
+
+ if (NT_SUCCESS(Status)) {
+ if (pbPayload != nullptr) {
+ WdfMemoryGetBuffer(OutputMemory, &cbMaxBufferSize);
+
+ if (cbMaxBufferSize < (cbPayload + cbUsedBufferSize)) {
+ // We are unable to copy the payload into the output memory,
+ // Returning this signals to the client to send a bigger buffer
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else {
+ Status = WdfMemoryCopyFromBuffer(OutputMemory, cbUsedBufferSize, pbPayload, cbPayload);
+ }
+ }
+
+ if (NT_SUCCESS(Status)) {
+ fDelivered = true;
+ cbUsedBufferSize += cbPayload;
+ }
+ }
+
+ if (!CompleteRequest(Status, cbUsedBufferSize, true)) {
+ fDelivered = false;
+ }
+ }
+
+ MethodReturnBool(fDelivered);
+}
+
+
+bool
+CFileObject::CompleteRequest(
+ _In_ NTSTATUS CompletionStatus,
+ _In_ size_t cbSize,
+ _In_ bool fIsCancelable
+ )
+{
+ MethodEntry("CompletionStatus = %!STATUS!, cbSize = %d, fIsCancelable = %!bool!",
+ CompletionStatus, (DWORD)cbSize, fIsCancelable);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ bool fCompleted = false;
+
+ if (m_Request != nullptr) {
+ if (fIsCancelable) {
+ Status = WdfRequestUnmarkCancelable(m_Request);
+ }
+
+ if (NT_SUCCESS(Status)) {
+ WdfRequestCompleteWithInformation(m_Request, CompletionStatus, cbSize);
+ m_Request = nullptr;
+ fCompleted = true;
+ }
+ }
+
+ MethodReturnBool(fCompleted);
+}
+
+void CFileObject::PurgeQueue()
+{
+ m_dwQueueSize = 0;
+
+ while (!IsListEmpty(&m_Queue)) {
+ delete CPayload::FromListEntry(RemoveHeadList(&m_Queue));
+ }
+} \ No newline at end of file
diff --git a/nfc/Simulator/Src/FileContext.h b/nfc/Simulator/Src/FileContext.h
new file mode 100644
index 00000000..d6470423
--- /dev/null
+++ b/nfc/Simulator/Src/FileContext.h
@@ -0,0 +1,268 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ filecontext.h
+
+Abstract:
+
+ This header file defines the structure type for context associated with the file object
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+Revision History:
+
+--*/
+#pragma once
+
+class CPayload
+{
+public:
+ CPayload()
+ {
+ m_pbPayload = nullptr;
+ m_cbPayload = 0;
+ InitializeListHead(&m_ListEntry);
+ }
+ ~CPayload()
+ {
+ SAFE_DELETEARRAY(m_pbPayload);
+ }
+ NTSTATUS Initialize(
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+ {
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ m_pbPayload = new BYTE[cbPayload];
+
+ if (m_pbPayload != nullptr) {
+ m_cbPayload = cbPayload;
+ RtlCopyMemory(m_pbPayload, pbPayload, cbPayload);
+ }
+ else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ return Status;
+ }
+ PBYTE GetPayload()
+ {
+ return m_pbPayload;
+ }
+ DWORD GetSize()
+ {
+ return m_cbPayload;
+ }
+ PLIST_ENTRY GetListEntry()
+ {
+ return &m_ListEntry;
+ }
+ static CPayload* FromListEntry(PLIST_ENTRY pEntry)
+ {
+ return (CPayload*) CONTAINING_RECORD(pEntry, CPayload, m_ListEntry);
+ }
+
+private:
+ PBYTE m_pbPayload;
+ DWORD m_cbPayload;
+ LIST_ENTRY m_ListEntry;
+};
+
+class CFileObject
+{
+public:
+ CFileObject(WDFFILEOBJECT FileObject);
+ ~CFileObject();
+
+public:
+ static EVT_WDF_OBJECT_CONTEXT_DESTROY OnDestroy;
+ static EVT_WDF_REQUEST_CANCEL OnRequestCancel;
+
+public:
+ NTSTATUS Enable();
+ NTSTATUS Disable();
+ NTSTATUS SetType(_In_ PCWSTR pszType);
+ NTSTATUS GetNextSubscribedMessage(_In_ WDFREQUEST Request);
+ NTSTATUS SetPayload(_In_ DWORD cbPayload, _In_reads_bytes_(cbPayload) PBYTE pbPayload);
+ NTSTATUS GetNextTransmittedMessage(_In_ WDFREQUEST Request);
+ NTSTATUS GetNextSecureElementPayload(_In_ WDFREQUEST Request);
+ NTSTATUS SubscribeForEvent(_In_ GUID& SecureElementId, _In_ SECURE_ELEMENT_EVENT_TYPE SecureElementEventType);
+ NTSTATUS BeginProximity(_In_ BEGIN_PROXIMITY_ARGS *pArgs, _In_ IConnectionCallback* pCallback);
+
+ void HandleArrivalEvent();
+ void HandleRemovalEvent();
+ void HandleReceivedMessage(_In_ PCWSTR pszType, _In_ DWORD cbPayload, _In_reads_bytes_(cbPayload) PBYTE pbPayload);
+ void HandleMessageTransmitted();
+ void HandleReceiveHcePacket(_In_ USHORT uConnectionId, _In_ DWORD cbPayload, _In_reads_bytes_(cbPayload) PBYTE pbPayload);
+ void HandleSecureElementEvent(SECURE_ELEMENT_EVENT_INFO* pInfo);
+
+public:
+ void SetRoleSubcription()
+ {
+ m_Role = ROLE_SUBSCRIPTION;
+ }
+ void SetRolePublication()
+ {
+ m_Role = ROLE_PUBLICATION;
+ }
+ BOOL SetRoleArrivedSubcription()
+ {
+ if (m_Role == ROLE_SUBSCRIPTION)
+ {
+ m_Role = ROLE_ARRIVEDSUBSCRIPTION;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ BOOL SetRoleDepartedSubcription()
+ {
+ if (m_Role == ROLE_SUBSCRIPTION)
+ {
+ m_Role = ROLE_DEPARTEDSUBSCRIPTION;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ void SetRoleSmartCardReader()
+ {
+ m_Role = ROLE_SMARTCARDREADER;
+ }
+ void SetRoleSecureElementEvent()
+ {
+ m_Role = ROLE_SECUREELEMENTEVENT;
+ }
+ void SetRoleSecureElementManager()
+ {
+ m_Role = ROLE_SECUREELEMENTMANAGER;
+ }
+ void SetRoleSimulation()
+ {
+ m_Role = ROLE_SIMULATION;
+ }
+ void SetRoleRadioManager()
+ {
+ m_Role = ROLE_RADIOMANAGER;
+ }
+
+public:
+ BOOL IsNormalSubscription()
+ {
+ return (m_Role == ROLE_SUBSCRIPTION);
+ }
+ BOOL IsArrivedSubscription()
+ {
+ return (m_Role == ROLE_ARRIVEDSUBSCRIPTION);
+ }
+ BOOL IsDepartedSubscription()
+ {
+ return (m_Role == ROLE_DEPARTEDSUBSCRIPTION);
+ }
+ BOOL IsSubscription()
+ {
+ return (m_Role == ROLE_SUBSCRIPTION) || (m_Role == ROLE_ARRIVEDSUBSCRIPTION) || (m_Role == ROLE_DEPARTEDSUBSCRIPTION);
+ }
+ BOOL IsPublication()
+ {
+ return (m_Role == ROLE_PUBLICATION);
+ }
+ BOOL IsSmartCardReader()
+ {
+ return (m_Role == ROLE_SMARTCARDREADER);
+ }
+ BOOL IsSecureElementEvent()
+ {
+ return (m_Role == ROLE_SECUREELEMENTEVENT);
+ }
+ BOOL IsSecureElementManager()
+ {
+ return (m_Role == ROLE_SECUREELEMENTMANAGER);
+ }
+ BOOL IsRoleSimulation()
+ {
+ return (m_Role == ROLE_SIMULATION);
+ }
+ BOOL IsRoleRadioManager()
+ {
+ return (m_Role == ROLE_RADIOMANAGER);
+ }
+ BOOL IsRoleUndefined()
+ {
+ return (m_Role == ROLE_UNDEFINED);
+ }
+ PCWSTR GetType()
+ {
+ return m_pszType;
+ }
+ DWORD GetSize()
+ {
+ return m_Payload.GetSize();
+ }
+ PBYTE GetPayload()
+ {
+ return m_Payload.GetPayload();
+ }
+ BOOL IsEnabled()
+ {
+ return m_fEnabled;
+ }
+ GUID& GetSecureElementId()
+ {
+ return m_SecureElementId;
+ }
+ SECURE_ELEMENT_EVENT_TYPE GetSecureElementEventType()
+ {
+ return m_SecureElementEventType;
+ }
+ PLIST_ENTRY GetListEntry()
+ {
+ return &m_ListEntry;
+ }
+ static CFileObject* FromListEntry(PLIST_ENTRY pEntry)
+ {
+ return (CFileObject*) CONTAINING_RECORD(pEntry, CFileObject, m_ListEntry);
+ }
+
+private:
+ void HandleReceivedMessage(_In_ DWORD cbPayload, _In_reads_bytes_(cbPayload) PBYTE pbPayload);
+ bool CompleteRequest(_In_ DWORD cbPayload, _In_reads_bytes_opt_(cbPayload) PBYTE pbPayload);
+ bool CompleteRequest(_In_ NTSTATUS CompletionStatus, _In_ size_t cbSize, _In_ bool fIsCancelable);
+ void PurgeQueue();
+ void Cancel();
+
+private:
+ enum ROLE
+ {
+ ROLE_UNDEFINED,
+ ROLE_SUBSCRIPTION,
+ ROLE_ARRIVEDSUBSCRIPTION,
+ ROLE_DEPARTEDSUBSCRIPTION,
+ ROLE_PUBLICATION,
+ ROLE_SMARTCARDREADER,
+ ROLE_SECUREELEMENTEVENT,
+ ROLE_SECUREELEMENTMANAGER,
+ ROLE_SIMULATION,
+ ROLE_RADIOMANAGER
+ };
+
+ WDFFILEOBJECT m_FileObject; // The Fx File object this CFileObject is associated with
+ ROLE m_Role;
+ PWSTR m_pszType;
+ BOOL m_fEnabled;
+ DWORD m_dwQueueSize;
+ LIST_ENTRY m_Queue; // Unique to ROLE_SUBSCRIPTION and ROLE_SECUREELEMENTEVENT
+ CPayload m_Payload; // Unique to ROLE_PUBLICATION
+ size_t m_cCompleteReady; // Unique to ROLE_PUBLICATION
+ CConnection* m_pConnection; // Unique to ROLE_SIMULATION
+ WDFREQUEST m_Request; // Pended "Get Next" Request
+ CRITICAL_SECTION m_RoleLock;
+ LIST_ENTRY m_ListEntry;
+ GUID m_SecureElementId; // Unique to ROLE_SECUREELEMENTEVENT
+ SECURE_ELEMENT_EVENT_TYPE m_SecureElementEventType; // Unique to ROLE_SECUREELEMENTEVENT
+};
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CFileObject, GetFileObject); \ No newline at end of file
diff --git a/nfc/Simulator/Src/Internal.h b/nfc/Simulator/Src/Internal.h
new file mode 100644
index 00000000..ad642628
--- /dev/null
+++ b/nfc/Simulator/Src/Internal.h
@@ -0,0 +1,84 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Internal.h
+
+Abstract:
+
+ This module contains the local type definitions for the UMDF driver.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+//
+// Include the type specific headers.
+//
+#include <windows.h>
+#include <ntstatus.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <malloc.h>
+#pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union
+#include <wudfwdm.h>
+#include <devioctl.h>
+#include <wdf.h>
+#define INIT_GUID
+#include <initguid.h>
+#include <ntassert.h>
+#include <winsmcrd.h>
+#include <stdlib.h>
+#include <strsafe.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <mswsock.h>
+#include <new.h>
+#include <objbase.h>
+#include <coguid.h>
+#include <nfpdev.h>
+#include <nfcsedev.h>
+#include <nfcradiodev.h>
+#include <ncidef.h>
+
+//
+// Define the tracing GUID for this driver
+//
+#define TRACE_CONTROL_GUID (12579E92, 1B46, 40A6, 9CFC, C718A677830B)
+
+#ifndef SAFE_DELETEARRAY
+#define SAFE_DELETEARRAY(x) if ((x) != nullptr) { delete [] (x); (x) = nullptr; }
+#endif
+
+#ifndef SAFE_DELETE
+#define SAFE_DELETE(x) if ((x) != nullptr) { delete (x); (x) = nullptr; }
+#endif
+
+#ifndef SAFE_CLOSEHANDLE
+#define SAFE_CLOSEHANDLE(x) if ((x) != nullptr) { CloseHandle(x); (x) = nullptr; }
+#endif
+
+#ifndef SAFE_FREELIBRARY
+#define SAFE_FREELIBRARY(x) if ((x) != nullptr) { FreeLibrary(x); (x) = nullptr; }
+#endif
+
+#include "nfcsimulatorddi.h"
+#include "constants.h"
+#include "linklist.h"
+#include "wppdefs.h"
+#include "connection.h"
+#include "filecontext.h"
+#include "secureelement.h"
+#include "driver.h"
+#include "device.h"
+#include "smartcard.h"
+#include "smartcardreader.h"
+#include "routingtable.h"
+#include "queue.h"
+
diff --git a/nfc/Simulator/Src/Internalsrc.cpp b/nfc/Simulator/Src/Internalsrc.cpp
new file mode 100644
index 00000000..1e8fe6f2
--- /dev/null
+++ b/nfc/Simulator/Src/Internalsrc.cpp
@@ -0,0 +1 @@
+#include "Internal.h" \ No newline at end of file
diff --git a/nfc/Simulator/Src/LinkList.h b/nfc/Simulator/Src/LinkList.h
new file mode 100644
index 00000000..682d7420
--- /dev/null
+++ b/nfc/Simulator/Src/LinkList.h
@@ -0,0 +1,121 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+
+#pragma once
+
+//
+// Calculate the address of the base of the structure given its type, and an
+// address of a field within the structure.
+//
+#ifndef CONTAINING_RECORD
+#define CONTAINING_RECORD(address, type, field) \
+ ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field)))
+#endif
+
+
+#ifndef InitializeListHead
+
+FORCEINLINE
+VOID
+InitializeListHead(
+ _Out_ PLIST_ENTRY ListHead
+ )
+{
+ ListHead->Flink = ListHead->Blink = ListHead;
+ return;
+}
+
+_Must_inspect_result_
+BOOLEAN
+CFORCEINLINE
+IsListEmpty(
+ _In_ const LIST_ENTRY * ListHead
+ )
+{
+ return (BOOLEAN)(ListHead->Flink == ListHead);
+}
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveHeadList(
+ _Inout_ PLIST_ENTRY ListHead
+ )
+{
+ PLIST_ENTRY Flink;
+ PLIST_ENTRY Entry;
+
+ Entry = ListHead->Flink;
+ Flink = Entry->Flink;
+ ListHead->Flink = Flink;
+ Flink->Blink = ListHead;
+ return Entry;
+}
+
+FORCEINLINE
+PLIST_ENTRY
+RemoveTailList(
+ _Inout_ PLIST_ENTRY ListHead
+ )
+{
+ PLIST_ENTRY Blink;
+ PLIST_ENTRY Entry;
+
+ Entry = ListHead->Blink;
+ Blink = Entry->Blink;
+ ListHead->Blink = Blink;
+ Blink->Flink = ListHead;
+ return Entry;
+}
+
+FORCEINLINE
+BOOLEAN
+RemoveEntryList(
+ _In_ PLIST_ENTRY Entry
+ )
+{
+ PLIST_ENTRY Blink;
+ PLIST_ENTRY Flink;
+
+ Flink = Entry->Flink;
+ Blink = Entry->Blink;
+ Blink->Flink = Flink;
+ Flink->Blink = Blink;
+ return (BOOLEAN)(Flink == Blink);
+}
+
+FORCEINLINE
+VOID
+InsertTailList(
+ _Inout_ PLIST_ENTRY ListHead,
+ _Inout_ __drv_aliasesMem PLIST_ENTRY Entry
+ )
+{
+ PLIST_ENTRY Blink;
+
+ Blink = ListHead->Blink;
+ Entry->Flink = ListHead;
+ Entry->Blink = Blink;
+ Blink->Flink = Entry;
+ ListHead->Blink = Entry;
+ return;
+}
+
+FORCEINLINE
+VOID
+InsertHeadList(
+ _Inout_ PLIST_ENTRY ListHead,
+ _Inout_ __drv_aliasesMem PLIST_ENTRY Entry
+ )
+{
+ PLIST_ENTRY Flink;
+
+ Flink = ListHead->Flink;
+ Entry->Flink = Flink;
+ Entry->Blink = ListHead;
+ Flink->Blink = Entry;
+ ListHead->Flink = Entry;
+ return;
+}
+
+#endif // InitializeListHead
diff --git a/nfc/Simulator/Src/NfcDriverSim.vcxproj b/nfc/Simulator/Src/NfcDriverSim.vcxproj
new file mode 100644
index 00000000..70b3e49c
--- /dev/null
+++ b/nfc/Simulator/Src/NfcDriverSim.vcxproj
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{E60D786C-D146-4B1A-835D-D62B883D7F00}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{2082F9B4-EC5F-4180-9398-6493BA69FB07}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>UMDF</DriverType>
+ <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="Driver.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="Device.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="Queue.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="Connection.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="FileContext.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="SocketListener.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="SecureElement.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="SmartCardReader.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="SmartCard.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="RoutingTable.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <Inf Include="NfcSimulator.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <Verbose>true</Verbose>
+ <CopyOutput>.\$(IntDir)\NfcSimulator.inf</CopyOutput>
+ </Inf>
+ <OtherWpp Include="NfcSimulator.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ </OtherWpp>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>NfcDriverSim</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>NfcDriverSim</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>NfcDriverSim</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>NfcDriverSim</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <BaseAddress>0x2000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <BaseAddress>0x2000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <BaseAddress>0x2000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <BaseAddress>0x2000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM=1</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.\$(IntDir);..\inc;$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <ModuleDefinitionFile>NfcSimulator.def</ModuleDefinitionFile>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <ModuleDefinitionFile>NfcSimulator.def</ModuleDefinitionFile>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <ModuleDefinitionFile>NfcSimulator.def</ModuleDefinitionFile>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <ModuleDefinitionFile>NfcSimulator.def</ModuleDefinitionFile>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Internalsrc.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>Internal.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\Internal.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="NfcSimulator.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/nfc/Simulator/Src/NfcDriverSim.vcxproj.Filters b/nfc/Simulator/Src/NfcDriverSim.vcxproj.Filters
new file mode 100644
index 00000000..bc53424e
--- /dev/null
+++ b/nfc/Simulator/Src/NfcDriverSim.vcxproj.Filters
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{F02AF408-2502-49D2-B3D0-F9C353878FA6}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{18A112F1-3B09-4196-8A5A-4D653CB64F5C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{85A45C49-C7DD-4CD3-85D3-AFB43AFF2962}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{7D686BE0-2BB7-4EB9-B71C-9A7698008D64}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Connection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Driver.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="FileContext.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Internalsrc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Queue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="RoutingTable.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SecureElement.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SmartCard.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SmartCardReader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SocketListener.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="NfcSimulator.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="NfcSimulator.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="NfcSimulator.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/nfc/Simulator/Src/NfcSimulator.def b/nfc/Simulator/Src/NfcSimulator.def
new file mode 100644
index 00000000..c765118c
--- /dev/null
+++ b/nfc/Simulator/Src/NfcSimulator.def
@@ -0,0 +1,6 @@
+;
+; Copyright (c) Microsoft Corporation. All rights reserved.
+;
+LIBRARY "NfcDriverSim.dll"
+
+EXPORTS
diff --git a/nfc/Simulator/Src/NfcSimulator.inx b/nfc/Simulator/Src/NfcSimulator.inx
new file mode 100644
index 00000000..465c3d5b
--- /dev/null
+++ b/nfc/Simulator/Src/NfcSimulator.inx
Binary files differ
diff --git a/nfc/Simulator/Src/NfcSimulator.rc b/nfc/Simulator/Src/NfcSimulator.rc
new file mode 100644
index 00000000..859eb8ec
--- /dev/null
+++ b/nfc/Simulator/Src/NfcSimulator.rc
@@ -0,0 +1,15 @@
+//---------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation, All Rights Reserved
+//---------------------------------------------------------------------------
+
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NFC Simulator Driver"
+#define VER_INTERNALNAME_STR "NfcDriverSim.dll"
+#define VER_ORIGINALFILENAME_STR "NfcDriverSim.dll"
+
+#include "common.ver"
diff --git a/nfc/Simulator/Src/Queue.cpp b/nfc/Simulator/Src/Queue.cpp
new file mode 100644
index 00000000..c72dfba9
--- /dev/null
+++ b/nfc/Simulator/Src/Queue.cpp
@@ -0,0 +1,2420 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ queue.cpp
+
+Abstract:
+
+ This file implements the I/O queue interface and performs the ioctl operations.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "Internal.h"
+#include "Queue.tmh"
+
+CQueue::CQueue(WDFQUEUE Queue) :
+ m_Queue(Queue),
+ m_SmartCardReader(WdfIoQueueGetDevice(Queue)),
+ m_SocketListener(this),
+ m_pSEManager(nullptr),
+ m_pHCEConnection(nullptr),
+ m_NfpRadioState(TRUE),
+ m_NfpRadioOffPolicyOverride(FALSE),
+ m_NfpRadioOffSystemOverride(FALSE),
+ m_SERadioState(TRUE),
+ m_NfpInterfaceCreated(FALSE),
+ m_ScInterfaceCreated(FALSE),
+ m_SEInterfaceCreated(FALSE),
+ m_RoutingTable(this),
+ m_HCEConnectionId(0)
+{
+ NT_ASSERT(m_Queue != nullptr);
+
+ InitializeListHead(&m_SubsList);
+ InitializeListHead(&m_ArrivalSubsList);
+ InitializeListHead(&m_DepartureSubsList);
+ InitializeListHead(&m_PubsList);
+ InitializeListHead(&m_ConnectionList);
+ InitializeListHead(&m_SecureElementList);
+ InitializeListHead(&m_SEEventsList);
+
+ InitializeCriticalSection(&m_SubsLock);
+ InitializeCriticalSection(&m_PubsLock);
+ InitializeCriticalSection(&m_ConnectionLock);
+ InitializeCriticalSection(&m_SEManagerLock);
+ InitializeCriticalSection(&m_SEEventsLock);
+ InitializeCriticalSection(&m_RadioLock);
+ InitializeCriticalSection(&m_pHCEConnectionLock);
+}
+
+CQueue::~CQueue()
+{
+ DeleteCriticalSection(&m_SubsLock);
+ DeleteCriticalSection(&m_PubsLock);
+ DeleteCriticalSection(&m_ConnectionLock);
+ DeleteCriticalSection(&m_SEEventsLock);
+ DeleteCriticalSection(&m_RadioLock);
+ DeleteCriticalSection(&m_pHCEConnectionLock);
+
+ m_Queue = nullptr;
+}
+
+NTSTATUS CQueue::Initialize()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WSADATA WsaData = {};
+
+ DECLARE_CONST_UNICODE_STRING(RMNamespace, RM_NAMESPACE);
+ DECLARE_CONST_UNICODE_STRING(SCNamespace, SMARTCARD_READER_NAMESPACE);
+ DECLARE_CONST_UNICODE_STRING(SimulatorNamespace, SIM_NAMESPACE);
+
+ ReadSettingsFromRegistry();
+
+ if (WSAStartup(MAKEWORD(2,2), &WsaData) != 0) {
+ Status = STATUS_INTERNAL_ERROR;
+ goto Exit;
+ }
+
+
+ if (!NT_SUCCESS(m_SmartCardReader.Initialize())) {
+ Status = STATUS_INTERNAL_ERROR;
+ goto Exit;
+ }
+
+ if (FAILED(m_SocketListener.Bind())) {
+ Status = STATUS_INTERNAL_ERROR;
+ goto Exit;
+ }
+
+ if (FAILED(m_SocketListener.EnableAccepting())) {
+ Status = STATUS_INTERNAL_ERROR;
+ goto Exit;
+ }
+
+ EnumerateSecureElements();
+ m_RoutingTable.Initialize(WdfIoQueueGetDevice(m_Queue));
+
+ // Register for NFP Radio Manager interface
+ Status = WdfDeviceCreateDeviceInterface(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_NFC_RADIO_MEDIA_DEVICE_INTERFACE,
+ &RMNamespace);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreateDeviceInterface failed with %!STATUS!", Status);
+ goto Exit;
+ }
+
+ if (IsNfpRadioEnabled()) {
+ // Register for Proximity interface
+ Status = WdfDeviceCreateDeviceInterface(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_NFP,
+ nullptr);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreateDeviceInterface failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+ m_NfpInterfaceCreated = TRUE;
+
+ // Register for Smart Card interface
+ Status = WdfDeviceCreateDeviceInterface(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_SMARTCARD_READER,
+ &SCNamespace);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreateDeviceInterface failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+ m_ScInterfaceCreated = TRUE;
+ }
+
+ if (IsSERadioEnabled()) {
+ // Register for Secure Element interface
+ Status = WdfDeviceCreateDeviceInterface(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_NFCSE,
+ nullptr);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreateDeviceInterface failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+ m_SEInterfaceCreated = TRUE;
+ }
+
+ // Register for Simulator interface
+ Status = WdfDeviceCreateDeviceInterface(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_NFCSIM,
+ &SimulatorNamespace);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreateDeviceInterface failed with %!STATUS!", Status);
+ goto Exit;
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CQueue::Deinitialize()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ while (!IsListEmpty(&m_SecureElementList)) {
+ delete CSecureElement::FromListEntry(RemoveHeadList(&m_SecureElementList));
+ }
+
+
+ m_SocketListener.StopAccepting();
+ m_SmartCardReader.Deinitialize();
+
+ while (!IsListEmpty(&m_ConnectionList)) {
+ delete CConnection::FromListEntry(RemoveHeadList(&m_ConnectionList));
+ }
+
+ WSACleanup();
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+BOOLEAN CQueue::IsNfpRadioEnabled()
+{
+ BOOLEAN NfpRadioState;
+
+ EnterCriticalSection(&m_RadioLock);
+ NfpRadioState = m_NfpRadioState;
+ LeaveCriticalSection(&m_RadioLock);
+
+ return NfpRadioState;
+}
+
+BOOLEAN CQueue::IsSERadioEnabled()
+{
+ BOOLEAN SERadioState;
+
+ EnterCriticalSection(&m_RadioLock);
+ SERadioState = m_SERadioState;
+ LeaveCriticalSection(&m_RadioLock);
+
+ return SERadioState;
+}
+
+NTSTATUS CQueue::DetectRole(CFileObject *pFileObject, PCWSTR pszFileName)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PCWSTR pszProtocol = nullptr;
+ PCWSTR pszType = nullptr;
+
+ MethodEntry("pszFileName = %S", pszFileName);
+
+ if (IsStringPrefixed(pszFileName, PUBS_NAMESPACE)) {
+ if (IsNfpRadioEnabled()) {
+ pFileObject->SetRolePublication();
+ pszProtocol = pszFileName + PUBS_NAMESPACE_CHARS;
+ }
+ else {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ else if (IsStringPrefixed(pszFileName, SUBS_NAMESPACE)) {
+ if (IsNfpRadioEnabled()) {
+ pFileObject->SetRoleSubcription();
+ pszProtocol = pszFileName + SUBS_NAMESPACE_CHARS;
+ }
+ else {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ else if (IsStringEqual(pszFileName, SEEVENTS_NAMESPACE)) {
+ if (IsSERadioEnabled()) {
+ pFileObject->SetRoleSecureElementEvent();
+ }
+ else {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ else if (IsStringEqual(pszFileName, SEMANAGE_NAMESPACE)) {
+ if (IsSERadioEnabled()) {
+ pFileObject->SetRoleSecureElementManager();
+ }
+ else {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ else if (IsStringEqual(pszFileName, SMARTCARD_READER_NAMESPACE)) {
+ if (IsNfpRadioEnabled()) {
+ pFileObject->SetRoleSmartCardReader();
+ }
+ else {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ else if (IsStringEqual(pszFileName, SIM_NAMESPACE)) {
+ pFileObject->SetRoleSimulation();
+ }
+ else if (IsStringEqual(pszFileName, RM_NAMESPACE)) {
+ pFileObject->SetRoleRadioManager();
+ }
+ else {
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ if (NT_SUCCESS(Status) && pszProtocol != nullptr) {
+ Status = STATUS_OBJECT_PATH_NOT_FOUND;
+
+ if (IsStringPrefixed(pszProtocol, WINDOWS_PROTOCOL)) {
+ pszType = pszProtocol + WINDOWS_PROTOCOL_CHARS;
+
+ if (*pszType == L'.') {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ else if (*pszType == L':') {
+ pszType = pszType + 1;
+
+ if (pFileObject->IsPublication() && IsStringEqual(pszType, WRITETAG_TYPE)) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ else if (IsStringPrefixed(pszType, WINDOWSURI_TYPE)) {
+ pszType = pszType + WINDOWSURI_TYPE_CHARS;
+
+ if (*pszType == L'\0') {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ else if (*pszType == L':') {
+ pszType = pszType + 1;
+
+ if (pFileObject->IsPublication() && IsStringEqual(pszType, WRITETAG_TYPE)) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ }
+ else if (IsStringPrefixed(pszType, WINDOWSMIME_TYPE)) {
+ pszType = pszType + WINDOWSMIME_TYPE_CHARS;
+
+ if (*pszType == L'\0') {
+ if (pFileObject->IsNormalSubscription()) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ else if (*pszType == L':') {
+ pszType = pszType + 1;
+
+ if (pFileObject->IsPublication() && IsStringEqual(pszType, WRITETAG_TYPE)) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ else if (*pszType == L'.') {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ }
+ else if (IsStringPrefixed(pszProtocol, NDEF_PROTOCOL)) {
+ pszType = pszProtocol + NDEF_PROTOCOL_CHARS;
+
+ if (*pszType == L'\0') {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ else if (*pszType == L':') {
+ pszType = pszType + 1;
+
+ if (pFileObject->IsPublication()) {
+ if (IsStringEqual(pszType, WRITETAG_TYPE)) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ else {
+ if (IsStringPrefixed(pszType, NDEF_EXT_TYPE) ||
+ IsStringPrefixed(pszType, NDEF_MIME_TYPE) ||
+ IsStringPrefixed(pszType, NDEF_URI_TYPE) ||
+ IsStringPrefixed(pszType, NDEF_WKT_TYPE) ||
+ IsStringPrefixed(pszType, NDEF_UNKNOWN_TYPE)) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ }
+ }
+ else if (pFileObject->IsPublication()) {
+ if (IsStringEqual(pszProtocol, LAUNCHAPP_WRITETAG_PROTOCOL)) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ else if (pFileObject->IsNormalSubscription()) {
+ if (IsStringEqual(pszProtocol, DEVICE_ARRIVED)) {
+ if (pFileObject->SetRoleArrivedSubcription()) {
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else if (IsStringEqual(pszProtocol, DEVICE_DEPARTED)) {
+ if (pFileObject->SetRoleDepartedSubcription()) {
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else if (IsStringEqual(pszProtocol, PAIRING_BLUETOOTH_PROTOCOL) ||
+ IsStringEqual(pszProtocol, PAIRING_UPNP_PROTOCOL) ||
+ IsStringEqual(pszProtocol, WRITEABLETAG_PROTOCOL)) {
+ Status = pFileObject->SetType(pszProtocol);
+ }
+ }
+ }
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+void
+CQueue::OnFileCreate(
+ _In_ WDFDEVICE Device,
+ _In_ WDFREQUEST Request,
+ _In_ WDFFILEOBJECT FileObject
+ )
+{
+ MethodEntry("Request = %p, FileObject = %p", Request, FileObject);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ PUNICODE_STRING FileName = nullptr;
+ PCWSTR pszFileName = nullptr;
+ CFileObject *pFileObject = nullptr;
+
+ UNREFERENCED_PARAMETER(Device);
+
+ // Construct file object on the preallocated buffer using placement 'new'
+ pFileObject = new (GetFileObject(FileObject)) CFileObject(FileObject);
+
+ if (pFileObject == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ FileName = WdfFileObjectGetFileName(FileObject);
+
+ if ((FileName != nullptr) && (FileName->Length > 0)) {
+ NT_ASSERT(FileName->Buffer != nullptr);
+
+ if ((FileName->Length / sizeof(WCHAR)) > MaxCchType) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ pszFileName = FileName->Buffer;
+ pszFileName = (pszFileName[0] == L'\\') ? pszFileName+1 : pszFileName;
+
+ Status = DetectRole(pFileObject, pszFileName);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Exit;
+ }
+
+ TraceInfo("pszFileName = %S pFileObject = %p", pszFileName, pFileObject);
+ }
+
+ if (pFileObject->IsNormalSubscription()) {
+ EnterCriticalSection(&m_SubsLock);
+ InsertHeadList(&m_SubsList, pFileObject->GetListEntry());
+ LeaveCriticalSection(&m_SubsLock);
+ }
+ else if (pFileObject->IsArrivedSubscription()) {
+ EnterCriticalSection(&m_SubsLock);
+ InsertHeadList(&m_ArrivalSubsList, pFileObject->GetListEntry());
+ LeaveCriticalSection(&m_SubsLock);
+ }
+ else if (pFileObject->IsDepartedSubscription()) {
+ EnterCriticalSection(&m_SubsLock);
+ InsertHeadList(&m_DepartureSubsList, pFileObject->GetListEntry());
+ LeaveCriticalSection(&m_SubsLock);
+ }
+ else if (pFileObject->IsSmartCardReader()) {
+ Status = m_SmartCardReader.AddClient(pFileObject);
+ }
+ else if (pFileObject->IsSecureElementManager()) {
+ EnterCriticalSection(&m_SEManagerLock);
+ Status = InterlockedCompareExchangePointer((void**)&m_pSEManager, pFileObject, nullptr) == nullptr ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
+ LeaveCriticalSection(&m_SEManagerLock);
+ }
+
+Exit:
+ TraceInfo("%!FUNC! Completing Request with Status %!STATUS!", Status);
+ WdfRequestComplete(Request, Status);
+
+ MethodReturnVoid();
+}
+
+void CQueue::OnFileClose(_In_ WDFFILEOBJECT FileObject)
+{
+ MethodEntry("...");
+
+ CFileObject* pFileObject = GetFileObject(FileObject);
+ CRITICAL_SECTION *pLock = nullptr;
+ LIST_ENTRY* pHead = nullptr;
+
+ NT_ASSERT(pFileObject != nullptr);
+
+ if (pFileObject->IsNormalSubscription()) {
+ pLock = &m_SubsLock;
+ pHead = &m_SubsList;
+ }
+ else if (pFileObject->IsArrivedSubscription()) {
+ pLock = &m_SubsLock;
+ pHead = &m_ArrivalSubsList;
+ }
+ else if (pFileObject->IsDepartedSubscription()) {
+ pLock = &m_SubsLock;
+ pHead = &m_DepartureSubsList;
+ }
+ else if (pFileObject->IsPublication()) {
+ pLock = &m_PubsLock;
+ pHead = &m_PubsList;
+ }
+ else if (pFileObject->IsSmartCardReader()) {
+ m_SmartCardReader.RemoveClient(pFileObject);
+ }
+ else if (pFileObject->IsSecureElementEvent()) {
+ pLock = &m_SEEventsLock;
+ pHead = &m_SEEventsList;
+ }
+ else if (pFileObject->IsSecureElementManager()) {
+ EnterCriticalSection(&m_SEManagerLock);
+ InterlockedCompareExchangePointer((void**)&m_pSEManager, nullptr, pFileObject);
+ LeaveCriticalSection(&m_SEManagerLock);
+
+ for (LIST_ENTRY* pEntry = m_SecureElementList.Flink;
+ pEntry != &m_SecureElementList;
+ pEntry = pEntry->Flink) {
+ CSecureElement::FromListEntry(pEntry)->SetEmulationMode(EmulationOff);
+ }
+ }
+
+ if (pHead != nullptr) {
+ EnterCriticalSection(pLock);
+
+ for (LIST_ENTRY* pEntry = pHead->Flink;
+ pEntry != pHead;
+ pEntry = pEntry->Flink) {
+ if (pEntry == pFileObject->GetListEntry()) {
+ RemoveEntryList(pEntry);
+ break;
+ }
+ }
+ LeaveCriticalSection(pLock);
+ }
+
+ MethodReturnVoid();
+}
+
+VOID
+CQueue::OnIoDeviceControl(
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+{
+ FunctionEntry("...");
+
+ CQueue *pQueue = GetQueueObject(Queue);
+
+ NT_ASSERT(pQueue != nullptr);
+ pQueue->OnIoDeviceControl(Request, IoControlCode, InputBufferLength, OutputBufferLength);
+
+ FunctionReturnVoid();
+}
+
+void
+CQueue::OnIoDeviceControl(
+ _In_ WDFREQUEST Request,
+ _In_ ULONG IoControlCode,
+ _In_ size_t InputBufferLength,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("Request = %p, IoControlCode = 0x%x InputBufferLength=%d OutputBufferLength=%d",
+ Request, IoControlCode, (DWORD)InputBufferLength, (DWORD)OutputBufferLength);
+
+ NTSTATUS Status = STATUS_INVALID_DEVICE_STATE;
+
+ switch (IoControlCode)
+ {
+ case IOCTL_NFP_GET_MAX_MESSAGE_BYTES:
+ case IOCTL_NFP_GET_KILO_BYTES_PER_SECOND:
+ case IOCTL_NFP_DISABLE:
+ case IOCTL_NFP_ENABLE:
+ case IOCTL_NFP_SET_PAYLOAD:
+ case IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE:
+ case IOCTL_NFP_GET_NEXT_TRANSMITTED_MESSAGE:
+ case IOCTL_NFCSIM_BEGIN_PROXIMITY:
+ {
+ const DISPATCH_ENTRY DispatchTable[] =
+ {
+ { IOCTL_NFP_ENABLE, 0, 0, &CQueue::OnNfpEnable },
+ { IOCTL_NFP_DISABLE, 0, 0, &CQueue::OnNfpDisable },
+ { IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE, 0, sizeof(DWORD), &CQueue::OnNfpGetNextSubscribedMessage },
+ { IOCTL_NFP_SET_PAYLOAD, MinCbPayload, 0, &CQueue::OnNfpSetPayload },
+ { IOCTL_NFP_GET_NEXT_TRANSMITTED_MESSAGE, 0, 0, &CQueue::OnNfpGetNextTransmittedMessage },
+ { IOCTL_NFP_GET_MAX_MESSAGE_BYTES, 0, sizeof(DWORD), &CQueue::OnNfpGetMaxMessageBytes },
+ { IOCTL_NFP_GET_KILO_BYTES_PER_SECOND, 0, sizeof(DWORD), &CQueue::OnNfpGetTransmissionRateKbps },
+ { IOCTL_NFCSIM_BEGIN_PROXIMITY, sizeof(BEGIN_PROXIMITY_ARGS), 0, &CQueue::OnNfpBeginProximity },
+ };
+
+ if (IsNfpRadioEnabled()) {
+ Status = DispatchMessage(DispatchTable, _countof(DispatchTable), Request, IoControlCode, InputBufferLength, OutputBufferLength);
+ }
+ }
+ break;
+
+ case IOCTL_NFCSE_ENUM_ENDPOINTS:
+ case IOCTL_NFCSE_SUBSCRIBE_FOR_EVENT:
+ case IOCTL_NFCSE_GET_NEXT_EVENT:
+ case IOCTL_NFCSE_SET_CARD_EMULATION_MODE:
+ case IOCTL_NFCSIM_TRIGGER_SEEVENT:
+ case IOCTL_NFCSE_GET_NFCC_CAPABILITIES:
+ case IOCTL_NFCSE_GET_ROUTING_TABLE:
+ case IOCTL_NFCSE_SET_ROUTING_TABLE:
+ case IOCTL_NFCSE_HCE_REMOTE_RECV:
+ case IOCTL_NFCSE_HCE_REMOTE_SEND:
+ {
+ const DISPATCH_ENTRY DispatchTable[] =
+ {
+ { IOCTL_NFCSE_SET_CARD_EMULATION_MODE, sizeof(SECURE_ELEMENT_SET_CARD_EMULATION_MODE_INFO), 0, &CQueue::OnSESetCardEmulationMode },
+ { IOCTL_NFCSE_GET_NEXT_EVENT, 0, sizeof(DWORD), &CQueue::OnSEGetNextEvent },
+ { IOCTL_NFCSE_SUBSCRIBE_FOR_EVENT, sizeof(SECURE_ELEMENT_EVENT_SUBSCRIPTION_INFO), 0, &CQueue::OnSESubscribeForEvent },
+ { IOCTL_NFCSE_ENUM_ENDPOINTS, 0, sizeof(DWORD), &CQueue::OnSEEnumEndpoints },
+ { IOCTL_NFCSE_GET_NFCC_CAPABILITIES, 0, sizeof(SECURE_ELEMENT_NFCC_CAPABILITIES), &CQueue::OnSEGetNfccCapabilities },
+ { IOCTL_NFCSE_GET_ROUTING_TABLE, 0, sizeof(DWORD), &CQueue::OnSEGetRoutingTable },
+ { IOCTL_NFCSE_SET_ROUTING_TABLE, sizeof(SECURE_ELEMENT_ROUTING_TABLE), 0, &CQueue::OnSESetRoutingTable },
+ { IOCTL_NFCSE_HCE_REMOTE_RECV, 0, sizeof(DWORD), &CQueue::OnSEHCERemoteRecv },
+ { IOCTL_NFCSE_HCE_REMOTE_SEND, 2 * sizeof(USHORT) + 2, 0, &CQueue::OnSEHCERemoteSend },
+ { IOCTL_NFCSIM_TRIGGER_SEEVENT, SECURE_ELEMENT_EVENT_INFO_HEADER, 0, &CQueue::OnSETriggerEvent },
+ };
+
+ if (IsSERadioEnabled()) {
+ Status = DispatchMessage(DispatchTable, _countof(DispatchTable), Request, IoControlCode, InputBufferLength, OutputBufferLength);
+ }
+ }
+ break;
+
+ case IOCTL_SMARTCARD_EJECT:
+ case IOCTL_SMARTCARD_GET_LAST_ERROR:
+ case IOCTL_SMARTCARD_SET_ATTRIBUTE:
+ case IOCTL_SMARTCARD_SWALLOW:
+ case IOCTL_SMARTCARD_GET_ATTRIBUTE:
+ case IOCTL_SMARTCARD_GET_STATE:
+ case IOCTL_SMARTCARD_IS_ABSENT:
+ case IOCTL_SMARTCARD_IS_PRESENT:
+ case IOCTL_SMARTCARD_POWER:
+ case IOCTL_SMARTCARD_SET_PROTOCOL:
+ case IOCTL_SMARTCARD_TRANSMIT:
+ {
+ const DISPATCH_ENTRY DispatchTable[] =
+ {
+ { IOCTL_SMARTCARD_GET_ATTRIBUTE, sizeof(DWORD), 0, &CQueue::OnSCGetAttribute },
+ { IOCTL_SMARTCARD_SET_ATTRIBUTE, sizeof(DWORD), 0, &CQueue::OnSCSetAttribute },
+ { IOCTL_SMARTCARD_GET_STATE, 0, sizeof(DWORD), &CQueue::OnSCGetState },
+ { IOCTL_SMARTCARD_POWER, sizeof(DWORD), 0, &CQueue::OnSCPower },
+ { IOCTL_SMARTCARD_SET_PROTOCOL, sizeof(DWORD), sizeof(DWORD), &CQueue::OnSCSetProtocol },
+ { IOCTL_SMARTCARD_IS_ABSENT, 0, 0, &CQueue::OnSCIsAbsent },
+ { IOCTL_SMARTCARD_IS_PRESENT, 0, 0, &CQueue::OnSCIsPresent },
+ { IOCTL_SMARTCARD_TRANSMIT, sizeof(SCARD_IO_REQUEST)+1, sizeof(SCARD_IO_REQUEST)+2, &CQueue::OnSCTransmit },
+ { IOCTL_SMARTCARD_GET_LAST_ERROR, 0, 0, &CQueue::OnSCGetLastError },
+ };
+
+ if (IsNfpRadioEnabled()) {
+ Status = DispatchMessage(DispatchTable, _countof(DispatchTable), Request, IoControlCode, InputBufferLength, OutputBufferLength);
+ }
+ }
+ break;
+
+ case IOCTL_NFCRM_SET_RADIO_STATE:
+ case IOCTL_NFCRM_QUERY_RADIO_STATE:
+ case IOCTL_NFCSERM_SET_RADIO_STATE:
+ case IOCTL_NFCSERM_QUERY_RADIO_STATE:
+ {
+ const DISPATCH_ENTRY DispatchTable[] =
+ {
+ { IOCTL_NFCRM_SET_RADIO_STATE, sizeof(NFCRM_SET_RADIO_STATE), 0, &CQueue::OnNfpSetRadioState },
+ { IOCTL_NFCRM_QUERY_RADIO_STATE, 0, sizeof(NFCRM_RADIO_STATE), &CQueue::OnNfpQueryRadioState },
+ };
+
+ Status = DispatchMessage(DispatchTable, _countof(DispatchTable), Request, IoControlCode, InputBufferLength, OutputBufferLength);
+ }
+ break;
+
+ default:
+ {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+ }
+
+ if (Status != STATUS_PENDING) {
+ TraceInfo("%!FUNC! Completing Request with Status %!STATUS!", Status);
+ WdfRequestComplete(Request, Status);
+ }
+
+ MethodReturnVoid();
+}
+
+BOOL CQueue::ValidateMessage(_In_ CFileObject *pFileObject, _In_ ULONG IoControlCode)
+{
+ switch (IoControlCode)
+ {
+ case IOCTL_NFP_GET_MAX_MESSAGE_BYTES:
+ case IOCTL_NFP_GET_KILO_BYTES_PER_SECOND:
+ {
+ return TRUE;
+ }
+
+ case IOCTL_NFP_DISABLE:
+ case IOCTL_NFP_ENABLE:
+ {
+ return (pFileObject->IsPublication() || pFileObject->IsSubscription());
+ }
+
+ case IOCTL_NFP_SET_PAYLOAD:
+ case IOCTL_NFP_GET_NEXT_TRANSMITTED_MESSAGE:
+ {
+ return pFileObject->IsPublication();
+ }
+
+ case IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE:
+ {
+ return pFileObject->IsSubscription();
+ }
+
+ case IOCTL_NFCSE_GET_NFCC_CAPABILITIES:
+ case IOCTL_NFCSE_ENUM_ENDPOINTS:
+ {
+ return TRUE;
+ }
+
+ case IOCTL_NFCSE_GET_NEXT_EVENT:
+ case IOCTL_NFCSE_SUBSCRIBE_FOR_EVENT:
+ {
+ return pFileObject->IsSecureElementEvent();
+ }
+
+ case IOCTL_NFCSE_GET_ROUTING_TABLE:
+ case IOCTL_NFCSE_SET_ROUTING_TABLE:
+ case IOCTL_NFCSE_HCE_REMOTE_SEND:
+ case IOCTL_NFCSE_HCE_REMOTE_RECV:
+ case IOCTL_NFCSE_SET_CARD_EMULATION_MODE:
+ {
+ return pFileObject->IsSecureElementManager();
+ }
+
+ case IOCTL_SMARTCARD_EJECT:
+ case IOCTL_SMARTCARD_GET_LAST_ERROR:
+ case IOCTL_SMARTCARD_SET_ATTRIBUTE:
+ case IOCTL_SMARTCARD_SWALLOW:
+ case IOCTL_SMARTCARD_GET_ATTRIBUTE:
+ case IOCTL_SMARTCARD_GET_STATE:
+ case IOCTL_SMARTCARD_IS_ABSENT:
+ case IOCTL_SMARTCARD_IS_PRESENT:
+ case IOCTL_SMARTCARD_POWER:
+ case IOCTL_SMARTCARD_SET_PROTOCOL:
+ case IOCTL_SMARTCARD_TRANSMIT:
+ {
+ return pFileObject->IsSmartCardReader();
+ }
+
+ case IOCTL_NFCRM_SET_RADIO_STATE:
+ case IOCTL_NFCRM_QUERY_RADIO_STATE:
+ {
+ return pFileObject->IsRoleRadioManager();
+ }
+
+ case IOCTL_NFCSIM_BEGIN_PROXIMITY:
+ case IOCTL_NFCSIM_TRIGGER_SEEVENT:
+ {
+ return pFileObject->IsRoleSimulation();
+ }
+ }
+
+ return FALSE;
+}
+
+NTSTATUS
+CQueue::DispatchMessage(
+ _In_reads_(TableEntries) const DISPATCH_ENTRY rgDispatchTable[],
+ _In_ DWORD TableEntries,
+ _In_ WDFREQUEST Request,
+ _In_ ULONG IoControlCode,
+ _In_ size_t InputBufferLength,
+ _In_ size_t OutputBufferLength
+ )
+{
+ NTSTATUS Status = STATUS_NOT_SUPPORTED;
+ PVOID InputBuffer = nullptr;
+ PVOID OutputBuffer = nullptr;
+ CFileObject *pFileObject = GetFileObject(WdfRequestGetFileObject(Request));
+
+ for (DWORD TableEntry = 0; TableEntry < TableEntries; TableEntry++) {
+ if (rgDispatchTable[TableEntry].IoControlCode != IoControlCode)
+ continue;
+
+ if (InputBufferLength >= rgDispatchTable[TableEntry].MinInputBufferLength &&
+ OutputBufferLength >= rgDispatchTable[TableEntry].MinOutputBufferLength) {
+ if (InputBufferLength != 0) {
+ Status = WdfRequestRetrieveInputBuffer(Request, 0, &InputBuffer, nullptr);
+ NT_ASSERT(NT_SUCCESS(Status));
+ }
+
+ if (OutputBufferLength != 0) {
+ Status = WdfRequestRetrieveOutputBuffer(Request, 0, &OutputBuffer, nullptr);
+ NT_ASSERT(NT_SUCCESS(Status));
+ }
+
+ if (ValidateMessage(pFileObject, IoControlCode)) {
+ Status = (this->*rgDispatchTable[TableEntry].DispatchHandler)(
+ pFileObject,
+ Request,
+ InputBuffer,
+ InputBufferLength,
+ OutputBuffer,
+ OutputBufferLength);
+ }
+ else {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+CQueue::OnNfpEnable(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = pFileObject->Enable();
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpDisable(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = pFileObject->Disable();
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpSetPayload(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (InputBufferLength > MaxCbPayload) {
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto Exit;
+ }
+
+ Status = pFileObject->SetPayload((DWORD)InputBufferLength, (PBYTE)InputBuffer);
+
+ if (NT_SUCCESS(Status)) {
+ MESSAGE* pMessage = new MESSAGE();
+
+ if (pMessage != nullptr) {
+ pMessage->Initialize(pFileObject->GetType(), pFileObject->GetSize(), pFileObject->GetPayload());
+
+ EnterCriticalSection(&m_ConnectionLock);
+
+ for (LIST_ENTRY* pEntry = m_ConnectionList.Flink;
+ pEntry != &m_ConnectionList;
+ pEntry = pEntry->Flink) {
+ CConnection* pConnection = CConnection::FromListEntry(pEntry);
+
+ if (SUCCEEDED(pConnection->TransmitMessage(pMessage))) {
+ pFileObject->HandleMessageTransmitted();
+ }
+ }
+ LeaveCriticalSection(&m_ConnectionLock);
+
+ EnterCriticalSection(&m_PubsLock);
+ InsertHeadList(&m_PubsList, pFileObject->GetListEntry());
+ LeaveCriticalSection(&m_PubsLock);
+
+ delete pMessage;
+ }
+ else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpGetNextSubscribedMessage(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = pFileObject->GetNextSubscribedMessage(Request);
+ fCompleteRequest = !NT_SUCCESS(Status);
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpGetNextTransmittedMessage(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = pFileObject->GetNextTransmittedMessage(Request);
+ fCompleteRequest = !NT_SUCCESS(Status);
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpGetMaxMessageBytes(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ DWORD *pcbMaxPayload = (DWORD*)OutputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ //
+ // Since the output buffer has already been validated
+ // to contain 4 bytes, we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ *pcbMaxPayload = MaxCbPayload;
+ WdfRequestCompleteWithInformation(Request, Status, sizeof(DWORD));
+ fCompleteRequest = FALSE;
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpGetTransmissionRateKbps(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ DWORD *pdwKilobytesPerSecond = (DWORD*)OutputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ //
+ // Since the output buffer has already been validated
+ // to contain 4 bytes, we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ *pdwKilobytesPerSecond = KilobytesPerSecond;
+ WdfRequestCompleteWithInformation(Request, Status, sizeof(DWORD));
+ fCompleteRequest = FALSE;
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpBeginProximity(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BEGIN_PROXIMITY_ARGS *pArgs = (BEGIN_PROXIMITY_ARGS*)InputBuffer;
+
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ //
+ // Since the input buffer has already been validated
+ // for input buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(BEGIN_PROXIMITY_ARGS) <= InputBufferLength);
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = pFileObject->BeginProximity(pArgs, this);
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpSetRadioState(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNFCRM_SET_RADIO_STATE pRadioState = (PNFCRM_SET_RADIO_STATE)InputBuffer;
+ BOOLEAN NfpRadioState;
+ DECLARE_CONST_UNICODE_STRING(SCNamespace, SMARTCARD_READER_NAMESPACE);
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ _Analysis_assume_(sizeof(NFCRM_SET_RADIO_STATE) <= InputBufferLength);
+
+ EnterCriticalSection(&m_RadioLock);
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (pRadioState->SystemStateUpdate) {
+ m_NfpRadioOffSystemOverride = !pRadioState->MediaRadioOn;
+ }
+ else {
+ //
+ // Since the request is modifying the radio state independent of the
+ // system state, set the system state override to FALSE
+ //
+ m_NfpRadioOffSystemOverride = FALSE;
+ m_NfpRadioOffPolicyOverride = !pRadioState->MediaRadioOn;
+ }
+
+ NfpRadioState = !m_NfpRadioOffSystemOverride && !m_NfpRadioOffPolicyOverride;
+
+ if (NfpRadioState == m_NfpRadioState) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ if (NfpRadioState) {
+ if (!m_NfpInterfaceCreated) {
+ // Register for Proximity interface
+ Status = WdfDeviceCreateDeviceInterface(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_NFP,
+ nullptr);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreateDeviceInterface failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+ m_NfpInterfaceCreated = TRUE;
+ }
+
+ WdfDeviceSetDeviceInterfaceState(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_NFP,
+ nullptr,
+ TRUE);
+
+ if (!m_ScInterfaceCreated) {
+ // Register for Smart Card interface
+ Status = WdfDeviceCreateDeviceInterface(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_SMARTCARD_READER,
+ &SCNamespace);
+
+ if (!NT_SUCCESS(Status)) {
+ TraceInfo("WdfDeviceCreateDeviceInterface failed with Status %!STATUS!", Status);
+ goto Exit;
+ }
+
+ m_ScInterfaceCreated = TRUE;
+ }
+
+ WdfDeviceSetDeviceInterfaceState(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_SMARTCARD_READER,
+ &SCNamespace,
+ TRUE);
+ }
+ else {
+ if (m_NfpInterfaceCreated) {
+ WdfDeviceSetDeviceInterfaceState(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_NFP,
+ nullptr,
+ FALSE);
+ }
+
+ if (m_ScInterfaceCreated) {
+ WdfDeviceSetDeviceInterfaceState(
+ WdfIoQueueGetDevice(m_Queue),
+ (LPGUID) &GUID_DEVINTERFACE_SMARTCARD_READER,
+ &SCNamespace,
+ FALSE);
+ }
+ }
+
+ m_NfpRadioState = NfpRadioState;
+
+Exit:
+ WriteSettingsToRegistry();
+ LeaveCriticalSection(&m_RadioLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnNfpQueryRadioState(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ PNFCRM_RADIO_STATE pRadioState = (PNFCRM_RADIO_STATE)OutputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ _Analysis_assume_(sizeof(NFCRM_RADIO_STATE) <= OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ pRadioState->MediaRadioOn = IsNfpRadioEnabled();
+ WdfRequestCompleteWithInformation(Request, Status, sizeof(NFCRM_RADIO_STATE));
+ fCompleteRequest = FALSE;
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSEEnumEndpoints(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ SECURE_ELEMENT_ENDPOINT_INFO rgEndpointInfo[MaxSecureElements] = {};
+ SECURE_ELEMENT_ENDPOINT_LIST *pEndpointList = (SECURE_ELEMENT_ENDPOINT_LIST*)OutputBuffer;
+ DWORD cbOutputBuffer = 0;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+
+ //
+ // Since the output buffer has already been validated
+ // for output buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ pEndpointList->NumberOfEndpoints = 0;
+
+ for (LIST_ENTRY* pEntry = m_SecureElementList.Flink;
+ pEntry != &m_SecureElementList && pEndpointList->NumberOfEndpoints < _countof(rgEndpointInfo);
+ pEntry = pEntry->Flink) {
+ SECURE_ELEMENT_ENDPOINT_INFO Info;
+
+ Info.guidSecureElementId = CSecureElement::FromListEntry(pEntry)->GetIdentifier();
+ Info.eSecureElementType = CSecureElement::FromListEntry(pEntry)->GetType();
+
+ rgEndpointInfo[pEndpointList->NumberOfEndpoints++] = Info;
+ }
+
+ cbOutputBuffer = sizeof(DWORD);
+
+ if ((cbOutputBuffer + (pEndpointList->NumberOfEndpoints * sizeof(SECURE_ELEMENT_ENDPOINT_INFO))) <= OutputBufferLength) {
+ RtlCopyMemory(pEndpointList->EndpointList, rgEndpointInfo, pEndpointList->NumberOfEndpoints * sizeof(SECURE_ELEMENT_ENDPOINT_INFO));
+ cbOutputBuffer += (pEndpointList->NumberOfEndpoints * sizeof(SECURE_ELEMENT_ENDPOINT_INFO));
+ }
+ else {
+ // Returning this signals to the client to send a bigger buffer
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ WdfRequestCompleteWithInformation(Request, Status, cbOutputBuffer);
+ fCompleteRequest = FALSE;
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSESubscribeForEvent(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ SECURE_ELEMENT_EVENT_SUBSCRIPTION_INFO *pInfo = (SECURE_ELEMENT_EVENT_SUBSCRIPTION_INFO*)InputBuffer;
+ CSecureElement *pSecureElement = nullptr;
+
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ //
+ // Since the input buffer has already been validated
+ // for input buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(SECURE_ELEMENT_EVENT_SUBSCRIPTION_INFO) <= InputBufferLength);
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (IsEqualGUID(pInfo->guidSecureElementId, GUID_NULL) ||
+ NT_SUCCESS(Status = GetSecureElementObject(pInfo->guidSecureElementId, &pSecureElement))) {
+ Status = pFileObject->SubscribeForEvent(pInfo->guidSecureElementId, pInfo->eEventType);
+
+ if (NT_SUCCESS(Status)) {
+ EnterCriticalSection(&m_SEEventsLock);
+ InsertHeadList(&m_SEEventsList, pFileObject->GetListEntry());
+ LeaveCriticalSection(&m_SEEventsLock);
+ }
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSEGetNextEvent(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = pFileObject->GetNextSecureElementPayload(Request);
+ fCompleteRequest = !NT_SUCCESS(Status);
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSESetCardEmulationMode(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ SECURE_ELEMENT_SET_CARD_EMULATION_MODE_INFO *pMode = (SECURE_ELEMENT_SET_CARD_EMULATION_MODE_INFO*)InputBuffer;
+ CSecureElement *pSecureElement = nullptr;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ //
+ // Since the input buffer has already been validated
+ // for input buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(SECURE_ELEMENT_SET_CARD_EMULATION_MODE_INFO) <= InputBufferLength);
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = GetSecureElementObject(pMode->guidSecureElementId, &pSecureElement);
+
+ if (NT_SUCCESS(Status)) {
+ Status = pSecureElement->SetEmulationMode(pMode->eMode);
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSETriggerEvent(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ SECURE_ELEMENT_EVENT_INFO *pInfo = (SECURE_ELEMENT_EVENT_INFO*)InputBuffer;
+ CSecureElement *pSecureElement = nullptr;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ //
+ // Since the input buffer has already been validated
+ // for input buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(SECURE_ELEMENT_EVENT_INFO_HEADER <= InputBufferLength);
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (pInfo->guidSecureElementId == GUID_NULL) {
+ for (LIST_ENTRY* pEntry = m_SecureElementList.Flink;
+ pEntry != &m_SecureElementList;
+ pEntry = pEntry->Flink) {
+ pInfo->guidSecureElementId = CSecureElement::FromListEntry(pEntry)->GetIdentifier();
+ HandleSecureElementEvent(pInfo);
+ }
+ }
+ else {
+ Status = GetSecureElementObject(pInfo->guidSecureElementId, &pSecureElement);
+
+ if (NT_SUCCESS(Status)) {
+ HandleSecureElementEvent(pInfo);
+ }
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSEGetNfccCapabilities(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ PSECURE_ELEMENT_NFCC_CAPABILITIES pCapabilities = (PSECURE_ELEMENT_NFCC_CAPABILITIES)OutputBuffer;
+ BOOL fCompleteRequest = TRUE;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ //
+ // Since the input buffer has already been validated
+ // for input buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(SECURE_ELEMENT_NFCC_CAPABILITIES) <= OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ pCapabilities->cbMaxRoutingTableSize = m_RoutingTable.MaxRoutingTableSize();
+ pCapabilities->IsAidRoutingSupported = m_RoutingTable.IsAidRoutingSupported();
+ pCapabilities->IsProtocolRoutingSupported = m_RoutingTable.IsProtocolRoutingSupported();
+ pCapabilities->IsTechRoutingSupported = m_RoutingTable.IsTechRoutingSupported();
+
+ WdfRequestCompleteWithInformation(Request, Status, sizeof(SECURE_ELEMENT_NFCC_CAPABILITIES));
+ fCompleteRequest = FALSE;
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSESetRoutingTable(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable = (PSECURE_ELEMENT_ROUTING_TABLE)InputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ //
+ // Since the input buffer has already been validated
+ // for input buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(SECURE_ELEMENT_ROUTING_TABLE) <= InputBufferLength);
+
+ if (pRoutingTable->NumberOfEntries == 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if ((sizeof(SECURE_ELEMENT_ROUTING_TABLE) + (pRoutingTable->NumberOfEntries - 1) * sizeof(SECURE_ELEMENT_ROUTING_TABLE_ENTRY)) < InputBufferLength) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = m_RoutingTable.SetRoutingTable(pRoutingTable);
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSEGetRoutingTable(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ DWORD cbOutputBuffer = 0;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBuffer);
+
+ //
+ // Since the output buffer has already been validated
+ // for output buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = m_RoutingTable.GetRoutingTable(OutputBuffer, OutputBufferLength, &cbOutputBuffer);
+ WdfRequestCompleteWithInformation(Request, Status, cbOutputBuffer);
+ fCompleteRequest = FALSE;
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSEHCERemoteRecv(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ GUID guidSecureElementId;
+ BOOL fCompleteRequest = TRUE;
+
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (!NT_SUCCESS(GetSecureElementId(DeviceHost, &guidSecureElementId))) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto Exit;
+ }
+
+ Status = pFileObject->GetNextSecureElementPayload(Request);
+ fCompleteRequest = !NT_SUCCESS(Status);
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSEHCERemoteSend(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ GUID guidSecureElementId;
+ MESSAGE* pMessage = nullptr;
+ PSECURE_ELEMENT_HCE_DATA_PACKET pDataPacket = (PSECURE_ELEMENT_HCE_DATA_PACKET)InputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ //
+ // Since the input buffer has already been validated
+ // for input buffer length so we know we can safely make this assumption
+ //
+ _Analysis_assume_(2 * sizeof(USHORT) + 2 <= InputBufferLength);
+
+ EnterCriticalSection(&m_pHCEConnectionLock);
+
+ if (OutputBufferLength != 0 ||
+ pDataPacket->bConnectionId != m_HCEConnectionId) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (pDataPacket->cbPayload > MaxCbPayload) {
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto Exit;
+ }
+
+ if (!NT_SUCCESS(GetSecureElementId(DeviceHost, &guidSecureElementId))) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto Exit;
+ }
+
+ if (m_pHCEConnection == nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ pMessage = new MESSAGE();
+
+ if (pMessage == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ pMessage->Initialize(HCE_MESSAGE_TYPE_TRANSMIT, pDataPacket->cbPayload, pDataPacket->pbPayload);
+
+ if (FAILED(m_pHCEConnection->TransmitMessage(pMessage))) {
+ Status = STATUS_DATA_ERROR;
+ goto Exit;
+ }
+
+Exit:
+ SAFE_DELETE(pMessage);
+ LeaveCriticalSection(&m_pHCEConnectionLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCGetLastError(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ DWORD *pdwError = (DWORD*)OutputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ *pdwError = STATUS_SUCCESS;
+ WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, sizeof(DWORD));
+
+ MethodReturn(STATUS_PENDING, "Status = %!STATUS!", STATUS_SUCCESS);
+}
+
+NTSTATUS
+CQueue::OnSCGetAttribute(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ DWORD *pdwAttributeId = (DWORD*)InputBuffer;
+ DWORD cbOutputBuffer = (DWORD)OutputBufferLength;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+
+ _Analysis_assume_(sizeof(DWORD) <= InputBufferLength);
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ Status = m_SmartCardReader.GetAttribute(*pdwAttributeId, (PBYTE)OutputBuffer, &cbOutputBuffer);
+
+ if (NT_SUCCESS(Status)) {
+ WdfRequestCompleteWithInformation(Request, Status, cbOutputBuffer);
+ fCompleteRequest = FALSE;
+ }
+
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCSetAttribute(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ DWORD *pdwAttributeId = (DWORD*)InputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ _Analysis_assume_(sizeof(DWORD) <= InputBufferLength);
+
+ Status = m_SmartCardReader.SetAttribute(*pdwAttributeId);
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCGetState(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ DWORD *pdwState = (DWORD*)OutputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ *pdwState = m_SmartCardReader.GetState();
+ WdfRequestCompleteWithInformation(Request, Status, sizeof(DWORD));
+
+ MethodReturn(STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCIsAbsent(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = m_SmartCardReader.IsAbsent(Request);
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCIsPresent(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBuffer);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+
+ if (InputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (OutputBufferLength != 0) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Status = m_SmartCardReader.IsPresent(Request);
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCPower(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ DWORD *pdwPower = (DWORD*)InputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(Request);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBuffer);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ _Analysis_assume_(sizeof(DWORD) <= InputBufferLength);
+
+ Status = m_SmartCardReader.SetPower(*pdwPower);
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCSetProtocol(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ DWORD *pdwProtocol = (DWORD*)InputBuffer;
+ DWORD *pdwSelectedProtocol = (DWORD*)OutputBuffer;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ _Analysis_assume_(sizeof(DWORD) <= InputBufferLength);
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ Status = m_SmartCardReader.SetProtocol(*pdwProtocol, pdwSelectedProtocol);
+
+ if (NT_SUCCESS(Status)) {
+ WdfRequestCompleteWithInformation(Request, Status, sizeof(DWORD));
+ fCompleteRequest = FALSE;
+ }
+
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CQueue::OnSCTransmit(
+ _In_ CFileObject* pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOL fCompleteRequest = TRUE;
+ size_t BytesTransferred = 0;
+
+ UNREFERENCED_PARAMETER(pFileObject);
+
+ //
+ // Since the input and buffer buffer length has already been validated
+ // for input buffer length we need to have atleast one byte to transfer (discarding the header)
+ // for output buffer length we should atleast be able to store status codes SW1+SW2
+ //
+ _Analysis_assume_(sizeof(SCARD_IO_REQUEST)+1 <= InputBufferLength);
+ _Analysis_assume_(sizeof(SCARD_IO_REQUEST)+2 <= OutputBufferLength);
+
+ Status = m_SmartCardReader.Transmit((PBYTE)InputBuffer, InputBufferLength, (PBYTE)OutputBuffer, OutputBufferLength, &BytesTransferred);
+
+ if (NT_SUCCESS(Status)) {
+ WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, BytesTransferred);
+ fCompleteRequest = FALSE;
+ }
+
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+void CQueue::ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket)
+{
+ MethodEntry("...");
+
+ CConnection* pConnection;
+
+ if (CConnection::Create(this, &pConnection)) {
+ // Mark it as an inbound connection, so we know to delete it when it's removed from the list
+ pConnection->SetInboundConnection();
+ pConnection->ValidateAccept(Socket, pMagicPacket);
+
+ Socket = INVALID_SOCKET;
+ }
+
+ if (Socket != INVALID_SOCKET) {
+ closesocket(Socket);
+ }
+
+ MethodReturnVoid();
+}
+
+void CQueue::ConnectionEstablished(_In_ CConnection* pConnection)
+{
+ MethodEntry("...");
+
+ if (pConnection->GetConnectionType() == CONNECTION_TYPE_P2P) {
+ EnterCriticalSection(&m_ConnectionLock);
+
+ if (IsListEmpty(&m_ConnectionList)) {
+ HandleArrivalEvent();
+ }
+
+ InsertHeadList(&m_ConnectionList, pConnection->GetListEntry());
+ LeaveCriticalSection(&m_ConnectionLock);
+
+ MESSAGE* pMessage = new MESSAGE();
+
+ if (pMessage != nullptr) {
+ EnterCriticalSection(&m_PubsLock);
+
+ for (LIST_ENTRY* pEntry = m_PubsList.Flink;
+ pEntry != &m_PubsList;
+ pEntry = pEntry->Flink) {
+ CFileObject* pPub = CFileObject::FromListEntry(pEntry);
+
+ if (pPub->IsEnabled()) {
+ pMessage->Initialize(pPub->GetType(), pPub->GetSize(), pPub->GetPayload());
+
+ if (SUCCEEDED(pConnection->TransmitMessage(pMessage))) {
+ pPub->HandleMessageTransmitted();
+ }
+ }
+ }
+ LeaveCriticalSection(&m_PubsLock);
+
+ delete pMessage;
+ }
+ }
+ else if (pConnection->GetConnectionType() == CONNECTION_TYPE_TAG) {
+ m_SmartCardReader.CardArrived(pConnection);
+ }
+ else if (pConnection->GetConnectionType() == CONNECTION_TYPE_HCE) {
+ SECURE_ELEMENT_EVENT_INFO_AND_PAYLOAD(sizeof(SECURE_ELEMENT_HCE_ACTIVATION_PAYLOAD)) EventInfo;
+
+ if (NT_SUCCESS(GetSecureElementId(DeviceHost, &EventInfo.Info.guidSecureElementId))) {
+ EnterCriticalSection(&m_pHCEConnectionLock);
+
+ if (m_pHCEConnection == nullptr) {
+ PSECURE_ELEMENT_HCE_ACTIVATION_PAYLOAD pbEventPayload = NULL;
+
+ m_pHCEConnection = pConnection;
+ m_HCEConnectionId++;
+
+ EventInfo.Info.eEventType = HceActivated;
+ EventInfo.Info.cbEventData = sizeof(SECURE_ELEMENT_HCE_ACTIVATION_PAYLOAD);
+
+ pbEventPayload = (PSECURE_ELEMENT_HCE_ACTIVATION_PAYLOAD)EventInfo.Info.pbEventData;
+
+ pbEventPayload->bConnectionId = m_HCEConnectionId;
+ pbEventPayload->eRfTechType = NFC_RF_TECHNOLOGY_A;
+ pbEventPayload->eRfProtocolType = PROTOCOL_ISO_DEP;
+
+ HandleSecureElementEvent(&EventInfo.Info);
+ }
+
+ LeaveCriticalSection(&m_pHCEConnectionLock);
+ }
+ }
+
+ MethodReturnVoid();
+}
+
+BOOL CQueue::ConnectionTerminated(_In_ CConnection* pConnection)
+{
+ MethodEntry("pConnection = 0x%p", pConnection);
+
+ BOOL fConnectionDeleted = FALSE;
+
+ if (pConnection->GetConnectionType() == CONNECTION_TYPE_P2P) {
+ LIST_ENTRY* pRemoveListEntry = pConnection->GetListEntry();
+
+ EnterCriticalSection(&m_ConnectionLock);
+
+ for (LIST_ENTRY* pEntry = m_ConnectionList.Flink;
+ pEntry != &m_ConnectionList;
+ pEntry = pEntry->Flink) {
+ if (pEntry == pRemoveListEntry) {
+ RemoveEntryList(pEntry);
+ break;
+ }
+ }
+
+ if (IsListEmpty(&m_ConnectionList)) {
+ HandleRemovalEvent();
+ }
+ LeaveCriticalSection(&m_ConnectionLock);
+
+ if (pConnection->IsInboundConnection()) {
+ delete pConnection;
+ fConnectionDeleted = TRUE;
+ }
+ }
+ else if (pConnection->GetConnectionType() == CONNECTION_TYPE_TAG) {
+ fConnectionDeleted = m_SmartCardReader.CardRemoved(pConnection);
+ }
+ else if (pConnection->GetConnectionType() == CONNECTION_TYPE_HCE) {
+ SECURE_ELEMENT_EVENT_INFO_AND_PAYLOAD(sizeof(USHORT)) EventInfo;
+
+ if (NT_SUCCESS(GetSecureElementId(DeviceHost, &EventInfo.Info.guidSecureElementId))) {
+ EnterCriticalSection(&m_pHCEConnectionLock);
+
+ if (m_pHCEConnection != nullptr) {
+ m_pHCEConnection = nullptr;
+
+ EventInfo.Info.eEventType = HceDeactivated;
+ EventInfo.Info.cbEventData = sizeof(USHORT);
+
+ *((USHORT*)EventInfo.Info.pbEventData) = m_HCEConnectionId;
+
+ HandleSecureElementEvent(&EventInfo.Info);
+ }
+ LeaveCriticalSection(&m_pHCEConnectionLock);
+ }
+ }
+
+ MethodReturnBool(fConnectionDeleted);
+}
+
+void CQueue::HandleArrivalEvent()
+{
+ MethodEntry("void");
+
+ EnterCriticalSection(&m_SubsLock);
+
+ for (LIST_ENTRY* pEntry = m_ArrivalSubsList.Flink;
+ pEntry != &m_ArrivalSubsList;
+ pEntry = pEntry->Flink) {
+ CFileObject::FromListEntry(pEntry)->HandleArrivalEvent();
+ }
+ LeaveCriticalSection(&m_SubsLock);
+
+ MethodReturnVoid();
+}
+
+void CQueue::HandleRemovalEvent()
+{
+ MethodEntry("void");
+
+ EnterCriticalSection(&m_SubsLock);
+
+ for (LIST_ENTRY* pEntry = m_DepartureSubsList.Flink;
+ pEntry != &m_DepartureSubsList;
+ pEntry = pEntry->Flink) {
+ CFileObject::FromListEntry(pEntry)->HandleRemovalEvent();
+ }
+ LeaveCriticalSection(&m_SubsLock);
+
+ MethodReturnVoid();
+}
+
+void CQueue::HandleReceivedMessage(_In_ CONNECTION_TYPE ConnType, _In_ MESSAGE* pMessage)
+{
+ MethodEntry("pMessage->m_szType = '%S'", pMessage->m_szType);
+
+ if (ConnType == CONNECTION_TYPE_P2P) {
+ if ((pMessage->m_cbPayload > 0) && (pMessage->m_cbPayload <= MaxCbPayload)) {
+ EnterCriticalSection(&m_SubsLock);
+
+ for (LIST_ENTRY* pEntry = m_SubsList.Flink; pEntry != &m_SubsList; pEntry = pEntry->Flink) {
+ CFileObject* pSub = CFileObject::FromListEntry(pEntry);
+ pSub->HandleReceivedMessage(pMessage->m_szType, pMessage->m_cbPayload, pMessage->m_Payload);
+ }
+ LeaveCriticalSection(&m_SubsLock);
+ }
+ }
+ else if (ConnType == CONNECTION_TYPE_TAG) {
+ m_SmartCardReader.MessageReceived(pMessage);
+ }
+ else if (ConnType == CONNECTION_TYPE_HCE) {
+ EnterCriticalSection(&m_SEManagerLock);
+
+ if (m_pSEManager != nullptr) {
+ m_pSEManager->HandleReceiveHcePacket((USHORT)m_HCEConnectionId, pMessage->m_cbPayload, pMessage->m_Payload);
+ }
+ LeaveCriticalSection(&m_SEManagerLock);
+ }
+
+ MethodReturnVoid();
+}
+
+void CQueue::HandleSecureElementEvent(SECURE_ELEMENT_EVENT_INFO *pInfo)
+{
+ MethodEntry("...");
+
+ CSecureElement *pSecureElement = nullptr;
+
+ if (NT_SUCCESS(GetSecureElementObject(pInfo->guidSecureElementId, &pSecureElement))) {
+ if (pSecureElement->GetEmulationMode() != EmulationOff) {
+ EnterCriticalSection(&m_SEEventsLock);
+
+ for (LIST_ENTRY* pEntry = m_SEEventsList.Flink;
+ pEntry != &m_SEEventsList;
+ pEntry = pEntry->Flink) {
+ CFileObject::FromListEntry(pEntry)->HandleSecureElementEvent(pInfo);
+ }
+ LeaveCriticalSection(&m_SEEventsLock);
+ }
+ }
+
+ MethodReturnVoid();
+}
+
+void CQueue::EnumerateSecureElements()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFKEY KeyHandle = nullptr;
+ WDFCOLLECTION Collection = nullptr;
+ GUID SecureElementId;
+ UNICODE_STRING GuidString;
+ CSecureElement *pSecureElement = nullptr;
+
+ DECLARE_CONST_UNICODE_STRING(SEEndpointsKey, SE_ENDPOINTS_KEY);
+
+ Status = WdfDeviceOpenRegistryKey(
+ WdfIoQueueGetDevice(m_Queue),
+ PLUGPLAY_REGKEY_DEVICE,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &KeyHandle);
+
+ if (NT_SUCCESS(Status) && (KeyHandle != nullptr)) {
+ Status = WdfCollectionCreate(WDF_NO_OBJECT_ATTRIBUTES, &Collection);
+
+ if (NT_SUCCESS(Status) && (Collection != nullptr)) {
+ Status = WdfRegistryQueryMultiString(
+ KeyHandle,
+ &SEEndpointsKey,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ Collection);
+
+ if (NT_SUCCESS(Status)) {
+ ULONG Count = WdfCollectionGetCount(Collection);
+
+ for (ULONG Index = 0; Index < Count; Index++) {
+ WdfStringGetUnicodeString((WDFSTRING) WdfCollectionGetItem(Collection, Index), &GuidString);
+
+ if (SUCCEEDED(CLSIDFromString(GuidString.Buffer, &SecureElementId)) &&
+ (pSecureElement = new CSecureElement(SecureElementId, IsEqualGUID(SecureElementId, GUID_DH_SECURE_ELEMENT) ? DeviceHost : External)) != nullptr) {
+ TraceInfo("Secure Element Id=%S Type=%d", GuidString.Buffer, pSecureElement->GetType());
+ InsertHeadList(&m_SecureElementList, pSecureElement->GetListEntry());
+ }
+ }
+ }
+
+ WdfObjectDelete(Collection);
+ }
+
+ WdfRegistryClose(KeyHandle);
+ }
+
+ MethodReturnVoid();
+}
+
+void CQueue::ReadSettingsFromRegistry()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFKEY KeyHandle = nullptr;
+ ULONG NfpRadioOffPolicyOverride = 0, NfpRadioOffSystemOverride = 0;
+
+ DECLARE_CONST_UNICODE_STRING(NfpRadioTurnedOffKey, NFP_RADIO_TURNED_OFF_KEY);
+ DECLARE_CONST_UNICODE_STRING(NfpRadioFlightModeKey, NFP_RADIO_FLIGHT_MODE_KEY);
+
+ Status = WdfDeviceOpenRegistryKey(
+ WdfIoQueueGetDevice(m_Queue),
+ PLUGPLAY_REGKEY_DEVICE | WDF_REGKEY_DEVICE_SUBKEY,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &KeyHandle);
+
+ if (NT_SUCCESS(Status) && (KeyHandle != nullptr)) {
+ Status = WdfRegistryQueryULong(
+ KeyHandle,
+ &NfpRadioTurnedOffKey,
+ &NfpRadioOffPolicyOverride);
+
+ if (NT_SUCCESS(Status)) {
+ TraceInfo("%S = %d", NFP_RADIO_TURNED_OFF_KEY, NfpRadioOffPolicyOverride);
+ m_NfpRadioOffPolicyOverride = (NfpRadioOffPolicyOverride != 0);
+ }
+
+ Status = WdfRegistryQueryULong(
+ KeyHandle,
+ &NfpRadioFlightModeKey,
+ &NfpRadioOffSystemOverride);
+
+ if (NT_SUCCESS(Status)) {
+ TraceInfo("%S = %d", NFP_RADIO_FLIGHT_MODE_KEY, NfpRadioOffSystemOverride);
+ m_NfpRadioOffSystemOverride = (NfpRadioOffSystemOverride != 0);
+ }
+
+ m_NfpRadioState = !m_NfpRadioOffPolicyOverride && !m_NfpRadioOffSystemOverride;
+
+ WdfRegistryClose(KeyHandle);
+ }
+
+ MethodReturnVoid();
+}
+
+void CQueue::WriteSettingsToRegistry()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFKEY KeyHandle = nullptr;
+
+ DECLARE_CONST_UNICODE_STRING(NfpRadioTurnedOffKey, NFP_RADIO_TURNED_OFF_KEY);
+ DECLARE_CONST_UNICODE_STRING(NfpRadioFlightModeKey, NFP_RADIO_FLIGHT_MODE_KEY);
+
+ Status = WdfDeviceOpenRegistryKey(
+ WdfIoQueueGetDevice(m_Queue),
+ PLUGPLAY_REGKEY_DEVICE | WDF_REGKEY_DEVICE_SUBKEY,
+ GENERIC_ALL & ~(GENERIC_WRITE | KEY_CREATE_SUB_KEY | WRITE_DAC),
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &KeyHandle);
+
+ if (NT_SUCCESS(Status) && (KeyHandle != nullptr)) {
+ Status = WdfRegistryAssignULong(
+ KeyHandle,
+ &NfpRadioTurnedOffKey,
+ m_NfpRadioOffPolicyOverride);
+
+ if (NT_SUCCESS(Status)) {
+ TraceInfo("%S = %d successfully persisted", NFP_RADIO_TURNED_OFF_KEY, m_NfpRadioOffPolicyOverride);
+ }
+
+ Status = WdfRegistryAssignULong(
+ KeyHandle,
+ &NfpRadioFlightModeKey,
+ m_NfpRadioOffSystemOverride);
+
+ if (NT_SUCCESS(Status)) {
+ TraceInfo("%S = %d successfully persisted", NFP_RADIO_FLIGHT_MODE_KEY, m_NfpRadioOffSystemOverride);
+ }
+
+ WdfRegistryClose(KeyHandle);
+ }
+
+ MethodReturnVoid();
+}
+
+NTSTATUS CQueue::GetSecureElementObject(GUID &SecureElementId, CSecureElement **ppSecureElement)
+{
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ for (LIST_ENTRY* pEntry = m_SecureElementList.Flink;
+ pEntry != &m_SecureElementList;
+ pEntry = pEntry->Flink) {
+ if (SecureElementId == CSecureElement::FromListEntry(pEntry)->GetIdentifier()) {
+ *ppSecureElement = CSecureElement::FromListEntry(pEntry);
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS CQueue::GetSecureElementId(SECURE_ELEMENT_TYPE eType, GUID *pSecureElementId)
+{
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ *pSecureElementId = GUID_NULL;
+
+ for (LIST_ENTRY* pEntry = m_SecureElementList.Flink;
+ (pEntry != &m_SecureElementList);
+ pEntry = pEntry->Flink) {
+ if (CSecureElement::FromListEntry(pEntry)->GetType() == eType) {
+ *pSecureElementId = CSecureElement::FromListEntry(pEntry)->GetIdentifier();
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ return Status;
+}
+
diff --git a/nfc/Simulator/Src/Queue.h b/nfc/Simulator/Src/Queue.h
new file mode 100644
index 00000000..40ac6982
--- /dev/null
+++ b/nfc/Simulator/Src/Queue.h
@@ -0,0 +1,217 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file defines the queue callback interface.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+Revision History:
+
+--*/
+
+#pragma once
+
+static const int KilobytesPerSecond = 20;
+static const int MinCbPayload = 1;
+static const int MaxCbPayload = 10240;
+static const int MaxCchType = 507; // maximum message type length is 5 for "?ubs\\", 250 for protocol + 250 for subtype + 1 each for dot "." and nullptr terminator.
+static const int MaxCchTypeNetwork = 502; // maximum message type length over the network is 250 for protocol + 250 for subtype + 1 each for dot "." and nullptr terminator.
+static const int MinCchType = 2;
+static const int MaxCchMimeType = 256;
+static const int MaxSecureElements = 16;
+
+#define SIM_NAMESPACE L"Simulator"
+#define SIM_NAMESPACE_CHARS ARRAYSIZE(SIM_NAMESPACE) - 1
+
+#define NFP_RADIO_TURNED_OFF_KEY L"NfpRadioTurnedOff"
+#define NFP_RADIO_FLIGHT_MODE_KEY L"NfpRadioFlightMode"
+
+#define SE_ENDPOINTS_KEY L"SEEndpoints"
+#define HCE_MESSAGE_TYPE_TRANSMIT L"HCETransmit"
+
+struct MESSAGE
+{
+ MESSAGE() : m_cbPayload(0)
+ {
+ RtlZeroMemory(m_szType, sizeof(m_szType));
+ RtlZeroMemory(m_Payload, sizeof(m_Payload));
+ }
+
+ void Initialize(
+ _In_ PCWSTR szType,
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+ {
+ RtlZeroMemory(m_szType, sizeof(m_szType));
+ RtlZeroMemory(m_Payload, sizeof(m_Payload));
+
+ m_cbPayload = cbPayload;
+ StringCchCopy(m_szType, _countof(m_szType), szType);
+ RtlCopyMemory(m_Payload, pbPayload, cbPayload);
+ }
+
+ wchar_t m_szType[MaxCchTypeNetwork];
+ DWORD m_cbPayload;
+ BYTE m_Payload[MaxCbPayload];
+};
+
+class CQueue
+ : public IValidateAccept,
+ public IConnectionCallback
+{
+public:
+ CQueue(WDFQUEUE Queue);
+ ~CQueue();
+
+public:
+ static EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL OnIoDeviceControl;
+
+ NTSTATUS Initialize();
+ NTSTATUS Deinitialize();
+
+ BOOLEAN IsNfpRadioEnabled();
+ BOOLEAN IsSERadioEnabled();
+
+ void OnFileCreate(_In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ WDFFILEOBJECT FileObject);
+ void OnFileClose(_In_ WDFFILEOBJECT FileObject);
+
+ void OnIoDeviceControl(_In_ WDFREQUEST Request, _In_ ULONG IoControlCode, _In_ size_t InputBufferLength, _In_ size_t OutputBufferLength);
+
+public:
+ //IValidateAccept
+ void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket);
+
+ //IConnectionCallback
+ virtual void HandleReceivedMessage(_In_ CONNECTION_TYPE ConnType, _In_ MESSAGE* pMessageData);
+ virtual void ConnectionEstablished(_In_ CConnection* pConnection);
+ virtual BOOL ConnectionTerminated(_In_ CConnection* pConnection);
+
+public:
+ CSmartCardReader* GetSmartCardReader() { return &m_SmartCardReader; }
+ NTSTATUS GetSecureElementId(SECURE_ELEMENT_TYPE eType, GUID *pSecureElementId);
+
+private:
+ NTSTATUS DetectRole(CFileObject *pFileObject, PCWSTR pszFileName);
+ void HandleArrivalEvent();
+ void HandleRemovalEvent();
+ void HandleSecureElementEvent(SECURE_ELEMENT_EVENT_INFO *pInfo);
+ void EnumerateSecureElements();
+ void ReadSettingsFromRegistry();
+ void WriteSettingsToRegistry();
+ NTSTATUS GetSecureElementObject(GUID &SecureElementId, CSecureElement **ppSecureElement);
+
+private:
+ typedef NTSTATUS (CQueue::EVT_DISPATCH_HANDLER)(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength);
+
+ typedef NTSTATUS (CQueue::*PFN_DISPATCH_HANDLER)(
+ _In_ CFileObject *pFileObject,
+ _In_ WDFREQUEST Request,
+ _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength);
+
+private:
+ // Proximity DDI
+ EVT_DISPATCH_HANDLER OnNfpEnable;
+ EVT_DISPATCH_HANDLER OnNfpDisable;
+ EVT_DISPATCH_HANDLER OnNfpSetPayload;
+ EVT_DISPATCH_HANDLER OnNfpGetNextSubscribedMessage;
+ EVT_DISPATCH_HANDLER OnNfpGetNextTransmittedMessage;
+ EVT_DISPATCH_HANDLER OnNfpGetMaxMessageBytes;
+ EVT_DISPATCH_HANDLER OnNfpGetTransmissionRateKbps;
+ EVT_DISPATCH_HANDLER OnNfpBeginProximity;
+ EVT_DISPATCH_HANDLER OnNfpSetRadioState;
+ EVT_DISPATCH_HANDLER OnNfpQueryRadioState;
+
+ // Secure Element DDI
+ EVT_DISPATCH_HANDLER OnSEEnumEndpoints;
+ EVT_DISPATCH_HANDLER OnSESubscribeForEvent;
+ EVT_DISPATCH_HANDLER OnSEGetNextEvent;
+ EVT_DISPATCH_HANDLER OnSESetCardEmulationMode;
+ EVT_DISPATCH_HANDLER OnSETriggerEvent;
+ EVT_DISPATCH_HANDLER OnSEGetNfccCapabilities;
+ EVT_DISPATCH_HANDLER OnSESetRoutingTable;
+ EVT_DISPATCH_HANDLER OnSEGetRoutingTable;
+ EVT_DISPATCH_HANDLER OnSEHCERemoteRecv;
+ EVT_DISPATCH_HANDLER OnSEHCERemoteSend;
+
+ // Smart Card DDI
+ EVT_DISPATCH_HANDLER OnSCGetAttribute;
+ EVT_DISPATCH_HANDLER OnSCSetAttribute;
+ EVT_DISPATCH_HANDLER OnSCGetState;
+ EVT_DISPATCH_HANDLER OnSCIsAbsent;
+ EVT_DISPATCH_HANDLER OnSCIsPresent;
+ EVT_DISPATCH_HANDLER OnSCPower;
+ EVT_DISPATCH_HANDLER OnSCSetProtocol;
+ EVT_DISPATCH_HANDLER OnSCTransmit;
+ EVT_DISPATCH_HANDLER OnSCGetLastError;
+
+private:
+ typedef struct _DISPATCH_ENTRY
+ {
+ ULONG IoControlCode;
+ size_t MinInputBufferLength;
+ size_t MinOutputBufferLength;
+ PFN_DISPATCH_HANDLER DispatchHandler;
+ }
+ DISPATCH_ENTRY, *PDISPATCH_ENTRY;
+
+ NTSTATUS DispatchMessage(
+ _In_reads_(TableEntries) const DISPATCH_ENTRY rgDispatchTable[],
+ _In_ DWORD TableEntries,
+ _In_ WDFREQUEST Request,
+ _In_ ULONG IoControlCode,
+ _In_ size_t InputBufferLength,
+ _In_ size_t OutputBufferLength);
+
+ BOOL ValidateMessage(_In_ CFileObject *pFileObject, _In_ ULONG IoControlCode);
+
+ WDFQUEUE m_Queue;
+ LIST_ENTRY m_SubsList;
+ LIST_ENTRY m_ArrivalSubsList;
+ LIST_ENTRY m_DepartureSubsList;
+ CRITICAL_SECTION m_SubsLock;
+ LIST_ENTRY m_PubsList;
+ CRITICAL_SECTION m_PubsLock;
+ LIST_ENTRY m_ConnectionList;
+ CRITICAL_SECTION m_ConnectionLock;
+ CSocketListener m_SocketListener;
+ LIST_ENTRY m_SecureElementList;
+ LIST_ENTRY m_SEEventsList;
+ CRITICAL_SECTION m_SEEventsLock;
+ CFileObject* m_pSEManager;
+ CRITICAL_SECTION m_SEManagerLock;
+ CSmartCardReader m_SmartCardReader;
+ CRITICAL_SECTION m_pHCEConnectionLock;
+ CConnection* m_pHCEConnection;
+ USHORT m_HCEConnectionId;
+ CRITICAL_SECTION m_RadioLock;
+ BOOLEAN m_NfpRadioState;
+ BOOLEAN m_NfpRadioOffPolicyOverride;
+ BOOLEAN m_NfpRadioOffSystemOverride;
+ BOOLEAN m_SERadioState;
+ BOOLEAN m_NfpInterfaceCreated;
+ BOOLEAN m_ScInterfaceCreated;
+ BOOLEAN m_SEInterfaceCreated;
+ CRoutingTable m_RoutingTable;
+};
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CQueue, GetQueueObject);
+
diff --git a/nfc/Simulator/Src/RoutingTable.cpp b/nfc/Simulator/Src/RoutingTable.cpp
new file mode 100644
index 00000000..5a15796a
--- /dev/null
+++ b/nfc/Simulator/Src/RoutingTable.cpp
@@ -0,0 +1,388 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ routingtable.cpp
+
+Abstract:
+
+ Implements the NFC routing table class
+
+Environment:
+
+ User-mode only.
+
+--*/
+
+#include "Internal.h"
+#include "RoutingTable.tmh"
+
+#define MAX_ROUTING_TABLE_SIZE_KEY L"MaxRoutingTableSize"
+#define AID_ROUTING_SUPPORTED_KEY L"IsAidRoutingSupported"
+#define PROTOCOL_ROUTING_SUPPORTED_KEY L"IsProtRoutingSupported"
+#define TECH_ROUTING_SUPPORTED_KEY L"IsTechRoutingSupported"
+
+#define DEFAULT_MAX_ROUTING_TABLE_SIZE 255
+
+CRoutingTable::CRoutingTable(_In_ CQueue *pQueue)
+ : m_pQueue(pQueue),
+ m_pRoutingTable(nullptr),
+ m_RoutingTableMaxSize(0),
+ m_IsAidRoutingSupported(TRUE),
+ m_IsTechRoutingSupported(TRUE),
+ m_IsProtocolRoutingSupported(TRUE),
+ m_cbMaxRoutingTableSize(DEFAULT_MAX_ROUTING_TABLE_SIZE)
+{
+ InitializeCriticalSection(&m_RoutingTableLock);
+}
+
+CRoutingTable::~CRoutingTable()
+{
+ SAFE_DELETEARRAY(m_pRoutingTable);
+ m_RoutingTableMaxSize = 0;
+ DeleteCriticalSection(&m_RoutingTableLock);
+}
+
+VOID CRoutingTable::Initialize(WDFDEVICE Device)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFKEY KeyHandle = nullptr;
+ ULONG uValue = 0;
+
+ DECLARE_CONST_UNICODE_STRING(MaxRoutingTableSizeKey, MAX_ROUTING_TABLE_SIZE_KEY);
+ DECLARE_CONST_UNICODE_STRING(AidRoutingSupportedKey, AID_ROUTING_SUPPORTED_KEY);
+ DECLARE_CONST_UNICODE_STRING(ProtocolRoutingSupportedKey, PROTOCOL_ROUTING_SUPPORTED_KEY);
+ DECLARE_CONST_UNICODE_STRING(TechRoutingSupportedKey, TECH_ROUTING_SUPPORTED_KEY);
+
+ Status = WdfDeviceOpenRegistryKey(
+ Device,
+ PLUGPLAY_REGKEY_DEVICE | WDF_REGKEY_DEVICE_SUBKEY,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &KeyHandle);
+
+ if (NT_SUCCESS(Status) && (KeyHandle != nullptr)) {
+ Status = WdfRegistryQueryULong(
+ KeyHandle,
+ &MaxRoutingTableSizeKey,
+ &uValue);
+
+ if (NT_SUCCESS(Status) && uValue <= ((USHORT)0xFFFF)) { // MAX_USHORT
+ TraceInfo("MaxRoutingTableSize=%d", uValue);
+ m_cbMaxRoutingTableSize = (USHORT)uValue;
+ }
+
+ Status = WdfRegistryQueryULong(
+ KeyHandle,
+ &AidRoutingSupportedKey,
+ &uValue);
+
+ if (NT_SUCCESS(Status)) {
+ TraceInfo("IsAidRoutingSupported=%d", uValue);
+ m_IsAidRoutingSupported = (uValue != 0);
+ }
+
+ Status = WdfRegistryQueryULong(
+ KeyHandle,
+ &ProtocolRoutingSupportedKey,
+ &uValue);
+
+ if (NT_SUCCESS(Status)) {
+ TraceInfo("IsProtocolRoutingSupported=%d", uValue);
+ m_IsProtocolRoutingSupported = (uValue != 0);
+ }
+
+ Status = WdfRegistryQueryULong(
+ KeyHandle,
+ &TechRoutingSupportedKey,
+ &uValue);
+
+ if (NT_SUCCESS(Status)) {
+ TraceInfo("IsTechRoutingSupported=%d", uValue);
+ m_IsTechRoutingSupported = (uValue != 0);
+ }
+
+ WdfRegistryClose(KeyHandle);
+ }
+
+ Status = SetDefaultRoutingTable();
+
+ MethodReturnVoid();
+}
+
+NTSTATUS CRoutingTable::ValidateRoutingTable(_In_ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ DWORD cbTableSize = NCI_PROTO_ROUTING_ENTRY_SIZE; // Implicit NFC-DEP route
+
+ for (DWORD nIndex = 0; (nIndex < pRoutingTable->NumberOfEntries) && NT_SUCCESS(Status); nIndex++) {
+ switch (pRoutingTable->TableEntries[nIndex].eRoutingType) {
+ case RoutingTypeAid:
+ Status = ValidateAidRoute(&pRoutingTable->TableEntries[nIndex]);
+ cbTableSize += NCI_AID_ROUTING_ENTRY_SIZE(pRoutingTable->TableEntries[nIndex].AidRoutingInfo.cbAid);
+ break;
+
+ case RoutingTypeProtocol:
+ Status = ValidateProtocolRoute(&pRoutingTable->TableEntries[nIndex]);
+ cbTableSize += NCI_PROTO_ROUTING_ENTRY_SIZE;
+ break;
+
+ case RoutingTypeTech:
+ Status = ValidateTechRoute(&pRoutingTable->TableEntries[nIndex]);
+ cbTableSize += NCI_TECH_ROUTING_ENTRY_SIZE;
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Status = ValidateRouteUnique(pRoutingTable, nIndex);
+ }
+ }
+
+ if (NT_SUCCESS(Status) && cbTableSize > MaxRoutingTableSize()) {
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CRoutingTable::ValidateAidRoute(_In_ PSECURE_ELEMENT_ROUTING_TABLE_ENTRY pRoutingEntry)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NT_ASSERT(pRoutingEntry->eRoutingType == RoutingTypeAid);
+
+ if (!IsAidRoutingSupported()) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto Exit;
+ }
+
+ if ((pRoutingEntry->AidRoutingInfo.cbAid < ISO_7816_MINIMUM_AID_LENGTH) ||
+ (pRoutingEntry->AidRoutingInfo.cbAid > ISO_7816_MAXIMUM_AID_LENGTH)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CRoutingTable::ValidateProtocolRoute(_In_ PSECURE_ELEMENT_ROUTING_TABLE_ENTRY pRoutingEntry)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NT_ASSERT(pRoutingEntry->eRoutingType == RoutingTypeProtocol);
+
+ if (!IsProtocolRoutingSupported()) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto Exit;
+ }
+
+ if (pRoutingEntry->ProtoRoutingInfo.eRfProtocolType != PROTOCOL_T1T &&
+ pRoutingEntry->ProtoRoutingInfo.eRfProtocolType != PROTOCOL_T2T &&
+ pRoutingEntry->ProtoRoutingInfo.eRfProtocolType != PROTOCOL_T3T &&
+ pRoutingEntry->ProtoRoutingInfo.eRfProtocolType != PROTOCOL_ISO_DEP) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CRoutingTable::ValidateTechRoute(_In_ PSECURE_ELEMENT_ROUTING_TABLE_ENTRY pRoutingEntry)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NT_ASSERT(pRoutingEntry->eRoutingType == RoutingTypeTech);
+
+ if (!IsTechRoutingSupported()) {
+ Status = STATUS_NOT_SUPPORTED;
+ goto Exit;
+ }
+
+ if (pRoutingEntry->TechRoutingInfo.eRfTechType != NFC_RF_TECHNOLOGY_A &&
+ pRoutingEntry->TechRoutingInfo.eRfTechType != NFC_RF_TECHNOLOGY_B &&
+ pRoutingEntry->TechRoutingInfo.eRfTechType != NFC_RF_TECHNOLOGY_F) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CRoutingTable::ValidateRouteUnique(_In_ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable, _In_ DWORD EndIndex)
+{
+ _Analysis_assume_(EndIndex < pRoutingTable->NumberOfEntries);
+
+ for (DWORD nIndex = 0; (nIndex < EndIndex); nIndex++) {
+ if (pRoutingTable->TableEntries[nIndex].eRoutingType !=
+ pRoutingTable->TableEntries[EndIndex].eRoutingType) {
+ continue;
+ }
+
+ switch (pRoutingTable->TableEntries[nIndex].eRoutingType) {
+ case RoutingTypeAid:
+ if ((pRoutingTable->TableEntries[nIndex].AidRoutingInfo.cbAid ==
+ pRoutingTable->TableEntries[EndIndex].AidRoutingInfo.cbAid) &&
+ (memcmp(pRoutingTable->TableEntries[nIndex].AidRoutingInfo.pbAid,
+ pRoutingTable->TableEntries[EndIndex].AidRoutingInfo.pbAid,
+ pRoutingTable->TableEntries[nIndex].AidRoutingInfo.cbAid) == 0)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+ break;
+
+ case RoutingTypeProtocol:
+ if (pRoutingTable->TableEntries[nIndex].ProtoRoutingInfo.eRfProtocolType ==
+ pRoutingTable->TableEntries[EndIndex].ProtoRoutingInfo.eRfProtocolType) {
+ return STATUS_INVALID_PARAMETER;
+ }
+ break;
+
+ case RoutingTypeTech:
+ if (pRoutingTable->TableEntries[nIndex].TechRoutingInfo.eRfTechType ==
+ pRoutingTable->TableEntries[EndIndex].TechRoutingInfo.eRfTechType) {
+ return STATUS_INVALID_PARAMETER;
+ }
+ break;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS CRoutingTable::GetRoutingTable(_Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, size_t OutputBufferLength, DWORD* pcbOutputBuffer)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable = (PSECURE_ELEMENT_ROUTING_TABLE)OutputBuffer;
+
+ _Analysis_assume_(sizeof(DWORD) <= OutputBufferLength);
+
+ EnterCriticalSection(&m_RoutingTableLock);
+
+ pRoutingTable->NumberOfEntries = m_pRoutingTable->NumberOfEntries;
+ *pcbOutputBuffer = sizeof(m_pRoutingTable->NumberOfEntries);
+
+ if ((*pcbOutputBuffer + m_pRoutingTable->NumberOfEntries * sizeof(SECURE_ELEMENT_ROUTING_TABLE_ENTRY)) > OutputBufferLength) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto Exit;
+ }
+
+ RtlCopyMemory(pRoutingTable->TableEntries, m_pRoutingTable->TableEntries, m_pRoutingTable->NumberOfEntries * sizeof(SECURE_ELEMENT_ROUTING_TABLE_ENTRY));
+ *pcbOutputBuffer += m_pRoutingTable->NumberOfEntries * sizeof(SECURE_ELEMENT_ROUTING_TABLE_ENTRY);
+
+Exit:
+ LeaveCriticalSection(&m_RoutingTableLock);
+ return Status;
+}
+
+NTSTATUS CRoutingTable::SetDefaultRoutingTable()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ GUID SecureElementId = GUID_NULL;
+
+ Status = m_pQueue->GetSecureElementId(External, &SecureElementId);
+
+ if (NT_SUCCESS(Status))
+ {
+ if (IsTechRoutingSupported()) {
+ SECURE_ELEMENT_ROUTING_TABLE_AND_ENTRIES(3) RoutingTable;
+
+ RoutingTable.Table.NumberOfEntries = 3;
+ RoutingTable.Table.TableEntries[0].eRoutingType = RoutingTypeTech;
+ RoutingTable.Table.TableEntries[0].TechRoutingInfo.eRfTechType = NFC_RF_TECHNOLOGY_A;
+ RoutingTable.Table.TableEntries[0].TechRoutingInfo.guidSecureElementId = SecureElementId;
+ RoutingTable.Table.TableEntries[1].eRoutingType = RoutingTypeTech;
+ RoutingTable.Table.TableEntries[1].TechRoutingInfo.eRfTechType = NFC_RF_TECHNOLOGY_B;
+ RoutingTable.Table.TableEntries[1].TechRoutingInfo.guidSecureElementId = SecureElementId;
+ RoutingTable.Table.TableEntries[2].eRoutingType = RoutingTypeTech;
+ RoutingTable.Table.TableEntries[2].TechRoutingInfo.eRfTechType = NFC_RF_TECHNOLOGY_F;
+ RoutingTable.Table.TableEntries[2].TechRoutingInfo.guidSecureElementId = SecureElementId;
+
+ Status = SetRoutingTable(&RoutingTable.Table);
+ }
+ else if (IsProtocolRoutingSupported()) {
+ SECURE_ELEMENT_ROUTING_TABLE RoutingTable;
+
+ RoutingTable.NumberOfEntries = 1;
+ RoutingTable.TableEntries[0].eRoutingType = RoutingTypeProtocol;
+ RoutingTable.TableEntries[0].TechRoutingInfo.eRfTechType = PROTOCOL_ISO_DEP;
+ RoutingTable.TableEntries[0].TechRoutingInfo.guidSecureElementId = SecureElementId;
+
+ Status = SetRoutingTable(&RoutingTable);
+ }
+ else {
+ Status = STATUS_NOT_SUPPORTED;
+ TraceInfo("Neither Technology and Procotol routing is supported");
+ }
+ }
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CRoutingTable::ResizeRoutingTable(DWORD NumberOfEntries)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DWORD cbRoutingTable = sizeof(SECURE_ELEMENT_ROUTING_TABLE) +
+ sizeof(SECURE_ELEMENT_ROUTING_TABLE_ENTRY) * (NumberOfEntries-1);
+
+ if (m_RoutingTableMaxSize >= NumberOfEntries) {
+ Status = STATUS_SUCCESS;
+ goto Exit;
+ }
+
+ SAFE_DELETEARRAY(m_pRoutingTable);
+ m_RoutingTableMaxSize = 0;
+
+ m_pRoutingTable = (PSECURE_ELEMENT_ROUTING_TABLE) new BYTE[cbRoutingTable];
+
+ if (m_pRoutingTable == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ m_pRoutingTable->NumberOfEntries = 0;
+ m_RoutingTableMaxSize = NumberOfEntries;
+
+Exit:
+ return Status;
+}
+
+NTSTATUS CRoutingTable::SetRoutingTable(_In_ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable)
+{
+ NTSTATUS Status = ValidateRoutingTable(pRoutingTable);
+
+ if (NT_SUCCESS(Status)) {
+ EnterCriticalSection(&m_RoutingTableLock);
+
+ Status = ResizeRoutingTable(pRoutingTable->NumberOfEntries);
+
+ if (NT_SUCCESS(Status)) {
+ DWORD cbSize = sizeof(SECURE_ELEMENT_ROUTING_TABLE) + (pRoutingTable->NumberOfEntries - 1) * sizeof(SECURE_ELEMENT_ROUTING_TABLE_ENTRY);
+ RtlCopyMemory(m_pRoutingTable, pRoutingTable, cbSize);
+ }
+
+ LeaveCriticalSection(&m_RoutingTableLock);
+ }
+
+ return Status;
+}
diff --git a/nfc/Simulator/Src/RoutingTable.h b/nfc/Simulator/Src/RoutingTable.h
new file mode 100644
index 00000000..2f234d6d
--- /dev/null
+++ b/nfc/Simulator/Src/RoutingTable.h
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ RoutingTable.h
+
+Abstract:
+
+ This header file defines the listen mode routing table
+
+Environment:
+
+ User Mode
+
+--*/
+#pragma once
+
+class CRoutingTable
+{
+public:
+ CRoutingTable(_In_ CQueue *pQueue);
+ ~CRoutingTable();
+
+ VOID Initialize(_In_ WDFDEVICE Device);
+ NTSTATUS SetRoutingTable(_In_ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable);
+ NTSTATUS GetRoutingTable(_Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, size_t OutputBufferLength, DWORD* pcbOutputBuffer);
+
+ FORCEINLINE BOOLEAN IsAidRoutingSupported() const { return m_IsAidRoutingSupported; }
+ FORCEINLINE BOOLEAN IsTechRoutingSupported() const { return m_IsTechRoutingSupported; }
+ FORCEINLINE BOOLEAN IsProtocolRoutingSupported() const { return m_IsProtocolRoutingSupported; }
+ FORCEINLINE USHORT MaxRoutingTableSize() const { return m_cbMaxRoutingTableSize; }
+
+private:
+ NTSTATUS ValidateRoutingTable(_In_ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable);
+ NTSTATUS ValidateAidRoute(_In_ PSECURE_ELEMENT_ROUTING_TABLE_ENTRY pRoutingEntry);
+ NTSTATUS ValidateProtocolRoute(_In_ PSECURE_ELEMENT_ROUTING_TABLE_ENTRY pRoutingEntry);
+ NTSTATUS ValidateTechRoute(_In_ PSECURE_ELEMENT_ROUTING_TABLE_ENTRY pRoutingEntry);
+ NTSTATUS ValidateRouteUnique(_In_ PSECURE_ELEMENT_ROUTING_TABLE pRoutingTable, _In_ DWORD EndIndex);
+
+ NTSTATUS SetDefaultRoutingTable();
+ NTSTATUS ResizeRoutingTable(DWORD NumberOfEntries);
+
+private:
+ CQueue* m_pQueue;
+ PSECURE_ELEMENT_ROUTING_TABLE
+ m_pRoutingTable;
+ CRITICAL_SECTION m_RoutingTableLock;
+ DWORD m_RoutingTableMaxSize;
+ BOOLEAN m_IsAidRoutingSupported;
+ BOOLEAN m_IsTechRoutingSupported;
+ BOOLEAN m_IsProtocolRoutingSupported;
+ USHORT m_cbMaxRoutingTableSize;
+};
diff --git a/nfc/Simulator/Src/SecureElement.cpp b/nfc/Simulator/Src/SecureElement.cpp
new file mode 100644
index 00000000..9273c948
--- /dev/null
+++ b/nfc/Simulator/Src/SecureElement.cpp
@@ -0,0 +1,52 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ secureelement.cpp
+
+Abstract:
+
+ Implements the secure element class
+
+Environment:
+
+ User-mode only.
+
+--*/
+
+#include "Internal.h"
+#include "SecureElement.tmh"
+
+CSecureElement::CSecureElement(
+ const GUID& SecureElementId,
+ SECURE_ELEMENT_TYPE SecureElementType
+ )
+ : m_SecureElementId(SecureElementId),
+ m_SecureElementType(SecureElementType),
+ m_EmulationMode(EmulationOff)
+{
+ InitializeListHead(&m_ListEntry);
+}
+
+CSecureElement::~CSecureElement()
+{
+}
+
+NTSTATUS CSecureElement::SetEmulationMode(SECURE_ELEMENT_CARD_EMULATION_MODE EmulationMode)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (m_EmulationMode == EmulationMode) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ m_EmulationMode = EmulationMode;
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+} \ No newline at end of file
diff --git a/nfc/Simulator/Src/SecureElement.h b/nfc/Simulator/Src/SecureElement.h
new file mode 100644
index 00000000..e0e325b0
--- /dev/null
+++ b/nfc/Simulator/Src/SecureElement.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ secureelement.h
+
+Abstract:
+
+ This header file defines the secure element object
+
+Environment:
+
+ User Mode
+
+--*/
+#pragma once
+
+class CSecureElement
+{
+public:
+ CSecureElement(const GUID& SecureElementId, SECURE_ELEMENT_TYPE SecureElementType);
+ ~CSecureElement();
+
+public:
+ NTSTATUS SetEmulationMode(SECURE_ELEMENT_CARD_EMULATION_MODE Mode);
+
+public:
+ GUID GetIdentifier()
+ {
+ return m_SecureElementId;
+ }
+ SECURE_ELEMENT_TYPE GetType()
+ {
+ return m_SecureElementType;
+ }
+ SECURE_ELEMENT_CARD_EMULATION_MODE GetEmulationMode()
+ {
+ return m_EmulationMode;
+ }
+ PLIST_ENTRY GetListEntry()
+ {
+ return &m_ListEntry;
+ }
+ static CSecureElement* FromListEntry(PLIST_ENTRY pEntry)
+ {
+ return (CSecureElement*) CONTAINING_RECORD(pEntry, CSecureElement, m_ListEntry);
+ }
+
+private:
+ GUID m_SecureElementId; // Secure Element GUID identifier
+ SECURE_ELEMENT_TYPE m_SecureElementType; // Secure Element type
+ SECURE_ELEMENT_CARD_EMULATION_MODE m_EmulationMode; // Emulation mode of the Secure Element
+ LIST_ENTRY m_ListEntry; // Secure Element list entry
+};
diff --git a/nfc/Simulator/Src/SmartCard.cpp b/nfc/Simulator/Src/SmartCard.cpp
new file mode 100644
index 00000000..eba0fd94
--- /dev/null
+++ b/nfc/Simulator/Src/SmartCard.cpp
@@ -0,0 +1,312 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ smartcard.cpp
+
+Abstract:
+
+ This file implements the NFC smart card class.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "Internal.h"
+#include "SmartCard.tmh"
+
+CSmartCardRequest::CSmartCardRequest(_In_ CSmartCard *pSmartCard)
+ : m_pSmartCard(pSmartCard),
+ m_cbPayload(0),
+ m_hCompletionEvent(CreateEvent(nullptr, FALSE, FALSE, nullptr))
+{
+ RtlZeroMemory(m_Payload, sizeof(m_Payload));
+ InitializeListHead(&m_ListEntry);
+ m_dwSequenceNum = m_pSmartCard->AddRequest(this);
+}
+
+CSmartCardRequest::~CSmartCardRequest()
+{
+ m_pSmartCard->RemoveRequest(this);
+ SAFE_CLOSEHANDLE(m_hCompletionEvent);
+}
+
+VOID
+CSmartCardRequest::CompleteRequest(
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+{
+ RtlZeroMemory(m_Payload, sizeof(m_Payload));
+
+ if (cbPayload <= sizeof(m_Payload)) {
+ RtlCopyMemory(m_Payload, pbPayload, cbPayload);
+ m_cbPayload = cbPayload;
+ }
+
+ SetEvent(m_hCompletionEvent);
+}
+
+NTSTATUS CSmartCardRequest::WaitForCompletion()
+{
+ return (WaitForSingleObject(m_hCompletionEvent, ResponseTimeoutInMs) == WAIT_OBJECT_0) ? STATUS_SUCCESS : STATUS_IO_TIMEOUT;
+}
+
+CSmartCard::CSmartCard(_In_ WDFDEVICE Device, _In_ CConnection* pConnection)
+ : m_Device(Device),
+ m_pConnection(pConnection),
+ m_dwSequenceNum(0)
+{
+ InitializeListHead(&m_RequestList);
+ InitializeCriticalSection(&m_ConnectionLock);
+ InitializeCriticalSection(&m_RequestListLock);
+}
+
+CSmartCard::~CSmartCard()
+{
+ EnterCriticalSection(&m_RequestListLock);
+
+ while (!IsListEmpty(&m_RequestList)) {
+ delete CSmartCardRequest::FromListEntry(RemoveHeadList(&m_RequestList));
+ }
+ LeaveCriticalSection(&m_RequestListLock);
+
+ DeleteCriticalSection(&m_ConnectionLock);
+ DeleteCriticalSection(&m_RequestListLock);
+
+ SAFE_DELETE(m_pConnection);
+}
+
+NTSTATUS
+CSmartCard::SendCommand(
+ _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength,
+ _Out_ size_t* BytesTransferred
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ MESSAGE *pMessage = nullptr;
+ DWORD dwSequenceNum = 0;
+ CSmartCardRequest *pRequest = nullptr;
+ BYTE* pbPayload = nullptr;
+
+ *BytesTransferred = 0;
+
+ if (InputBufferLength > MaxCbPayload) {
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto Exit;
+ }
+
+ pRequest = new CSmartCardRequest(this);
+
+ if (pRequest == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ pbPayload = new BYTE[InputBufferLength + sizeof(DWORD)];
+
+ if (pbPayload == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ dwSequenceNum = pRequest->GetSequenceNum();
+
+ RtlCopyMemory(pbPayload, &dwSequenceNum, sizeof(DWORD));
+ RtlCopyMemory(pbPayload + sizeof(DWORD), InputBuffer, InputBufferLength);
+
+ pMessage = new MESSAGE();
+
+ if (pMessage == nullptr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ pMessage->Initialize(SMARTCARD_MESSAGE_TYPE_TRANSMIT, (DWORD)InputBufferLength + sizeof(DWORD), pbPayload);
+
+ EnterCriticalSection(&m_ConnectionLock);
+
+ if (FAILED(m_pConnection->TransmitMessage(pMessage))) {
+ Status = STATUS_DATA_ERROR;
+ LeaveCriticalSection(&m_ConnectionLock);
+ goto Exit;
+ }
+ LeaveCriticalSection(&m_ConnectionLock);
+
+ Status = pRequest->WaitForCompletion();
+
+ if (NT_SUCCESS(Status)) {
+ *BytesTransferred = pRequest->GetPayloadSize();
+
+ if (OutputBufferLength >= *BytesTransferred) {
+ RtlCopyMemory(OutputBuffer, pRequest->GetPayload(), *BytesTransferred);
+ }
+ else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+Exit:
+ SAFE_DELETE(pMessage);
+ SAFE_DELETEARRAY(pbPayload);
+ SAFE_DELETE(pRequest);
+
+ MethodReturn(Status, "Status = %!STATUS! Output buffer size = %d and payload size = %d", Status, (DWORD)OutputBufferLength, (DWORD)*BytesTransferred);
+}
+
+BOOL CSmartCard::ResponseReceived(_In_ MESSAGE* pMessage)
+{
+ MethodEntry("...");
+
+ BOOL fHandled = FALSE;
+ DWORD dwSequenceNum = 0;
+
+ if (CompareStringOrdinal(pMessage->m_szType, -1, SMARTCARD_MESSAGE_TYPE_TRANSMIT, -1, FALSE) == CSTR_EQUAL) {
+ if (pMessage->m_cbPayload >= sizeof(DWORD)) {
+ RtlCopyMemory(&dwSequenceNum, pMessage->m_Payload, sizeof(DWORD));
+ TraceInfo("Sequence number = %d and Payload size = %d", dwSequenceNum, pMessage->m_cbPayload);
+
+ EnterCriticalSection(&m_RequestListLock);
+
+ for (LIST_ENTRY* pEntry = m_RequestList.Flink;
+ pEntry != &m_RequestList;
+ pEntry = pEntry->Flink) {
+ CSmartCardRequest *pRequest = CSmartCardRequest::FromListEntry(pEntry);
+
+ if (dwSequenceNum == pRequest->GetSequenceNum()) {
+ pRequest->CompleteRequest(pMessage->m_cbPayload - sizeof(DWORD), pMessage->m_Payload + sizeof(DWORD));
+ fHandled = TRUE;
+ break;
+ }
+ }
+ LeaveCriticalSection(&m_RequestListLock);
+ }
+ }
+
+ MethodReturnBool(fHandled);
+}
+
+DWORD CSmartCard::AddRequest(_In_ CSmartCardRequest *pRequest)
+{
+ NT_ASSERT(pRequest != nullptr);
+
+ EnterCriticalSection(&m_RequestListLock);
+ InsertHeadList(&m_RequestList, pRequest->GetListEntry());
+ LeaveCriticalSection(&m_RequestListLock);
+
+ return InterlockedIncrement(&m_dwSequenceNum);
+}
+
+VOID CSmartCard::RemoveRequest(_In_ CSmartCardRequest *pRequest)
+{
+ NT_ASSERT(pRequest != nullptr);
+
+ EnterCriticalSection(&m_RequestListLock);
+
+ for (LIST_ENTRY* pEntry = m_RequestList.Flink;
+ pEntry != &m_RequestList;
+ pEntry = pEntry->Flink) {
+ if (pRequest == CSmartCardRequest::FromListEntry(pEntry)) {
+ RemoveEntryList(pEntry);
+ break;
+ }
+ }
+ LeaveCriticalSection(&m_RequestListLock);
+}
+
+NTSTATUS
+CSmartCard::GetAtr(
+ _Out_writes_bytes_(*pcbAtr) PBYTE pbAtr,
+ _Inout_ LPDWORD pcbAtr
+ )
+{
+ FunctionEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFKEY hKey = nullptr;
+ WDFMEMORY Memory;
+ DWORD Type;
+ PBYTE Buffer = nullptr;
+ size_t BufferSize = 0;
+ DECLARE_CONST_UNICODE_STRING(KeyValue, L"Atr");
+
+ Status = WdfDeviceOpenRegistryKey(
+ m_Device,
+ PLUGPLAY_REGKEY_DEVICE,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &hKey);
+
+ if (NT_SUCCESS(Status)) {
+ Status = WdfRegistryQueryMemory(hKey, &KeyValue, PagedPool, nullptr, &Memory, &Type);
+
+ if (NT_SUCCESS(Status)) {
+ NT_ASSERT(Type == REG_BINARY);
+
+ Buffer = (PBYTE) WdfMemoryGetBuffer(Memory, &BufferSize);
+
+ if (*pcbAtr < BufferSize) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else {
+ *pcbAtr = (DWORD)BufferSize;
+ RtlCopyMemory(pbAtr, Buffer, BufferSize);
+ }
+
+ WdfObjectDelete(Memory);
+ }
+
+ WdfRegistryClose(hKey);
+ }
+
+ FunctionReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CSmartCard::GetIccType(
+ _Out_writes_bytes_(*pcbIccType) PBYTE pbIccType,
+ _Inout_ LPDWORD pcbIccType
+ )
+{
+ FunctionEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFKEY hKey = nullptr;
+ DWORD Value = 0;
+ BYTE bValue = 0;
+ DECLARE_CONST_UNICODE_STRING(KeyValue, L"IccType");
+
+ Status = WdfDeviceOpenRegistryKey(
+ m_Device,
+ PLUGPLAY_REGKEY_DEVICE,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &hKey);
+
+ if (NT_SUCCESS(Status)) {
+ (VOID) WdfRegistryQueryULong(hKey, &KeyValue, &Value);
+
+ bValue = (BYTE)(Value & 0xFF);
+
+ if (*pcbIccType < sizeof(bValue)) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else {
+ *pcbIccType = sizeof(bValue);
+ RtlCopyMemory(pbIccType, &bValue, sizeof(bValue));
+ }
+
+ WdfRegistryClose(hKey);
+ }
+
+ FunctionReturn(Status, "Status = %!STATUS!", Status);
+}
diff --git a/nfc/Simulator/Src/SmartCard.h b/nfc/Simulator/Src/SmartCard.h
new file mode 100644
index 00000000..0831c1f8
--- /dev/null
+++ b/nfc/Simulator/Src/SmartCard.h
@@ -0,0 +1,100 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ smartcard.h
+
+Abstract:
+
+ The SmartCard simulates the communication channel with the selected smart card.
+
+Environment:
+
+ User Mode
+
+--*/
+#pragma once
+
+static const int MaxResponsePayload = 1024;
+static const int ResponseTimeoutInMs = 10000;
+
+#define SMARTCARD_MESSAGE_TYPE_TRANSMIT L"SCTransmit"
+
+class CSmartCard;
+
+class CSmartCardRequest
+{
+public:
+ CSmartCardRequest(_In_ CSmartCard *pSmartCard);
+ ~CSmartCardRequest();
+
+public:
+ VOID CompleteRequest(_In_ DWORD cbPayload, _In_reads_bytes_(cbPayload) PBYTE pbPayload);
+ NTSTATUS WaitForCompletion();
+
+public:
+ DWORD GetSequenceNum()
+ {
+ return m_dwSequenceNum;
+ }
+ DWORD GetPayloadSize()
+ {
+ return m_cbPayload;
+ }
+ BYTE* GetPayload()
+ {
+ return (BYTE*)m_Payload;
+ }
+ PLIST_ENTRY GetListEntry()
+ {
+ return &m_ListEntry;
+ }
+ static CSmartCardRequest* FromListEntry(PLIST_ENTRY pEntry)
+ {
+ return (CSmartCardRequest*) CONTAINING_RECORD(pEntry, CSmartCardRequest, m_ListEntry);
+ }
+
+private:
+ CSmartCard* m_pSmartCard; // smart card object
+ HANDLE m_hCompletionEvent; // event indicate if the request is completed
+ DWORD m_dwSequenceNum; // sequence number for the transmit request/response
+ DWORD m_cbPayload; // size of the payload
+ BYTE m_Payload[MaxResponsePayload]; // payload buffer
+ LIST_ENTRY m_ListEntry; // list entry
+};
+
+class CSmartCard
+{
+public:
+ CSmartCard(_In_ WDFDEVICE Device, _In_ CConnection* pConnection);
+ ~CSmartCard();
+
+public:
+ NTSTATUS SendCommand(
+ _In_reads_bytes_(InputBufferLength) PVOID InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
+ _In_ size_t OutputBufferLength,
+ _Out_ size_t* BytesTransferred);
+
+ BOOL ResponseReceived(_In_ MESSAGE* pMessage);
+
+ NTSTATUS GetAtr(_Out_writes_bytes_(*pcbAtr) PBYTE pbAtr, _Inout_ LPDWORD pcbAtr);
+ NTSTATUS GetIccType(_Out_writes_bytes_(*pcbIccType) PBYTE pbIccType, _Inout_ LPDWORD pcbIccType);
+
+private:
+ DWORD AddRequest(_In_ CSmartCardRequest *pRequest);
+ VOID RemoveRequest(_In_ CSmartCardRequest *pRequest);
+
+private:
+ friend class CSmartCardRequest;
+
+ WDFDEVICE m_Device;
+ CRITICAL_SECTION m_ConnectionLock; // lock for the connection pointer
+ CConnection* m_pConnection; // connection object
+ DWORD volatile m_dwSequenceNum; // sequence number of the transmit command
+ LIST_ENTRY m_RequestList; // list of pending request
+ CRITICAL_SECTION m_RequestListLock; // lock for the response list
+};
diff --git a/nfc/Simulator/Src/SmartCardReader.cpp b/nfc/Simulator/Src/SmartCardReader.cpp
new file mode 100644
index 00000000..efae85d4
--- /dev/null
+++ b/nfc/Simulator/Src/SmartCardReader.cpp
@@ -0,0 +1,564 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ smartcardreader.cpp
+
+Abstract:
+
+ Implements the NFC smart card reader class.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "Internal.h"
+#include "SmartCardReader.tmh"
+
+CSmartCardReader::CSmartCardReader(WDFDEVICE Device) :
+ m_Device(Device),
+ m_pSmartCard(nullptr),
+ m_fVirtualPowered(FALSE),
+ m_pCurrentClient(nullptr)
+{
+ srand((unsigned) GetTickCount());
+ InitializeCriticalSection(&m_SmartCardLock);
+}
+
+CSmartCardReader::~CSmartCardReader()
+{
+ DeleteCriticalSection(&m_SmartCardLock);
+}
+
+NTSTATUS CSmartCardReader::Initialize()
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDF_IO_QUEUE_CONFIG QueueConfig;
+
+ WDF_IO_QUEUE_CONFIG_INIT(&QueueConfig, WdfIoQueueDispatchManual);
+ QueueConfig.PowerManaged = WdfFalse;
+
+ Status = WdfIoQueueCreate(
+ m_Device,
+ &QueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &m_PresentQueue);
+
+ if (NT_SUCCESS(Status)) {
+ WDF_IO_QUEUE_CONFIG_INIT(&QueueConfig, WdfIoQueueDispatchManual);
+ QueueConfig.PowerManaged = WdfFalse;
+
+ Status = WdfIoQueueCreate(
+ m_Device,
+ &QueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &m_AbsentQueue);
+ }
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+VOID CSmartCardReader::Deinitialize()
+{
+ MethodEntry("...");
+
+ //
+ // Queue objects are parented to device by default so they
+ // are automatically deleted by framework when parent is deleted
+ //
+
+ SAFE_DELETE(m_pSmartCard);
+
+ MethodReturnVoid();
+}
+
+NTSTATUS CSmartCardReader::AddClient(CFileObject *pFileObject)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (InterlockedCompareExchangePointer((void**)&m_pCurrentClient, pFileObject, nullptr) != nullptr) {
+ Status = STATUS_ACCESS_DENIED;
+ goto Exit;
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+VOID CSmartCardReader::RemoveClient(CFileObject *pFileObject)
+{
+ MethodEntry("...");
+
+ InterlockedCompareExchangePointer((void**)&m_pCurrentClient, nullptr, pFileObject);
+
+ MethodReturnVoid();
+}
+
+NTSTATUS
+CSmartCardReader::GetAttribute(
+ _In_ DWORD dwAttributeId,
+ _Out_writes_bytes_(*pcbAttributeValue) PBYTE pbAttributeValue,
+ _Inout_ LPDWORD pcbAttributeValue
+ )
+{
+ MethodEntry("Attribute Id = 0x%x", dwAttributeId);
+
+ static const CHAR SCReaderVendorName[] = "Microsoft";
+ static const CHAR SCReaderVendorIfd[] = "IFD";
+ static const DWORD SCReaderVendorIfdVersion = 0x01000010; //1.0.0.1
+ static const DWORD SCReaderChannelId = SCARD_READER_TYPE_NFC << 16;
+ static const DWORD SCReaderProtocolTypes = SCARD_PROTOCOL_T1;
+ static const DWORD SCReaderDeviceUnit = 0;
+ static const DWORD SCReaderDefaultClk = 13560; // Default ICC CLK frequency
+ static const DWORD SCReaderMaxClk = 13560; // Max supported ICC CLK
+ static const DWORD SCReaderDefaultDataRate = 1; // ICC IO data rate
+ static const DWORD SCReaderMaxDataRate = 1;
+ static const DWORD SCReaderMaxIfsd = 254; // Max IFSD supported
+ static const DWORD SCReaderCharacteristics = SCARD_READER_CONTACTLESS;
+ static const DWORD SCReaderCurrentProtocolType = SCARD_PROTOCOL_T1;
+ static const DWORD SCReaderCurrentClk = 13560; // Current ICC CLK frequency in KHz
+ static const DWORD SCReaderCurrentD = 1;
+ static const DWORD SCReaderCurrentIfsc = 32; // Valid if current protocol is T=1
+ static const DWORD SCReaderCurrentIfsd = 254; // Valid if current protocol is T=1
+ static const DWORD SCReaderCurrentBwt = 4; // Valid if current protocol is T=1
+
+ const DISPATCH_ENTRY DispatchTable[] =
+ {
+ { SCARD_ATTR_VENDOR_NAME, (PBYTE)SCReaderVendorName, sizeof(SCReaderVendorName), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_VENDOR_IFD_TYPE, (PBYTE)SCReaderVendorIfd, sizeof(SCReaderVendorIfd), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_VENDOR_IFD_VERSION, (PBYTE)&SCReaderVendorIfdVersion, sizeof(SCReaderVendorIfdVersion), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_CHANNEL_ID, (PBYTE)&SCReaderChannelId, sizeof(SCReaderChannelId), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_PROTOCOL_TYPES, (PBYTE)&SCReaderProtocolTypes, sizeof(SCReaderProtocolTypes), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_DEVICE_UNIT, (PBYTE)&SCReaderDeviceUnit, sizeof(SCReaderDeviceUnit), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_DEFAULT_CLK, (PBYTE)&SCReaderDefaultClk, sizeof(SCReaderDefaultClk), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_MAX_CLK, (PBYTE)&SCReaderMaxClk, sizeof(SCReaderMaxClk), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_DEFAULT_DATA_RATE, (PBYTE)&SCReaderDefaultDataRate, sizeof(SCReaderDefaultDataRate), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_MAX_DATA_RATE, (PBYTE)&SCReaderMaxDataRate, sizeof(SCReaderMaxDataRate), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_MAX_IFSD, (PBYTE)&SCReaderMaxIfsd, sizeof(SCReaderMaxIfsd), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_CHARACTERISTICS, (PBYTE)&SCReaderCharacteristics, sizeof(SCReaderCharacteristics), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_CURRENT_PROTOCOL_TYPE, (PBYTE)&SCReaderCurrentProtocolType,sizeof(SCReaderCurrentProtocolType), &CSmartCardReader::GetCurrentProtocolType },
+ { SCARD_ATTR_CURRENT_CLK, (PBYTE)&SCReaderCurrentClk, sizeof(SCReaderCurrentClk), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_CURRENT_D, (PBYTE)&SCReaderCurrentD, sizeof(SCReaderCurrentD), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_CURRENT_IFSC, (PBYTE)&SCReaderCurrentIfsc, sizeof(SCReaderCurrentIfsc), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_CURRENT_IFSD, (PBYTE)&SCReaderCurrentIfsd, sizeof(SCReaderCurrentIfsd), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_CURRENT_BWT, (PBYTE)&SCReaderCurrentBwt, sizeof(SCReaderCurrentBwt), &CSmartCardReader::GetAttributeGeneric },
+ { SCARD_ATTR_ICC_PRESENCE, nullptr, 0, &CSmartCardReader::GetIccPresence },
+ { SCARD_ATTR_ATR_STRING, nullptr, 0, &CSmartCardReader::GetAtrString },
+ { SCARD_ATTR_ICC_TYPE_PER_ATR, nullptr, 0, &CSmartCardReader::GetIccTypePerAtr },
+ };
+
+ NTSTATUS Status = STATUS_NOT_SUPPORTED;
+
+ for (DWORD TableEntry = 0; TableEntry < _countof(DispatchTable); TableEntry++) {
+ if (DispatchTable[TableEntry].dwAttributeId == dwAttributeId) {
+ Status = (this->*DispatchTable[TableEntry].pfnDispatchHandler)(DispatchTable[TableEntry].pbAttributeValue,
+ (DWORD)DispatchTable[TableEntry].cbAttributeValue,
+ pbAttributeValue,
+ pcbAttributeValue);
+ break;
+ }
+ }
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CSmartCardReader::SetAttribute(_In_ DWORD dwAttributeId)
+{
+ return (dwAttributeId == SCARD_ATTR_DEVICE_IN_USE ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED);
+}
+
+NTSTATUS CSmartCardReader::SetPower(_In_ DWORD dwPower)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ EnterCriticalSection(&m_SmartCardLock);
+
+ if (m_pSmartCard == nullptr) {
+ Status = STATUS_NO_MEDIA;
+ goto Exit;
+ }
+
+ switch (dwPower)
+ {
+ case SCARD_COLD_RESET:
+ case SCARD_WARM_RESET:
+ m_fVirtualPowered = TRUE;
+ break;
+
+ case SCARD_POWER_DOWN:
+ m_fVirtualPowered = FALSE;
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+Exit:
+ LeaveCriticalSection(&m_SmartCardLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CSmartCardReader::SetProtocol(_In_ DWORD dwProtocol, _Out_ DWORD *pdwSelectedProtocol)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (m_pSmartCard == nullptr) {
+ Status = STATUS_NO_MEDIA;
+ goto Exit;
+ }
+
+ if (((dwProtocol & SCARD_PROTOCOL_DEFAULT) != 0) ||
+ ((dwProtocol & SCARD_PROTOCOL_T1) != 0) ) {
+ *pdwSelectedProtocol = SCARD_PROTOCOL_T1;
+ }
+ else if (((dwProtocol & SCARD_PROTOCOL_RAW) != 0) ||
+ ((dwProtocol & SCARD_PROTOCOL_T0) != 0) ||
+ ((dwProtocol & SCARD_PROTOCOL_Tx) != 0) ) {
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ else if (dwProtocol == SCARD_PROTOCOL_OPTIMAL) {
+ *pdwSelectedProtocol = SCARD_PROTOCOL_T1;
+ }
+ else {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CSmartCardReader::IsAbsent(_In_ WDFREQUEST Request)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFREQUEST OutRequest = nullptr;
+ BOOL fCompleteRequest = TRUE;
+
+ if (m_pSmartCard == nullptr) {
+ Status = STATUS_SUCCESS;
+ goto Exit;
+ }
+
+ if (NT_SUCCESS(WdfIoQueueFindRequest(
+ m_AbsentQueue,
+ nullptr,
+ WdfRequestGetFileObject(Request),
+ nullptr,
+ &OutRequest))) {
+ WdfObjectDereference(OutRequest);
+ Status = STATUS_DEVICE_BUSY;
+ goto Exit;
+ }
+
+ Status = WdfRequestForwardToIoQueue(Request, m_AbsentQueue);
+ fCompleteRequest = !NT_SUCCESS(Status);
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS CSmartCardReader::IsPresent(_In_ WDFREQUEST Request)
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ WDFREQUEST OutRequest = nullptr;
+ BOOL fCompleteRequest = TRUE;
+
+ if (m_pSmartCard != nullptr) {
+ Status = STATUS_SUCCESS;
+ goto Exit;
+ }
+
+ if (NT_SUCCESS(WdfIoQueueFindRequest(
+ m_PresentQueue,
+ nullptr,
+ WdfRequestGetFileObject(Request),
+ nullptr,
+ &OutRequest))) {
+ WdfObjectDereference(OutRequest);
+ Status = STATUS_DEVICE_BUSY;
+ goto Exit;
+ }
+
+ Status = WdfRequestForwardToIoQueue(Request, m_PresentQueue);
+ fCompleteRequest = !NT_SUCCESS(Status);
+
+Exit:
+ MethodReturn(fCompleteRequest ? Status : STATUS_PENDING, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CSmartCardReader::Transmit(
+ _In_reads_bytes_opt_(InputBufferLength) PBYTE InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PBYTE OutputBuffer,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t* BytesTransferred
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ SCARD_IO_REQUEST *InputRequest = (SCARD_IO_REQUEST*)InputBuffer;
+ SCARD_IO_REQUEST *OutputRequest = (SCARD_IO_REQUEST*)OutputBuffer;
+
+ EnterCriticalSection(&m_SmartCardLock);
+
+ if (m_pSmartCard == nullptr) {
+ Status = STATUS_NO_MEDIA;
+ goto Exit;
+ }
+
+ if (InputRequest->dwProtocol != SCARD_PROTOCOL_T1) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ Status = m_pSmartCard->SendCommand(
+ InputBuffer + sizeof(SCARD_IO_REQUEST),
+ InputBufferLength - sizeof(SCARD_IO_REQUEST),
+ OutputBuffer + sizeof(SCARD_IO_REQUEST),
+ OutputBufferLength - sizeof(SCARD_IO_REQUEST),
+ BytesTransferred);
+
+ if (NT_SUCCESS(Status)) {
+ // Store the header information (SCARD_IO_REQUEST) in the output buffer
+ OutputRequest->dwProtocol = SCARD_PROTOCOL_T1;
+ OutputRequest->cbPciLength = sizeof(SCARD_IO_REQUEST);
+ *BytesTransferred += sizeof(SCARD_IO_REQUEST);
+ }
+
+Exit:
+ LeaveCriticalSection(&m_SmartCardLock);
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+DWORD CSmartCardReader::GetState()
+{
+ if (m_pSmartCard != nullptr) {
+ return (m_fVirtualPowered ? SCARD_SPECIFIC : SCARD_SWALLOWED);
+ }
+
+ return SCARD_ABSENT;
+}
+
+BOOL CSmartCardReader::MessageReceived(_In_ MESSAGE* pMessage)
+{
+ MethodEntry("...");
+
+ BOOL fHandled = FALSE;
+
+ if (m_pSmartCard != nullptr) {
+ fHandled = m_pSmartCard->ResponseReceived(pMessage);
+ }
+
+ MethodReturnBool(fHandled);
+}
+
+BOOL CSmartCardReader::CardArrived(_In_ CConnection* pConnection)
+{
+ MethodEntry("void");
+
+ BOOL fTakeConnection = FALSE;
+ WDFREQUEST Request = nullptr;
+
+ EnterCriticalSection(&m_SmartCardLock);
+
+ m_fVirtualPowered = TRUE;
+
+ if (m_pSmartCard == nullptr) {
+ m_pSmartCard = new CSmartCard(m_Device, pConnection);
+
+ if (m_pSmartCard != nullptr) {
+ fTakeConnection = TRUE;
+
+ while (NT_SUCCESS(WdfIoQueueRetrieveNextRequest(m_PresentQueue, &Request))) {
+ TraceInfo("%!FUNC! Completing Request with Status %!STATUS!", STATUS_SUCCESS);
+ WdfRequestComplete(Request, STATUS_SUCCESS);
+ }
+ }
+ }
+
+ LeaveCriticalSection(&m_SmartCardLock);
+
+ MethodReturnBool(fTakeConnection);
+}
+
+BOOL CSmartCardReader::CardRemoved(_In_ CConnection* pConnection)
+{
+ MethodEntry("void");
+
+ UNREFERENCED_PARAMETER(pConnection);
+
+ BOOL fConnectionDeleted = FALSE;
+ WDFREQUEST Request = nullptr;
+
+ EnterCriticalSection(&m_SmartCardLock);
+
+ m_fVirtualPowered = FALSE;
+
+ if (m_pSmartCard != nullptr) {
+ SAFE_DELETE(m_pSmartCard);
+
+ while (NT_SUCCESS(WdfIoQueueRetrieveNextRequest(m_AbsentQueue, &Request))) {
+ TraceInfo("%!FUNC! Completing Request with Status %!STATUS!", STATUS_SUCCESS);
+ WdfRequestComplete(Request, STATUS_SUCCESS);
+ }
+
+ fConnectionDeleted = TRUE;
+ }
+
+ LeaveCriticalSection(&m_SmartCardLock);
+
+ MethodReturnBool(fConnectionDeleted);
+}
+
+FORCEINLINE NTSTATUS
+CopyToBuffer(
+ _In_reads_bytes_(cbAttributeValue) const VOID *pbAttributeValue,
+ _In_ DWORD cbAttributeValue,
+ _Out_writes_bytes_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (*pcbOutputBuffer < cbAttributeValue) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+
+ RtlCopyMemory(pbOutputBuffer, pbAttributeValue, cbAttributeValue);
+ *pcbOutputBuffer = cbAttributeValue;
+
+Exit:
+ return Status;
+}
+
+NTSTATUS
+CSmartCardReader::GetAttributeGeneric(
+ _In_opt_bytecount_(cbAttributeValue) PBYTE pbAttributeValue,
+ _In_ DWORD cbAttributeValue,
+ _Out_bytecap_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ Status = CopyToBuffer(pbAttributeValue, cbAttributeValue, pbOutputBuffer, pcbOutputBuffer);
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CSmartCardReader::GetCurrentProtocolType(
+ _In_opt_bytecount_(cbCurrentProtocolType) PBYTE pbCurrentProtocolType,
+ _In_ DWORD cbCurrentProtocolType,
+ _Out_bytecap_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer
+ )
+{
+ MethodEntry("...");
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (m_pSmartCard == nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ Status = CopyToBuffer(pbCurrentProtocolType, cbCurrentProtocolType, pbOutputBuffer, pcbOutputBuffer);
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CSmartCardReader::GetAtrString(
+ _In_opt_bytecount_(cbAttributeValue) PBYTE pbAttributeValue,
+ _In_ DWORD cbAttributeValue,
+ _Out_bytecap_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer
+ )
+{
+ MethodEntry("...");
+
+ UNREFERENCED_PARAMETER(pbAttributeValue);
+ UNREFERENCED_PARAMETER(cbAttributeValue);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (m_pSmartCard == nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ Status = m_pSmartCard->GetAtr(pbOutputBuffer, pcbOutputBuffer);
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CSmartCardReader::GetIccTypePerAtr(
+ _In_opt_bytecount_(cbAttributeValue) PBYTE pbAttributeValue,
+ _In_ DWORD cbAttributeValue,
+ _Out_bytecap_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer
+ )
+{
+ MethodEntry("...");
+
+ UNREFERENCED_PARAMETER(pbAttributeValue);
+ UNREFERENCED_PARAMETER(cbAttributeValue);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (m_pSmartCard == nullptr) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ goto Exit;
+ }
+
+ Status = m_pSmartCard->GetIccType(pbOutputBuffer, pcbOutputBuffer);
+
+Exit:
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
+
+NTSTATUS
+CSmartCardReader::GetIccPresence(
+ _In_opt_bytecount_(cbAttributeValue) PBYTE pbAttributeValue,
+ _In_ DWORD cbAttributeValue,
+ _Out_bytecap_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer
+ )
+{
+ MethodEntry("...");
+
+ UNREFERENCED_PARAMETER(pbAttributeValue);
+ UNREFERENCED_PARAMETER(cbAttributeValue);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ BYTE IccPresence = (m_pSmartCard == nullptr ? 0x0 : 0x1);
+
+ Status = CopyToBuffer(&IccPresence, sizeof(IccPresence), pbOutputBuffer, pcbOutputBuffer);
+
+ MethodReturn(Status, "Status = %!STATUS!", Status);
+}
diff --git a/nfc/Simulator/Src/SmartCardReader.h b/nfc/Simulator/Src/SmartCardReader.h
new file mode 100644
index 00000000..fa0cf06f
--- /dev/null
+++ b/nfc/Simulator/Src/SmartCardReader.h
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ smartcardreader.h
+
+Abstract:
+
+ The SmartCardReader encapsulate all the smart card related operations.
+
+Environment:
+
+ User Mode
+
+--*/
+#pragma once
+
+class CSmartCardReader
+{
+public:
+ CSmartCardReader(WDFDEVICE Device);
+ ~CSmartCardReader();
+
+public:
+ NTSTATUS Initialize();
+ VOID Deinitialize();
+ NTSTATUS AddClient(CFileObject *pFileObject);
+ VOID RemoveClient(CFileObject *pFileObject);
+
+ NTSTATUS GetAttribute(_In_ DWORD dwAttributeId, _Out_writes_bytes_(*pcbAttributeValue) PBYTE pbAttributeValue, _Inout_ LPDWORD pcbAttributeValue);
+ NTSTATUS SetAttribute(_In_ DWORD dwAttributeId);
+ NTSTATUS IsAbsent(_In_ WDFREQUEST Request);
+ NTSTATUS IsPresent(_In_ WDFREQUEST Request);
+ NTSTATUS SetPower(_In_ DWORD dwPower);
+ NTSTATUS SetProtocol(_In_ DWORD dwProtocol, _Out_ DWORD *pdwSelectedProtocol);
+
+ NTSTATUS Transmit(
+ _In_reads_bytes_opt_(InputBufferLength) PBYTE InputBuffer,
+ _In_ size_t InputBufferLength,
+ _Out_writes_bytes_opt_(OutputBufferLength) PBYTE OutputBuffer,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t* BytesTransferred);
+
+ DWORD GetState();
+ BOOL CardArrived(_In_ CConnection* pConnection);
+ BOOL CardRemoved(_In_ CConnection* pConnection);
+ BOOL MessageReceived(_In_ MESSAGE* pMessage);
+
+private:
+ typedef NTSTATUS
+ (CSmartCardReader::EVT_DISPATCH_HANDLER) (
+ _In_opt_bytecount_(cbAttributeValue) PBYTE pbAttributeValue,
+ _In_ DWORD cbAttributeValue,
+ _Out_bytecap_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer);
+
+ typedef NTSTATUS
+ (CSmartCardReader::*PFN_DISPATCH_HANDLER) (
+ _In_opt_bytecount_(cbAttributeValue) PBYTE pbAttributeValue,
+ _In_ DWORD cbAttributeValue,
+ _Out_bytecap_(*pcbOutputBuffer) PBYTE pbOutputBuffer,
+ _Inout_ LPDWORD pcbOutputBuffer);
+
+ EVT_DISPATCH_HANDLER GetAttributeGeneric;
+ EVT_DISPATCH_HANDLER GetCurrentProtocolType;
+ EVT_DISPATCH_HANDLER GetIccPresence;
+ EVT_DISPATCH_HANDLER GetAtrString;
+ EVT_DISPATCH_HANDLER GetIccTypePerAtr;
+
+private:
+ typedef struct _DISPATCH_ENTRY {
+ DWORD dwAttributeId;
+ PBYTE pbAttributeValue;
+ size_t cbAttributeValue;
+ PFN_DISPATCH_HANDLER pfnDispatchHandler;
+ } DISPATCH_ENTRY, *PDISPATCH_ENTRY;
+
+ WDFDEVICE m_Device;
+ WDFQUEUE m_PresentQueue;
+ WDFQUEUE m_AbsentQueue;
+ CSmartCard* m_pSmartCard;
+ CRITICAL_SECTION m_SmartCardLock;
+ BOOL m_fVirtualPowered;
+ CFileObject* m_pCurrentClient;
+};
diff --git a/nfc/Simulator/Src/SocketListener.cpp b/nfc/Simulator/Src/SocketListener.cpp
new file mode 100644
index 00000000..1276c28d
--- /dev/null
+++ b/nfc/Simulator/Src/SocketListener.cpp
@@ -0,0 +1,185 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ socketlistener.cpp
+
+Abstract:
+
+ Implements a socket listener class
+
+Environment:
+
+ User-mode only.
+
+--*/
+
+#include "Internal.h"
+#include "SocketListener.tmh"
+
+HRESULT SetSocketIpv6Only(_In_ SOCKET socket, _In_ BOOL Ipv6Only)
+{
+ FunctionEntry("...");
+
+ HRESULT hr = S_OK;
+
+ if (setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&Ipv6Only, sizeof(Ipv6Only)) == SOCKET_ERROR) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+
+ FunctionReturnHR(hr);
+}
+
+HRESULT CSocketListener::EnableAccepting()
+{
+ MethodEntry("...");
+
+ HRESULT hr = S_OK;
+
+ if (_ThreadpoolIo == nullptr) {
+ _ThreadpoolIo = CreateThreadpoolIo((HANDLE)_ListenSocket, s_AcceptThreadProc, this, nullptr);
+
+ if (_ThreadpoolIo == nullptr) {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (SUCCEEDED(hr)) {
+ if (listen(_ListenSocket, 2) == SOCKET_ERROR) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = BeginAccept();
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING)) {
+ hr = S_OK;
+ }
+ }
+ }
+
+ MethodReturnHR(hr);
+}
+
+void CSocketListener::StopAccepting()
+{
+ MethodEntry("void");
+
+ SOCKET listenSocket = InterlockedExchange(&_ListenSocket, INVALID_SOCKET);
+
+ if (listenSocket != INVALID_SOCKET) {
+ closesocket(listenSocket);
+ }
+
+ PTP_IO threadpoolIo = (PTP_IO)InterlockedExchangePointer((PVOID*)&_ThreadpoolIo, nullptr);
+
+ if (threadpoolIo != nullptr) {
+ // Don't wait for threadpool callbacks when this thread is actually the threadpool callback
+ if (_ThreadpoolThreadId != GetCurrentThreadId()) {
+ WaitForThreadpoolIoCallbacks(threadpoolIo, false);
+ }
+ CloseThreadpoolIo(threadpoolIo);
+ }
+
+ if (_ClientSocket != INVALID_SOCKET) {
+ closesocket(_ClientSocket);
+ _ClientSocket = INVALID_SOCKET;
+ }
+
+ MethodReturnVoid();
+}
+
+HRESULT CSocketListener::BeginAccept()
+{
+ MethodEntry("void");
+
+ HRESULT hr = S_OK;
+ ULONG_PTR cbReceived = 0;
+
+ _ClientSocket = socket(AF_INET6, SOCK_STREAM, 0);
+
+ if (_ClientSocket == INVALID_SOCKET) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = SetSocketIpv6Only(_ClientSocket, FALSE);
+ }
+
+ if (SUCCEEDED(hr)) {
+ PTP_IO threadpoolIo = _ThreadpoolIo;
+
+ if (threadpoolIo != nullptr) {
+ StartThreadpoolIo(threadpoolIo);
+ ZeroMemory(&_Overlapped, sizeof(_Overlapped));
+
+ if (!AcceptEx(
+ _ListenSocket,
+ _ClientSocket,
+ &_AcceptBuffer,
+ sizeof(_AcceptBuffer.MagicPacket),
+ sizeof(_AcceptBuffer.DestAddress),
+ sizeof(_AcceptBuffer.SourceAddress),
+ (LPDWORD)&cbReceived,
+ &_Overlapped)) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+
+ if (hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING)) {
+ CancelThreadpoolIo(threadpoolIo);
+ StopAccepting();
+ }
+ }
+ }
+ }
+
+ MethodReturnHR(hr);
+}
+
+void CSocketListener::AcceptThreadProc(_In_ HRESULT hr, _In_ ULONG_PTR cbReceived)
+{
+ MethodEntry("hr = %!HRESULT!, cbReceived = %d", hr, (ULONG)cbReceived);
+
+ if (SUCCEEDED(hr)) {
+ if (cbReceived == sizeof(_AcceptBuffer.MagicPacket)) {
+ _pValidator->ValidateAccept(_ClientSocket, &_AcceptBuffer.MagicPacket);
+ }
+ else {
+ closesocket(_ClientSocket);
+ }
+
+ _ClientSocket = INVALID_SOCKET;
+ }
+
+ BeginAccept();
+
+ MethodReturnVoid();
+}
+
+HRESULT CSocketListener::Bind()
+{
+ MethodEntry("void");
+
+ HRESULT hr = S_OK;
+
+ if (SUCCEEDED(hr)) {
+ _ListenSocket = socket(AF_INET6, SOCK_STREAM, 0);
+
+ if (_ListenSocket == INVALID_SOCKET) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = SetSocketIpv6Only(_ListenSocket, FALSE);
+ }
+
+ if (SUCCEEDED(hr)) {
+ if (bind(_ListenSocket, (const sockaddr*)&_ListenAddress, (int)sizeof(_ListenAddress)) == SOCKET_ERROR) {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+ }
+
+ MethodReturnHR(hr);
+} \ No newline at end of file
diff --git a/nfc/Simulator/Src/SocketListener.h b/nfc/Simulator/Src/SocketListener.h
new file mode 100644
index 00000000..dfbec369
--- /dev/null
+++ b/nfc/Simulator/Src/SocketListener.h
@@ -0,0 +1,85 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Abstract:
+
+ Declares a socket listener class
+
+Environment:
+
+ User-mode only.
+
+--*/
+#pragma once
+
+#define NFC_DRIVER_SIM_LISTEN_PORT 9299
+
+struct ACCEPT_BUFFER
+{
+ GUID MagicPacket;
+ SOCKADDR_STORAGE DestAddress;
+ SOCKADDR_STORAGE SourceAddress;
+};
+
+class IValidateAccept
+{
+public:
+ virtual void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket) = 0;
+};
+
+class CSocketListener
+{
+public:
+ CSocketListener(_In_ IValidateAccept* pValidator) :
+ _pValidator(pValidator),
+ _ThreadpoolIo(nullptr),
+ _ListenSocket(INVALID_SOCKET),
+ _ClientSocket(INVALID_SOCKET)
+ {
+ ZeroMemory(&_Overlapped, sizeof(_Overlapped));
+
+ ZeroMemory(&_ListenAddress, sizeof(_ListenAddress));
+ _ListenAddress.sin6_family = AF_INET6;
+ _ListenAddress.sin6_port = htons(NFC_DRIVER_SIM_LISTEN_PORT);
+ }
+
+ ~CSocketListener()
+ {
+ StopAccepting();
+ _pValidator = nullptr;
+ }
+
+public:
+ HRESULT Bind();
+ HRESULT EnableAccepting();
+ void StopAccepting();
+
+private:
+ HRESULT BeginAccept();
+ void AcceptThreadProc(_In_ HRESULT hr, _In_ ULONG_PTR cbReceived);
+
+ static void CALLBACK s_AcceptThreadProc(
+ _Inout_ PTP_CALLBACK_INSTANCE /*Instance*/,
+ _Inout_ PVOID Context,
+ _Inout_opt_ PVOID /*Overlapped*/,
+ _In_ ULONG IoResult,
+ _In_ ULONG_PTR NumberOfBytesTransferred,
+ _Inout_ PTP_IO /*Io*/)
+ {
+ CSocketListener* pSocketListener = (CSocketListener*)Context;
+ pSocketListener->_ThreadpoolThreadId = GetCurrentThreadId();
+ pSocketListener->AcceptThreadProc(HRESULT_FROM_WIN32(IoResult), NumberOfBytesTransferred);
+ pSocketListener->_ThreadpoolThreadId = 0;
+ }
+
+private:
+ sockaddr_in6 _ListenAddress;
+ ACCEPT_BUFFER _AcceptBuffer;
+ OVERLAPPED _Overlapped;
+ volatile PTP_IO _ThreadpoolIo;
+ DWORD _ThreadpoolThreadId;
+ IValidateAccept* _pValidator;
+ SOCKET _ListenSocket;
+ SOCKET _ClientSocket;
+};
diff --git a/nfc/Simulator/Src/WppDefs.h b/nfc/Simulator/Src/WppDefs.h
new file mode 100644
index 00000000..b102c461
--- /dev/null
+++ b/nfc/Simulator/Src/WppDefs.h
@@ -0,0 +1,367 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved
+
+Abstract:
+
+ WPP tracing macro definitions.
+
+--*/
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(NFC, TRACE_CONTROL_GUID, \
+ WPP_DEFINE_BIT(EntryExit) \
+ WPP_DEFINE_BIT(AllocFree) \
+ WPP_DEFINE_BIT(Info) \
+ WPP_DEFINE_BIT(Warning) \
+ WPP_DEFINE_BIT(Error) \
+ WPP_DEFINE_BIT(NoisyEntryExit) \
+ WPP_DEFINE_BIT(NoisyAllocFree) \
+ WPP_DEFINE_BIT(NoisyInfo) \
+ WPP_DEFINE_BIT(NoisyWarning))
+
+//
+// Used for trace messages indentation
+//
+const char __indentSpacer[] =
+" "
+" "
+" "
+" "
+" "
+" ";
+
+#define INDENT_STR(indent) \
+ (__indentSpacer + ((sizeof(__indentSpacer) >= (indent)*5) ? (sizeof(__indentSpacer)-2-(indent)*5) : 0))
+
+//
+// Stores a pointer to current tracing context
+//
+extern DWORD __g_tracingTlsSlot;
+
+//
+// This macro declares the global variable that will store TLS index for the
+// tracing context pointer.
+//
+#define DECLARE_TRACING_TLS DWORD __g_tracingTlsSlot = TLS_OUT_OF_INDEXES
+
+//
+// To be used only within EXE init routines or by the Tracer.
+//
+inline bool TracingTlsInitialize()
+{
+ if (__g_tracingTlsSlot == TLS_OUT_OF_INDEXES) {
+ __g_tracingTlsSlot = TlsAlloc();
+ if (__g_tracingTlsSlot == TLS_OUT_OF_INDEXES) {
+ return false;
+ }
+ }
+ return true;
+}
+
+//
+// To be used only within EXE exit routines or by the Tracer.
+//
+inline void TracingTlsFree()
+{
+ if (__g_tracingTlsSlot != TLS_OUT_OF_INDEXES) {
+ TlsFree(__g_tracingTlsSlot);
+ __g_tracingTlsSlot = TLS_OUT_OF_INDEXES;
+ }
+}
+
+namespace TracingInternal {
+//
+// Used for storing current tracing context within a TLS slot
+//
+struct TracingContext
+{
+ ULONG CallDepth; // Current depth of internal calls
+ DWORD Context; // A context value (used to correlate scenarios that cross-threads)
+};
+
+//
+// Auto-incrementing and decrementing variable
+//
+class AutoStackDepth
+{
+public:
+ __forceinline AutoStackDepth(ULONG *pCallDepth)
+ : _pCallDepth(pCallDepth)
+ {
+ if (_pCallDepth) {
+ ++*_pCallDepth;
+ }
+ }
+
+ __forceinline ~AutoStackDepth()
+ {
+ if (_pCallDepth) {
+ --*_pCallDepth;
+ }
+ }
+
+private:
+ AutoStackDepth(AutoStackDepth& rh);
+ const AutoStackDepth& operator =(AutoStackDepth& rh);
+
+private:
+ ULONG* _pCallDepth;
+};
+
+//
+// Sets new value to a variable but saves old value and restores it on destruction
+//
+template <class T>
+class AutoRestoredValue
+{
+public:
+ __forceinline AutoRestoredValue(T* pVar, T newVal)
+ : _pVar(pVar)
+ , _oldVal()
+ {
+ if (_pVar) {
+ _oldVal = *_pVar;
+ *_pVar = newVal;
+ }
+ }
+
+ __forceinline ~AutoRestoredValue()
+ {
+ if (_pVar) {
+ *_pVar = _oldVal;
+ }
+ }
+
+private:
+ AutoRestoredValue(AutoRestoredValue& rh);
+ const AutoRestoredValue& operator =(AutoRestoredValue& rh);
+
+private:
+ T* _pVar;
+ T _oldVal;
+};
+
+//
+// Auto-pointer stored in TLS
+//
+template <class Pointee>
+class AutoTlsPtr
+{
+public:
+ __forceinline AutoTlsPtr()
+ : _dwSlotIndex(TLS_OUT_OF_INDEXES)
+ {
+ }
+
+ __forceinline ~AutoTlsPtr()
+ {
+ if (_dwSlotIndex != TLS_OUT_OF_INDEXES)
+ {
+ LPVOID pCtx = TlsGetValue(_dwSlotIndex);
+ if (pCtx) {
+ TlsSetValue(_dwSlotIndex, nullptr);
+ }
+ }
+ }
+
+ __forceinline void Attach(Pointee* pCtx, DWORD dwSlotIndex)
+ {
+ _dwSlotIndex = dwSlotIndex;
+ TlsSetValue(_dwSlotIndex, pCtx);
+ }
+
+private:
+ DWORD _dwSlotIndex;
+};
+
+} // namespace TracingInternal
+
+//
+// This macro should be used at entry point of all functions with tracing.
+// It reads from a Tracing context structure stored in the TLS.
+// If the slot contains a nullptr a new TracingContext is used. An object
+// is created that increments CallDepth and auto-decrements it on function exit.
+//
+#define USE_DEFAULT_TRACING_CONTEXT \
+ TracingInternal::TracingContext* __pCtx = (TracingInternal::TracingContext*)TlsGetValue(__g_tracingTlsSlot); \
+ TracingInternal::AutoTlsPtr<TracingInternal::TracingContext> __autoTlsPtr; \
+ TracingInternal::TracingContext __ctx; \
+ if (__pCtx == nullptr) { \
+ __pCtx = &__ctx; \
+ __pCtx->CallDepth = 0; \
+ __autoTlsPtr.Attach(__pCtx, __g_tracingTlsSlot); \
+ } \
+ TracingInternal::AutoStackDepth __autoStackDepth(&__pCtx->CallDepth);
+
+// MACRO: MethodEntry
+//
+// begin_wpp config
+// USEPREFIX (MethodEntry, "%!STDPREFIX!%s-->this(%p):%!FUNC!(", INDENT_STR(__pCtx->CallDepth), this);
+// FUNC MethodEntry{ENTRYLEVEL=EntryExit}(MSG, ...);
+// USESUFFIX (MethodEntry, ")");
+// end_wpp
+#define WPP_ENTRYLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_ENTRYLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_ENTRYLEVEL_PRE(LEVEL) USE_DEFAULT_TRACING_CONTEXT;
+
+// MACRO: MethodReturn
+//
+// begin_wpp config
+// USEPREFIX (MethodReturn, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): ", INDENT_STR(__pCtx->CallDepth), this);
+// FUNC MethodReturn{RETURNLEVEL=EntryExit}(RET, MSG, ...);
+// end_wpp
+#define WPP_RETURNLEVEL_RET_ENABLED(LEVEL, Ret) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_RETURNLEVEL_RET_LOGGER(LEVEL, Ret) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_RETURNLEVEL_RET_POST(LEVEL, Ret) ;return Ret;
+
+// MACRO: MethodReturnHR
+//
+// begin_wpp config
+// USEPREFIX (MethodReturnHR, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): %!HRESULT!", INDENT_STR(__pCtx->CallDepth), this, __hr);
+// FUNC MethodReturnHR{RETURNHRLEVEL=EntryExit}(HR);
+// end_wpp
+#define WPP_RETURNHRLEVEL_HR_ENABLED(LEVEL, hr) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_RETURNHRLEVEL_HR_LOGGER(LEVEL, hr) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_RETURNHRLEVEL_HR_PRE(LEVEL, hr) { \
+ HRESULT __hr = hr;
+#define WPP_RETURNHRLEVEL_HR_POST(LEVEL, hr) ;return __hr; \
+ }
+
+// MACRO: MethodReturnVoid
+//
+// begin_wpp config
+// USEPREFIX (MethodReturnVoid, "%!STDPREFIX!%s<--this(%p):%!FUNC!()", INDENT_STR(__pCtx->CallDepth), this);
+// FUNC MethodReturnVoid{RETURNVOIDLEVEL=EntryExit}(...);
+// end_wpp
+#define WPP_RETURNVOIDLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_RETURNVOIDLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_RETURNVOIDLEVEL_POST(LEVEL) ;return;
+
+// MACRO: MethodReturnBool
+//
+// begin_wpp config
+// USEPREFIX (MethodReturnBool, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): %!bool!", INDENT_STR(__pCtx->CallDepth), this, __bRet);
+// FUNC MethodReturnBool{RETURNBOOLLEVEL=EntryExit}(BOOLRETVAL);
+// end_wpp
+#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_ENABLED(LEVEL, bRet) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_LOGGER(LEVEL, bRet) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_PRE(LEVEL, bRet) { \
+ bool __bRet = (bRet ? true : false);
+#define WPP_RETURNBOOLLEVEL_BOOLRETVAL_POST(LEVEL, bRet) ;return __bRet; \
+ }
+
+// MACRO: MethodReturnPtr
+//
+// begin_wpp config
+// USEPREFIX (MethodReturnPtr, "%!STDPREFIX!%s<--this(%p):%!FUNC!(): %p", INDENT_STR(__pCtx->CallDepth), this, __ptrRetVal);
+// FUNC MethodReturnPtr{RETURNPTRLEVEL=EntryExit}(TYPE, PRET);
+// end_wpp
+#define WPP_RETURNPTRLEVEL_TYPE_PRET_ENABLED(LEVEL, Type, pRet) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_RETURNPTRLEVEL_TYPE_PRET_LOGGER(LEVEL, Type, pRet) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_RETURNPTRLEVEL_TYPE_PRET_PRE(LEVEL, Type, pRet) { \
+ Type __pRet = pRet;
+#define WPP_RETURNPTRLEVEL_TYPE_PRET_POST(LEVEL, Type, pRet) ;return __pRet; \
+ }
+
+// MACRO: FunctionEntry
+//
+// begin_wpp config
+// USEPREFIX (FunctionEntry, "%!STDPREFIX!%s-->%!FUNC!(", INDENT_STR(__pCtx->CallDepth));
+// FUNC FunctionEntry{FUNCENTRYLEVEL=EntryExit}(MSG, ...);
+// USESUFFIX (FunctionEntry, ")");
+// end_wpp
+#define WPP_FUNCENTRYLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_FUNCENTRYLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_FUNCENTRYLEVEL_PRE(LEVEL) USE_DEFAULT_TRACING_CONTEXT;
+
+// MACRO: FunctionReturn
+//
+// begin_wpp config
+// USEPREFIX (FunctionReturn, "%!STDPREFIX!%s<--%!FUNC!(): ", INDENT_STR(__pCtx->CallDepth));
+// FUNC FunctionReturn{FUNCRETURNLEVEL=EntryExit}(RET, MSG, ...);
+// end_wpp
+#define WPP_FUNCRETURNLEVEL_RET_ENABLED(LEVEL, Ret) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_FUNCRETURNLEVEL_RET_LOGGER(LEVEL, Ret) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_FUNCRETURNLEVEL_RET_POST(LEVEL, Ret) ;return Ret;
+
+// MACRO: FunctionReturnHR
+//
+// begin_wpp config
+// USEPREFIX (FunctionReturnHR, "%!STDPREFIX!%s<--%!FUNC!(): %!HRESULT!", INDENT_STR(__pCtx->CallDepth), __hr);
+// FUNC FunctionReturnHR{FUNCRETURNHRLEVEL=EntryExit}(HR);
+// end_wpp
+#define WPP_FUNCRETURNHRLEVEL_HR_ENABLED(LEVEL, hr) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_FUNCRETURNHRLEVEL_HR_LOGGER(LEVEL, hr) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_FUNCRETURNHRLEVEL_HR_PRE(LEVEL, hr) { \
+ HRESULT __hr = hr;
+#define WPP_FUNCRETURNHRLEVEL_HR_POST(LEVEL, hr) ;return __hr; \
+ }
+
+// MACRO: FunctionReturnVoid
+//
+// begin_wpp config
+// USEPREFIX (FunctionReturnVoid, "%!STDPREFIX!%s<--%!FUNC!()", INDENT_STR(__pCtx->CallDepth));
+// FUNC FunctionReturnVoid{FUNCRETURNLEVELVOID=EntryExit}(...);
+// end_wpp
+#define WPP_FUNCRETURNLEVELVOID_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_FUNCRETURNLEVELVOID_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_FUNCRETURNLEVELVOID_POST(LEVEL) ;return;
+
+// MACRO: FunctionReturnBool
+//
+// begin_wpp config
+// USEPREFIX (FunctionReturnBool, "%!STDPREFIX!%s<--%!FUNC!(): %!bool!", INDENT_STR(__pCtx->CallDepth), __bRet);
+// FUNC FunctionReturnBool{FUNCRETURNLEVELBOOL=EntryExit}(BOOLRETVAL);
+// end_wpp
+#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_ENABLED(LEVEL, bRet) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_LOGGER(LEVEL, bRet) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_PRE(LEVEL, bRet) { \
+ bool __bRet = (bRet ? true : false);
+#define WPP_FUNCRETURNLEVELBOOL_BOOLRETVAL_POST(LEVEL, bRet) ;return __bRet; \
+ }
+
+// MACRO: FunctionReturnPtr
+//
+// begin_wpp config
+// USEPREFIX (FunctionReturnPtr, "%!STDPREFIX!%s<--%!FUNC!(): %p", INDENT_STR(__pCtx->CallDepth), __pRet);
+// FUNC FunctionReturnPtr{FUNCRETURNLEVELPTR=EntryExit}(TYPE, PRET);
+// end_wpp
+#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_ENABLED(LEVEL, Type, pRet) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_LOGGER(LEVEL, Type, pRet) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_PRE(LEVEL, Type, pRet) { \
+ Type __pRet = pRet;
+#define WPP_FUNCRETURNLEVELPTR_TYPE_PRET_POST(LEVEL, Type, pRet) ;return __pRet; \
+ }
+
+// MACRO: TraceASSERT
+//
+// begin_wpp config
+// USEPREFIX (TraceASSERT, "%!STDPREFIX!%sWARN: ASSERTION FAILED - expression \"%s\" is false.", INDENT_STR(__pCtx->CallDepth+1), #EXPR);
+// FUNC TraceASSERT{ASSERTLEVEL=Warning}(EXPR);
+// end_wpp
+#define WPP_ASSERTLEVEL_EXPR_ENABLED(LEVEL, EXPR) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_ASSERTLEVEL_EXPR_LOGGER(LEVEL, EXPR) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_ASSERTLEVEL_EXPR_PRE(LEVEL, EXPR) if (!(EXPR)) \
+ {
+#define WPP_ASSERTLEVEL_EXPR_POST(LEVEL, EXPR) ;NT_ASSERT(FALSE); \
+ }
+
+//MACRO: TraceErrorHR
+//
+// begin_wpp config
+// USEPREFIX (TraceErrorHR, "%!STDPREFIX!%sERROR: ", INDENT_STR(__pCtx->CallDepth+1));
+// FUNC TraceErrorHR{ERRORLEVEL=Error}(HR, MSG, ...);
+// USESUFFIX (TraceErrorHR, ": %!HRESULT!", HR);
+// end_wpp
+#define WPP_ERRORLEVEL_HR_ENABLED(LEVEL, HR) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_ERRORLEVEL_HR_LOGGER(LEVEL, HR) WPP_LEVEL_LOGGER(LEVEL)
+
+// MACRO: TraceInfo
+//
+// begin_wpp config
+// USEPREFIX (TraceInfo, "%!STDPREFIX!%s", INDENT_STR(__pCtx->CallDepth+1));
+// FUNC TraceInfo{INFOLEVEL=Info}(MSG, ...);
+// end_wpp
+#define WPP_INFOLEVEL_ENABLED(LEVEL) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_INFOLEVEL_LOGGER(LEVEL) WPP_LEVEL_LOGGER(LEVEL)