diff options
Diffstat (limited to 'nfc/Simulator')
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 Binary files differnew file mode 100644 index 00000000..465c3d5b --- /dev/null +++ b/nfc/Simulator/Src/NfcSimulator.inx 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) |
