summaryrefslogtreecommitdiff
path: root/nfp
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /nfp
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'nfp')
-rw-r--r--nfp/net/ReadMe.md11
-rw-r--r--nfp/net/driver/Connection.cpp296
-rw-r--r--nfp/net/driver/FileContext.cpp713
-rw-r--r--nfp/net/driver/FileContext.h340
-rw-r--r--nfp/net/driver/NetNfpProvider.vcxproj265
-rw-r--r--nfp/net/driver/NetNfpProvider.vcxproj.Filters60
-rw-r--r--nfp/net/driver/Queue.cpp824
-rw-r--r--nfp/net/driver/Queue.h175
-rw-r--r--nfp/net/driver/connection.h125
-rw-r--r--nfp/net/driver/device.cpp261
-rw-r--r--nfp/net/driver/device.h73
-rw-r--r--nfp/net/driver/dllsup.cpp112
-rw-r--r--nfp/net/driver/driver.cpp150
-rw-r--r--nfp/net/driver/driver.h53
-rw-r--r--nfp/net/driver/exports.def6
-rw-r--r--nfp/net/driver/internal.h152
-rw-r--r--nfp/net/driver/list.h119
-rw-r--r--nfp/net/driver/netnfpprovider.inx83
-rw-r--r--nfp/net/driver/netnfpprovider.rc18
-rw-r--r--nfp/net/driver/socketlistener.cpp222
-rw-r--r--nfp/net/driver/socketlistener.h84
-rw-r--r--nfp/net/driver/wppdefs.h452
-rw-r--r--nfp/net/exe/NetNfpControl.cpp579
-rw-r--r--nfp/net/exe/NetNfpControl.vcxproj262
-rw-r--r--nfp/net/exe/NetNfpControl.vcxproj.Filters25
-rw-r--r--nfp/net/exe/precomp.h37
-rw-r--r--nfp/net/exe/precompsrc.cpp1
-rw-r--r--nfp/net/inc/NetNfp.h32
-rw-r--r--nfp/net/netnfp.sln46
29 files changed, 5576 insertions, 0 deletions
diff --git a/nfp/net/ReadMe.md b/nfp/net/ReadMe.md
new file mode 100644
index 00000000..aeb2c630
--- /dev/null
+++ b/nfp/net/ReadMe.md
@@ -0,0 +1,11 @@
+Near-Field Proximity Sample Driver (UMDF Version 1)
+===================================================
+
+This sample demonstrates how to use User-Mode Driver Framework (UMDF) version 1 to write a near-field proximity driver.
+
+Typically, a near-field proximity driver would use near-field technologies such as Near Field Communication (NFC), TransferJet, or Bump. However, this sample uses a TCP/IPv6 network connection and a static configuration between two machines to simulate near-field interaction.
+
+Related technologies
+--------------------
+[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456)
+
diff --git a/nfp/net/driver/Connection.cpp b/nfp/net/driver/Connection.cpp
new file mode 100644
index 00000000..1aed9008
--- /dev/null
+++ b/nfp/net/driver/Connection.cpp
@@ -0,0 +1,296 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Author:
+
+ Travis Martin (TravM) 06-24-2010
+
+--*/
+#include "internal.h"
+
+#include "Connection.tmh"
+
+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 dwIgnore;
+ OVERLAPPED Overlapped;
+ ZeroMemory(&Overlapped, sizeof(Overlapped));
+ if (!ReadFile((HANDLE)Socket, pBuffer, cbBuffer, &dwIgnore, &Overlapped))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
+ {
+ if (!GetOverlappedResult((HANDLE)Socket, &Overlapped, &dwIgnore, TRUE))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+ }
+ return hr;
+}
+
+//CConnection
+// static
+HRESULT CConnection::Create(_In_ IConnectionCallback* pCallback, _Outptr_ CConnection** ppConnection)
+{
+ CConnection* pConnection;
+ pConnection = new CConnection(pCallback);
+ HRESULT hr = (pConnection != NULL ? S_OK : E_OUTOFMEMORY);
+ if (SUCCEEDED(hr))
+ {
+ *ppConnection = pConnection;
+ }
+
+ return hr;
+}
+
+void CConnection::Terminate()
+{
+ MethodEntry("void");
+
+ // Only want to terminate once
+ STATE PriorState = (STATE)(InterlockedExchange((long*)&_State, (long)TERMINATED));
+ if (PriorState != TERMINATED)
+ {
+ // Graceful shutdown
+ shutdown(_Socket, SD_SEND);
+
+ // Don't wait for threadpool callbacks when this thread is actually the threadpool callback
+ if (_ThreadpoolThreadId != GetCurrentThreadId())
+ {
+ // Let the ReceiveThreadProc gracefully shutdown
+ WaitForThreadpoolWorkCallbacks(_ThreadpoolWork, false);
+ }
+
+ SOCKET Socket = (SOCKET)InterlockedExchangePointer((PVOID*)&_Socket, (PVOID)INVALID_SOCKET);
+ if (Socket != INVALID_SOCKET)
+ {
+ closesocket(Socket);
+ }
+ }
+
+ MethodReturnVoid();
+}
+
+/* 9C7D2C68-5AD8-4A14-BE20-F8741D60D100 */
+const GUID MAGIC_PACKET =
+ {0x9C7D2C68, 0x5AD8, 0x4A14, {0xBE, 0x20, 0xF8, 0x74, 0x1D, 0x60, 0xD1, 0x00}};
+
+HRESULT CConnection::InitializeAsClient(_In_ BEGIN_PROXIMITY_ARGS* pArgs)
+{
+ pArgs->szName[MAX_PATH-1] = L'\0';
+
+ MethodEntry("pArgs->szName = '%S'",
+ pArgs->szName);
+
+ // Open a TCP/IP Socket to the remote Network NearFieldProximity device
+ HRESULT hr = S_OK;
+
+ _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, NULL))
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ TraceErrorHR(hr, L"WSAConnectByName FAILED");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (setsockopt(_Socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == SOCKET_ERROR)
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Send the Magic Packet
+ if (send(_Socket, (char*)&MAGIC_PACKET, sizeof(MAGIC_PACKET), 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, sizeof(MAGIC_PACKET)) != 0)
+ {
+ hr = E_FAIL;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // This doesn't take the socket, because we're the client and already
+ // have the socket in _Socket.
+ hr = FinalizeEstablish(INVALID_SOCKET);
+ }
+ }
+
+
+ if (FAILED(hr))
+ {
+ if (_Socket != INVALID_SOCKET)
+ {
+ // Abortive shutdown of the 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, sizeof(MAGIC_PACKET)) != 0)
+ {
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Send the MAGIC_PACKET
+ if (send(Socket, (char*)&MAGIC_PACKET, sizeof(MAGIC_PACKET), 0) == SOCKET_ERROR)
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = FinalizeEstablish(Socket);
+ }
+
+ if (FAILED(hr))
+ {
+ // Abortive shutdown of the socket
+ 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)
+ {
+ // Already established (or terminated), drop this
+ hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Init Threadpool work item for the receieve thread proc.
+ _ThreadpoolWork = CreateThreadpoolWork(s_ReceiveThreadProc, this, NULL);
+ if (_ThreadpoolWork == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ else
+ {
+ if (Socket != INVALID_SOCKET)
+ {
+ // Take ownership of the socket
+ _Socket = Socket;
+ }
+ SubmitThreadpoolWork(_ThreadpoolWork);
+
+ _pCallback->ConnectionEstablished(this);
+ }
+ }
+
+ MethodReturnHR(hr);
+}
+
+BOOL CConnection::ReceiveThreadProc()
+{
+ MethodEntry("void");
+
+ MESSAGE* pMessage = new MESSAGE();
+ if (pMessage == NULL)
+ {
+ Terminate();
+ }
+ else
+ {
+ while (_Socket != INVALID_SOCKET)
+ {
+ if (recv(_Socket, (char*)pMessage, sizeof(*pMessage), MSG_WAITALL) == sizeof(*pMessage))
+ {
+ _pCallback->HandleReceivedMessage(pMessage);
+ }
+ else
+ {
+ Terminate();
+ break;
+ }
+ }
+ delete pMessage;
+ }
+
+ // The connection is now terminated
+ BOOL fConnectionDeleted = _pCallback->ConnectionTerminated(this);
+
+ MethodReturnBool(fConnectionDeleted);
+}
+
+HRESULT CConnection::TransmitMessage(_In_ MESSAGE* pMessage)
+{
+ 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();
+ }
+ }
+
+ return hr;
+}
+
diff --git a/nfp/net/driver/FileContext.cpp b/nfp/net/driver/FileContext.cpp
new file mode 100644
index 00000000..193c637a
--- /dev/null
+++ b/nfp/net/driver/FileContext.cpp
@@ -0,0 +1,713 @@
+/*++
+
+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:
+
+ user mode only
+
+Revision History:
+
+--*/
+#include "internal.h"
+
+#include "FileContext.tmh"
+
+CFileContext::~CFileContext()
+{
+ MethodEntry("void");
+
+ while (!IsListEmpty(&m_SubscribedMessageQueue))
+ {
+ delete CMyPayload::FromListEntry(RemoveHeadList(&m_SubscribedMessageQueue));
+ }
+
+ if (m_pszType != NULL)
+ {
+ delete [] m_pszType;
+ m_pszType = NULL;
+ }
+
+ if (m_pConnection != NULL)
+ {
+ delete m_pConnection;
+ m_pConnection = NULL;
+ }
+
+ m_pWdfFile = NULL;
+
+ EnterCriticalSection(&m_RoleLock);
+ CompleteRequest(E_ABORT, 0, true);
+ LeaveCriticalSection(&m_RoleLock);
+
+ DeleteCriticalSection(&m_RoleLock);
+
+ MethodReturnVoid();
+}
+
+HRESULT
+CFileContext::Disable()
+{
+ MethodEntry("void");
+
+ EnterCriticalSection(&m_RoleLock);
+
+ HRESULT hr = S_OK;
+ if ((m_Role == ROLE_UNDEFINED) || (m_Role == ROLE_PROXIMITY))
+ {
+ // Only Pub/Sub handles can be disabled
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+
+ if (!m_fEnabled)
+ {
+ // Already disabled
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ m_fEnabled = FALSE;
+
+ CompleteRequest(HRESULT_FROM_NT(STATUS_CANCELLED), 0, true);
+
+ // Purge all already received payloads
+ while (!IsListEmpty(&m_SubscribedMessageQueue))
+ {
+ delete CMyPayload::FromListEntry(RemoveHeadList(&m_SubscribedMessageQueue));
+ }
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnHR(hr);
+}
+
+HRESULT
+CFileContext::Enable()
+{
+ MethodEntry("void");
+
+ EnterCriticalSection(&m_RoleLock);
+
+ HRESULT hr = S_OK;
+ if ((m_Role == ROLE_UNDEFINED) || (m_Role == ROLE_PROXIMITY))
+ {
+ // Only Pub/Sub handles can be enabled
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+
+ if (m_fEnabled)
+ {
+ // Already enabled
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ m_fEnabled = TRUE;
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnHR(hr);
+}
+
+HRESULT
+CFileContext::SetType(_In_ PCWSTR pszType)
+{
+ MethodEntry("pszType = '%S'", pszType);
+
+ HRESULT hr = S_OK;
+ WUDF_SAMPLE_DRIVER_ASSERT(m_pszType == NULL);
+
+ SIZE_T cchStr = wcslen(pszType) + 1;
+ if ((cchStr > MinCchType) && (cchStr < MaxCchType))
+ {
+ m_pszType = new WCHAR[cchStr];
+ if (m_pszType != NULL)
+ {
+ hr = StringCchCopy(m_pszType, cchStr, pszType);
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+
+ MethodReturnHR(hr);
+}
+
+#define STATUS_BUFFER_TOO_SMALL 0xC0000023L
+#define STATUS_BUFFER_OVERFLOW 0x80000005L
+
+
+bool
+CFileContext::CompleteOneGetNextSubscribedMessage(
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_opt_(cbPayload) PBYTE pbPayload
+ )
+/*
+ * m_RoleLock must already be acquired
+ */
+{
+ MethodEntry("cbPayload = 0x%d",
+ (DWORD)cbPayload);
+
+ WUDF_SAMPLE_DRIVER_ASSERT(m_pWdfRequest != NULL);
+
+ bool fDelivered = false;
+ IWDFMemory* pWdfOutputMemory;
+ m_pWdfRequest->GetOutputMemory(&pWdfOutputMemory);
+ if (pWdfOutputMemory != NULL)
+ {
+ SIZE_T cbOutputBuffer = 0;
+ // Set the first 4 bytes as the size of the payload as a hint for future
+ // subscriptions.
+ HRESULT hr = pWdfOutputMemory->CopyFromBuffer(0, &cbPayload, 4);
+ if (SUCCEEDED(hr))
+ {
+ cbOutputBuffer = 4;
+ if (pbPayload != NULL)
+ {
+ if (pWdfOutputMemory->GetSize() < (cbPayload + 4))
+ {
+ // We are unable to copy the payload into the output memory,
+ // Returning this signals to the client to send a bigger buffer
+ hr = HRESULT_FROM_NT(STATUS_BUFFER_OVERFLOW);
+ }
+ else
+ {
+ hr = pWdfOutputMemory->CopyFromBuffer(4, pbPayload, cbPayload);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ fDelivered = true;
+ cbOutputBuffer += cbPayload;
+ if (m_dwQueueSize > 0)
+ {
+ m_dwQueueSize--;
+ }
+ }
+ }
+ pWdfOutputMemory->Release();
+
+ if (!CompleteRequest(hr, cbOutputBuffer, true))
+ {
+ fDelivered = false;
+ }
+ }
+
+ MethodReturnBool(fDelivered);
+}
+
+HRESULT
+CFileContext::GetNextSubscribedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest)
+{
+ MethodEntry("...");
+
+ EnterCriticalSection(&m_RoleLock);
+
+ HRESULT hr = S_OK;
+ if (m_pWdfRequest != NULL)
+ {
+ // Only one pended request at a time allowed
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+
+ if (!m_fEnabled)
+ {
+ // The handle is disabled
+ hr = HRESULT_FROM_NT(HRESULT_FROM_NT(STATUS_CANCELLED));
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ IWDFMemory* pWdfInputMemory;
+ pWdfRequest->GetInputMemory(&pWdfInputMemory);
+ SIZE_T cbInput;
+ if (pWdfInputMemory->GetDataBuffer(&cbInput) == NULL)
+ {
+ if (m_Role == ROLE_SUBSCRIPTION)
+ {
+ m_pWdfRequest = pWdfRequest;
+ m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread
+
+ if ((m_pWdfRequest != NULL) && !IsListEmpty(&m_SubscribedMessageQueue))
+ {
+ CMyPayload* pMyPayload =
+ CMyPayload::FromListEntry(m_SubscribedMessageQueue.Flink);
+
+ if (CompleteOneGetNextSubscribedMessage(pMyPayload->GetSize(),
+ pMyPayload->GetPayload()))
+ {
+ RemoveHeadList(&m_SubscribedMessageQueue);
+ delete pMyPayload;
+ }
+ }
+ }
+ else if (m_Role == ROLE_ARRIVEDSUBSCRIPTION)
+ {
+ m_pWdfRequest = pWdfRequest;
+ m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread
+ if (m_pWdfRequest != NULL)
+ {
+ CompleteOneArrivalEvent();
+ }
+ }
+ else if (m_Role == ROLE_DEPARTEDSUBSCRIPTION)
+ {
+ m_pWdfRequest = pWdfRequest;
+ m_pWdfRequest->MarkCancelable(pCallbackCancel); // MarkCancelable can run the OnCancel routine in this thread
+ if (m_pWdfRequest != NULL)
+ {
+ CompleteOneRemovalEvent();
+ }
+ }
+ else
+ {
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ pWdfInputMemory->Release();
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnHR(hr);
+}
+
+HRESULT
+CFileContext::SetPayload(_In_ IWDFIoRequest* pWdfRequest)
+{
+ MethodEntry("...");
+
+ EnterCriticalSection(&m_RoleLock);
+
+ HRESULT hr = S_OK;
+ if ((m_Role != ROLE_PUBLICATION) || (m_MyPayload.GetPayload() != NULL))
+ {
+ // SetPayload can only be called once per handle
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ IWDFMemory* pWdfOutputMemory;
+ pWdfRequest->GetOutputMemory(&pWdfOutputMemory);
+ SIZE_T cbOutput;
+ if (pWdfOutputMemory->GetDataBuffer(&cbOutput) == NULL)
+ {
+ IWDFMemory* pWdfMemory;
+ pWdfRequest->GetInputMemory(&pWdfMemory);
+ if (pWdfMemory != NULL)
+ {
+ SIZE_T cbPayload = pWdfMemory->GetSize();
+ if ((cbPayload > 0) && (cbPayload <= MaxCbPayload))
+ {
+ hr = m_MyPayload.Initialize((DWORD)cbPayload, (PBYTE)pWdfMemory->GetDataBuffer(NULL));
+ }
+ else
+ {
+ hr = HRESULT_FROM_NT(STATUS_INVALID_BUFFER_SIZE);
+ }
+
+ pWdfMemory->Release();
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ pWdfOutputMemory->Release();
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnHR(hr);
+}
+
+HRESULT
+CFileContext::GetNextTransmittedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest)
+{
+ MethodEntry("...");
+
+ EnterCriticalSection(&m_RoleLock);
+
+ HRESULT hr = S_OK;
+ if ((m_Role != ROLE_PUBLICATION) || (m_pWdfRequest != NULL))
+ {
+ // Only one pended request at a time allowed
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+
+ if (!m_fEnabled)
+ {
+ // The handle is disabled
+ hr = HRESULT_FROM_NT(HRESULT_FROM_NT(STATUS_CANCELLED));
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ IWDFMemory* pWdfInputMemory;
+ pWdfRequest->GetInputMemory(&pWdfInputMemory);
+ SIZE_T cbInput;
+ if (pWdfInputMemory->GetDataBuffer(&cbInput) == NULL)
+ {
+ IWDFMemory* pWdfOutputMemory;
+ pWdfRequest->GetOutputMemory(&pWdfOutputMemory);
+ SIZE_T cbOutput;
+ if (pWdfOutputMemory->GetDataBuffer(&cbOutput) == NULL)
+ {
+ m_pWdfRequest = pWdfRequest;
+
+ if (m_cCompleteReady > 0)
+ {
+ if (CompleteRequest(S_OK, 0, false))
+ {
+ m_cCompleteReady--;
+ }
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ pWdfOutputMemory->Release();
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ pWdfInputMemory->Release();
+ }
+
+ if (SUCCEEDED(hr) && (m_pWdfRequest != NULL))
+ {
+ m_pWdfRequest->MarkCancelable(pCallbackCancel);
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnHR(hr);
+}
+
+HRESULT
+CFileContext::BeginProximity(
+ _In_ IWDFIoRequest* pWdfRequest,
+ _In_ IConnectionCallback* pCallback
+ )
+{
+ MethodEntry("...");
+
+ EnterCriticalSection(&m_RoleLock);
+
+ HRESULT hr = S_OK;
+ if (m_Role != ROLE_UNDEFINED)
+ {
+ // BeginProximity can only be called once per handle
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ }
+ else
+ {
+ m_Role = ROLE_PROXIMITY;
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ if (SUCCEEDED(hr))
+ {
+ IWDFMemory* pWdfMemory;
+ pWdfRequest->GetInputMemory(&pWdfMemory);
+ if (pWdfMemory != NULL)
+ {
+ if (pWdfMemory->GetSize() == sizeof(BEGIN_PROXIMITY_ARGS))
+ {
+ hr = CConnection::Create(pCallback, &m_pConnection);
+ if (SUCCEEDED(hr))
+ {
+ BEGIN_PROXIMITY_ARGS* pArgs =
+ (BEGIN_PROXIMITY_ARGS*)pWdfMemory->GetDataBuffer(NULL);
+ hr = m_pConnection->InitializeAsClient(pArgs);
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+
+ pWdfMemory->Release();
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+
+
+ if (FAILED(hr))
+ {
+ m_pConnection = NULL;
+ }
+
+ MethodReturnHR(hr);
+}
+
+VOID
+CFileContext::HandleArrivalEvent()
+{
+ WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_ARRIVEDSUBSCRIPTION);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ if (m_fEnabled)
+ {
+ m_cCompleteReady++;
+ CompleteOneArrivalEvent();
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+}
+
+VOID
+CFileContext::HandleRemovalEvent()
+{
+ WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_DEPARTEDSUBSCRIPTION);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ if (m_fEnabled)
+ {
+ m_cCompleteReady++;
+ CompleteOneRemovalEvent();
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+}
+
+VOID
+CFileContext::CompleteOneArrivalEvent()
+{
+ MethodEntry("void");
+
+ WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_ARRIVEDSUBSCRIPTION);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ if (m_cCompleteReady > 0)
+ {
+ if (m_pWdfRequest != NULL)
+ {
+ // Arrival payload should either be a DWORD = 1 or 0
+ // 1 == Device capable of bi-directional communication
+ // 0 == Device is a dumb tag
+ DWORD ArrivalFlags = 0x1;
+ if (CompleteOneGetNextSubscribedMessage(sizeof(ArrivalFlags), (PBYTE)&ArrivalFlags))
+ {
+ m_cCompleteReady--;
+ }
+ }
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnVoid();
+}
+
+VOID
+CFileContext::CompleteOneRemovalEvent()
+{
+ MethodEntry("void");
+
+ WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_DEPARTEDSUBSCRIPTION);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ if (m_cCompleteReady > 0)
+ {
+ if (m_pWdfRequest != NULL)
+ {
+ // Removal payload should be a single zeroed DWORD
+ DWORD RemovalFlags = 0x0;
+ if (CompleteOneGetNextSubscribedMessage(sizeof(RemovalFlags), (PBYTE)&RemovalFlags))
+ {
+ m_cCompleteReady--;
+ }
+ }
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnVoid();
+}
+
+void
+CFileContext::HandleReceivedPublication(
+ _In_ PCWSTR pszType,
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+{
+ MethodEntry("...");
+
+ WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_SUBSCRIPTION);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ if (m_fEnabled)
+ {
+ bool fSubscriptionMatches = false;
+ BYTE* pbNewPayload = NULL;
+
+ 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))
+ {
+ // If this is a WindowsMime message, and the subscription is for the general WINDOWSMIME_PROTOCOL type,
+ // the Mime type needs to be added to the message payload.
+ CHAR szMimeType[MaxCchMimeType + 1] = {};
+ // Copy the mime type and convert from wide to multibyte chars
+ if (SUCCEEDED(StringCchPrintfA(szMimeType, ARRAYSIZE(szMimeType), "%S", pszType + WINDOWSMIME_PROTOCOL_CHARS + 1)))
+ {
+ pbNewPayload = new BYTE[cbPayload + MaxCchMimeType];
+ if (pbNewPayload != NULL)
+ {
+ TraceInfo("Received Mime message of type = '%s'", szMimeType);
+ CopyMemory(pbNewPayload, szMimeType, MaxCchMimeType);
+ CopyMemory(pbNewPayload + MaxCchMimeType, pbPayload, cbPayload);
+ cbPayload += MaxCchMimeType;
+ pbPayload = pbNewPayload;
+
+ fSubscriptionMatches = true;
+ }
+ }
+ }
+ else if (CompareStringOrdinal(pszType, -1, m_pszType, -1, FALSE) == CSTR_EQUAL)
+ {
+ fSubscriptionMatches = true;
+ }
+
+ if (fSubscriptionMatches)
+ {
+ bool fDelivered = false;
+
+ if (m_pWdfRequest != NULL)
+ {
+ fDelivered = CompleteOneGetNextSubscribedMessage(cbPayload, pbPayload);
+ }
+
+ if ((!fDelivered) && (m_dwQueueSize < MAX_MESSAGE_QUEUE_SIZE))
+ {
+ // Add message to the client delivery queue
+
+ CMyPayload* pMyPayload = new CMyPayload();
+ if (pMyPayload)
+ {
+ if (SUCCEEDED(pMyPayload->Initialize(cbPayload, pbPayload)))
+ {
+ InsertTailList(&m_SubscribedMessageQueue, pMyPayload->GetListEntry());
+ m_dwQueueSize++;
+ }
+ else
+ {
+ delete pMyPayload;
+ }
+ }
+ }
+ }
+
+ delete [] pbNewPayload;
+ }
+ else
+ {
+ TraceErrorHR(HRESULT_FROM_NT(STATUS_CANCELLED), "Subscription Disabled!");
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnVoid();
+}
+
+void
+CFileContext::HandleMessageTransmitted()
+{
+ MethodEntry("void");
+
+ WUDF_SAMPLE_DRIVER_ASSERT(m_Role == ROLE_PUBLICATION);
+
+ EnterCriticalSection(&m_RoleLock);
+
+ if (!CompleteRequest(S_OK, 0, true))
+ {
+ m_cCompleteReady++;
+ }
+
+ LeaveCriticalSection(&m_RoleLock);
+
+ MethodReturnVoid();
+}
+
+void
+CFileContext::OnCancel()
+{
+ EnterCriticalSection(&m_RoleLock);
+
+ CompleteRequest(E_ABORT, 0, false);
+
+ LeaveCriticalSection(&m_RoleLock);
+}
+
+bool
+CFileContext::CompleteRequest(_In_ HRESULT hr, _In_ SIZE_T cbSize, _In_ bool fIsCancelable)
+/*
+ * m_RoleLock must already be acquired
+ */
+{
+ MethodEntry("hr = %!HRESULT!, cbSize = %d, fIsCancelable = %!bool!",
+ hr, (DWORD)cbSize, fIsCancelable);
+
+ bool fCompleted = false;
+ if (m_pWdfRequest != NULL)
+ {
+ bool fCompleteRequest = true;
+ if (fIsCancelable)
+ {
+ if (m_pWdfRequest->UnmarkCancelable() == HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED))
+ {
+ fCompleteRequest = false;
+ }
+ }
+
+ if (fCompleteRequest)
+ {
+ m_pWdfRequest->CompleteWithInformation(hr, cbSize);
+ m_pWdfRequest = NULL;
+ fCompleted = true;
+ }
+ }
+
+ MethodReturnBool(fCompleted);
+}
diff --git a/nfp/net/driver/FileContext.h b/nfp/net/driver/FileContext.h
new file mode 100644
index 00000000..0247636e
--- /dev/null
+++ b/nfp/net/driver/FileContext.h
@@ -0,0 +1,340 @@
+/*++
+
+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:
+
+ user mode only
+
+Revision History:
+
+--*/
+#pragma once
+
+class CMyPayload
+{
+public:
+ CMyPayload()
+ {
+ m_pbPayload = NULL;
+ m_cbPayload = 0;
+
+ InitializeListHead(&m_ListEntry);
+ }
+ ~CMyPayload()
+ {
+ if (m_pbPayload != NULL)
+ {
+ delete [] m_pbPayload;
+ m_pbPayload = NULL;
+ }
+ }
+
+ STDMETHOD(Initialize)(
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+ {
+ HRESULT hr = S_OK;
+ m_pbPayload = new BYTE[cbPayload];
+ if (m_pbPayload != NULL)
+ {
+ m_cbPayload = cbPayload;
+ CopyMemory(m_pbPayload, pbPayload, cbPayload);
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+ return hr;
+ }
+
+ PBYTE GetPayload()
+ {
+ return m_pbPayload;
+ }
+ DWORD GetSize()
+ {
+ return m_cbPayload;
+ }
+
+ PLIST_ENTRY GetListEntry()
+ {
+ return &m_ListEntry;
+ }
+ static CMyPayload* FromListEntry(PLIST_ENTRY pEntry)
+ {
+ return (CMyPayload*) CONTAINING_RECORD(pEntry, CMyPayload, m_ListEntry);
+ }
+
+private:
+ PBYTE m_pbPayload;
+ DWORD m_cbPayload;
+
+ LIST_ENTRY m_ListEntry;
+};
+
+/*
+ * Use this to refactor to only keep one copy of received messages
+ *
+class CMyPayloadItem
+{
+public:
+ CMyPayloadItem(_In_ CMyPayload* pPayload)
+ {
+ m_spPayload = pPayload;
+ InitializeListHead(&m_ListEntry);
+ }
+ ~CMyPayloadItem()
+ {
+ }
+
+ PBYTE GetPayload()
+ {
+ return m_spPayload->GetPayload();
+ }
+ DWORD GetSize()
+ {
+ return m_spPayload->GetSize();
+ }
+
+ PLIST_ENTRY GetListEntry()
+ {
+ return &m_ListEntry;
+ }
+ static CMyPayloadItem* FromListEntry(PLIST_ENTRY pEntry)
+ {
+ return (CMyPayloadItem*) CONTAINING_RECORD(pEntry, CMyPayloadItem, m_ListEntry);
+ }
+
+private:
+ CComPtr<CMyPayload> m_spPayload;
+
+ LIST_ENTRY m_ListEntry;
+};
+*/
+
+class CFileContext
+{
+public:
+
+ CFileContext() :
+ m_Role(ROLE_UNDEFINED),
+ m_pszType(NULL),
+ m_fEnabled(TRUE),
+ m_dwQueueSize(0),
+ m_cCompleteReady(0),
+ m_pConnection(NULL),
+ m_pWdfRequest(NULL)
+ {
+ InitializeListHead(&m_SubscribedMessageQueue);
+
+ InitializeListHead(&m_ListEntry);
+
+ InitializeCriticalSection(&m_RoleLock);
+ }
+
+ ~CFileContext();
+
+ HRESULT
+ Disable();
+
+ HRESULT
+ Enable();
+
+ HRESULT
+ SetType(_In_ PCWSTR pszType);
+
+ HRESULT
+ GetNextSubscribedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest);
+
+ HRESULT
+ SetPayload(_In_ IWDFIoRequest* pWdfRequest);
+
+ HRESULT
+ GetNextTransmittedMessage(_In_ IRequestCallbackCancel* pCallbackCancel, _In_ IWDFIoRequest* pWdfRequest);
+
+ HRESULT
+ BeginProximity(
+ _In_ IWDFIoRequest* pWdfRequest,
+ _In_ IConnectionCallback* pCallback
+ );
+
+ VOID
+ HandleArrivalEvent();
+ VOID
+ HandleRemovalEvent();
+
+ void
+ HandleReceivedPublication(
+ _In_ PCWSTR pszType,
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ );
+
+ void
+ HandleMessageTransmitted();
+
+ void
+ OnCancel();
+
+ 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;
+ }
+
+ 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);
+ }
+ BOOL
+ IsPublication()
+ {
+ return (m_Role == ROLE_PUBLICATION);
+ }
+
+ PCWSTR
+ GetType()
+ {
+ return m_pszType;
+ }
+
+ DWORD
+ GetSize()
+ {
+ return m_MyPayload.GetSize();
+ }
+
+ PBYTE
+ GetPayload()
+ {
+ return m_MyPayload.GetPayload();
+ }
+
+ BOOL
+ IsEnabled()
+ {
+ return m_fEnabled;
+ }
+
+ PLIST_ENTRY GetListEntry()
+ {
+ return &m_ListEntry;
+ }
+ static CFileContext* FromListEntry(PLIST_ENTRY pEntry)
+ {
+ return (CFileContext*) CONTAINING_RECORD(pEntry, CFileContext, m_ListEntry);
+ }
+
+private:
+
+ VOID
+ CompleteOneArrivalEvent();
+ VOID
+ CompleteOneRemovalEvent();
+
+ bool
+ CompleteOneGetNextSubscribedMessage(
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_opt_(cbPayload) PBYTE pbPayload
+ );
+
+ bool
+ CompleteRequest(
+ _In_ HRESULT hr,
+ _In_ SIZE_T cbSize,
+ _In_ bool fIsCancelable
+ );
+
+private:
+
+ enum ROLE
+ {
+ ROLE_UNDEFINED,
+ ROLE_SUBSCRIPTION,
+ ROLE_ARRIVEDSUBSCRIPTION,
+ ROLE_DEPARTEDSUBSCRIPTION,
+ ROLE_PUBLICATION,
+ ROLE_PROXIMITY
+ };
+
+ ROLE m_Role;
+
+ PWSTR m_pszType;
+
+ BOOL m_fEnabled;
+
+ DWORD m_dwQueueSize;
+
+ // Queue of received messages
+ LIST_ENTRY m_SubscribedMessageQueue; // Unique to ROLE_SUBSCRIPTION
+
+ CMyPayload m_MyPayload; // Unique to ROLE_PUBLICATION
+ SIZE_T m_cCompleteReady; // Unique to ROLE_PUBLICATION, ROLE_ARRIVEDSUBSCRIPTION, and ROLE_DEPARTEDSUBSCRIPTION
+
+ CConnection* m_pConnection; // Unique to ROLE_PROXIMITY
+
+ // Pended "Get Next" Request.
+ IWDFIoRequest* m_pWdfRequest;
+
+ // The Fx File object this CFileObject is a companion to
+ IWDFFile* m_pWdfFile;
+
+ CRITICAL_SECTION m_RoleLock;
+
+ LIST_ENTRY m_ListEntry;
+};
diff --git a/nfp/net/driver/NetNfpProvider.vcxproj b/nfp/net/driver/NetNfpProvider.vcxproj
new file mode 100644
index 00000000..da21fa09
--- /dev/null
+++ b/nfp/net/driver/NetNfpProvider.vcxproj
@@ -0,0 +1,265 @@
+<?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>{756016BF-4187-4482-A0BE-CEE1698BD129}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{9E5FA410-9825-4FD4-845A-FFEDEE9AF94B}</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="dllsup.cpp; driver.cpp; device.cpp; queue.cpp; connection.cpp; FileContext.cpp; SocketListener.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ </ClCompile>
+ <Inf Include="NetNfpProvider.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <Verbose>true</Verbose>
+ <CopyOutput>.\$(IntDir)\NetNfpProvider.inf</CopyOutput>
+ </Inf>
+ <OtherWpp Include="NetNfpProvider.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppScanConfigurationData>WppDefs.h</WppScanConfigurationData>
+ </OtherWpp>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>NetNfpProvider</TargetName>
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>NetNfpProvider</TargetName>
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>NetNfpProvider</TargetName>
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>NetNfpProvider</TargetName>
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol>
+ <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib;$(SDK_LIB_PATH)\mswsock.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="NetNfpProvider.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </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/nfp/net/driver/NetNfpProvider.vcxproj.Filters b/nfp/net/driver/NetNfpProvider.vcxproj.Filters
new file mode 100644
index 00000000..cfe106d2
--- /dev/null
+++ b/nfp/net/driver/NetNfpProvider.vcxproj.Filters
@@ -0,0 +1,60 @@
+<?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>{1A46FC37-1F58-4A1C-AD58-4C8F0BFF8004}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{558A638D-8A37-44D7-BB58-296F1AEE8066}</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>{06C2D74D-F153-45FD-9B8F-09D1A0CD979F}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{D6F88F8A-6CD0-44DA-BC07-EEFF2E791D12}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="connection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllsup.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="queue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SocketListener.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="exports.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\NetNfpProvider.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include="NetNfpProvider.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="NetNfpProvider.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/nfp/net/driver/Queue.cpp b/nfp/net/driver/Queue.cpp
new file mode 100644
index 00000000..129a5439
--- /dev/null
+++ b/nfp/net/driver/Queue.cpp
@@ -0,0 +1,824 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ queue.cpp
+
+Abstract:
+
+ This file implements the I/O queue interface and performs
+ the read/write/ioctl operations.
+
+Environment:
+
+ user mode only
+
+Revision History:
+
+--*/
+#include "internal.h"
+
+#include "queue.tmh"
+
+CMyQueue::CMyQueue(
+ VOID
+ )
+{
+ InitializeListHead(&m_SubsHead);
+ InitializeListHead(&m_ArrivalSubsHead);
+ InitializeListHead(&m_DepartureSubsHead);
+ InitializeListHead(&m_PubsHead);
+ InitializeListHead(&m_ConnectionHead);
+
+ InitializeCriticalSection(&m_SubsLock);
+ InitializeCriticalSection(&m_PubsLock);
+ InitializeCriticalSection(&m_ConnectionLock);
+}
+
+CMyQueue::~CMyQueue(
+ VOID
+ )
+{
+ MethodEntry("void");
+
+ m_SocketListener.StopAccepting();
+
+ while (!IsListEmpty(&m_ConnectionHead))
+ {
+ delete CConnection::FromListEntry(RemoveHeadList(&m_ConnectionHead));
+ }
+
+ DeleteCriticalSection(&m_SubsLock);
+ DeleteCriticalSection(&m_PubsLock);
+ DeleteCriticalSection(&m_ConnectionLock);
+}
+
+//
+// Initialize
+//
+
+HRESULT
+CMyQueue::Initialize(
+ _In_ CMyDevice * Device
+ )
+/*++
+
+Routine Description:
+
+ Queue Initialize helper routine.
+ This routine will Create a default parallel queue associated with the Fx device object
+ and pass the IUnknown for this queue
+
+Aruments:
+ Device object pointer
+
+Return Value:
+
+ S_OK if Initialize succeeds
+
+--*/
+{
+ MethodEntry("...");
+
+ CComPtr<IWDFIoQueue> fxQueue;
+
+ HRESULT hr;
+
+ //
+ // Create the I/O Queue object.
+ //
+ {
+ CComPtr<IUnknown> pUnk;
+
+ HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk);
+
+ WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI));
+
+ hr = Device->GetFxDevice()->CreateIoQueue(
+ pUnk,
+ TRUE,
+ WdfIoQueueDispatchParallel,
+ TRUE,
+ FALSE,
+ &fxQueue
+ );
+ }
+
+ if (FAILED(hr))
+ {
+ TraceErrorHR(hr, "Failed to initialize driver queue");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_SocketListener.Bind();
+ if (FAILED(hr))
+ {
+ TraceErrorHR(hr, "Failed to Bind");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_SocketListener.EnableAccepting(this);
+ if (FAILED(hr))
+ {
+ TraceErrorHR(hr, "Failed to EnableAccepting");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ m_FxQueue = fxQueue;
+ }
+
+ MethodReturnHR(hr);
+}
+
+HRESULT
+CMyQueue::Configure(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Queue configuration function .
+ It is called after queue object has been succesfully initialized.
+
+Aruments:
+
+ NONE
+
+ Return Value:
+
+ S_OK if succeeds.
+
+--*/
+{
+ MethodEntry("void");
+
+ HRESULT hr = S_OK;
+
+ MethodReturnHR(hr);
+}
+
+
+STDMETHODIMP_(void)
+CMyQueue::OnCreateFile(
+ _In_ IWDFIoQueue* /*pWdfQueue*/,
+ _In_ IWDFIoRequest* pWdfRequest,
+ _In_ IWDFFile* pWdfFile
+ )
+
+/*++
+
+Routine Description:
+
+ Create callback from the framework for this default parallel queue
+
+ The create request will create a socket connection , create a file i/o target associated
+ with the socket handle for this connection and store in the file object context.
+
+Aruments:
+
+ pWdfQueue - Framework Queue instance
+ pWdfRequest - Framework Request instance
+ pWdfFile - WDF file object for this create
+
+ Return Value:
+
+ VOID
+
+--*/
+{
+ MethodEntry("pWdfRequest = %p, pWdfFile = %p",
+ pWdfRequest, pWdfFile);
+
+ HRESULT hr = S_OK;
+
+ //
+ // Create file context for this file object
+ //
+
+ CFileContext *pContext = new CFileContext();
+ if (NULL == pContext)
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+ TraceErrorHR(hr, "Could not create file context");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ DWORD cchFileName = 0;
+ hr = pWdfFile->RetrieveFileName(NULL, &cchFileName);
+ if (SUCCEEDED(hr) && (cchFileName > 0) && (cchFileName <= MaxCchType))
+ {
+ // Allocate a buffer big enough for the filename plus some extra to prevent
+ // overruns in the parsing below: The extra needs to be larger than the biggest
+ // *_CHARS value. The value 20 is overly big, but allows room to grow without
+ // hitting the OACR issue again. If the OACR issue is hit, just increase this
+ // to be larger than the biggest *_CHARS value used below in parsing.
+ DWORD cchFileNameBuffer = cchFileName + 20;
+ PWSTR pszFileNameBuffer = new WCHAR[cchFileNameBuffer];
+ hr = (pszFileNameBuffer != NULL) ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr))
+ {
+ ZeroMemory(pszFileNameBuffer, cchFileNameBuffer * sizeof(WCHAR));
+
+ hr = pWdfFile->RetrieveFileName(pszFileNameBuffer, &cchFileName);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ PCWSTR pszFileName = pszFileNameBuffer;
+ if (pszFileNameBuffer[0] == L'\\')
+ {
+ // If it exists, remove the inital slash
+ pszFileName++;
+ cchFileName--;
+ }
+
+ TraceInfo("cchFileName = %d, pszFileName = %S", cchFileName, pszFileName);
+
+ PCWSTR pszProtocol = NULL;
+ if (CompareStringOrdinal(pszFileName, PUBS_NAMESPACE_CHARS,
+ PUBS_NAMESPACE, PUBS_NAMESPACE_CHARS,
+ TRUE) == CSTR_EQUAL)
+ {
+ pContext->SetRolePublication();
+ pszProtocol = pszFileName + PUBS_NAMESPACE_CHARS;
+ }
+ else if (CompareStringOrdinal(pszFileName, SUBS_NAMESPACE_CHARS,
+ SUBS_NAMESPACE, SUBS_NAMESPACE_CHARS,
+ TRUE) == CSTR_EQUAL)
+ {
+ pContext->SetRoleSubcription();
+ pszProtocol = pszFileName + SUBS_NAMESPACE_CHARS;
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (CompareStringOrdinal(pszProtocol, WINDOWS_PROTOCOL_CHARS,
+ WINDOWS_PROTOCOL, WINDOWS_PROTOCOL_CHARS,
+ TRUE) == CSTR_EQUAL)
+ {
+ pContext->SetType(pszProtocol);
+ }
+ else if (CompareStringOrdinal(pszProtocol, -1,
+ WINDOWSURI_PROTOCOL, -1,
+ TRUE) == CSTR_EQUAL)
+ {
+ pContext->SetType(pszProtocol);
+ }
+ else if (CompareStringOrdinal(pszProtocol, WINDOWSMIME_PROTOCOL_CHARS,
+ WINDOWSMIME_PROTOCOL, WINDOWSMIME_PROTOCOL_CHARS,
+ TRUE) == CSTR_EQUAL)
+ {
+ pContext->SetType(pszProtocol);
+ }
+ else if (CompareStringOrdinal(pszProtocol, -1, DEVICE_ARRIVED, -1,
+ TRUE) == CSTR_EQUAL)
+ {
+ if (!pContext->SetRoleArrivedSubcription())
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ else if (CompareStringOrdinal(pszProtocol, -1, DEVICE_DEPARTED, -1,
+ TRUE) == CSTR_EQUAL)
+ {
+ if (!pContext->SetRoleDepartedSubcription())
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ else if (CompareStringOrdinal(pszProtocol, PAIRING_PROTOCOL_CHARS,
+ PAIRING_PROTOCOL, PAIRING_PROTOCOL_CHARS,
+ TRUE) == CSTR_EQUAL)
+ {
+ pContext->SetType(pszProtocol);
+ }
+ else if (CompareStringOrdinal(pszProtocol, NDEF_PROTOCOL_CHARS,
+ NDEF_PROTOCOL, NDEF_PROTOCOL_CHARS,
+ TRUE) == CSTR_EQUAL)
+ {
+ PCWSTR pszType = pszProtocol + NDEF_PROTOCOL_CHARS;
+
+ if (CompareStringOrdinal(pszType, NDEF_EMPTY_TYPE_CHARS,
+ NDEF_EMPTY_TYPE, NDEF_EMPTY_TYPE_CHARS,
+ TRUE) != CSTR_EQUAL)
+ {
+ pContext->SetType(pszProtocol);
+ }
+ else
+ {
+ hr = HRESULT_FROM_NT(STATUS_INVALID_PARAMETER);
+ }
+ }
+ else
+ {
+ hr = HRESULT_FROM_NT(STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+ }
+ }
+
+ if (pszFileNameBuffer != NULL)
+ {
+ delete [] pszFileNameBuffer;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pWdfFile->AssignContext(NULL, (void*)pContext);
+ if (FAILED(hr))
+ {
+ TraceErrorHR(hr, "Unable to Assign Context to this File Object");
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ EnterCriticalSection(&m_SubsLock);
+
+ if (pContext->IsNormalSubscription())
+ {
+ // Place this CFileContext into a list of Subscriptions
+ InsertHeadList(&m_SubsHead, pContext->GetListEntry());
+ }
+ else if (pContext->IsArrivedSubscription())
+ {
+ // Place this CFileContext into a list of arrival registrations
+ InsertHeadList(&m_ArrivalSubsHead, pContext->GetListEntry());
+ }
+ else if (pContext->IsDepartedSubscription())
+ {
+ // Place this CFileContext into a list of removal registrations
+ InsertHeadList(&m_DepartureSubsHead, pContext->GetListEntry());
+ }
+
+ LeaveCriticalSection(&m_SubsLock);
+ }
+
+ if (FAILED(hr))
+ {
+ if (pContext != NULL)
+ {
+ delete pContext;
+ pContext = NULL;
+ }
+ }
+
+ pWdfRequest->Complete(hr);
+
+ MethodReturnVoid();
+}
+
+STDMETHODIMP_(void)
+CMyQueue::OnCloseFile(
+ _In_ IWDFFile* pWdfFileObject
+ )
+/*++
+
+ Routine Description:
+
+ This method is called when an app closes the file handle to this device.
+ This will free the context memory associated with this file object, close
+ the connection object associated with this file object and delete the file
+ handle i/o target object associated with this file object.
+
+ Arguments:
+
+ pWdfFileObject - the framework file object for which close is handled.
+
+ Return Value:
+
+ None
+
+--*/
+{
+ MethodEntry("...");
+
+ HRESULT hr = S_OK ;
+ CFileContext* pContext = NULL;
+ hr = pWdfFileObject->RetrieveContext((void**)&pContext);
+ if (SUCCEEDED(hr) && (pContext != NULL))
+ {
+ CRITICAL_SECTION* pCritSec = NULL;
+ LIST_ENTRY* pHead = NULL;
+
+ if (pContext->IsNormalSubscription())
+ {
+ pCritSec = &m_SubsLock;
+ pHead = &m_SubsHead;
+ }
+ else if (pContext->IsArrivedSubscription())
+ {
+ pCritSec = &m_SubsLock;
+ pHead = &m_ArrivalSubsHead;
+ }
+ else if (pContext->IsDepartedSubscription())
+ {
+ pCritSec = &m_SubsLock;
+ pHead = &m_DepartureSubsHead;
+ }
+ else if (pContext->IsPublication())
+ {
+ pCritSec = &m_PubsLock;
+ pHead = &m_PubsHead;
+ }
+
+ if (pHead != NULL)
+ {
+ EnterCriticalSection(pCritSec);
+
+ LIST_ENTRY* pFindEntry = pContext->GetListEntry();
+ LIST_ENTRY* pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ if (pEntry == pFindEntry)
+ {
+ RemoveEntryList(pEntry);
+ break;
+ }
+
+ pEntry = pEntry->Flink;
+ }
+
+ LeaveCriticalSection(pCritSec);
+ }
+
+ delete pContext;
+ }
+
+ MethodReturnVoid();
+}
+
+STDMETHODIMP_ (void)
+CMyQueue::OnCancel(
+ _In_ IWDFIoRequest* pWdfRequest
+ )
+{
+ MethodEntry("pWdfRequest = %p",
+ pWdfRequest);
+
+ IWDFFile* pFxFile;
+ pWdfRequest->GetFileObject(&pFxFile);
+ if (pFxFile != NULL)
+ {
+ CFileContext* pFileContext;
+ HRESULT hr = pFxFile->RetrieveContext((void**)&pFileContext);
+ if (SUCCEEDED(hr))
+ {
+ pFileContext->OnCancel();
+ }
+ }
+
+ MethodReturnVoid();
+}
+
+#define IOCTL_BEGIN_PROXIMITY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1000, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+STDMETHODIMP_ (void)
+CMyQueue::OnDeviceIoControl(
+ _In_ IWDFIoQueue* /*pWdfQueue*/,
+ _In_ IWDFIoRequest* pWdfRequest,
+ _In_ ULONG ControlCode,
+ _In_ SIZE_T /*InBufferSize*/,
+ _In_ SIZE_T /*OutBufferSize*/
+ )
+{
+ MethodEntry("pWdfRequest = %p, ControlCode = %d",
+ pWdfRequest, ControlCode);
+
+ IWDFFile* pFxFile;
+
+ pWdfRequest->GetFileObject(&pFxFile);
+
+ bool fCompleteRequest = true;
+
+ CFileContext *pFileContext;
+ HRESULT hr = pFxFile->RetrieveContext((void**)&pFileContext);
+ if (SUCCEEDED(hr))
+ {
+ switch (ControlCode)
+ {
+ case IOCTL_NFP_GET_MAX_MESSAGE_BYTES:
+ {
+ IWDFMemory* pWdfOutputMemory;
+ pWdfRequest->GetOutputMemory(&pWdfOutputMemory);
+ if (pWdfOutputMemory != NULL)
+ {
+ SIZE_T cbOutputBuffer = 0;
+ // Set the first 4 bytes as the maximum message size of this device/driver
+ DWORD dwMaxCbPayload = MaxCbPayload;
+ hr = pWdfOutputMemory->CopyFromBuffer(0, &dwMaxCbPayload, 4);
+ if (SUCCEEDED(hr))
+ {
+ cbOutputBuffer = 4;
+ }
+ pWdfOutputMemory->Release();
+
+ pWdfRequest->CompleteWithInformation(hr, cbOutputBuffer);
+ fCompleteRequest = false;
+ }
+ }
+ break;
+
+ case IOCTL_NFP_GET_KILO_BYTES_PER_SECOND:
+ {
+ IWDFMemory* pWdfOutputMemory;
+ pWdfRequest->GetOutputMemory(&pWdfOutputMemory);
+ if (pWdfOutputMemory != NULL)
+ {
+ SIZE_T cbOutputBuffer = 0;
+ // Set the first 4 bytes as transfer speed of this device/driver
+ DWORD dwKilobytesPerSecond = KilobytesPerSecond;
+ hr = pWdfOutputMemory->CopyFromBuffer(0, &dwKilobytesPerSecond, 4);
+ if (SUCCEEDED(hr))
+ {
+ cbOutputBuffer = 4;
+ }
+ pWdfOutputMemory->Release();
+
+ pWdfRequest->CompleteWithInformation(hr, cbOutputBuffer);
+ fCompleteRequest = false;
+ }
+ }
+ break;
+
+ case IOCTL_NFP_DISABLE:
+ hr = pFileContext->Disable();
+ break;
+
+ case IOCTL_NFP_ENABLE:
+ hr = pFileContext->Enable();
+ break;
+
+ case IOCTL_NFP_SET_PAYLOAD:
+ hr = pFileContext->SetPayload(pWdfRequest);
+ if (SUCCEEDED(hr))
+ {
+ MESSAGE* pMessage = new MESSAGE();
+ hr = (pMessage != NULL) ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr))
+ {
+ pMessage->Initialize(pFileContext->GetType(), pFileContext->GetSize(), pFileContext->GetPayload());
+
+ EnterCriticalSection(&m_ConnectionLock);
+
+ for (LIST_ENTRY* pEntry = m_ConnectionHead.Flink;
+ pEntry != &m_ConnectionHead;
+ pEntry = pEntry->Flink)
+ {
+ CConnection* pConnection = CConnection::FromListEntry(pEntry);
+ if (SUCCEEDED(pConnection->TransmitMessage(pMessage)))
+ {
+ pFileContext->HandleMessageTransmitted();
+ }
+ }
+
+ LeaveCriticalSection(&m_ConnectionLock);
+
+ // Place this CFileContext into a list of published messages
+ EnterCriticalSection(&m_PubsLock);
+ InsertHeadList(&m_PubsHead, pFileContext->GetListEntry());
+ LeaveCriticalSection(&m_PubsLock);
+
+ delete pMessage;
+ }
+ }
+ break;
+
+ case IOCTL_BEGIN_PROXIMITY:
+ hr = pFileContext->BeginProximity(pWdfRequest, this);
+ break;
+
+ case IOCTL_NFP_GET_NEXT_SUBSCRIBED_MESSAGE:
+ hr = pFileContext->GetNextSubscribedMessage(this, pWdfRequest);
+ if (SUCCEEDED(hr))
+ {
+ fCompleteRequest = false;
+ }
+ break;
+
+ case IOCTL_NFP_GET_NEXT_TRANSMITTED_MESSAGE:
+ hr = pFileContext->GetNextTransmittedMessage(this, pWdfRequest);
+ if (SUCCEEDED(hr))
+ {
+ fCompleteRequest = false;
+ }
+ break;
+
+ default:
+ hr = HRESULT_FROM_NT(STATUS_INVALID_DEVICE_STATE);
+ break;
+ }
+ }
+
+ if (fCompleteRequest)
+ {
+ TraceInfo("Completing Request: %!HRESULT!", hr);
+ pWdfRequest->Complete(hr);
+ }
+
+ MethodReturnVoid();
+}
+
+void
+CMyQueue::ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket)
+{
+ MethodEntry("...");
+
+ CConnection* pConnection;
+ HRESULT hr = CConnection::Create(this, &pConnection);
+ if (SUCCEEDED(hr))
+ {
+ // 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
+CMyQueue::HandleReceivedMessage(_In_ MESSAGE* pMessage)
+{
+ MethodEntry("pMessage->m_szType = '%S'",
+ pMessage->m_szType);
+
+ if ((pMessage->m_cbPayload > 0) && (pMessage->m_cbPayload <= MaxCbPayload))
+ {
+ EnterCriticalSection(&m_SubsLock);
+
+ LIST_ENTRY* pEntry = m_SubsHead.Flink;
+ while (pEntry != &m_SubsHead)
+ {
+ CFileContext* pSub = CFileContext::FromListEntry(pEntry);
+
+ pSub->HandleReceivedPublication(pMessage->m_szType,
+ pMessage->m_cbPayload,
+ pMessage->m_Payload);
+
+ pEntry = pEntry->Flink;
+ }
+
+ LeaveCriticalSection(&m_SubsLock);
+ }
+
+ MethodReturnVoid();
+}
+
+void
+CMyQueue::ConnectionEstablished(_In_ CConnection* pConnection)
+{
+ MethodEntry("...");
+
+ EnterCriticalSection(&m_ConnectionLock);
+ BOOL fFirstConnection = IsListEmpty(&m_ConnectionHead);
+ InsertHeadList(&m_ConnectionHead, pConnection->GetListEntry());
+ LeaveCriticalSection(&m_ConnectionLock);
+
+ if (fFirstConnection)
+ {
+ AddArrivalEvent();
+ }
+
+ MESSAGE* pMessage = new MESSAGE();
+ if (pMessage != NULL)
+ {
+ EnterCriticalSection(&m_PubsLock);
+
+ LIST_ENTRY* pEntry = m_PubsHead.Flink;
+ while (pEntry != &m_PubsHead)
+ {
+ CFileContext* pPub = CFileContext::FromListEntry(pEntry);
+ if (pPub->IsEnabled())
+ {
+ pMessage->Initialize(pPub->GetType(), pPub->GetSize(), pPub->GetPayload());
+ if (SUCCEEDED(pConnection->TransmitMessage(pMessage)))
+ {
+ pPub->HandleMessageTransmitted();
+ }
+ }
+ pEntry = pEntry->Flink;
+ }
+
+ LeaveCriticalSection(&m_PubsLock);
+ delete pMessage;
+ }
+
+ MethodReturnVoid();
+}
+
+BOOL
+CMyQueue::ConnectionTerminated(_In_ CConnection* pConnection)
+{
+ MethodEntry("pConnection = 0x%p",
+ pConnection);
+
+ LIST_ENTRY* pRemoveListEntry = pConnection->GetListEntry();
+
+ EnterCriticalSection(&m_ConnectionLock);
+ LIST_ENTRY* pEntry = m_ConnectionHead.Flink;
+ while (pEntry != &m_ConnectionHead)
+ {
+ if (pEntry == pRemoveListEntry)
+ {
+ RemoveEntryList(pEntry);
+ break;
+ }
+ pEntry = pEntry->Flink;
+ }
+ BOOL fNoMoreConnections = IsListEmpty(&m_ConnectionHead);
+
+ LeaveCriticalSection(&m_ConnectionLock);
+
+ BOOL fConnectionDeleted = FALSE;
+ if (pConnection->IsInboundConnection())
+ {
+ delete pConnection;
+ fConnectionDeleted = TRUE;
+ }
+
+ if (fNoMoreConnections)
+ {
+ AddRemovalEvent();
+ }
+
+ MethodReturnBool(fConnectionDeleted);
+}
+
+void
+CMyQueue::AddArrivalEvent()
+{
+ MethodEntry("void");
+
+ EnterCriticalSection(&m_SubsLock);
+
+ for (LIST_ENTRY* pEntry = m_ArrivalSubsHead.Flink;
+ pEntry != &m_ArrivalSubsHead;
+ pEntry = pEntry->Flink)
+ {
+ CFileContext::FromListEntry(pEntry)->HandleArrivalEvent();
+ }
+
+ LeaveCriticalSection(&m_SubsLock);
+
+ MethodReturnVoid();
+}
+
+void
+CMyQueue::AddRemovalEvent()
+{
+ MethodEntry("void");
+
+ EnterCriticalSection(&m_SubsLock);
+
+ for (LIST_ENTRY* pEntry = m_DepartureSubsHead.Flink;
+ pEntry != &m_DepartureSubsHead;
+ pEntry = pEntry->Flink)
+ {
+ CFileContext::FromListEntry(pEntry)->HandleRemovalEvent();
+ }
+
+ LeaveCriticalSection(&m_SubsLock);
+
+ MethodReturnVoid();
+}
+
+STDMETHODIMP_(void)
+CMyQueue::OnCleanup(
+ _In_ IWDFObject* /*pWdfObject*/
+ )
+{
+ MethodEntry("...");
+
+ //
+ // CMyQueue has a reference to framework device object via m_Queue.
+ // Framework queue object has a reference to CMyQueue object via the callbacks.
+ // This leads to circular reference and both the objects can't be destroyed until this circular reference is broken.
+ // To break the circular reference we release the reference to the framework queue object here in OnCleanup.
+ //
+
+ m_FxQueue = NULL;
+
+ MethodReturnVoid();
+}
diff --git a/nfp/net/driver/Queue.h b/nfp/net/driver/Queue.h
new file mode 100644
index 00000000..55b2ff39
--- /dev/null
+++ b/nfp/net/driver/Queue.h
@@ -0,0 +1,175 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ This file defines the queue callback interface.
+
+Environment:
+
+ user mode only
+
+Revision History:
+
+--*/
+
+#pragma once
+
+#include "device.h"
+#include "Connection.h"
+
+static const int KilobytesPerSecond = 20;
+
+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 NULL 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 NULL terminator.
+static const int MinCchType = 2;
+static const int MaxCchMimeType = 256;
+
+#define WINDOWS_PROTOCOL L"Windows."
+#define WINDOWS_PROTOCOL_CHARS 8
+
+#define WINDOWSURI_PROTOCOL L"WindowsUri"
+
+#define WINDOWSMIME_PROTOCOL L"WindowsMime"
+#define WINDOWSMIME_PROTOCOL_CHARS 11
+
+#define PUBS_NAMESPACE L"Pubs\\"
+#define PUBS_NAMESPACE_CHARS 5
+
+#define SUBS_NAMESPACE L"Subs\\"
+#define SUBS_NAMESPACE_CHARS 5
+
+#define DEVICE_ARRIVED L"DeviceArrived"
+#define DEVICE_DEPARTED L"DeviceDeparted"
+
+#define PAIRING_PROTOCOL L"Pairing:"
+#define PAIRING_PROTOCOL_CHARS 8
+
+#define NDEF_PROTOCOL L"NDEF"
+#define NDEF_PROTOCOL_CHARS 4
+
+#define NDEF_EMPTY_TYPE L"Empty"
+#define NDEF_EMPTY_TYPE_CHARS 5
+
+struct MESSAGE
+{
+ MESSAGE() :
+ m_cbPayload(0)
+ {
+ ZeroMemory(m_szType, sizeof(m_szType));
+ ZeroMemory(m_Payload, sizeof(m_Payload));
+ }
+
+ void Initialize(
+ _In_ PCWSTR szType,
+ _In_ DWORD cbPayload,
+ _In_reads_bytes_(cbPayload) PBYTE pbPayload
+ )
+ {
+ ZeroMemory(m_szType, sizeof(m_szType));
+ ZeroMemory(m_Payload, sizeof(m_Payload));
+
+ m_cbPayload = cbPayload;
+ StringCchCopy(m_szType, ARRAY_SIZE(m_szType), szType);
+ CopyMemory(m_Payload, pbPayload, cbPayload);
+ }
+
+ wchar_t m_szType[MaxCchTypeNetwork];
+ DWORD m_cbPayload;
+ BYTE m_Payload[MaxCbPayload];
+};
+
+
+//
+// Queue Callback Object.
+//
+
+class ATL_NO_VTABLE CMyQueue :
+ public CComObjectRootEx<CComMultiThreadModel>,
+ public IQueueCallbackCreate,
+ public IQueueCallbackDeviceIoControl,
+ public IRequestCallbackCancel,
+ public IObjectCleanup,
+ public IValidateAccept,
+ public IConnectionCallback
+{
+public:
+
+DECLARE_NOT_AGGREGATABLE(CMyQueue)
+
+BEGIN_COM_MAP(CMyQueue)
+ COM_INTERFACE_ENTRY(IQueueCallbackCreate)
+ COM_INTERFACE_ENTRY(IQueueCallbackDeviceIoControl)
+ COM_INTERFACE_ENTRY(IRequestCallbackCancel)
+ COM_INTERFACE_ENTRY(IObjectCleanup)
+END_COM_MAP()
+
+public:
+
+ //IQueueCallbackCreate
+ STDMETHOD_(void,OnCreateFile)(_In_ IWDFIoQueue* pWdfQueue, _In_ IWDFIoRequest* pWDFRequest, _In_ IWDFFile* pWdfFileObject);
+
+ //IQueueCallbackDeviceIoControl
+ STDMETHOD_(void,OnDeviceIoControl)(_In_ IWDFIoQueue* pWdfQueue, _In_ IWDFIoRequest* pWDFRequest, _In_ ULONG ControlCode, _In_ SIZE_T InBufferSize, _In_ SIZE_T OutBufferSize);
+
+ //IObjectCleanup
+ STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject);
+
+ //IValidateAccept
+ void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket);
+
+
+ //IRequestCallbackCancel
+ STDMETHODIMP_(void)
+ OnCancel(
+ _In_ IWDFIoRequest* pWdfRequest
+ );
+
+ //IConnectionCallback
+ virtual void HandleReceivedMessage(_In_ MESSAGE* pMessageData);
+ virtual void ConnectionEstablished(_In_ CConnection* pBthConnection);
+ virtual BOOL ConnectionTerminated(_In_ CConnection* pBthConnection);
+
+public:
+ CMyQueue();
+ ~CMyQueue();
+
+ STDMETHOD(Initialize)(_In_ CMyDevice * Device);
+
+ HRESULT
+ Configure(
+ VOID
+ );
+
+ STDMETHODIMP_(void)
+ OnCloseFile(
+ _In_ IWDFFile* pWdfFileObject
+ );
+
+private:
+
+ void AddArrivalEvent();
+ void AddRemovalEvent();
+
+private:
+ CComPtr<IWDFIoQueue> m_FxQueue;
+
+ LIST_ENTRY m_SubsHead;
+ LIST_ENTRY m_ArrivalSubsHead;
+ LIST_ENTRY m_DepartureSubsHead;
+ CRITICAL_SECTION m_SubsLock;
+
+ LIST_ENTRY m_PubsHead;
+ CRITICAL_SECTION m_PubsLock;
+
+ LIST_ENTRY m_ConnectionHead;
+ CRITICAL_SECTION m_ConnectionLock;
+
+ CSocketListener m_SocketListener;
+};
diff --git a/nfp/net/driver/connection.h b/nfp/net/driver/connection.h
new file mode 100644
index 00000000..6ab900e0
--- /dev/null
+++ b/nfp/net/driver/connection.h
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Abstract:
+
+ Defines a simple NearFieldProximity Provider implementation using the network
+ for use in selfhosting.
+
+Author:
+
+ Travis Martin (TravM) 06-24-2010
+
+--*/
+#pragma once
+
+#include "SocketListener.h"
+
+class CConnection;
+
+struct MESSAGE;
+
+interface IConnectionCallback
+{
+ virtual void HandleReceivedMessage(_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(NULL),
+ _fInboundConnection(false)
+ {
+ }
+
+public:
+
+ virtual ~CConnection()
+ {
+ Terminate();
+
+ if (_ThreadpoolWork != NULL)
+ {
+ // Don't wait for threadpool callbacks when this thread is actually the threadpool callback
+ if (_ThreadpoolThreadId != GetCurrentThreadId())
+ {
+ WaitForThreadpoolWorkCallbacks(_ThreadpoolWork, false);
+ }
+ CloseThreadpoolWork(_ThreadpoolWork);
+ _ThreadpoolWork = NULL;
+ }
+ }
+
+ static HRESULT Create(_In_ IConnectionCallback* pCallback, _Outptr_ 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);
+ }
+
+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;
+
+};
diff --git a/nfp/net/driver/device.cpp b/nfp/net/driver/device.cpp
new file mode 100644
index 00000000..599d57b5
--- /dev/null
+++ b/nfp/net/driver/device.cpp
@@ -0,0 +1,261 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ Device.cpp
+
+Abstract:
+
+ This module contains the implementation of the UMDF sample
+ driver's device callback object.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#include "internal.h"
+#include "device.tmh"
+
+HRESULT
+CMyDevice::Initialize(
+ _In_ IWDFDriver* FxDriver,
+ _In_ IWDFDeviceInitialize* FxDeviceInit
+ )
+/*++
+
+ Routine Description:
+
+ This method initializes the device callback object and creates the
+ partner device object.
+
+ The method should perform any device-specific configuration that:
+ * could fail (these can't be done in the constructor)
+ * must be done before the partner object is created -or-
+ * can be done after the partner object is created and which aren't
+ influenced by any device-level parameters the parent (the driver
+ in this case) might set.
+
+ Arguments:
+
+ FxDeviceInit - the settings for this device.
+ FxDriver - IWDF Driver for this device.
+
+ Return Value:
+
+ status.
+
+--*/
+{
+ MethodEntry("...");
+
+ CComPtr<IWDFDevice> fxDevice;
+ HRESULT hr;
+
+ //
+ // Configure things like the locking model before we go to create our
+ // partner device.
+ //
+
+ //
+ // Set the locking model
+ //
+
+ FxDeviceInit->SetLockingConstraint(None);
+
+ //
+ // TODO: Any per-device initialization which must be done before
+ // creating the partner object.
+ //
+
+ //
+ // Create a new FX device object and assign the new callback object to
+ // handle any device level events that occur.
+ //
+
+ //
+ // QueryIUnknown references the IUnknown interface that it returns
+ // (which is the same as referencing the device). We pass that to
+ // CreateDevice, which takes its own reference if everything works.
+ //
+
+ CComPtr<IUnknown> pUnk;
+ HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk);
+ WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI));
+
+ hr = FxDriver->CreateDevice(FxDeviceInit, pUnk, &fxDevice);
+
+ //
+ // If that succeeded then set our FxDevice member variable.
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ m_FxDevice = fxDevice;
+ }
+
+ MethodReturnHR(hr);
+}
+
+HRESULT
+CMyDevice::Configure(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This method is called after the device callback object has been initialized
+ and returned to the driver. It would setup the device's queues and their
+ corresponding callback objects.
+
+ Arguments:
+
+ FxDevice - the framework device object for which we're handling events.
+
+ Return Value:
+
+ status
+
+--*/
+{
+ MethodEntry("void");
+
+ //
+ // Create a new instance of our Queue callback object
+ //
+ CComObject<CMyQueue> * defaultQueue = NULL;
+ HRESULT hr = CComObject<CMyQueue>::CreateInstance(&defaultQueue);
+
+ if (SUCCEEDED(hr))
+ {
+ defaultQueue->AddRef();
+ hr = defaultQueue->Initialize(this);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = defaultQueue->Configure();
+ }
+
+ //
+ // Create and Enable Device Interfaces for this device.
+ //
+ if (SUCCEEDED(hr))
+ {
+ hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_NETNFP,
+ NULL);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_FxDevice->AssignDeviceInterfaceState(&GUID_DEVINTERFACE_NETNFP,
+ NULL,
+ TRUE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_NFP,
+ NULL);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_FxDevice->AssignDeviceInterfaceState(&GUID_DEVINTERFACE_NFP,
+ NULL,
+ TRUE);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // Save a pointer to our queue, so we can lock it during file cleanup
+ //
+ m_MyQueue = defaultQueue;
+ }
+
+ //
+ // Release the reference we took on the queue object.
+ // The framework took its own references on the object's callback interfaces
+ // when we called m_FxDevice->CreateIoQueue, and will manage the object's lifetime.
+ //
+ SAFE_RELEASE(defaultQueue);
+
+ MethodReturnHR(hr);
+}
+
+STDMETHODIMP_(void)
+CMyDevice::OnCloseFile(
+ _In_ IWDFFile* pWdfFileObject
+ )
+{
+ MethodEntry("...");
+
+ m_MyQueue->OnCloseFile(pWdfFileObject);
+
+ MethodReturnVoid();
+}
+
+STDMETHODIMP_(void)
+CMyDevice::OnCleanupFile(
+ _In_ IWDFFile* /*pWdfFileObject*/
+ )
+/*++
+
+ Routine Description:
+
+ This method is when app with open handle device terminates.
+
+ Arguments:
+
+ pWdfFileObject - the framework file object for which close is handled.
+
+ Return Value:
+
+ None
+
+--*/
+{
+}
+
+STDMETHODIMP_(void)
+CMyDevice::OnCleanup(
+ _In_ IWDFObject* pWdfObject
+ )
+/*++
+
+ Routine Description:
+
+ This device callback method is invoked by the framework when the WdfObject
+ is about to be released by the framework.
+
+ Arguments:
+
+ pWdfObject - the framework device object for which OnCleanup.
+
+ Return Value:
+
+ None
+
+--*/
+{
+ MethodEntry("...");
+
+ WUDF_SAMPLE_DRIVER_ASSERT(pWdfObject == m_FxDevice);
+
+ m_MyQueue = NULL;
+
+ //
+ // CMyDevice has a reference to framework device object via m_Device.
+ // Framework device object has a reference to CMyDevice object via the callbacks.
+ // This leads to circular reference and both the objects can't be destroyed until this circular reference is broken.
+ // To break the circular reference we release the reference to the framework device object here in OnCleanup.
+ //
+ m_FxDevice = NULL;
+
+ MethodReturnVoid();
+}
diff --git a/nfp/net/driver/device.h b/nfp/net/driver/device.h
new file mode 100644
index 00000000..c4eeb121
--- /dev/null
+++ b/nfp/net/driver/device.h
@@ -0,0 +1,73 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Device.h
+
+Abstract:
+
+ This module contains the type definitions for the sample
+ driver's device callback class.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+#pragma once
+
+class CMyQueue;
+
+class ATL_NO_VTABLE CMyDevice :
+ public CComObjectRootEx<CComMultiThreadModel>,
+ public IFileCallbackCleanup,
+ public IFileCallbackClose,
+ public IObjectCleanup
+{
+public:
+
+DECLARE_NOT_AGGREGATABLE(CMyDevice)
+
+BEGIN_COM_MAP(CMyDevice)
+ COM_INTERFACE_ENTRY(IFileCallbackCleanup)
+ COM_INTERFACE_ENTRY(IFileCallbackClose)
+ COM_INTERFACE_ENTRY(IObjectCleanup)
+END_COM_MAP()
+
+public:
+
+ //IFileCallbackCleanup
+ STDMETHOD_(void,OnCleanupFile)(_In_ IWDFFile* pWdfFileObject);
+ //IFileCallbackClose
+ STDMETHOD_(void,OnCloseFile)(_In_ IWDFFile* pWdfFileObject);
+ //IObjectCleanup
+ STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject);
+
+public:
+
+ STDMETHOD(Initialize)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit);
+
+ HRESULT
+ Configure(
+ VOID
+ );
+
+ IWDFDevice *
+ GetFxDevice(
+ VOID
+ )
+ {
+ return m_FxDevice;
+ }
+
+private:
+ CComPtr<IWDFDevice> m_FxDevice;
+
+ CMyQueue* m_MyQueue;
+
+ HRESULT ReadAndAssignPropertyStoreValue();
+ HRESULT GetAnsiValFromPropVariant(_In_ PROPVARIANT val, _Inout_ LPSTR *PropertyValueA);
+
+};
diff --git a/nfp/net/driver/dllsup.cpp b/nfp/net/driver/dllsup.cpp
new file mode 100644
index 00000000..85c866ec
--- /dev/null
+++ b/nfp/net/driver/dllsup.cpp
@@ -0,0 +1,112 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ dllsup.cpp
+
+Abstract:
+
+ This module contains the implementation of the UMDF Socktecho Sample
+ Driver's entry point and its exported functions for providing COM support.
+
+ This module can be copied without modification to a new UMDF driver. It
+ depends on some of the code in comsup.cpp & comsup.h to handle DLL
+ registration and creating the first class factory.
+
+ This module is dependent on the following defines:
+
+ MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing
+ tracing.
+
+ MYDRIVER_CLASS_ID - A GUID encoded in struct format used to
+ initialize the driver's ClassID.
+
+ These are defined in internal.h for the sample. If you choose
+ to use a different primary include file, you should ensure they are
+ defined there as well.
+
+Environment:
+
+ WDF User-Mode Driver Framework (WDF:UMDF)
+
+--*/
+
+#include "internal.h"
+#include "dllsup.tmh"
+
+const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID;
+
+class CNetNfpProviderModule : public CAtlDllModuleT< CNetNfpProviderModule >
+{
+};
+
+
+OBJECT_ENTRY_AUTO(CLSID_MyDriverCoClass, CMyDriver)
+
+
+CNetNfpProviderModule _AtlModule;
+
+BOOL
+WINAPI
+DllMain(
+ HINSTANCE ModuleHandle,
+ DWORD Reason,
+ PVOID Reserved
+ )
+/*++
+
+ Routine Description:
+
+ This is the entry point and exit point for the I/O trace driver. This
+ does very little as the I/O trace driver has minimal global data.
+
+ This method initializes tracing.
+
+ Arguments:
+
+ ModuleHandle - the DLL handle for this module.
+
+ Reason - the reason this entry point was called.
+
+ Reserved - unused
+
+ Return Value:
+
+ TRUE
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER( ModuleHandle );
+
+ if (DLL_PROCESS_ATTACH == Reason)
+ {
+ //
+ // Initialize tracing.
+ //
+
+ WPP_INIT_TRACING(MYDRIVER_TRACING_ID);
+ TracingTlsInitialize();
+
+ }
+ else if (DLL_PROCESS_DETACH == Reason)
+ {
+ //
+ // Cleanup tracing.
+ //
+
+ TracingTlsFree();
+ WPP_CLEANUP();
+ }
+
+ return _AtlModule.DllMain(Reason, Reserved);
+;
+}
+
+_Check_return_
+STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv)
+{
+ return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
+}
diff --git a/nfp/net/driver/driver.cpp b/nfp/net/driver/driver.cpp
new file mode 100644
index 00000000..2c28f16e
--- /dev/null
+++ b/nfp/net/driver/driver.cpp
@@ -0,0 +1,150 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved.
+
+Module Name:
+
+ Driver.cpp
+
+Abstract:
+
+ This module contains the implementation of the UMDF Socketecho Sample's
+ core driver callback object.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+#include "internal.h"
+
+#include "driver.tmh"
+
+DECLARE_TRACING_TLS;
+
+STDMETHODIMP
+CMyDriver::OnInitialize(
+ _In_ IWDFDriver* /*pWdfDriver*/
+ )
+
+
+/*++
+
+ Routine Description:
+
+ This routine is invoked by the framework at driver load .
+ This method will invoke the Winsock Library for using
+ Winsock API in this driver.
+
+ Arguments:
+
+ pWdfDriver - Framework driver object
+
+ Return Value:
+
+ S_OK if successful, or error otherwise.
+
+--*/
+
+{
+ MethodEntry("...");
+
+ HRESULT hr = S_OK;
+
+ WSADATA wsaData;
+ int result = WSAStartup(MAKEWORD(2,2), &wsaData);
+ if (result != 0)
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ TraceErrorHR(hr, "Failed to initialize Winsock 2.0");
+ }
+
+ MethodReturnHR(hr);
+}
+
+STDMETHODIMP_(void)
+CMyDriver::OnDeinitialize(
+ _In_ IWDFDriver* /*pWdfDriver*/
+ )
+
+/*++
+ Routine Description:
+
+ The FX invokes this method when it unloads the driver.
+ This routine will Cleanup Winsock library
+
+ Arguments:
+
+ pWdfDriver - the Fx driver object.
+
+ Return Value:
+
+ None
+
+ --*/
+{
+ MethodEntry("...");
+
+ WSACleanup();
+
+ MethodReturnVoid();
+}
+
+STDMETHODIMP
+CMyDriver::OnDeviceAdd(
+ _In_ IWDFDriver *FxWdfDriver,
+ _In_ IWDFDeviceInitialize *FxDeviceInit
+ )
+/*++
+
+ Routine Description:
+
+ The FX invokes this method when it wants to install our driver on a device
+ stack. This method creates a device callback object, then calls the Fx
+ to create an Fx device object and associate the new callback object with
+ it.
+
+ Arguments:
+
+ FxWdfDriver - the Fx driver object.
+
+ FxDeviceInit - the initialization information for the device.
+
+ Return Value:
+
+ status
+
+--*/
+{
+ MethodEntry("...");
+
+ //
+ // Create a new instance of our device callback object
+ //
+
+ CComObject<CMyDevice> * device;
+ HRESULT hr = CComObject<CMyDevice>::CreateInstance(&device);
+ if (SUCCEEDED(hr))
+ {
+ device->AddRef();
+ hr = device->Initialize(FxWdfDriver, FxDeviceInit);
+ if (SUCCEEDED(hr))
+ {
+ //
+ // If that succeeded then call the device's configure method. This
+ // allows the device to create any queues or other structures that it
+ // needs now that the corresponding fx device object has been created.
+ //
+ hr = device->Configure();
+ }
+
+ //
+ // Release the reference we took on the device object.
+ // The framework took its own references on the object's callback interfaces
+ // when we called FxWdfDriver->CreateDevice, and will manage the object's lifetime.
+ //
+ SAFE_RELEASE(device);
+ }
+
+ MethodReturnHR(hr);
+}
diff --git a/nfp/net/driver/driver.h b/nfp/net/driver/driver.h
new file mode 100644
index 00000000..6affa20f
--- /dev/null
+++ b/nfp/net/driver/driver.h
@@ -0,0 +1,53 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Driver.h
+
+Abstract:
+
+ This module contains the type definitions for the UMDF Socketecho sample's
+ driver callback class.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+//
+// This class handles driver events for the socktecho sample. In particular
+// it supports the OnDeviceAdd event, which occurs when the driver is called
+// to setup per-device handlers for a new device stack.
+//
+
+extern const GUID CLSID_MyDriverCoClass;
+
+class ATL_NO_VTABLE CMyDriver :
+ public CComObjectRootEx<CComMultiThreadModel>,
+ public CComCoClass<CMyDriver, &CLSID_MyDriverCoClass>,
+ public IDriverEntry
+{
+public:
+
+DECLARE_NOT_AGGREGATABLE(CMyDriver)
+
+DECLARE_CLASSFACTORY();
+
+DECLARE_NO_REGISTRY();
+
+BEGIN_COM_MAP(CMyDriver)
+ COM_INTERFACE_ENTRY(IDriverEntry)
+END_COM_MAP()
+
+public:
+ // IDriverEntry
+ STDMETHOD(OnInitialize)(_In_ IWDFDriver* pWdfDriver);
+ STDMETHOD(OnDeviceAdd)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit);
+ STDMETHOD_(void,OnDeinitialize)(_In_ IWDFDriver* pWdfDriver);
+};
+
diff --git a/nfp/net/driver/exports.def b/nfp/net/driver/exports.def
new file mode 100644
index 00000000..964e5f79
--- /dev/null
+++ b/nfp/net/driver/exports.def
@@ -0,0 +1,6 @@
+; exports.def : Declares the module parameters.
+
+LIBRARY "NetNfpProvider"
+
+EXPORTS
+ DllGetClassObject PRIVATE
diff --git a/nfp/net/driver/internal.h b/nfp/net/driver/internal.h
new file mode 100644
index 00000000..80aa0152
--- /dev/null
+++ b/nfp/net/driver/internal.h
@@ -0,0 +1,152 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ Internal.h
+
+Abstract:
+
+ This module contains the local type definitions for the UMDF Socketecho sample
+ driver sample.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+
+#pragma once
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
+//
+// Include the winsock headers before any other windows headers.
+//
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+//
+// Include the WUDF DDI
+//
+
+#include "wudfddi.h"
+
+//
+// Use specstrings for in/out annotation of function parameters.
+//
+
+#include "specstrings.h"
+
+//
+// Define the tracing GUID for this driver
+//
+
+#define TRACE_CONTROL_GUID (12579E92,1B46,40A6,9CFC,C718A677830B)
+
+
+//
+// Driver specific #defines
+//
+
+#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\NetNfpProvider"
+
+/* 278F44F0-FF5C-4FE3-BF20-F8AA158EA7BC */
+#define MYDRIVER_CLASS_ID { 0x278F44F0, 0xFF5C, 0x4FE3, {0xBF, 0x20, 0xF8, 0xAA, 0x15, 0x8E, 0xA7, 0xBC} }
+#ifndef SAFE_RELEASE
+#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }}
+#endif
+
+__forceinline
+#ifdef _PREFAST_
+__declspec(noreturn)
+#endif
+VOID
+WdfTestNoReturn(
+ VOID
+ )
+{
+ // do nothing.
+}
+
+#define WUDF_SAMPLE_DRIVER_ASSERT(p) \
+{ \
+ if ( !(p) ) \
+ { \
+ DebugBreak(); \
+ WdfTestNoReturn(); \
+ } \
+}
+
+//
+// define the maximum size of the message queue
+//
+
+#define MAX_MESSAGE_QUEUE_SIZE 50
+
+//
+// MessageId: STATUS_CANCELLED
+//
+// MessageText:
+//
+// The I/O request was canceled.
+//
+#define STATUS_CANCELLED (0xC0000120L)
+
+//
+// MessageId: STATUS_INVALID_DEVICE_STATE
+//
+// MessageText:
+//
+// The device is not in a valid state to perform this request.
+//
+#define STATUS_INVALID_DEVICE_STATE (0xC0000184L)
+
+//
+// MessageId: STATUS_INVALID_BUFFER_SIZE
+//
+// MessageText:
+//
+// The size of the buffer is invalid for the specified operation.
+//
+#define STATUS_INVALID_BUFFER_SIZE (0xC0000206L)
+
+//
+// MessageId: STATUS_OBJECT_PATH_NOT_FOUND
+//
+// MessageText:
+//
+// {Path Not Found}
+// The path %hs does not exist.
+//
+#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS)0xC000003AL)
+
+//
+// Include the type specific headers.
+//
+#include <atlbase.h>
+#include <atlcom.h>
+
+// Windows Headers
+#include <initguid.h>
+#include <Winsock2.h>
+#include <Mswsock.h>
+#include <Strsafe.h>
+#include <devioctl.h>
+#include <nfpdev.h>
+
+// Sample headers
+#include "NetNfp.h"
+#include "WppDefs.h"
+#include "list.h"
+#include "connection.h"
+#include "filecontext.h"
+#include "driver.h"
+#include "device.h"
+#include "queue.h"
+
+_Analysis_mode_(_Analysis_operator_new_null_)
+
diff --git a/nfp/net/driver/list.h b/nfp/net/driver/list.h
new file mode 100644
index 00000000..d2bfce3f
--- /dev/null
+++ b/nfp/net/driver/list.h
@@ -0,0 +1,119 @@
+#pragma once
+
+FORCEINLINE
+VOID
+InitializeListHead(
+ _Out_ PLIST_ENTRY ListHead
+ )
+{
+ ListHead->Flink = ListHead->Blink = ListHead;
+}
+
+_Check_return_
+BOOLEAN
+FORCEINLINE
+IsListEmpty(
+ _In_ const LIST_ENTRY * ListHead
+ )
+{
+ return (BOOLEAN)(ListHead->Flink == ListHead);
+}
+
+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
+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
+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;
+}
+
+
+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;
+}
+
+FORCEINLINE
+VOID
+AppendTailList(
+ _Inout_ PLIST_ENTRY ListHead,
+ _Inout_ PLIST_ENTRY ListToAppend
+ )
+{
+ PLIST_ENTRY ListEnd = ListHead->Blink;
+
+ ListHead->Blink->Flink = ListToAppend;
+ ListHead->Blink = ListToAppend->Blink;
+ ListToAppend->Blink->Flink = ListHead;
+ ListToAppend->Blink = ListEnd;
+}
diff --git a/nfp/net/driver/netnfpprovider.inx b/nfp/net/driver/netnfpprovider.inx
new file mode 100644
index 00000000..0f2d246f
--- /dev/null
+++ b/nfp/net/driver/netnfpprovider.inx
@@ -0,0 +1,83 @@
+;
+; NetNfpProvider.inf
+;
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=Proximity
+ClassGuid={5630831C-06C9-4856-B327-F5D32586E060}
+Provider=%MSFT%
+CatalogFile=nfp.cat
+DriverVer=03/20/2003,5.00.3788
+
+[Manufacturer]
+%MSFTWUDF%=Microsoft,NT$ARCH$
+
+[Microsoft.NT$ARCH$]
+%NetNfpProviderName%=NetNfpProvider_Install,WUDF\NetNfpProvider
+
+[SourceDisksFiles]
+NetNfpProvider.dll=1
+
+
+[SourceDisksNames]
+1 = %MediaDescription%
+
+; =================== WUDF NetNfpProvider Test Driver ==================================
+
+[NetNfpProvider_Install]
+CopyFiles=UMDFDriverCopy
+
+[NetNfpProvider_Install.hw]
+AddReg=NetNfpProvider_AddReg
+
+[NetNfpProvider_Install.Services]
+AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall
+
+[NetNfpProvider_Install.CoInstallers]
+AddReg = NetNfpProvider_Install.CoInstallers_AddReg
+CopyFiles = CoInstallers_CopyFiles
+
+[NetNfpProvider_Install.CoInstallers_AddReg]
+HKR,,CoInstallers32,0x00010000,"WUDFCoinstaller.dll"
+
+
+
+[CoInstallers_CopyFiles]
+;WudfUpdate_$UMDFCOINSTALLERVERSION$.dll
+
+[NetNfpProvider_Install.Wdf]
+UmdfService=NetNfpProvider, NetNfpProvider_Driver_Install
+UmdfServiceOrder=NetNfpProvider
+UmdfDispatcher=FileHandle
+
+[NetNfpProvider_AddReg]
+HKR,"NetNfpProvider","Server",0x00010001,1
+
+[WUDFRD_ServiceInstall]
+ServiceType=1
+StartType=3
+ErrorControl=1
+ServiceBinary=%12%\WUDFRd.sys
+
+[NetNfpProvider_Driver_Install]
+UmdfLibraryVersion=$UMDFVERSION$
+DriverCLSID="{278F44F0-FF5C-4FE3-BF20-F8AA158EA7BC}"
+ServiceBinary="%12%\UMDF\NetNfpProvider.dll"
+
+[DestinationDirs]
+UMDFDriverCopy=12,UMDF
+
+[UMDFDriverCopy]
+NetNfpProvider.dll
+
+; =================== Generic ==================================
+
+[Strings]
+MSFT="Microsoft"
+MSFTWUDF="Microsoft Windows Driver Kit Sample (Proximity)"
+MediaDescription="Microsoft Network NearFieldProximity Provider Installation Media"
+NetNfpProviderName="Network NearFieldProximity Provider"
+
+
+
diff --git a/nfp/net/driver/netnfpprovider.rc b/nfp/net/driver/netnfpprovider.rc
new file mode 100644
index 00000000..98d1f8ab
--- /dev/null
+++ b/nfp/net/driver/netnfpprovider.rc
@@ -0,0 +1,18 @@
+//---------------------------------------------------------------------------
+// Skeleton.rc
+//
+// 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 "WDF:UMDF Network NearFieldProximity Provider"
+#define VER_INTERNALNAME_STR "NetNfpProvider"
+#define VER_ORIGINALFILENAME_STR "NetNfpProvider.dll"
+
+#include "common.ver"
diff --git a/nfp/net/driver/socketlistener.cpp b/nfp/net/driver/socketlistener.cpp
new file mode 100644
index 00000000..3aaa687b
--- /dev/null
+++ b/nfp/net/driver/socketlistener.cpp
@@ -0,0 +1,222 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Abstract:
+
+ Implements a socket listener class
+
+Author:
+
+ Travis Martin (TravM) 06-24-2010
+
+Environment:
+
+ User-mode only.
+
+--*/
+#include "internal.h"
+
+#include "SocketListener.tmh"
+
+HRESULT SetSocketIpv6Only(_In_ SOCKET socket, _In_ BOOL Ipv6Only)
+{
+ HRESULT hr = S_OK;
+ if (setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&Ipv6Only, sizeof(Ipv6Only)) == SOCKET_ERROR)
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ USE_DEFAULT_TRACING_CONTEXT;
+ TraceErrorHR(hr, "setsockopt IPV6_V6ONLY");
+ }
+ return hr;
+}
+
+HRESULT CSocketListener::EnableAccepting(_In_ IValidateAccept* pValidator)
+{
+ HRESULT hr = S_OK;
+ if (_pValidator == NULL)
+ {
+ USE_DEFAULT_TRACING_CONTEXT;
+
+ _ThreadpoolIo = CreateThreadpoolIo((HANDLE)_ListenSocket, s_AcceptThreadProc, this, NULL);
+ if (_ThreadpoolIo == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ int backlog = 2;
+ if (listen(_ListenSocket, backlog) == SOCKET_ERROR)
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // We're now accepting
+ _pValidator = pValidator;
+
+ hr = BeginAccept();
+ if (hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
+ {
+ hr = S_OK;
+ }
+ }
+
+ TraceInfo("EnableAccepting(): %!HRESULT!", hr);
+ }
+
+ return 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, NULL);
+ if (threadpoolIo != NULL)
+ {
+ // Don't wait for threadpool callbacks when this thread is actually the threadpool callback
+ if (_ThreadpoolThreadId != GetCurrentThreadId())
+ {
+ WaitForThreadpoolIoCallbacks(threadpoolIo, false);
+ }
+ CloseThreadpoolIo(threadpoolIo);
+ }
+
+ _pValidator = NULL;
+
+ if (_ClientSocket != INVALID_SOCKET)
+ {
+ closesocket(_ClientSocket);
+ _ClientSocket = INVALID_SOCKET;
+ }
+
+ MethodReturnVoid();
+}
+
+HRESULT CSocketListener::BeginAccept()
+{
+ MethodEntry("void");
+
+ HRESULT hr = S_OK;
+ _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 != NULL)
+ {
+ StartThreadpoolIo(threadpoolIo);
+
+ ULONG_PTR cbReceived = 0;
+ 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))
+ {
+ // Failed to accept, so cleanup
+ 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))
+ {
+ // Transfer ownership of _ClientSocket
+ _pValidator->ValidateAccept(_ClientSocket, &_AcceptBuffer.MagicPacket);
+ }
+ else
+ {
+ // Wrong header size, close immediately
+ closesocket(_ClientSocket);
+ }
+ _ClientSocket = INVALID_SOCKET;
+ }
+
+ // Start up another accept request
+ BeginAccept();
+
+ MethodReturnVoid();
+}
+
+HRESULT CSocketListener::Bind()
+{
+ MethodEntry("void");
+
+ // Create a SOCKET for connecting to this server
+ HRESULT hr = S_OK;
+ addrinfoW* pResult = NULL;
+ addrinfoW Hints = {};
+ Hints.ai_family = AF_INET6;
+ Hints.ai_socktype = SOCK_STREAM;
+ Hints.ai_flags = AI_PASSIVE;
+
+ // Resolve the server address and port
+ if (GetAddrInfoW(NULL, L"9299", &Hints, &pResult) != ERROR_SUCCESS )
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ // Create a SOCKET for connecting to server
+ _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))
+ {
+ // Setup the TCP listening socket
+ if (bind(_ListenSocket, pResult->ai_addr, (int)pResult->ai_addrlen) == SOCKET_ERROR)
+ {
+ hr = HRESULT_FROM_WIN32(WSAGetLastError());
+ }
+ }
+ FreeAddrInfoW(pResult);
+ }
+
+ MethodReturnHR(hr);
+}
+
diff --git a/nfp/net/driver/socketlistener.h b/nfp/net/driver/socketlistener.h
new file mode 100644
index 00000000..dffb11a2
--- /dev/null
+++ b/nfp/net/driver/socketlistener.h
@@ -0,0 +1,84 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Abstract:
+
+ Declares a socket listener class
+
+Author:
+
+ Travis Martin (TravM) 06-24-2010
+
+Environment:
+
+ User-mode only.
+
+--*/
+#pragma once
+
+struct ACCEPT_BUFFER
+{
+ GUID MagicPacket;
+
+ SOCKADDR_STORAGE DestAddress;
+ SOCKADDR_STORAGE SourceAddress;
+};
+
+interface IValidateAccept
+{
+ virtual void ValidateAccept(_In_ SOCKET Socket, _In_ GUID* pMagicPacket) = 0;
+};
+
+class CSocketListener
+{
+public:
+ CSocketListener() :
+ _pValidator(NULL),
+ _ThreadpoolIo(NULL),
+ _ListenSocket(INVALID_SOCKET),
+ _ClientSocket(INVALID_SOCKET)
+ {
+ ZeroMemory(&_Overlapped, sizeof(_Overlapped));
+ }
+
+ ~CSocketListener()
+ {
+ StopAccepting();
+ }
+
+public:
+ HRESULT Bind();
+ HRESULT EnableAccepting(_In_ IValidateAccept* pValidator);
+ 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:
+ ACCEPT_BUFFER _AcceptBuffer;
+
+ OVERLAPPED _Overlapped;
+ volatile PTP_IO _ThreadpoolIo;
+ DWORD _ThreadpoolThreadId;
+
+ IValidateAccept* _pValidator;
+
+ SOCKET _ListenSocket;
+ SOCKET _ClientSocket;
+};
diff --git a/nfp/net/driver/wppdefs.h b/nfp/net/driver/wppdefs.h
new file mode 100644
index 00000000..da0a176e
--- /dev/null
+++ b/nfp/net/driver/wppdefs.h
@@ -0,0 +1,452 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All Rights Reserved
+
+Abstract:
+
+ WPP Macro definitions.
+
+Author:
+
+ Travis Martin (TravM)
+
+--*/
+
+//
+// Helpful macros
+//
+
+#ifndef WIDEN2
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+#endif
+
+
+//
+// WPP definitions. Listed below is a set of WPP Trace macros. The comments
+// between "//begin_wpp config" and "//end_wpp" are used by the WPP pre-processor
+// to create the *.tmh files
+//
+
+
+#define PROXIMITY_COMMON_TRACE L"Microsoft\\Windows\\ProximityCommon"
+
+#ifndef TRACE_CONTROL_GUID
+#define TRACE_CONTROL_GUID (93bfc19b, a967, 4339, a3e6, 3a4cc30681d1)
+#endif
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(PROXIMITY, 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 non-WDTF 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 error: cannot allocate TLS slot
+ return false;
+ }
+ }
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// To be used only within non-WDTF 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)
+ {
+ WUDF_SAMPLE_DRIVER_ASSERT(_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
+// destrutcion
+//---------------------------------------------------------------------------
+template <class T>
+class AutoRestoredValue
+{
+public:
+ __forceinline AutoRestoredValue(T* pVar, T newVal)
+ : _pVar(pVar)
+ , _oldVal()
+ {
+ WUDF_SAMPLE_DRIVER_ASSERT(_pVar);
+ 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, NULL);
+ }
+ }
+ }
+
+ __forceinline Attach(Pointee* pCtx, DWORD dwSlotIndex)
+ {
+ _dwSlotIndex = dwSlotIndex;
+ TlsSetValue(_dwSlotIndex, pCtx);
+ }
+
+private:
+
+ DWORD _dwSlotIndex;
+};
+
+}
+
+
+//---------------------------------------------------------------------------
+// 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 NULL 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 == NULL) \
+ { \
+ __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) /*TraceMessage()*/; \
+ 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) /*TraceMessage()*/; \
+ 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) /*TraceMessage()*/; \
+ return __pRet; \
+ }
+//MACRO: MethodReturnIfNull
+//
+//begin_wpp config
+//USEPREFIX (MethodReturnIfNull, "%!STDPREFIX!%s<-this(%p):%!FUNC!(): E_POINTER %s=NULL, bailing out!", INDENT_STR(__pCtx->CallDepth), this, #PTR);
+//FUNC MethodReturnIfNull{METHOD_POINTER_LEVEL=EntryExit}(PTR);
+//end_wpp
+#define WPP_METHOD_POINTER_LEVEL_PTR_ENABLED(LEVEL, PTR) WPP_LEVEL_ENABLED(LEVEL)
+#define WPP_METHOD_POINTER_LEVEL_PTR_LOGGER(LEVEL, PTR) WPP_LEVEL_LOGGER(LEVEL)
+#define WPP_METHOD_POINTER_LEVEL_PTR_PRE(LEVEL, PTR) if ((PTR) == NULL) \
+ {
+#define WPP_METHOD_POINTER_LEVEL_PTR_POST(LEVEL, PTR) /*TraceMessage()*/; \
+ return E_POINTER; \
+ }
+//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) /*TraceMessage()*/; \
+ 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) /*TraceMessage()*/; \
+ 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) /*TraceMessage()*/; \
+ return __pRet; \
+ }
+
+
+
+// Define Non-empty debug break for checked builds only
+#ifndef NDEBUG
+ #define DEBUG_BREAK() __debugbreak()
+#else
+ #define DEBUG_BREAK() do {} while (false)
+#endif
+
+
+//MACRO: TraceASSERT
+//
+// ASSERT with tracing
+//
+//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) /*TraceMessage()*/; \
+ WUDF_SAMPLE_DRIVER_ASSERT(FALSE); \
+ }
+
+//MACRO: TraceErrorHR
+//
+// ERROR trace
+//
+//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) \ No newline at end of file
diff --git a/nfp/net/exe/NetNfpControl.cpp b/nfp/net/exe/NetNfpControl.cpp
new file mode 100644
index 00000000..b101d19e
--- /dev/null
+++ b/nfp/net/exe/NetNfpControl.cpp
@@ -0,0 +1,579 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// Module Name: NetNfpControl.cpp
+// Abstract: Windows Near-field Proximity Test tool. Designed for simulating proximity hardware.
+//
+// NetNfpControl console app allows control of the NetNfpProvider test driver.
+// Both the local and remote machine must have the NetNfpProvider driver installed.
+//
+// *USAGE*
+// NetNfpControl.exe <remoteMachine> [/e]
+// NetNfpControl.exe [<remoteMachine>] [/k]
+// NetNfpControl.exe /q
+//
+// Example: NetNfpControl.exe John-PC1
+// The first operating mode allows the user to specify a remote machine name (or IPv6 address)
+// that the local machine should connect to and simulate proximity with. After it's connected,
+// a simple key-press ends the simulated proximity link. The console app then exits.
+// If the option /e is specified, rather than the waiting for a key to be pressed, the tool
+// waits for the QUIT_NAMED_EVENT named event to be set. The named event can be set by running
+// NetNfpControl.exe /q.
+//
+// Example: NetNfpControl.exe John-PC1 /k
+// A second operating mode keeps the console app running with a Ctrl-F1 hotkey registered.
+// This hot key remains registered and functional even when the app is in the background.
+// When the hot key is intercepted, a near-field proximity event is simulated directly with
+// the specified remote machine.
+// Note: The console app needs to be running (only one one machine) to intercept the system hot key.
+//
+// Example: NetNfpControl.exe /k
+// A third operating mode also keeps the console app running with a Ctrl-F1 hotkey registered.
+// However, you'll have to run this on two or more machines at the same time. Pressing Ctrl-F1
+// on any two machines at the same time causes the machines to exchange their network name via
+// a file on a private share with a special file name.
+// - The server share used is hard coded to: \\scratch2\scratch\travm\proxrendezvous\
+// - Either create a file server with these folders shared, or change this to match yours.
+// - The file has an effective lifetime of 2 seconds.
+// - In the event of a collision (two clients posting an event during the same interval),
+// only one client 'wins'.
+//
+//
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma region Includes
+#include "precomp.h"
+#pragma endregion
+
+
+#pragma region Globals
+wchar_t g_szMachineName[MAX_PATH];
+PCWSTR g_pszRemoteMachineName = nullptr;
+#pragma endregion
+
+#define QUIT_NAMED_EVENT L"NetNfpControl_Quit_Event"
+
+
+//----------------------------------------------------------------------------------------------------------------------
+// Name: DEVICE_INTERFACE_DETAIL
+// Comments:
+//
+//----------------------------------------------------------------------------------------------------------------------
+///<summary>Device interface details.</summary>
+struct DEVICE_INTERFACE_DETAIL
+{
+ DWORD cbSize;
+ wchar_t szSymbolicLink[MAX_PATH*2];
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+// Name: BeginProximity
+// Comments:
+//
+//----------------------------------------------------------------------------------------------------------------------
+///<summary>Initalizes a proximity event.</summary>
+///<remarks>
+///</remarks>
+HRESULT BeginProximity(_In_ PCWSTR pszName, _Out_ HANDLE* pHandle)
+{
+ HRESULT hr = S_OK;
+ LPGUID pGuid = (LPGUID) &GUID_DEVINTERFACE_NETNFP;
+
+ HDEVINFO hDevSet = SetupDiGetClassDevs(pGuid, nullptr, nullptr, (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE));
+ if (hDevSet == INVALID_HANDLE_VALUE)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ DEVICE_INTERFACE_DETAIL deviceInterfaceDetail = {};
+ if (SUCCEEDED(hr))
+ {
+ SP_DEVICE_INTERFACE_DATA devInterfaceData = {sizeof(devInterfaceData)};
+ if (!SetupDiEnumDeviceInterfaces(hDevSet, nullptr, pGuid, 0, &devInterfaceData))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)&deviceInterfaceDetail;
+ pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+ if (!SetupDiGetDeviceInterfaceDetail(hDevSet, &devInterfaceData, pDetail,
+ sizeof(deviceInterfaceDetail), nullptr, nullptr))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ SetupDiDestroyDeviceInfoList(hDevSet);
+ }
+
+ HANDLE hProximity = INVALID_HANDLE_VALUE;
+ if (SUCCEEDED(hr))
+ {
+ hProximity = CreateFile(deviceInterfaceDetail.szSymbolicLink, GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hProximity == INVALID_HANDLE_VALUE)
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ BEGIN_PROXIMITY_ARGS args = {};
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCchCopy(args.szName, MAX_PATH, pszName);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ DWORD ignore;
+ if (!DeviceIoControl(hProximity, IOCTL_BEGIN_PROXIMITY, &args, sizeof(args), nullptr, 0, &ignore, nullptr))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (hProximity != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(hProximity);
+ hProximity = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ *pHandle = hProximity;
+
+ return hr;
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+// Name: AcquireFileLock
+// Comments:
+//
+//----------------------------------------------------------------------------------------------------------------------
+///<summary>Aquires a lock on a file.</summary>
+///<remarks>
+///</remarks>
+HANDLE AcquireFileLock(PCWSTR pszLockFilePath)
+{
+ HANDLE hLock = INVALID_HANDLE_VALUE;
+ for (int i = 0; i < 200; i++)
+ {
+ wprintf(L"Attempting to Acquire Lock: %u\n", (DWORD)GetTickCount64());
+ hLock = CreateFile(pszLockFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ if (hLock == INVALID_HANDLE_VALUE)
+ {
+ Sleep(50);
+ }
+ else
+ {
+ wprintf(L"Proximity Lock Acquired: %u\n", (DWORD)GetTickCount64());
+ break;
+ }
+ }
+
+ if (hLock == INVALID_HANDLE_VALUE)
+ {
+ wprintf(L"Proximity Lock Not Acquired, check network connectivity Error = %u.\n", GetLastError());
+ }
+
+ return hLock;
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+// Name: Proximity
+// Comments:
+//
+//----------------------------------------------------------------------------------------------------------------------
+///<summary>Initiates a proximity event.</summary>
+///<remarks>
+///</remarks>
+void Proximity()
+{
+ wprintf(L"Checking For Proximate Device\n");
+
+ SYSTEMTIME sysTime = {};
+ GetLocalTime(&sysTime);
+
+ wchar_t szDirectory[MAX_PATH];
+ StringCchPrintf(szDirectory, MAX_PATH, L"\\\\scratch2\\scratch\\travm\\proxrendezvous\\%u%02u%02u-%02u",
+ sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour);
+
+ CreateDirectory(szDirectory, NULL);
+
+ wchar_t szLockPath[MAX_PATH];
+ StringCchPrintf(szLockPath, MAX_PATH, L"%s\\lock.txt", szDirectory);
+
+ HANDLE hLock = AcquireFileLock(szLockPath);
+
+ wchar_t szOtherMachine[MAX_PATH] = {};
+ if (hLock != INVALID_HANDLE_VALUE)
+ {
+ wprintf(L"looking for available devices in proximity.\n");
+ wchar_t szFindPath[MAX_PATH];
+ StringCchPrintf(szFindPath, MAX_PATH, L"%s\\*.available", szDirectory);
+ WIN32_FIND_DATA findData;
+ HANDLE hFind = FindFirstFile(szFindPath, &findData);
+
+ wchar_t szFilePath[MAX_PATH];
+ bool fClient;
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ fClient = true;
+
+ wprintf(L"Proximate device found: ");
+ StringCchPrintf(szFilePath, MAX_PATH, L"%s\\%s", szDirectory, findData.cFileName);
+ HANDLE hFile = CreateFile(szFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ DWORD ignore;
+ (void)ReadFile(hFile, szOtherMachine, sizeof(szOtherMachine) - sizeof(wchar_t), &ignore, NULL);
+ szOtherMachine[MAX_PATH-1] = L'\0';
+ CloseHandle(hFile);
+ }
+
+ if (szOtherMachine[0] != L'\0')
+ {
+ wprintf(L"%s\n", szOtherMachine);
+ wchar_t szNewFileName[MAX_PATH];
+ StringCchPrintf(szNewFileName, MAX_PATH, L"%s\\%s.%s.%02u%02u", szDirectory, szOtherMachine, g_szMachineName, sysTime.wMinute, sysTime.wSecond);
+ MoveFile(szFilePath, szNewFileName);
+ }
+ }
+ else
+ {
+ fClient = false;
+
+ wprintf(L"No proximate device found yet. Placing proximity marker on share...\n");
+ StringCchPrintf(szFilePath, MAX_PATH, L"%s\\%s.available", szDirectory, g_szMachineName);
+ HANDLE hFile = CreateFile(szFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+ DWORD ignore;
+ WriteFile(hFile, g_szMachineName, sizeof(g_szMachineName), &ignore, NULL);
+ CloseHandle(hFile);
+ }
+
+ FindClose(hFind);
+ hFind = INVALID_HANDLE_VALUE;
+
+ CloseHandle(hLock);
+ DeleteFile(szLockPath);
+
+ if (fClient)
+ {
+ HANDLE hProximity;
+ HRESULT hr = BeginProximity(szOtherMachine, &hProximity);
+ if (SUCCEEDED(hr))
+ {
+ wprintf(L"In Proximity for 1 second...\n");
+ Sleep(1000);
+ CloseHandle(hProximity);
+ wprintf(L"Proximity Complete.\n");
+ }
+ else
+ {
+ wprintf(L"ERROR: BeginProximity() failed: 0x%x\n", hr);
+ }
+ }
+ else
+ {
+ wprintf(L"Other machine will initiate proximity...\n");
+ Sleep(2000);
+
+ bool fCompleted = true;
+ hLock = AcquireFileLock(szLockPath);
+ if (hLock != INVALID_HANDLE_VALUE)
+ {
+ wchar_t szNewFileName[MAX_PATH];
+ StringCchPrintf(szNewFileName, MAX_PATH, L"%s\\%s.%02u%02u.expired", szDirectory, g_szMachineName, sysTime.wMinute, sysTime.wSecond);
+ if (MoveFile(szFilePath, szNewFileName))
+ {
+ fCompleted = false;
+ }
+
+ CloseHandle(hLock);
+ DeleteFile(szLockPath);
+ }
+
+ if (fCompleted)
+ {
+ wprintf(L"Proximity Successful!\n");
+ }
+ else
+ {
+ wprintf(L"ERROR: Proximity Unsuccessful. No proximate device found!\n");
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+// Name: WndProc
+// Comments:
+//
+//----------------------------------------------------------------------------------------------------------------------
+///<summary>Windows call-back procedure.</summary>
+///<remarks>
+///Used to receive call-backs for the Windows system-wide Hot Key's
+///</remarks>
+LRESULT CALLBACK WndProc(
+ HWND hwnd, // handle to window
+ UINT uMsg, // message identifier
+ WPARAM wParam, // first message parameter
+ LPARAM lParam) // second message parameter
+{
+ switch (uMsg)
+ {
+ case WM_HOTKEY:
+ {
+ if (g_pszRemoteMachineName != nullptr)
+ {
+ HANDLE hProximity;
+ HRESULT hr = BeginProximity(g_pszRemoteMachineName, &hProximity);
+ if (SUCCEEDED(hr))
+ {
+ wprintf(L"In Proximity for 1 second...\n");
+ Sleep(1000);
+ CloseHandle(hProximity);
+ wprintf(L"Proximity Complete.\n");
+ }
+ else
+ {
+ wprintf(L"ERROR: BeginProximity() failed: 0x%x\n", hr);
+ }
+ }
+ else // No machine name specified, need to check for a name on the share
+ {
+ Proximity();
+ }
+ }
+ return 0;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+
+ //
+ // Process other messages.
+ //
+ default:
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+ }
+}
+
+__analysis_noreturn void Usage()
+{
+ wprintf(L"Usage: \n");
+ wprintf(L" NetNfpControl.exe <Machine Name or IP>\n");
+ wprintf(L" NetNfpControl.exe /e <Machine Name or IP>\n");
+ wprintf(L" NetNfpControl.exe /q\n");
+ wprintf(L" NetNfpControl.exe /k\n");
+ wprintf(L" NetNfpControl.exe /k <Machine Name or IP>\n");
+ wprintf(L"\n");
+ wprintf(L"The /k option registers a hotkey for entering proximity while selfhosting\n");
+ wprintf(L"The /e option keeps NetNfpControl.exe running until NetNfpControl.exe /q is called\n"
+ L" (or until the named event %s is set)\n", QUIT_NAMED_EVENT);
+ wprintf(L"The /q option sets the the named event %s (and exits), causing \n"
+ L" all the outstanding instances of 'NetNfpControl.exe /e' to exit\n", QUIT_NAMED_EVENT);
+
+ exit(1);
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+// Name: wmain
+// Comments: Main application entry point.
+//
+//----------------------------------------------------------------------------------------------------------------------
+///<summary>wmain.</summary>
+///<remarks>
+///Main application entry point.
+///</remarks>
+int _cdecl wmain(_In_ int argc, _In_reads_(argc) PWSTR* argv)
+{
+ wprintf(L"\n*** Network NearFieldProvider Control Executable ***\n\n");
+ if (argc < 2)
+ {
+ Usage();
+ }
+
+ bool fUseHotKey = false;
+ bool fWaitOnNamedEvent = false;
+ bool fQuitGlobalEventWaiters = false;
+
+ for (int i = 1; i < argc; i++)
+ {
+ if ((argv[i][0] == L'/') || (argv[i][0] == L'-'))
+ {
+ if ((argv[i][1] == L'k') || (argv[i][1] == L'K'))
+ {
+ fUseHotKey = true;
+ }
+ else if ((argv[i][1] == L'e') || (argv[i][1] == L'E'))
+ {
+ fWaitOnNamedEvent = true;
+ }
+ else if ((argv[i][1] == L'q') || (argv[i][1] == L'Q'))
+ {
+ fQuitGlobalEventWaiters = true;
+ }
+ else
+ {
+ wprintf(L"*** Unknown command line argument: '%ws' ***\n\n", argv[i]);
+ Usage();
+ }
+ }
+ else
+ {
+ if (g_pszRemoteMachineName != nullptr)
+ {
+ wprintf(L"*** Can't specify two machine names ***\n\n");
+ Usage();
+ }
+ g_pszRemoteMachineName = argv[i];
+ }
+ }
+
+ if (fUseHotKey)
+ {
+ if (g_pszRemoteMachineName != nullptr)
+ {
+ wprintf(L"Press Ctrl-F1 on this machine to initiate proximity with: '%ws'.\n\n", g_pszRemoteMachineName);
+ }
+ else
+ {
+ // Dynamic Keyboard hotkey version
+ wprintf(L"Press Ctrl-F1 on two machines at the same time to initiate proximity.\n\n");
+
+ DWORD cchMachineName = MAX_PATH;
+ if (!GetComputerNameEx(ComputerNameNetBIOS, g_szMachineName, &cchMachineName))
+ {
+ return FALSE;
+ }
+ }
+
+ // Register the window class for the main window.
+ WNDCLASS wc = {};
+ wc.lpfnWndProc = (WNDPROC)WndProc;
+ wc.hInstance = GetModuleHandle(NULL);
+ wc.lpszMenuName = L"MainMenu";
+ wc.lpszClassName = L"MainWndClass";
+
+ if (!RegisterClass(&wc))
+ {
+ return FALSE;
+ }
+
+ // Create the main window.
+ HWND hwndMain = CreateWindow(L"MainWndClass", L"Sample",
+ WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL,
+ (HMENU) NULL, GetModuleHandle(NULL), (LPVOID) NULL);
+
+ // If the main window cannot be created, terminate
+ // the application.
+ if (!hwndMain)
+ {
+ return FALSE;
+ }
+
+ if (!RegisterHotKey(hwndMain, 264334, MOD_CONTROL, VK_F1))
+ {
+ wprintf(L"ERROR: Ctrl-F1 Hotkey already registered!\n");
+ return FALSE;
+ }
+
+ // Start the message loop.
+
+ MSG msg;
+ BOOL bRet;
+ while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
+ {
+ if (bRet == -1)
+ {
+ // handle the error and possibly exit
+ }
+ else
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ // Return the exit code to the system.
+
+ return (int)msg.wParam;
+
+ }
+ else if (fQuitGlobalEventWaiters)
+ {
+ HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, QUIT_NAMED_EVENT);
+ if (NULL != hEvent)
+ {
+ wprintf(L"Quitting running instances of NetNfpControl.exe /e <machinename>\n");
+
+ BOOL bSetErr = SetEvent(hEvent);
+ if (!bSetErr)
+ {
+ wprintf(L"Failed to set named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, GetLastError());
+ }
+
+ CloseHandle(hEvent);
+ }
+ else
+ {
+ wprintf(L"Failed to open named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, GetLastError());
+ }
+ }
+ else
+ {
+ if (NULL == g_pszRemoteMachineName)
+ {
+ Usage();
+ }
+
+ wprintf(L"Attempting connect: '%ws' ...\n\n", g_pszRemoteMachineName);
+
+ HANDLE hProximity;
+ HRESULT hr = BeginProximity(g_pszRemoteMachineName, &hProximity);
+ if (SUCCEEDED(hr))
+ {
+ if (fWaitOnNamedEvent)
+ {
+ wprintf(L"run NetNfpControl.exe /q to end Proximity (or Set the named event %s)\n", QUIT_NAMED_EVENT);
+
+ HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, QUIT_NAMED_EVENT);
+ if (NULL != hEvent)
+ {
+ DWORD dwWaitErr = WaitForSingleObject(hEvent, INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitErr)
+ {
+ dwWaitErr = (WAIT_FAILED == dwWaitErr ? GetLastError() : dwWaitErr);
+ wprintf(L"Failed to wait on named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, dwWaitErr);
+ }
+
+ CloseHandle(hEvent);
+ }
+ else
+ {
+ wprintf(L"Failed to create/open named event %s (Err=0x%x)...\n", QUIT_NAMED_EVENT, GetLastError());
+ }
+ }
+ else
+ {
+ wprintf(L"Press Any Key to End Proximity.\n");
+ (void) _getch();
+ wprintf(L"Ending Proximity...\n");
+ }
+
+ CloseHandle(hProximity);
+ }
+ else
+ {
+ wprintf(L"BeginProximity() failed: 0x%x\n", hr);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/nfp/net/exe/NetNfpControl.vcxproj b/nfp/net/exe/NetNfpControl.vcxproj
new file mode 100644
index 00000000..b2eb94ff
--- /dev/null
+++ b/nfp/net/exe/NetNfpControl.vcxproj
@@ -0,0 +1,262 @@
+<?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>{4ABF1B83-9726-45DE-B705-A8458BCB0915}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{B57AFB72-58B6-45CF-8E49-3D56D66A2842}</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 />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</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" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>NetNfpControl</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>NetNfpControl</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>NetNfpControl</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>NetNfpControl</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <UseOfAtl>Dynamic</UseOfAtl>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);..\inc;..\driver</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;uuid.lib;user32.lib;ntdll.lib;user32.lib;oleacc.lib;SetupAPI.lib;Ws2_32.lib;mswsock.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="NetNfpControl.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="precompsrc.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </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/nfp/net/exe/NetNfpControl.vcxproj.Filters b/nfp/net/exe/NetNfpControl.vcxproj.Filters
new file mode 100644
index 00000000..c01e6141
--- /dev/null
+++ b/nfp/net/exe/NetNfpControl.vcxproj.Filters
@@ -0,0 +1,25 @@
+<?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>{1C29E1A2-5E3D-4A88-A8C5-2DBBA704EF00}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{5535C5B0-0DF3-4CF2-ACA9-2F899FA6CE1C}</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>{534D73C8-CECE-4D3E-9B06-469E2C777F49}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="NetNfpControl.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/nfp/net/exe/precomp.h b/nfp/net/exe/precomp.h
new file mode 100644
index 00000000..4748bcf8
--- /dev/null
+++ b/nfp/net/exe/precomp.h
@@ -0,0 +1,37 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// Module Name: precomp.h
+// Abstract:
+//
+// Precompiled header file for the NetNfpControl console app
+//
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma once
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+
+// Windows Headers
+#include <windows.h>
+#include <Winsock2.h>
+#include <Mswsock.h>
+#include <Ws2bth.h>
+#include <Ws2tcpip.h>
+#include <conio.h>
+#include <setupapi.h>
+#include <tchar.h>
+#include <strsafe.h>
+#include <winioctl.h>
+
+// ATL stuff
+#include <atlbase.h>
+
+// Common NetNfp header
+#include "NetNfp.h"
diff --git a/nfp/net/exe/precompsrc.cpp b/nfp/net/exe/precompsrc.cpp
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/nfp/net/exe/precompsrc.cpp
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/nfp/net/inc/NetNfp.h b/nfp/net/inc/NetNfp.h
new file mode 100644
index 00000000..b891313e
--- /dev/null
+++ b/nfp/net/inc/NetNfp.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (C) Microsoft Corporation, All Rights Reserved
+
+Module Name:
+
+ NetNfp.h
+
+Abstract:
+
+ This header contains definitions common to the both the NetNfpProvider.sys
+ driver and the NetNfpControl.exe.
+
+Environment:
+
+ User Mode
+
+--*/
+#pragma once
+
+
+/* 2DD081BE-1294-440B-AB9F-F0E9FDD77FBE */
+const GUID GUID_DEVINTERFACE_NETNFP =
+ {0x2DD081BE, 0x1294, 0x440B, {0xAB, 0x9F, 0xF0, 0xE9, 0xFD, 0xD7, 0x7F, 0xBE}};
+
+#define IOCTL_BEGIN_PROXIMITY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1000, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+struct BEGIN_PROXIMITY_ARGS
+{
+ WCHAR szName[MAX_PATH]; // Name or IP address
+};
+
diff --git a/nfp/net/netnfp.sln b/nfp/net/netnfp.sln
new file mode 100644
index 00000000..f8b5f6b2
--- /dev/null
+++ b/nfp/net/netnfp.sln
@@ -0,0 +1,46 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{6133A073-0A35-45D3-BC68-BA16B0F829D8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{4FD03920-D970-4A51-A2A1-A394DF683A03}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpProvider", "driver\NetNfpProvider.vcxproj", "{756016BF-4187-4482-A0BE-CEE1698BD129}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetNfpControl", "exe\NetNfpControl.vcxproj", "{4ABF1B83-9726-45DE-B705-A8458BCB0915}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|Win32.ActiveCfg = Debug|Win32
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|Win32.Build.0 = Debug|Win32
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|Win32.ActiveCfg = Release|Win32
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|Win32.Build.0 = Release|Win32
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|x64.ActiveCfg = Debug|x64
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Debug|x64.Build.0 = Debug|x64
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|x64.ActiveCfg = Release|x64
+ {756016BF-4187-4482-A0BE-CEE1698BD129}.Release|x64.Build.0 = Release|x64
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|Win32.Build.0 = Debug|Win32
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|Win32.ActiveCfg = Release|Win32
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|Win32.Build.0 = Release|Win32
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|x64.ActiveCfg = Debug|x64
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Debug|x64.Build.0 = Debug|x64
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|x64.ActiveCfg = Release|x64
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {756016BF-4187-4482-A0BE-CEE1698BD129} = {6133A073-0A35-45D3-BC68-BA16B0F829D8}
+ {4ABF1B83-9726-45DE-B705-A8458BCB0915} = {4FD03920-D970-4A51-A2A1-A394DF683A03}
+ EndGlobalSection
+EndGlobal