summaryrefslogtreecommitdiff
path: root/nfc/Simulator/Src/SmartCard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nfc/Simulator/Src/SmartCard.cpp')
-rw-r--r--nfc/Simulator/Src/SmartCard.cpp312
1 files changed, 312 insertions, 0 deletions
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);
+}