summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp3650
1 files changed, 3650 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp
new file mode 100644
index 00000000..44c7338c
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp
@@ -0,0 +1,3650 @@
+/* $Id: VBoxNetFltRt-win.cpp $ */
+/** @file
+ * VBoxNetFltRt-win.cpp - Bridged Networking Driver, Windows Specific Runtime Code.
+ */
+
+/*
+ * Copyright (C) 2011-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "VBoxNetFltCmn-win.h"
+#include <VBox/intnetinline.h>
+#include <iprt/thread.h>
+
+#include <iprt/nt/tdikrnl.h>
+#include <mstcpip.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/** represents the job element of the job queue
+ * see comments for VBOXNETFLT_JOB_QUEUE */
+typedef struct VBOXNETFLT_JOB
+{
+ /** link in the job queue */
+ LIST_ENTRY ListEntry;
+ /** job function to be executed */
+ PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine;
+ /** parameter to be passed to the job function */
+ PVOID pContext;
+ /** event that will be fired on job completion */
+ KEVENT CompletionEvent;
+ /** true if the job manager should use the completion even for completion indication, false-otherwise*/
+ bool bUseCompletionEvent;
+} VBOXNETFLT_JOB, *PVBOXNETFLT_JOB;
+
+/**
+ * represents the queue of jobs processed by the worker thread
+ *
+ * we use the thread to process tasks which are required to be done at passive level
+ * our callbacks may be called at APC level by IntNet, there are some tasks that we can not create at APC,
+ * e.g. thread creation. This is why we schedule such jobs to the worker thread working at passive level
+ */
+typedef struct VBOXNETFLT_JOB_QUEUE
+{
+ /* jobs */
+ LIST_ENTRY Jobs;
+ /* we are using ExInterlocked..List functions to access the jobs list */
+ KSPIN_LOCK Lock;
+ /** this event is used to initiate a job worker thread kill */
+ KEVENT KillEvent;
+ /** this event is used to notify a worker thread that jobs are added to the queue */
+ KEVENT NotifyEvent;
+ /** worker thread */
+ PKTHREAD pThread;
+} VBOXNETFLT_JOB_QUEUE, *PVBOXNETFLT_JOB_QUEUE;
+
+typedef struct _CREATE_INSTANCE_CONTEXT
+{
+#ifndef VBOXNETADP
+ PNDIS_STRING pOurName;
+ PNDIS_STRING pBindToName;
+#else
+ NDIS_HANDLE hMiniportAdapter;
+ NDIS_HANDLE hWrapperConfigurationContext;
+#endif
+ NDIS_STATUS Status;
+} CREATE_INSTANCE_CONTEXT, *PCREATE_INSTANCE_CONTEXT;
+
+/*contexts used for our jobs */
+/* Attach context */
+typedef struct _ATTACH_INFO
+{
+ PVBOXNETFLTINS pNetFltIf;
+ PCREATE_INSTANCE_CONTEXT pCreateContext;
+ bool fRediscovery;
+ int Status;
+} ATTACH_INFO, *PATTACH_INFO;
+
+/* general worker context */
+typedef struct _WORKER_INFO
+{
+ PVBOXNETFLTINS pNetFltIf;
+ int Status;
+} WORKER_INFO, *PWORKER_INFO;
+
+/* idc initialization */
+typedef struct _INIT_IDC_INFO
+{
+ VBOXNETFLT_JOB Job;
+ bool bInitialized;
+ volatile bool bStop;
+ volatile int rc;
+ KEVENT hCompletionEvent;
+} INIT_IDC_INFO, *PINIT_IDC_INFO;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** global job queue. some operations are required to be done at passive level, e.g. thread creation, adapter bind/unbind initiation,
+ * while IntNet typically calls us APC_LEVEL, so we just create a system thread in our DriverEntry and enqueue the jobs to that thread */
+static VBOXNETFLT_JOB_QUEUE g_VBoxJobQueue;
+volatile static bool g_bVBoxIdcInitialized;
+INIT_IDC_INFO g_VBoxInitIdcInfo;
+
+/**
+ * The (common) global data.
+ */
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+/* win-specific global data */
+VBOXNETFLTGLOBALS_WIN g_VBoxNetFltGlobalsWin = {{{0}}};
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define LIST_ENTRY_2_JOB(pListEntry) \
+ ( (PVBOXNETFLT_JOB)((uint8_t *)(pListEntry) - RT_UOFFSETOF(VBOXNETFLT_JOB, ListEntry)) )
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery);
+static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis);
+static int vboxNetFltWinFiniIdc();
+static void vboxNetFltWinFiniNetFltBase();
+static int vboxNetFltWinInitNetFltBase();
+static int vboxNetFltWinFiniNetFlt();
+static int vboxNetFltWinStartInitIdcProbing();
+static int vboxNetFltWinStopInitIdcProbing();
+
+
+
+/** makes the current thread to sleep for the given number of miliseconds */
+DECLHIDDEN(void) vboxNetFltWinSleep(ULONG milis)
+{
+ RTThreadSleep(milis);
+}
+
+/** wait for the given device to be dereferenced */
+DECLHIDDEN(void) vboxNetFltWinWaitDereference(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+#ifdef DEBUG
+ uint64_t StartNanoTS = RTTimeSystemNanoTS();
+ uint64_t CurNanoTS;
+#endif
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ while (ASMAtomicUoReadU32((volatile uint32_t *)&pState->cReferences))
+ {
+ vboxNetFltWinSleep(2);
+#ifdef DEBUG
+ CurNanoTS = RTTimeSystemNanoTS();
+ if (CurNanoTS - StartNanoTS > 20000000)
+ {
+ LogRel(("device not idle"));
+ AssertFailed();
+// break;
+ }
+#endif
+ }
+}
+
+/**
+ * mem functions
+ */
+/* allocates and zeroes the nonpaged memory of a given size */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMemAlloc(PVOID *ppvMemBuf, UINT cbLength)
+{
+#ifdef DEBUG_NETFLT_USE_EXALLOC
+ *ppvMemBuf = ExAllocatePoolWithTag(NonPagedPool, cbLength, VBOXNETFLT_MEM_TAG);
+ if (*ppvMemBuf)
+ {
+ NdisZeroMemory(*ppvMemBuf, cbLength);
+ return NDIS_STATUS_SUCCESS;
+ }
+ return NDIS_STATUS_FAILURE;
+#else
+ NDIS_STATUS fStatus = NdisAllocateMemoryWithTag(ppvMemBuf, cbLength, VBOXNETFLT_MEM_TAG);
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ NdisZeroMemory(*ppvMemBuf, cbLength);
+ return fStatus;
+#endif
+}
+
+/* frees memory allocated with vboxNetFltWinMemAlloc */
+DECLHIDDEN(void) vboxNetFltWinMemFree(PVOID pvMemBuf)
+{
+#ifdef DEBUG_NETFLT_USE_EXALLOC
+ ExFreePool(pvMemBuf);
+#else
+ NdisFreeMemory(pvMemBuf, 0, 0);
+#endif
+}
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+
+/* initializes packet info pool and allocates the cSize packet infos for the pool */
+static NDIS_STATUS vboxNetFltWinPpAllocatePacketInfoPool(PVBOXNETFLT_PACKET_INFO_POOL pPool, UINT cSize)
+{
+ UINT cbBufSize = sizeof(PACKET_INFO)*cSize;
+ PACKET_INFO * pPacketInfos;
+ NDIS_STATUS fStatus;
+ UINT i;
+
+ Assert(cSize > 0);
+
+ INIT_INTERLOCKED_PACKET_QUEUE(&pPool->Queue);
+
+ fStatus = vboxNetFltWinMemAlloc((PVOID*)&pPacketInfos, cbBufSize);
+
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLTPACKET_INFO pInfo;
+ pPool->pBuffer = pPacketInfos;
+
+ for (i = 0; i < cSize; i++)
+ {
+ pInfo = &pPacketInfos[i];
+ vboxNetFltWinQuEnqueueTail(&pPool->Queue.Queue, pInfo);
+ pInfo->pPool = pPool;
+ }
+ }
+ else
+ {
+ AssertFailed();
+ }
+
+ return fStatus;
+}
+
+/* frees the packet info pool */
+VOID vboxNetFltWinPpFreePacketInfoPool(PVBOXNETFLT_PACKET_INFO_POOL pPool)
+{
+ vboxNetFltWinMemFree(pPool->pBuffer);
+
+ FINI_INTERLOCKED_PACKET_QUEUE(&pPool->Queue)
+}
+
+#endif
+
+/**
+ * copies one string to another. in case the destination string size is not enough to hold the complete source string
+ * does nothing and returns NDIS_STATUS_RESOURCES .
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinCopyString(PNDIS_STRING pDst, PNDIS_STRING pSrc)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ if (pDst != pSrc)
+ {
+ if (pDst->MaximumLength < pSrc->Length)
+ {
+ AssertFailed();
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ pDst->Length = pSrc->Length;
+
+ if (pDst->Buffer != pSrc->Buffer)
+ {
+ NdisMoveMemory(pDst->Buffer, pSrc->Buffer, pSrc->Length);
+ }
+ }
+ }
+ return Status;
+}
+
+/************************************************************************************
+ * PINTNETSG pSG manipulation functions
+ ************************************************************************************/
+
+/* moves the contents of the given NDIS_BUFFER and all other buffers chained to it to the PINTNETSG
+ * the PINTNETSG is expected to contain one segment whose bugger is large enough to maintain
+ * the contents of the given NDIS_BUFFER and all other buffers chained to it */
+static NDIS_STATUS vboxNetFltWinNdisBufferMoveToSG0(PNDIS_BUFFER pBuffer, PINTNETSG pSG)
+{
+ PINTNETSEG paSeg;
+ uint8_t * ptr;
+ PVOID pVirtualAddress;
+ UINT cbCurrentLength;
+ NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
+
+ Assert(pSG->cSegsAlloc == 1);
+
+ paSeg = pSG->aSegs;
+ ptr = (uint8_t*)paSeg->pv;
+ paSeg->cb = 0;
+ paSeg->Phys = NIL_RTHCPHYS;
+ pSG->cbTotal = 0;
+
+ Assert(paSeg->pv);
+
+ while (pBuffer)
+ {
+ NdisQueryBufferSafe(pBuffer, &pVirtualAddress, &cbCurrentLength, NormalPagePriority);
+
+ if (!pVirtualAddress)
+ {
+ fStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pSG->cbTotal += cbCurrentLength;
+ paSeg->cb += cbCurrentLength;
+ NdisMoveMemory(ptr, pVirtualAddress, cbCurrentLength);
+ ptr += cbCurrentLength;
+
+ NdisGetNextBuffer(pBuffer, &pBuffer);
+ }
+
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ pSG->cSegsUsed = 1;
+ Assert(pSG->cbTotal == paSeg->cb);
+ }
+ return fStatus;
+}
+
+/* converts the PNDIS_BUFFER to PINTNETSG by making the PINTNETSG segments to point to the memory buffers the
+ * ndis buffer(s) point to (as opposed to vboxNetFltWinNdisBufferMoveToSG0 which copies the memory from ndis buffers(s) to PINTNETSG) */
+static NDIS_STATUS vboxNetFltWinNdisBuffersToSG(PNDIS_BUFFER pBuffer, PINTNETSG pSG)
+{
+ UINT cSegs = 0;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PVOID pVirtualAddress;
+ UINT cbCurrentLength;
+
+ while (pBuffer)
+ {
+ NdisQueryBufferSafe(pBuffer, &pVirtualAddress, &cbCurrentLength, NormalPagePriority);
+
+ if (!pVirtualAddress)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pSG->cbTotal += cbCurrentLength;
+ pSG->aSegs[cSegs].cb = cbCurrentLength;
+ pSG->aSegs[cSegs].pv = pVirtualAddress;
+ pSG->aSegs[cSegs].Phys = NIL_RTHCPHYS;
+ cSegs++;
+
+ NdisGetNextBuffer(pBuffer, &pBuffer);
+ }
+
+ AssertFatal(cSegs <= pSG->cSegsAlloc);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pSG->cSegsUsed = cSegs;
+ }
+
+ return Status;
+}
+
+static void vboxNetFltWinDeleteSG(PINTNETSG pSG)
+{
+ vboxNetFltWinMemFree(pSG);
+}
+
+static PINTNETSG vboxNetFltWinCreateSG(uint32_t cSegs)
+{
+ PINTNETSG pSG;
+ NTSTATUS Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]));
+ if (Status == STATUS_SUCCESS)
+ {
+ IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
+ return pSG;
+ }
+
+ return NULL;
+}
+
+/************************************************************************************
+ * packet queue functions
+ ************************************************************************************/
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+#if !defined(VBOXNETADP)
+static NDIS_STATUS vboxNetFltWinQuPostPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PINTNETSG pSG, uint32_t fFlags
+# ifdef DEBUG_NETFLT_PACKETS
+ , PNDIS_PACKET pTmpPacket
+# endif
+ )
+{
+ NDIS_STATUS Status;
+ PNDIS_PACKET pMyPacket;
+ bool bSrcHost = fFlags & PACKET_SRC_HOST;
+
+ LogFlow(("posting packet back to driver stack..\n"));
+
+ if (!pPacket)
+ {
+ /* INTNETSG was in the packet queue, create a new NdisPacket from INTNETSG*/
+ pMyPacket = vboxNetFltWinNdisPacketFromSG(pNetFlt,
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ bSrcHost, /* bool bToWire */
+ false); /* bool bCopyMemory */
+
+ Assert(pMyPacket);
+
+ NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_SUCCESS);
+
+ DBG_CHECK_PACKET_AND_SG(pMyPacket, pSG);
+
+#ifdef DEBUG_NETFLT_PACKETS
+ Assert(pTmpPacket);
+
+ DBG_CHECK_PACKET_AND_SG(pTmpPacket, pSG);
+
+ DBG_CHECK_PACKETS(pTmpPacket, pMyPacket);
+#endif
+
+ LogFlow(("non-ndis packet info, packet created (%p)\n", pMyPacket));
+ }
+ else
+ {
+ /* NDIS_PACKET was in the packet queue */
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+
+ if (!(fFlags & PACKET_MINE))
+ {
+ /* the packet is the one that was passed to us in send/receive callback
+ * According to the DDK, we can not post it further,
+ * instead we should allocate our own packet.
+ * So, allocate our own packet (pMyPacket) and copy the packet info there */
+ if (bSrcHost)
+ {
+ Status = vboxNetFltWinPrepareSendPacket(pNetFlt, pPacket, &pMyPacket/*, true*/);
+ LogFlow(("packet from wire, packet created (%p)\n", pMyPacket));
+ }
+ else
+ {
+ Status = vboxNetFltWinPrepareRecvPacket(pNetFlt, pPacket, &pMyPacket, false);
+ LogFlow(("packet from wire, packet created (%p)\n", pMyPacket));
+ }
+ }
+ else
+ {
+ /* the packet enqueued is ours, simply assign pMyPacket and zero pPacket */
+ pMyPacket = pPacket;
+ pPacket = NULL;
+ }
+ Assert(pMyPacket);
+ }
+
+ if (pMyPacket)
+ {
+ /* we have successfully initialized our packet, post it to the host or to the wire */
+ if (bSrcHost)
+ {
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ vboxNetFltWinLbPutSendPacket(pNetFlt, pMyPacket, false /* bFromIntNet */);
+#endif
+ NdisSend(&Status, pNetFlt->u.s.hBinding, pMyPacket);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ /* the status is NOT pending, complete the packet */
+ bool bTmp = vboxNetFltWinLbRemoveSendPacket(pNetFlt, pMyPacket);
+ Assert(bTmp);
+#endif
+ if (pPacket)
+ {
+ LogFlow(("status is not pending, completing packet (%p)\n", pPacket));
+
+ NdisIMCopySendCompletePerPacketInfo (pPacket, pMyPacket);
+
+ NdisFreePacket(pMyPacket);
+ }
+ else
+ {
+ /* should never be here since the PINTNETSG is stored only when the underlying miniport
+ * indicates NDIS_STATUS_RESOURCES, we should never have this when processing
+ * the "from-host" packets */
+ AssertFailed();
+ LogFlow(("status is not pending, freeing myPacket (%p)\n", pMyPacket));
+ vboxNetFltWinFreeSGNdisPacket(pMyPacket, false);
+ }
+ }
+ }
+ else
+ {
+ NdisMIndicateReceivePacket(pNetFlt->u.s.hMiniport, &pMyPacket, 1);
+
+ Status = NDIS_STATUS_PENDING;
+ /* the packet receive completion is always indicated via MiniportReturnPacket */
+ }
+ }
+ else
+ {
+ /*we failed to create our packet */
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+#endif
+
+static bool vboxNetFltWinQuProcessInfo(PVBOXNETFLTINS pNetFltIf, PPACKET_QUEUE_WORKER pWorker, PVOID pvPacket, const UINT fFlags)
+#else
+DECLHIDDEN(bool) vboxNetFltWinPostIntnet(PVBOXNETFLTINS pNetFltIf, PVOID pvPacket, const UINT fFlags)
+#endif
+{
+ PNDIS_PACKET pPacket = NULL;
+ PINTNETSG pSG = NULL;
+ NDIS_STATUS Status;
+#ifndef VBOXNETADP
+ bool bSrcHost;
+ bool bDropIt;
+# ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ bool bPending;
+# endif
+#endif
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ bool bDeleteSG = false;
+#endif
+#ifdef DEBUG_NETFLT_PACKETS
+ /* packet used for matching */
+ PNDIS_PACKET pTmpPacket = NULL;
+#endif
+
+#ifndef VBOXNETADP
+ bSrcHost = (fFlags & VBOXNETFLT_PACKET_SRC_HOST) != 0;
+#endif
+
+ /* we first need to obtain the INTNETSG to be passed to intnet */
+
+ /* the queue may contain two "types" of packets:
+ * the NDIS_PACKET and the INTNETSG.
+ * I.e. on send/receive we typically enqueue the NDIS_PACKET passed to us by ndis,
+ * however in case our ProtocolReceive is called or the packet's status is set to NDIS_STSTUS_RESOURCES
+ * in ProtocolReceivePacket, we must return the packet immediately on ProtocolReceive*** exit
+ * In this case we allocate the INTNETSG, copy the ndis packet data there and enqueue it.
+ * In this case the packet info flags has the VBOXNETFLT_PACKET_SG fag set
+ *
+ * Besides that the NDIS_PACKET contained in the queue could be either the one passed to us in our send/receive callback
+ * or the one created by us. The latter is possible in case our ProtocolReceive callback is called and we call NdisTransferData
+ * in this case we need to allocate the packet the data to be transferred to.
+ * If the enqueued packet is the one allocated by us the VBOXNETFLT_PACKET_MINE flag is set
+ * */
+ if ((fFlags & VBOXNETFLT_PACKET_SG) == 0)
+ {
+ /* we have NDIS_PACKET enqueued, we need to convert it to INTNETSG to be passed to intnet */
+ PNDIS_BUFFER pCurrentBuffer = NULL;
+ UINT cBufferCount;
+ UINT cbPacketLength;
+
+ pPacket = (PNDIS_PACKET)pvPacket;
+
+ LogFlow(("ndis packet info, packet (%p)\n", pPacket));
+
+ LogFlow(("preparing pSG"));
+ NdisQueryPacket(pPacket, NULL, &cBufferCount, &pCurrentBuffer, &cbPacketLength);
+ Assert(cBufferCount);
+
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ pSG = vboxNetFltWinCreateSG(cBufferCount);
+#else
+ /* we can not allocate the INTNETSG on stack since in this case we may get stack overflow
+ * somewhere outside of our driver (3 pages of system thread stack does not seem to be enough)
+ *
+ * since we have a "serialized" packet processing, i.e. all packets are being processed and passed
+ * to intnet by this thread, we just use one previously allocated INTNETSG which is stored in PVBOXNETFLTINS */
+ pSG = pWorker->pSG;
+
+ if (cBufferCount > pSG->cSegsAlloc)
+ {
+ pSG = vboxNetFltWinCreateSG(cBufferCount + 2);
+ if (pSG)
+ {
+ vboxNetFltWinDeleteSG(pWorker->pSG);
+ pWorker->pSG = pSG;
+ }
+ else
+ {
+ LogRel(("Failed to reallocate the pSG\n"));
+ }
+ }
+#endif
+
+ if (pSG)
+ {
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ bDeleteSG = true;
+#endif
+ /* reinitialize */
+ IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, pSG->cSegsAlloc, 0 /*cSegsUsed*/);
+
+ /* convert the ndis buffers to INTNETSG */
+ Status = vboxNetFltWinNdisBuffersToSG(pCurrentBuffer, pSG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ pSG = NULL;
+ }
+ else
+ {
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+ }
+ }
+ }
+ else
+ {
+ /* we have the INTNETSG enqueued. (see the above comment explaining why/when this may happen)
+ * just use the INTNETSG to pass it to intnet */
+#ifndef VBOXNETADP
+ /* the PINTNETSG is stored only when the underlying miniport
+ * indicates NDIS_STATUS_RESOURCES, we should never have this when processing
+ * the "from-host" packedts */
+ Assert(!bSrcHost);
+#endif
+ pSG = (PINTNETSG)pvPacket;
+
+ LogFlow(("not ndis packet info, pSG (%p)\n", pSG));
+ }
+
+#ifdef DEBUG_NETFLT_PACKETS
+ if (!pPacket && !pTmpPacket)
+ {
+ /* create tmp packet that woud be used for matching */
+ pTmpPacket = vboxNetFltWinNdisPacketFromSG(pNetFltIf,
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ bSrcHost, /* bool bToWire */
+ true); /* bool bCopyMemory */
+
+ NDIS_SET_PACKET_STATUS(pTmpPacket, NDIS_STATUS_SUCCESS);
+
+ DBG_CHECK_PACKET_AND_SG(pTmpPacket, pSG);
+
+ Assert(pTmpPacket);
+ }
+#endif
+ do
+ {
+#ifndef VBOXNETADP
+ /* the pSG was successfully initialized, post it to the netFlt*/
+ bDropIt = pSG ? pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, NULL /* pvIf */, pSG,
+ bSrcHost ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE
+ )
+ : false;
+#else
+ if (pSG)
+ {
+ pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_HOST);
+ STATISTIC_INCREASE(pNetFltIf->u.s.WinIf.cTxSuccess);
+ }
+ else
+ {
+ STATISTIC_INCREASE(pNetFltIf->u.s.WinIf.cTxError);
+ }
+#endif
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+
+# if !defined(VBOXNETADP)
+ if (!bDropIt)
+ {
+ Status = vboxNetFltWinQuPostPacket(pNetFltIf, pPacket, pSG, fFlags
+# ifdef DEBUG_NETFLT_PACKETS
+ , pTmpPacket
+# endif
+ );
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ /* we will process packet completion in the completion routine */
+ bPending = true;
+ break;
+ }
+ }
+ else
+# endif
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ /* drop it */
+ if (pPacket)
+ {
+ if (!(fFlags & PACKET_MINE))
+ {
+# if !defined(VBOXNETADP)
+ /* complete the packets */
+ if (fFlags & PACKET_SRC_HOST)
+ {
+# endif
+/* NDIS_SET_PACKET_STATUS(pPacket, Status); */
+ NdisMSendComplete(pNetFltIf->u.s.hMiniport, pPacket, Status);
+# if !defined(VBOXNETADP)
+ }
+ else
+ {
+# endif
+# ifndef VBOXNETADP
+ NdisReturnPackets(&pPacket, 1);
+# endif
+# if !defined(VBOXNETADP)
+ }
+# endif
+ }
+ else
+ {
+ Assert(!(fFlags & PACKET_SRC_HOST));
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ }
+ }
+ else
+ {
+ Assert(pSG);
+ vboxNetFltWinMemFree(pSG);
+ }
+# ifndef VBOXNETADP
+ bPending = false;
+# endif
+ } while (0);
+
+#ifdef DEBUG_NETFLT_PACKETS
+ if (pTmpPacket)
+ {
+ vboxNetFltWinFreeSGNdisPacket(pTmpPacket, true);
+ }
+#endif
+
+#ifndef VBOXNETADP
+ return bPending;
+#else
+ return false;
+#endif
+#else /* #ifdef VBOXNETFLT_NO_PACKET_QUEUE */
+ } while (0);
+
+ if (bDeleteSG)
+ vboxNetFltWinMemFree(pSG);
+
+# ifndef VBOXNETADP
+ return bDropIt;
+# else
+ return true;
+# endif
+#endif
+}
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+/*
+ * thread start function for the thread which processes the packets enqueued in our send and receive callbacks called by ndis
+ *
+ * ndis calls us at DISPATCH_LEVEL, while IntNet is using kernel functions which require Irql<DISPATCH_LEVEL
+ * this is why we can not immediately post packets to IntNet from our sen/receive callbacks
+ * instead we put the incoming packets to the queue and maintain the system thread running at passive level
+ * which processes the queue and posts the packets to IntNet, and further to the host or to the wire.
+ */
+static VOID vboxNetFltWinQuPacketQueueWorkerThreadProc(PVBOXNETFLTINS pNetFltIf)
+{
+ bool fResume = true;
+ NTSTATUS fStatus;
+ PPACKET_QUEUE_WORKER pWorker = &pNetFltIf->u.s.PacketQueueWorker;
+
+ PVOID apEvents[] = {
+ (PVOID)&pWorker->KillEvent,
+ (PVOID)&pWorker->NotifyEvent
+ };
+
+ while (fResume)
+ {
+ uint32_t cNumProcessed;
+ uint32_t cNumPostedToHostWire;
+
+ fStatus = KeWaitForMultipleObjects(RT_ELEMENTS(apEvents), apEvents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
+ if (!NT_SUCCESS(fStatus) || fStatus == STATUS_WAIT_0)
+ {
+ /* "kill" event was set
+ * will process queued packets and exit */
+ fResume = false;
+ }
+
+ LogFlow(("processing vboxNetFltWinQuPacketQueueWorkerThreadProc\n"));
+
+ cNumProcessed = 0;
+ cNumPostedToHostWire = 0;
+
+ do
+ {
+ PVBOXNETFLTPACKET_INFO pInfo;
+
+#ifdef DEBUG_NETFLT_PACKETS
+ /* packet used for matching */
+ PNDIS_PACKET pTmpPacket = NULL;
+#endif
+
+ /** @todo FIXME: !!! the better approach for performance would be to dequeue all packets at once
+ * and then go through all dequeued packets
+ * the same should be done for enqueue !!! */
+ pInfo = vboxNetFltWinQuInterlockedDequeueHead(&pWorker->PacketQueue);
+
+ if (!pInfo)
+ {
+ break;
+ }
+
+ LogFlow(("found info (0x%p)\n", pInfo));
+
+ if (vboxNetFltWinQuProcessInfo(pNetFltIf, pWorker, pInfo->pPacket, pInfo->fFlags))
+ {
+ cNumPostedToHostWire++;
+ }
+
+ vboxNetFltWinPpFreePacketInfo(pInfo);
+
+ cNumProcessed++;
+ } while (TRUE);
+
+ if (cNumProcessed)
+ {
+ vboxNetFltWinDecReferenceNetFlt(pNetFltIf, cNumProcessed);
+
+ Assert(cNumProcessed >= cNumPostedToHostWire);
+
+ if (cNumProcessed != cNumPostedToHostWire)
+ {
+ vboxNetFltWinDecReferenceWinIf(pNetFltIf, cNumProcessed - cNumPostedToHostWire);
+ }
+ }
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+#endif
+/**
+ * thread start function for the job processing thread
+ *
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static VOID vboxNetFltWinJobWorkerThreadProc(PVBOXNETFLT_JOB_QUEUE pQueue)
+{
+ bool fResume = true;
+ NTSTATUS Status;
+
+ PVOID apEvents[] = {
+ (PVOID)&pQueue->KillEvent,
+ (PVOID)&pQueue->NotifyEvent,
+ };
+
+ do
+ {
+ Status = KeWaitForMultipleObjects(RT_ELEMENTS(apEvents), apEvents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
+ Assert(NT_SUCCESS(Status));
+ if (!NT_SUCCESS(Status) || Status == STATUS_WAIT_0)
+ {
+ /* will process queued jobs and exit */
+ Assert(Status == STATUS_WAIT_0);
+ fResume = false;
+ }
+
+ do
+ {
+ PLIST_ENTRY pJobEntry = ExInterlockedRemoveHeadList(&pQueue->Jobs, &pQueue->Lock);
+ PVBOXNETFLT_JOB pJob;
+
+ if (!pJobEntry)
+ break;
+
+ pJob = LIST_ENTRY_2_JOB(pJobEntry);
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ pJob->pfnRoutine(pJob->pContext);
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ if (pJob->bUseCompletionEvent)
+ {
+ KeSetEvent(&pJob->CompletionEvent, 1, FALSE);
+ }
+ } while (TRUE);
+ } while (fResume);
+
+ Assert(Status == STATUS_WAIT_0);
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+/**
+ * enqueues the job to the job queue to be processed by the job worker thread
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static VOID vboxNetFltWinJobEnqueueJob(PVBOXNETFLT_JOB_QUEUE pQueue, PVBOXNETFLT_JOB pJob, bool bEnqueueHead)
+{
+ if (bEnqueueHead)
+ {
+ ExInterlockedInsertHeadList(&pQueue->Jobs, &pJob->ListEntry, &pQueue->Lock);
+ }
+ else
+ {
+ ExInterlockedInsertTailList(&pQueue->Jobs, &pJob->ListEntry, &pQueue->Lock);
+ }
+
+ KeSetEvent(&pQueue->NotifyEvent, 1, FALSE);
+}
+
+DECLINLINE(VOID) vboxNetFltWinJobInit(PVBOXNETFLT_JOB pJob, PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext, bool bUseEvent)
+{
+ pJob->pfnRoutine = pfnRoutine;
+ pJob->pContext = pContext;
+ pJob->bUseCompletionEvent = bUseEvent;
+ if (bUseEvent)
+ KeInitializeEvent(&pJob->CompletionEvent, NotificationEvent, FALSE);
+}
+
+/**
+ * enqueues the job to the job queue to be processed by the job worker thread and
+ * blocks until the job is done
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static VOID vboxNetFltWinJobSynchExec(PVBOXNETFLT_JOB_QUEUE pQueue, PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext)
+{
+ VBOXNETFLT_JOB Job;
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ vboxNetFltWinJobInit(&Job, pfnRoutine, pContext, true);
+
+ vboxNetFltWinJobEnqueueJob(pQueue, &Job, false);
+
+ KeWaitForSingleObject(&Job.CompletionEvent, Executive, KernelMode, FALSE, NULL);
+}
+
+/**
+ * enqueues the job to be processed by the job worker thread at passive level and
+ * blocks until the job is done
+ */
+DECLHIDDEN(VOID) vboxNetFltWinJobSynchExecAtPassive(PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext)
+{
+ vboxNetFltWinJobSynchExec(&g_VBoxJobQueue, pfnRoutine, pContext);
+}
+
+/**
+ * helper function used for system thread creation
+ */
+static NTSTATUS vboxNetFltWinQuCreateSystemThread(PKTHREAD *ppThread, PKSTART_ROUTINE pfnStartRoutine, PVOID pvStartContext)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ HANDLE hThread;
+ NTSTATUS Status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, (PKSTART_ROUTINE)pfnStartRoutine, pvStartContext);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Status = ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*)ppThread, NULL);
+ Assert(Status == STATUS_SUCCESS);
+ ZwClose(hThread);
+ if (Status == STATUS_SUCCESS)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /** @todo how would we fail in this case ?*/
+ }
+ return Status;
+}
+
+/**
+ * initialize the job queue
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static NTSTATUS vboxNetFltWinJobInitQueue(PVBOXNETFLT_JOB_QUEUE pQueue)
+{
+ NTSTATUS fStatus;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ NdisZeroMemory(pQueue, sizeof(VBOXNETFLT_JOB_QUEUE));
+
+ KeInitializeEvent(&pQueue->KillEvent, NotificationEvent, FALSE);
+
+ KeInitializeEvent(&pQueue->NotifyEvent, SynchronizationEvent, FALSE);
+
+ InitializeListHead(&pQueue->Jobs);
+
+ fStatus = vboxNetFltWinQuCreateSystemThread(&pQueue->pThread, (PKSTART_ROUTINE)vboxNetFltWinJobWorkerThreadProc, pQueue);
+ if (fStatus != STATUS_SUCCESS)
+ {
+ pQueue->pThread = NULL;
+ }
+ else
+ {
+ Assert(pQueue->pThread);
+ }
+
+ return fStatus;
+}
+
+/**
+ * deinitialize the job queue
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static void vboxNetFltWinJobFiniQueue(PVBOXNETFLT_JOB_QUEUE pQueue)
+{
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ if (pQueue->pThread)
+ {
+ KeSetEvent(&pQueue->KillEvent, 0, FALSE);
+
+ KeWaitForSingleObject(pQueue->pThread, Executive,
+ KernelMode, FALSE, NULL);
+ }
+}
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+
+/**
+ * initializes the packet queue
+ * */
+DECLHIDDEN(NTSTATUS) vboxNetFltWinQuInitPacketQueue(PVBOXNETFLTINS pInstance)
+{
+ NTSTATUS Status;
+ PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
+
+ AssertFatal(!pWorker->pSG);
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ KeInitializeEvent(&pWorker->KillEvent, NotificationEvent, FALSE);
+
+ KeInitializeEvent(&pWorker->NotifyEvent, SynchronizationEvent, FALSE);
+
+ INIT_INTERLOCKED_PACKET_QUEUE(&pWorker->PacketQueue);
+
+ do
+ {
+ Status = vboxNetFltWinPpAllocatePacketInfoPool(&pWorker->PacketInfoPool, VBOXNETFLT_PACKET_INFO_POOL_SIZE);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pWorker->pSG = vboxNetFltWinCreateSG(PACKET_QUEUE_SG_SEGS_ALLOC);
+ if (!pWorker->pSG)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ Status = vboxNetFltWinQuCreateSystemThread(&pWorker->pThread, (PKSTART_ROUTINE)vboxNetFltWinQuPacketQueueWorkerThreadProc, pInstance);
+ if (Status != STATUS_SUCCESS)
+ {
+ vboxNetFltWinPpFreePacketInfoPool(&pWorker->PacketInfoPool);
+ vboxNetFltWinMemFree(pWorker->pSG);
+ pWorker->pSG = NULL;
+ break;
+ }
+ }
+
+ } while (0);
+
+ return Status;
+}
+
+/*
+ * deletes the packet queue
+ */
+DECLHIDDEN(void) vboxNetFltWinQuFiniPacketQueue(PVBOXNETFLTINS pInstance)
+{
+ PINTNETSG pSG;
+ PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ /* using the pPacketQueueSG as an indicator that the packet queue is initialized */
+ RTSpinlockAcquire((pInstance)->hSpinlock);
+ if (pWorker->pSG)
+ {
+ pSG = pWorker->pSG;
+ pWorker->pSG = NULL;
+ RTSpinlockRelease((pInstance)->hSpinlock);
+ KeSetEvent(&pWorker->KillEvent, 0, FALSE);
+
+ KeWaitForSingleObject(pWorker->pThread, Executive,
+ KernelMode, FALSE, NULL);
+
+ vboxNetFltWinPpFreePacketInfoPool(&pWorker->PacketInfoPool);
+
+ vboxNetFltWinDeleteSG(pSG);
+
+ FINI_INTERLOCKED_PACKET_QUEUE(&pWorker->PacketQueue);
+ }
+ else
+ {
+ RTSpinlockRelease((pInstance)->hSpinlock);
+ }
+}
+
+#endif
+
+/*
+ * creates the INTNETSG containing one segment pointing to the buffer of size cbBufSize
+ * the INTNETSG created should be cleaned with vboxNetFltWinMemFree
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinAllocSG(UINT cbPacket, PINTNETSG *ppSG)
+{
+ NDIS_STATUS Status;
+ PINTNETSG pSG;
+
+ /* allocation:
+ * 1. SG_PACKET - with one aSegs pointing to
+ * 2. buffer of cbPacket containing the entire packet */
+ AssertCompileSizeAlignment(INTNETSG, sizeof(PVOID));
+ Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, cbPacket + sizeof(INTNETSG));
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ IntNetSgInitTemp(pSG, pSG + 1, cbPacket);
+ LogFlow(("pSG created (%p)\n", pSG));
+ *ppSG = pSG;
+ }
+ return Status;
+}
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+/**
+ * put the packet info to the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuEnqueueInfo(PVBOXNETFLTPACKET_QUEUE_WORKER pWorker, PVBOXNETFLTPACKET_INFO pInfo)
+{
+ vboxNetFltWinQuInterlockedEnqueueTail(&pWorker->PacketQueue, pInfo);
+
+ KeSetEvent(&pWorker->NotifyEvent, IO_NETWORK_INCREMENT, FALSE);
+}
+
+/**
+ * puts the packet to the queue
+ *
+ * @return NDIST_STATUS_SUCCESS iff the packet was enqueued successfully
+ * and error status otherwise.
+ * NOTE: that the success status does NOT mean that the packet processing is completed, but only that it was enqueued successfully
+ * the packet can be returned to the caller protocol/moniport only in case the bReleasePacket was set to true (in this case the copy of the packet was enqueued)
+ * or if vboxNetFltWinQuEnqueuePacket failed, i.e. the packet was NOT enqueued
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQuEnqueuePacket(PVBOXNETFLTINS pInstance, PVOID pPacket, const UINT fPacketFlags)
+{
+ PVBOXNETFLT_PACKET_INFO pInfo;
+ PVBOXNETFLT_PACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
+ NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ if (fPacketFlags & PACKET_COPY)
+ {
+ PNDIS_BUFFER pBuffer = NULL;
+ UINT cBufferCount;
+ UINT uBytesCopied = 0;
+ UINT cbPacketLength;
+ PINTNETSG pSG;
+
+ /* the packet is Ndis packet */
+ Assert(!(fPacketFlags & PACKET_SG));
+ Assert(!(fPacketFlags & PACKET_MINE));
+
+ NdisQueryPacket((PNDIS_PACKET)pPacket,
+ NULL,
+ &cBufferCount,
+ &pBuffer,
+ &cbPacketLength);
+
+
+ Assert(cBufferCount);
+
+ fStatus = vboxNetFltWinAllocSG(cbPacketLength, &pSG);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ break;
+ }
+
+ pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
+
+ if (!pInfo)
+ {
+ AssertFailed();
+ /** @todo what status to set? */
+ fStatus = NDIS_STATUS_FAILURE;
+ vboxNetFltWinMemFree(pSG);
+ break;
+ }
+
+ Assert(pInfo->pPool);
+
+ /* the packet we are queueing is SG, add PACKET_SG to flags */
+ SET_FLAGS_TO_INFO(pInfo, fPacketFlags | PACKET_SG);
+ SET_PACKET_TO_INFO(pInfo, pSG);
+
+ fStatus = vboxNetFltWinNdisBufferMoveToSG0(pBuffer, pSG);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ vboxNetFltWinPpFreePacketInfo(pInfo);
+ vboxNetFltWinMemFree(pSG);
+ break;
+ }
+
+ DBG_CHECK_PACKET_AND_SG((PNDIS_PACKET)pPacket, pSG);
+ }
+ else
+ {
+ pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
+
+ if (!pInfo)
+ {
+ AssertFailed();
+ /** @todo what status to set? */
+ fStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ Assert(pInfo->pPool);
+
+ SET_FLAGS_TO_INFO(pInfo, fPacketFlags);
+ SET_PACKET_TO_INFO(pInfo, pPacket);
+ }
+
+ vboxNetFltWinQuEnqueueInfo(pWorker, pInfo);
+
+ } while (0);
+
+ return fStatus;
+}
+#endif
+
+
+/*
+ * netflt
+ */
+#ifndef VBOXNETADP
+static NDIS_STATUS vboxNetFltWinSynchNdisRequest(PVBOXNETFLTINS pNetFlt, PNDIS_REQUEST pRequest)
+{
+ int rc;
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ /* 1. serialize */
+ rc = RTSemFastMutexRequest(pNetFlt->u.s.WinIf.hSynchRequestMutex); AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ NDIS_STATUS fRequestStatus = NDIS_STATUS_SUCCESS;
+
+ /* 2. set pNetFlt->u.s.pSynchRequest */
+ Assert(!pNetFlt->u.s.WinIf.pSynchRequest);
+ pNetFlt->u.s.WinIf.pSynchRequest = pRequest;
+
+ /* 3. call NdisRequest */
+ NdisRequest(&fRequestStatus, pNetFlt->u.s.WinIf.hBinding, pRequest);
+
+ if (fRequestStatus == NDIS_STATUS_PENDING)
+ {
+ /* 3.1 if pending wait and assign the resulting status */
+ KeWaitForSingleObject(&pNetFlt->u.s.WinIf.hSynchCompletionEvent, Executive,
+ KernelMode, FALSE, NULL);
+
+ fRequestStatus = pNetFlt->u.s.WinIf.SynchCompletionStatus;
+ }
+
+ /* 4. clear the pNetFlt->u.s.pSynchRequest */
+ pNetFlt->u.s.WinIf.pSynchRequest = NULL;
+
+ RTSemFastMutexRelease(pNetFlt->u.s.WinIf.hSynchRequestMutex); AssertRC(rc);
+ return fRequestStatus;
+ }
+ return NDIS_STATUS_FAILURE;
+}
+
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinGetMacAddress(PVBOXNETFLTINS pNetFlt, PRTMAC pMac)
+{
+ NDIS_REQUEST request;
+ NDIS_STATUS status;
+ request.RequestType = NdisRequestQueryInformation;
+ request.DATA.QUERY_INFORMATION.InformationBuffer = pMac;
+ request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(RTMAC);
+ request.DATA.QUERY_INFORMATION.Oid = OID_802_3_CURRENT_ADDRESS;
+ status = vboxNetFltWinSynchNdisRequest(pNetFlt, &request);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ }
+
+ return status;
+
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PVBOXNETFLTINS pNetFlt, NDIS_PHYSICAL_MEDIUM * pMedium)
+{
+ NDIS_REQUEST Request;
+ NDIS_STATUS Status;
+ Request.RequestType = NdisRequestQueryInformation;
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = pMedium;
+ Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_PHYSICAL_MEDIUM);
+ Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_PHYSICAL_MEDIUM;
+ Status = vboxNetFltWinSynchNdisRequest(pNetFlt, &Request);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (Status == NDIS_STATUS_NOT_SUPPORTED || Status == NDIS_STATUS_NOT_RECOGNIZED || Status == NDIS_STATUS_INVALID_OID)
+ {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ LogRel(("OID_GEN_PHYSICAL_MEDIUM failed: Status (0x%x)", Status));
+ AssertFailed();
+ }
+ }
+ return Status;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinIsPromiscuous(PVBOXNETFLTINS pNetFlt)
+{
+ /** @todo r=bird: This is too slow and is probably returning the wrong
+ * information. What we're interested in is whether someone besides us
+ * has put the interface into promiscuous mode. */
+ NDIS_REQUEST request;
+ NDIS_STATUS status;
+ ULONG filter;
+ Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt));
+ request.RequestType = NdisRequestQueryInformation;
+ request.DATA.QUERY_INFORMATION.InformationBuffer = &filter;
+ request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(filter);
+ request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ status = vboxNetFltWinSynchNdisRequest(pNetFlt, &request);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ return false;
+ }
+ return (filter & NDIS_PACKET_TYPE_PROMISCUOUS) != 0;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinSetPromiscuous(PVBOXNETFLTINS pNetFlt, bool bYes)
+{
+/** @todo Need to report changes to the switch via:
+ * pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, fPromisc);
+ */
+ Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt));
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ NDIS_REQUEST Request;
+ NDIS_STATUS fStatus;
+ ULONG fFilter;
+ ULONG fExpectedFilter;
+ ULONG fOurFilter;
+ Request.RequestType = NdisRequestQueryInformation;
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = &fFilter;
+ Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(fFilter);
+ Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ fStatus = vboxNetFltWinSynchNdisRequest(pNetFlt, &Request);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ return fStatus;
+ }
+
+ if (!pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized)
+ {
+ /* the cache was not initialized yet, initiate it with the current filter value */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = fFilter;
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+ }
+
+
+ if (bYes)
+ {
+ fExpectedFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
+ fOurFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+ else
+ {
+ fExpectedFilter = pNetFlt->u.s.WinIf.fUpperProtocolSetFilter;
+ fOurFilter = 0;
+ }
+
+ if (fExpectedFilter != fFilter)
+ {
+ Request.RequestType = NdisRequestSetInformation;
+ Request.DATA.SET_INFORMATION.InformationBuffer = &fExpectedFilter;
+ Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(fExpectedFilter);
+ Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ fStatus = vboxNetFltWinSynchNdisRequest(pNetFlt, &Request);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ return fStatus;
+ }
+ }
+ pNetFlt->u.s.WinIf.fOurSetFilter = fOurFilter;
+ return fStatus;
+ }
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+#else /* VBOXNETADP */
+
+/**
+ * Generates a new unique MAC address based on our vendor ID
+ */
+DECLHIDDEN(void) vboxNetFltWinGenerateMACAddress(RTMAC *pMac)
+{
+ /* temporary use a time info */
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+ pMac->au8[0] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 16) & 0xff);
+ pMac->au8[1] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 8) & 0xff);
+ pMac->au8[2] = (uint8_t)(VBOXNETADP_VENDOR_ID & 0xff);
+ pMac->au8[3] = (uint8_t)(NanoTS & 0xff0000);
+ pMac->au16[2] = (uint16_t)(NanoTS & 0xffff);
+}
+
+DECLHIDDEN(int) vboxNetFltWinMAC2NdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
+{
+ static const char s_achDigits[17] = "0123456789abcdef";
+ PWSTR pString;
+
+ /* validate parameters */
+ AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
+ AssertReturn(pNdisString->MaximumLength >= 13*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
+
+ pString = pNdisString->Buffer;
+
+ for (int i = 0; i < 6; i++)
+ {
+ uint8_t u8 = pMac->au8[i];
+ pString[0] = s_achDigits[(u8 >> 4) & 0xf];
+ pString[1] = s_achDigits[(u8/*>>0*/)& 0xf];
+ pString += 2;
+ }
+
+ pNdisString->Length = 12*sizeof(pNdisString->Buffer[0]);
+
+ *pString = L'\0';
+
+ return VINF_SUCCESS;
+}
+
+static int vboxNetFltWinWchar2Byte(WCHAR c, uint8_t *pb)
+{
+ if (c >= L'A' && c <= L'F')
+ *pb = (c - L'A') + 10;
+ else if (c >= L'a' && c <= L'f')
+ *pb = (c - L'a') + 10;
+ else if (c >= L'0' && c <= L'9')
+ *pb = (c - L'0');
+ else
+ return VERR_INVALID_PARAMETER;
+ return VINF_SUCCESS;
+}
+
+DECLHIDDEN(int) vboxNetFltWinMACFromNdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
+{
+
+ /* validate parameters */
+ AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
+ AssertReturn(pNdisString->Length >= 12*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
+
+ int rc = VINF_SUCCESS;
+ PWSTR pString = pNdisString->Buffer;
+ for (int i = 0; i < 6; i++)
+ {
+ uint8_t v1, v2;
+ rc = vboxNetFltWinWchar2Byte(pString[0], &v1);
+ if (RT_FAILURE(rc))
+ break;
+
+ rc = vboxNetFltWinWchar2Byte(pString[1], &v2);
+ if (RT_FAILURE(rc))
+ break;
+
+ pMac->au8[i] = (v1 << 4) | v2;
+
+ pString += 2;
+ }
+
+ return rc;
+}
+
+#endif /* VBOXNETADP */
+
+/**
+ * creates a NDIS_PACKET from the PINTNETSG
+ */
+DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PVBOXNETFLTINS pNetFlt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory)
+{
+ NDIS_STATUS fStatus;
+ PNDIS_PACKET pPacket;
+
+ Assert(pSG->aSegs[0].pv);
+ Assert(pSG->cbTotal >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+
+/** @todo Hrmpf, how can we fix this assumption? I fear this'll cause data
+ * corruption and maybe even BSODs ... */
+ AssertReturn(pSG->cSegsUsed == 1 || bCopyMemory, NULL);
+
+#ifdef VBOXNETADP
+ NdisAllocatePacket(&fStatus, &pPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+#else
+ NdisAllocatePacket(&fStatus, &pPacket, bToWire ? pNetFlt->u.s.WinIf.hSendPacketPool : pNetFlt->u.s.WinIf.hRecvPacketPool);
+#endif
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ PNDIS_BUFFER pBuffer;
+ PVOID pvMemBuf;
+
+ /** @todo generally we do not always need to zero-initialize the complete OOB data here, reinitialize only when/what we need,
+ * however we DO need to reset the status for the packets we indicate via NdisMIndicateReceivePacket to avoid packet loss
+ * in case the status contains NDIS_STATUS_RESOURCES */
+ VBOXNETFLT_OOB_INIT(pPacket);
+
+ if (bCopyMemory)
+ {
+ fStatus = vboxNetFltWinMemAlloc(&pvMemBuf, pSG->cbTotal);
+ Assert(fStatus == NDIS_STATUS_SUCCESS);
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ IntNetSgRead(pSG, pvMemBuf);
+ }
+ else
+ {
+ pvMemBuf = pSG->aSegs[0].pv;
+ }
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+#ifdef VBOXNETADP
+ NdisAllocateBuffer(&fStatus, &pBuffer,
+ pNetFlt->u.s.WinIf.hRecvBufferPool,
+ pvMemBuf,
+ pSG->cbTotal);
+#else
+ NdisAllocateBuffer(&fStatus, &pBuffer,
+ bToWire ? pNetFlt->u.s.WinIf.hSendBufferPool : pNetFlt->u.s.WinIf.hRecvBufferPool,
+ pvMemBuf,
+ pSG->cbTotal);
+#endif
+
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ NdisChainBufferAtBack(pPacket, pBuffer);
+
+ if (bToWire)
+ {
+ PVBOXNETFLT_PKTRSVD_PT pSendInfo = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ pSendInfo->pOrigPacket = NULL;
+ pSendInfo->pBufToFree = pBufToFree;
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ /* set "don't loopback" flags */
+ NdisGetPacketFlags(pPacket) = g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#else
+ NdisGetPacketFlags(pPacket) = 0;
+#endif
+ }
+ else
+ {
+ PVBOXNETFLT_PKTRSVD_MP pRecvInfo = (PVBOXNETFLT_PKTRSVD_MP)pPacket->MiniportReserved;
+ pRecvInfo->pOrigPacket = NULL;
+ pRecvInfo->pBufToFree = pBufToFree;
+
+ /* we must set the header size on receive */
+ NDIS_SET_PACKET_HEADER_SIZE(pPacket, VBOXNETFLT_PACKET_ETHEADER_SIZE);
+ /* NdisAllocatePacket zero-initializes the OOB data,
+ * but keeps the packet flags, clean them here */
+ NdisGetPacketFlags(pPacket) = 0;
+ }
+ /** @todo set out of bound data */
+ }
+ else
+ {
+ AssertFailed();
+ if (bCopyMemory)
+ {
+ vboxNetFltWinMemFree(pvMemBuf);
+ }
+ NdisFreePacket(pPacket);
+ pPacket = NULL;
+ }
+ }
+ else
+ {
+ AssertFailed();
+ NdisFreePacket(pPacket);
+ pPacket = NULL;
+ }
+ }
+ else
+ {
+ pPacket = NULL;
+ }
+
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+
+ return pPacket;
+}
+
+/*
+ * frees NDIS_PACKET created with vboxNetFltWinNdisPacketFromSG
+ */
+DECLHIDDEN(void) vboxNetFltWinFreeSGNdisPacket(PNDIS_PACKET pPacket, bool bFreeMem)
+{
+ UINT cBufCount;
+ PNDIS_BUFFER pFirstBuffer;
+ UINT uTotalPacketLength;
+ PNDIS_BUFFER pBuffer;
+
+ NdisQueryPacket(pPacket, NULL, &cBufCount, &pFirstBuffer, &uTotalPacketLength);
+
+ Assert(cBufCount == 1);
+
+ do
+ {
+ NdisUnchainBufferAtBack(pPacket, &pBuffer);
+ if (pBuffer != NULL)
+ {
+ PVOID pvMemBuf;
+ UINT cbLength;
+
+ NdisQueryBufferSafe(pBuffer, &pvMemBuf, &cbLength, NormalPagePriority);
+ NdisFreeBuffer(pBuffer);
+ if (bFreeMem)
+ {
+ vboxNetFltWinMemFree(pvMemBuf);
+ }
+ }
+ else
+ {
+ break;
+ }
+ } while (true);
+
+ NdisFreePacket(pPacket);
+}
+
+#if !defined(VBOXNETADP)
+static void vboxNetFltWinAssociateMiniportProtocol(PVBOXNETFLTGLOBALS_WIN pGlobalsWin)
+{
+ NdisIMAssociateMiniport(pGlobalsWin->Mp.hMiniport, pGlobalsWin->Pt.hProtocol);
+}
+#endif
+
+/*
+ * NetFlt driver unload function
+ */
+DECLHIDDEN(VOID) vboxNetFltWinUnload(IN PDRIVER_OBJECT DriverObject)
+{
+ int rc;
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ LogFlowFunc(("ENTER: DO (0x%x)\n", DriverObject));
+
+ rc = vboxNetFltWinFiniIdc();
+ if (RT_FAILURE(rc))
+ {
+ /** @todo we can not prevent driver unload here */
+ AssertFailed();
+
+ LogFlowFunc(("vboxNetFltWinFiniIdc - failed, busy.\n"));
+ }
+
+ vboxNetFltWinJobFiniQueue(&g_VBoxJobQueue);
+#ifndef VBOXNETADP
+ vboxNetFltWinPtDeregister(&g_VBoxNetFltGlobalsWin.Pt);
+#endif
+
+ vboxNetFltWinMpDeregister(&g_VBoxNetFltGlobalsWin.Mp);
+
+#ifndef VBOXNETADP
+ NdisFreeSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+#endif /* VBOXNETADP */
+
+ LogFlow(("LEAVE: DO (0x%x)\n", DriverObject));
+
+ vboxNetFltWinFiniNetFltBase();
+ /* don't use logging or any RT after de-init */
+}
+
+RT_C_DECLS_BEGIN
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
+
+RT_C_DECLS_END
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ int rc;
+
+ /* the idc registration is initiated via IOCTL since our driver
+ * can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
+ rc = vboxNetFltWinInitNetFltBase();
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ Status = vboxNetFltWinJobInitQueue(&g_VBoxJobQueue);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ ULONG MjVersion;
+ ULONG MnVersion;
+
+ /* note: we do it after we initialize the Job Queue */
+ vboxNetFltWinStartInitIdcProbing();
+
+ NdisZeroMemory(&g_VBoxNetFltGlobalsWin, sizeof (g_VBoxNetFltGlobalsWin));
+ KeInitializeEvent(&g_VBoxNetFltGlobalsWin.SynchEvent, SynchronizationEvent, TRUE /* signalled*/);
+
+ PsGetVersion(&MjVersion, &MnVersion,
+ NULL, /* PULONG BuildNumber OPTIONAL */
+ NULL /* PUNICODE_STRING CSDVersion OPTIONAL */
+ );
+
+ g_VBoxNetFltGlobalsWin.fPacketDontLoopBack = NDIS_FLAGS_DONT_LOOPBACK;
+
+ if (MjVersion == 5 && MnVersion == 0)
+ {
+ /* this is Win2k, we don't support it actually, but just in case */
+ g_VBoxNetFltGlobalsWin.fPacketDontLoopBack |= NDIS_FLAGS_SKIP_LOOPBACK_W2K;
+ }
+
+ g_VBoxNetFltGlobalsWin.fPacketIsLoopedBack = NDIS_FLAGS_IS_LOOPBACK_PACKET;
+
+#ifndef VBOXNETADP
+ RTListInit(&g_VBoxNetFltGlobalsWin.listFilters);
+ NdisAllocateSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+#endif
+
+ Status = vboxNetFltWinMpRegister(&g_VBoxNetFltGlobalsWin.Mp, DriverObject, RegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtRegister(&g_VBoxNetFltGlobalsWin.Pt, DriverObject, RegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+#endif
+ {
+#ifndef VBOXNETADP
+ vboxNetFltWinAssociateMiniportProtocol(&g_VBoxNetFltGlobalsWin);
+#endif
+ return STATUS_SUCCESS;
+
+//#ifndef VBOXNETADP
+// vboxNetFltWinPtDeregister(&g_VBoxNetFltGlobalsWin.Pt);
+//#endif
+ }
+#ifndef VBOXNETADP /* unreachable for VBOXNETADP because of the above return */
+ vboxNetFltWinMpDeregister(&g_VBoxNetFltGlobalsWin.Mp);
+# ifndef VBOXNETADP
+ NdisFreeSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+# endif
+#endif
+ }
+ vboxNetFltWinJobFiniQueue(&g_VBoxJobQueue);
+ }
+ vboxNetFltWinFiniNetFlt();
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+
+#ifndef VBOXNETADP
+/**
+ * creates and initializes the packet to be sent to the underlying miniport given a packet posted to our miniport edge
+ * according to DDK docs we must create our own packet rather than posting the one passed to us
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket)
+{
+ NDIS_STATUS Status;
+
+ NdisAllocatePacket(&Status, ppMyPacket, pNetFlt->u.s.WinIf.hSendPacketPool);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLT_PKTRSVD_PT pSendInfo = (PVBOXNETFLT_PKTRSVD_PT)((*ppMyPacket)->ProtocolReserved);
+ pSendInfo->pOrigPacket = pPacket;
+ pSendInfo->pBufToFree = NULL;
+ /* the rest will be filled on send */
+
+ vboxNetFltWinCopyPacketInfoOnSend(*ppMyPacket, pPacket);
+
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ NdisGetPacketFlags(*ppMyPacket) |= g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#endif
+ }
+ else
+ {
+ *ppMyPacket = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ * creates and initializes the packet to be sent to the upperlying protocol given a packet indicated to our protocol edge
+ * according to DDK docs we must create our own packet rather than posting the one passed to us
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareRecvPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket, bool bDpr)
+{
+ NDIS_STATUS Status;
+
+ if (bDpr)
+ {
+ Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+ NdisDprAllocatePacket(&Status, ppMyPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ }
+ else
+ {
+ NdisAllocatePacket(&Status, ppMyPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLT_PKTRSVD_MP pRecvInfo = (PVBOXNETFLT_PKTRSVD_MP)((*ppMyPacket)->MiniportReserved);
+ pRecvInfo->pOrigPacket = pPacket;
+ pRecvInfo->pBufToFree = NULL;
+
+ Status = vboxNetFltWinCopyPacketInfoOnRecv(*ppMyPacket, pPacket, false);
+ }
+ else
+ {
+ *ppMyPacket = NULL;
+ }
+ return Status;
+}
+#endif
+/**
+ * initializes the VBOXNETFLTINS (our context structure) and binds to the given adapter
+ */
+#if defined(VBOXNETADP)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext)
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName)
+#endif
+{
+ NDIS_STATUS Status;
+ do
+ {
+ ANSI_STRING AnsiString;
+ int rc;
+ PVBOXNETFLTINS pInstance;
+ USHORT cbAnsiName = pBindToMiniportName->Length;/* the length is is bytes ; *2 ;RtlUnicodeStringToAnsiSize(pBindToMiniportName)*/
+ CREATE_INSTANCE_CONTEXT Context;
+
+# ifndef VBOXNETADP
+ Context.pOurName = pOurMiniportName;
+ Context.pBindToName = pBindToMiniportName;
+# else
+ Context.hMiniportAdapter = hMiniportAdapter;
+ Context.hWrapperConfigurationContext = hWrapperConfigurationContext;
+# endif
+ Context.Status = NDIS_STATUS_SUCCESS;
+
+ AnsiString.Buffer = 0; /* will be allocated by RtlUnicodeStringToAnsiString */
+ AnsiString.Length = 0;
+ AnsiString.MaximumLength = cbAnsiName;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ Status = RtlUnicodeStringToAnsiString(&AnsiString, pBindToMiniportName, true);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ rc = vboxNetFltSearchCreateInstance(&g_VBoxNetFltGlobals, AnsiString.Buffer, &pInstance, &Context);
+ RtlFreeAnsiString(&AnsiString);
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ Assert(pInstance);
+
+ if (rc == VINF_ALREADY_INITIALIZED)
+ {
+ /* the case when our adapter was unbound while IntNet was connected to it */
+ /* the instance remains valid until IntNet disconnects from it, we simply search and re-use it*/
+ rc = vboxNetFltWinAttachToInterface(pInstance, &Context, true);
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
+ /* release netflt */
+ vboxNetFltRelease(pInstance, false);
+
+ break;
+ }
+ }
+
+ *ppNetFlt = pInstance;
+
+ } while (FALSE);
+
+ return Status;
+}
+/*
+ * deinitializes the VBOXNETFLTWIN
+ */
+DECLHIDDEN(VOID) vboxNetFltWinPtFiniWinIf(PVBOXNETFLTWIN pWinIf)
+{
+#ifndef VBOXNETADP
+ int rc;
+#endif
+
+ LogFlowFunc(("ENTER: pWinIf 0x%p\n", pWinIf));
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+#ifndef VBOXNETADP
+ if (pWinIf->MpDeviceName.Buffer)
+ {
+ vboxNetFltWinMemFree(pWinIf->MpDeviceName.Buffer);
+ }
+
+ FINI_INTERLOCKED_SINGLE_LIST(&pWinIf->TransferDataList);
+# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ FINI_INTERLOCKED_SINGLE_LIST(&pWinIf->SendPacketQueue);
+# endif
+ NdisFreeBufferPool(pWinIf->hSendBufferPool);
+ NdisFreePacketPool(pWinIf->hSendPacketPool);
+ rc = RTSemFastMutexDestroy(pWinIf->hSynchRequestMutex); AssertRC(rc);
+#endif
+
+ /* NOTE: NULL is a valid handle */
+ NdisFreeBufferPool(pWinIf->hRecvBufferPool);
+ NdisFreePacketPool(pWinIf->hRecvPacketPool);
+
+ LogFlowFunc(("LEAVE: pWinIf 0x%p\n", pWinIf));
+}
+
+#ifndef VBOXNETADP
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf, IN PNDIS_STRING pOurDeviceName)
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf)
+#endif
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifndef VBOXNETADP
+ int rc;
+#endif
+
+ LogFlowFunc(("ENTER: pWinIf 0x%p\n", pWinIf));
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ NdisZeroMemory(pWinIf, sizeof (VBOXNETFLTWIN));
+ NdisAllocatePacketPoolEx(&Status, &pWinIf->hRecvPacketPool,
+ VBOXNETFLT_PACKET_POOL_SIZE_NORMAL,
+ VBOXNETFLT_PACKET_POOL_SIZE_OVERFLOW,
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ /* NOTE: NULL is a valid handle !!! */
+ NdisAllocateBufferPool(&Status, &pWinIf->hRecvBufferPool, VBOXNETFLT_BUFFER_POOL_SIZE_RX);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pWinIf->MpState.PowerState = NdisDeviceStateD3;
+ vboxNetFltWinSetOpState(&pWinIf->MpState, kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ pWinIf->PtState.PowerState = NdisDeviceStateD3;
+ vboxNetFltWinSetOpState(&pWinIf->PtState, kVBoxNetDevOpState_Deinitialized);
+
+ NdisAllocateBufferPool(&Status,
+ &pWinIf->hSendBufferPool,
+ VBOXNETFLT_BUFFER_POOL_SIZE_TX);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ INIT_INTERLOCKED_SINGLE_LIST(&pWinIf->TransferDataList);
+
+# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ INIT_INTERLOCKED_SINGLE_LIST(&pWinIf->SendPacketQueue);
+# endif
+ NdisInitializeEvent(&pWinIf->OpenCloseEvent);
+
+ KeInitializeEvent(&pWinIf->hSynchCompletionEvent, SynchronizationEvent, FALSE);
+
+ NdisInitializeEvent(&pWinIf->MpInitCompleteEvent);
+
+ NdisAllocatePacketPoolEx(&Status, &pWinIf->hSendPacketPool,
+ VBOXNETFLT_PACKET_POOL_SIZE_NORMAL,
+ VBOXNETFLT_PACKET_POOL_SIZE_OVERFLOW,
+ sizeof (PVBOXNETFLT_PKTRSVD_PT));
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ rc = RTSemFastMutexCreate(&pWinIf->hSynchRequestMutex);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ Status = vboxNetFltWinMemAlloc((PVOID*)&pWinIf->MpDeviceName.Buffer, pOurDeviceName->Length);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pWinIf->MpDeviceName.MaximumLength = pOurDeviceName->Length;
+ pWinIf->MpDeviceName.Length = 0;
+ Status = vboxNetFltWinCopyString(&pWinIf->MpDeviceName, pOurDeviceName);
+#endif
+ return NDIS_STATUS_SUCCESS;
+#ifndef VBOXNETADP
+ // unreachable: vboxNetFltWinMemFree(pWinIf->MpDeviceName.Buffer);
+ }
+ RTSemFastMutexDestroy(pWinIf->hSynchRequestMutex);
+ }
+ else
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreePacketPool(pWinIf->hSendPacketPool);
+ }
+ NdisFreeBufferPool(pWinIf->hSendBufferPool);
+ }
+ NdisFreeBufferPool(pWinIf->hRecvBufferPool);
+#endif
+ }
+ NdisFreePacketPool(pWinIf->hRecvPacketPool);
+ }
+
+ LogFlowFunc(("LEAVE: pWinIf 0x%p, Status 0x%x\n", pWinIf, Status));
+
+ return Status;
+}
+
+/**
+ * match packets
+ */
+#define NEXT_LIST_ENTRY(_Entry) ((_Entry)->Flink)
+#define PREV_LIST_ENTRY(_Entry) ((_Entry)->Blink)
+#define FIRST_LIST_ENTRY NEXT_LIST_ENTRY
+#define LAST_LIST_ENTRY PREV_LIST_ENTRY
+
+#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
+
+#ifndef VBOXNETADP
+
+#ifdef DEBUG_misha
+
+RTMAC g_vboxNetFltWinVerifyMACBroadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+RTMAC g_vboxNetFltWinVerifyMACGuest = {0x08, 0x00, 0x27, 0x01, 0x02, 0x03};
+
+DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdr(PNDIS_PACKET pPacket)
+{
+ UINT cBufCount1;
+ PNDIS_BUFFER pBuffer1;
+ UINT uTotalPacketLength1;
+ RTNETETHERHDR* pEth;
+ UINT cbLength1 = 0;
+ UINT i = 0;
+
+ NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
+
+ Assert(pBuffer1);
+ Assert(uTotalPacketLength1 >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+ if (uTotalPacketLength1 < VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ return NULL;
+
+ NdisQueryBufferSafe(pBuffer1, &pEth, &cbLength1, NormalPagePriority);
+ Assert(cbLength1 >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+ if (cbLength1 < VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ return NULL;
+
+ return pEth;
+}
+
+DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdrSG(PINTNETSG pSG)
+{
+ Assert(pSG->cSegsUsed);
+ Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
+ Assert(pSG->aSegs[0].cb >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+
+ if (!pSG->cSegsUsed)
+ return NULL;
+
+ if (pSG->aSegs[0].cb < VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ return NULL;
+
+ return (PRTNETETHERHDR)pSG->aSegs[0].pv;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc)
+{
+ PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdr(pPacket);
+ Assert(pHdr);
+
+ if (!pHdr)
+ return false;
+
+ if (pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
+ return false;
+
+ if (pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
+ return false;
+
+ return true;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc)
+{
+ PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdrSG(pSG);
+ Assert(pHdr);
+
+ if (!pHdr)
+ return false;
+
+ if (pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
+ return false;
+
+ if (pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
+ return false;
+
+ return true;
+}
+#endif
+
+# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+/*
+ * answers whether the two given packets match based on the packet length and the first cbMatch bytes of the packets
+ * if cbMatch < 0 matches complete packets.
+ */
+DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch)
+{
+ UINT cBufCount1;
+ PNDIS_BUFFER pBuffer1;
+ UINT uTotalPacketLength1;
+ uint8_t *pbMemBuf1 = NULL;
+ UINT cbLength1 = 0;
+
+ UINT cBufCount2;
+ PNDIS_BUFFER pBuffer2;
+ UINT uTotalPacketLength2;
+ uint8_t *pbMemBuf2 = NULL;
+ UINT cbLength2 = 0;
+ bool bMatch = true;
+
+#ifdef DEBUG_NETFLT_PACKETS
+ bool bCompleteMatch = false;
+#endif
+
+ NdisQueryPacket(pPacket1, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
+ NdisQueryPacket(pPacket2, NULL, &cBufCount2, &pBuffer2, &uTotalPacketLength2);
+
+ Assert(pBuffer1);
+ Assert(pBuffer2);
+
+ if (uTotalPacketLength1 != uTotalPacketLength2)
+ {
+ bMatch = false;
+ }
+ else
+ {
+ UINT ucbLength2Match = 0;
+ UINT ucbMatch;
+ if (cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
+ {
+ /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
+ ucbMatch = uTotalPacketLength1;
+#ifdef DEBUG_NETFLT_PACKETS
+ bCompleteMatch = true;
+#endif
+ }
+ else
+ {
+ ucbMatch = (UINT)cbMatch;
+ }
+
+ for (;;)
+ {
+ if (!cbLength1)
+ {
+ NdisQueryBufferSafe(pBuffer1, &pbMemBuf1, &cbLength1, NormalPagePriority);
+ NdisGetNextBuffer(pBuffer1, &pBuffer1);
+ }
+ else
+ {
+ Assert(pbMemBuf1);
+ Assert(ucbLength2Match);
+ pbMemBuf1 += ucbLength2Match;
+ }
+
+ if (!cbLength2)
+ {
+ NdisQueryBufferSafe(pBuffer2, &pbMemBuf2, &cbLength2, NormalPagePriority);
+ NdisGetNextBuffer(pBuffer2, &pBuffer2);
+ }
+ else
+ {
+ Assert(pbMemBuf2);
+ Assert(ucbLength2Match);
+ pbMemBuf2 += ucbLength2Match;
+ }
+
+ ucbLength2Match = MIN(ucbMatch, cbLength1);
+ ucbLength2Match = MIN(ucbLength2Match, cbLength2);
+
+ if (memcmp(pbMemBuf1, pbMemBuf2, ucbLength2Match))
+ {
+ bMatch = false;
+ break;
+ }
+
+ ucbMatch -= ucbLength2Match;
+ if (!ucbMatch)
+ break;
+
+ cbLength1 -= ucbLength2Match;
+ cbLength2 -= ucbLength2Match;
+ }
+ }
+
+#ifdef DEBUG_NETFLT_PACKETS
+ if (bMatch && !bCompleteMatch)
+ {
+ /* check that the packets fully match */
+ DBG_CHECK_PACKETS(pPacket1, pPacket2);
+ }
+#endif
+
+ return bMatch;
+}
+
+/*
+ * answers whether the ndis packet and PINTNETSG match based on the packet length and the first cbMatch bytes of the packet and PINTNETSG
+ * if cbMatch < 0 matches complete packets.
+ */
+DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch)
+{
+ UINT cBufCount1;
+ PNDIS_BUFFER pBuffer1;
+ UINT uTotalPacketLength1;
+ uint8_t *pbMemBuf1 = NULL;
+ UINT cbLength1 = 0;
+ UINT uTotalPacketLength2 = pSG->cbTotal;
+ uint8_t *pbMemBuf2 = NULL;
+ UINT cbLength2 = 0;
+ bool bMatch = true;
+ bool bCompleteMatch = false;
+ UINT i = 0;
+
+ NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
+
+ Assert(pBuffer1);
+ Assert(pSG->cSegsUsed);
+ Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
+
+ if (uTotalPacketLength1 != uTotalPacketLength2)
+ {
+ AssertFailed();
+ bMatch = false;
+ }
+ else
+ {
+ UINT ucbLength2Match = 0;
+ UINT ucbMatch;
+
+ if (cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
+ {
+ /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
+ ucbMatch = uTotalPacketLength1;
+ bCompleteMatch = true;
+ }
+ else
+ {
+ ucbMatch = (UINT)cbMatch;
+ }
+
+ for (;;)
+ {
+ if (!cbLength1)
+ {
+ NdisQueryBufferSafe(pBuffer1, &pbMemBuf1, &cbLength1, NormalPagePriority);
+ NdisGetNextBuffer(pBuffer1, &pBuffer1);
+ }
+ else
+ {
+ Assert(pbMemBuf1);
+ Assert(ucbLength2Match);
+ pbMemBuf1 += ucbLength2Match;
+ }
+
+ if (!cbLength2)
+ {
+ Assert(i < pSG->cSegsUsed);
+ pbMemBuf2 = (uint8_t*)pSG->aSegs[i].pv;
+ cbLength2 = pSG->aSegs[i].cb;
+ i++;
+ }
+ else
+ {
+ Assert(pbMemBuf2);
+ Assert(ucbLength2Match);
+ pbMemBuf2 += ucbLength2Match;
+ }
+
+ ucbLength2Match = MIN(ucbMatch, cbLength1);
+ ucbLength2Match = MIN(ucbLength2Match, cbLength2);
+
+ if (memcmp(pbMemBuf1, pbMemBuf2, ucbLength2Match))
+ {
+ bMatch = false;
+ AssertFailed();
+ break;
+ }
+
+ ucbMatch -= ucbLength2Match;
+ if (!ucbMatch)
+ break;
+
+ cbLength1 -= ucbLength2Match;
+ cbLength2 -= ucbLength2Match;
+ }
+ }
+
+ if (bMatch && !bCompleteMatch)
+ {
+ /* check that the packets fully match */
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+ }
+ return bMatch;
+}
+
+# if 0
+/*
+ * answers whether the two PINTNETSGs match based on the packet length and the first cbMatch bytes of the PINTNETSG
+ * if cbMatch < 0 matches complete packets.
+ */
+static bool vboxNetFltWinMatchSGs(PINTNETSG pSG1, PINTNETSG pSG2, const INT cbMatch)
+{
+ UINT uTotalPacketLength1 = pSG1->cbTotal;
+ PVOID pbMemBuf1 = NULL;
+ UINT cbLength1 = 0;
+ UINT i1 = 0;
+ UINT uTotalPacketLength2 = pSG2->cbTotal;
+ PVOID pbMemBuf2 = NULL;
+ UINT cbLength2 = 0;
+
+ bool bMatch = true;
+ bool bCompleteMatch = false;
+ UINT i2 = 0;
+
+ Assert(pSG1->cSegsUsed);
+ Assert(pSG2->cSegsUsed);
+ Assert(pSG1->cSegsAlloc >= pSG1->cSegsUsed);
+ Assert(pSG2->cSegsAlloc >= pSG2->cSegsUsed);
+
+ if (uTotalPacketLength1 != uTotalPacketLength2)
+ {
+ AssertFailed();
+ bMatch = false;
+ }
+ else
+ {
+ UINT ucbMatch;
+ if (cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
+ {
+ /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
+ ucbMatch = uTotalPacketLength1;
+ bCompleteMatch = true;
+ }
+ else
+ {
+ ucbMatch = (UINT)cbMatch;
+ }
+
+ do
+ {
+ UINT ucbLength2Match;
+ if (!cbLength1)
+ {
+ Assert(i1 < pSG1->cSegsUsed);
+ pbMemBuf1 = pSG1->aSegs[i1].pv;
+ cbLength1 = pSG1->aSegs[i1].cb;
+ i1++;
+ }
+
+ if (!cbLength2)
+ {
+ Assert(i2 < pSG2->cSegsUsed);
+ pbMemBuf2 = pSG2->aSegs[i2].pv;
+ cbLength2 = pSG2->aSegs[i2].cb;
+ i2++;
+ }
+
+ ucbLength2Match = MIN(ucbMatch, cbLength1);
+ ucbLength2Match = MIN(ucbLength2Match, cbLength2);
+
+ if (memcmp(pbMemBuf1, pbMemBuf2, ucbLength2Match))
+ {
+ bMatch = false;
+ AssertFailed();
+ break;
+ }
+ ucbMatch -= ucbLength2Match;
+ cbLength1 -= ucbLength2Match;
+ cbLength2 -= ucbLength2Match;
+ } while (ucbMatch);
+ }
+
+ if (bMatch && !bCompleteMatch)
+ {
+ /* check that the packets fully match */
+ DBG_CHECK_SGS(pSG1, pSG2);
+ }
+ return bMatch;
+}
+# endif
+# endif
+#endif
+
+static void vboxNetFltWinFiniNetFltBase()
+{
+ do
+ {
+ vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+
+ RTR0Term();
+ } while (0);
+}
+
+/*
+ * Defines max timeout for waiting for driver unloading
+ * (3000 * 100 ms = 5 minutes)
+ */
+#define MAX_UNLOAD_PROBES 3000
+
+static int vboxNetFltWinFiniIdc()
+{
+ int rc;
+ int i;
+
+ vboxNetFltWinStopInitIdcProbing();
+
+ if (g_bVBoxIdcInitialized)
+ {
+ for (i = 0; (rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals)) == VERR_WRONG_ORDER
+ && i < MAX_UNLOAD_PROBES; i++)
+ {
+ RTThreadSleep(100);
+ }
+ if (i == MAX_UNLOAD_PROBES)
+ {
+ // seems something hungs in driver
+ LogFlow(("vboxNetFltWinFiniIdc - Can't delete Idc. pInH=%p cFRefs=%d fIDcOpen=%s",
+ g_VBoxNetFltGlobals.pInstanceHead, g_VBoxNetFltGlobals.cFactoryRefs,
+ g_VBoxNetFltGlobals.fIDCOpen ? "true" : "false"));
+ LogFlow(("vboxNetFltWinFiniIdc g_VBoxNetFltGlobalsWin cDvRefs=%d hDev=%x pDev=%p Mp=%x \n",
+ g_VBoxNetFltGlobalsWin.cDeviceRefs, g_VBoxNetFltGlobalsWin.hDevice,
+ g_VBoxNetFltGlobalsWin.pDevObj, g_VBoxNetFltGlobalsWin.Mp.hMiniport));
+ Assert(i == MAX_UNLOAD_PROBES);
+ return VERR_WRONG_ORDER;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ g_bVBoxIdcInitialized = false;
+ }
+ }
+ else
+ {
+ rc = VINF_SUCCESS;
+ }
+ return rc;
+
+}
+
+static int vboxNetFltWinFiniNetFlt()
+{
+ int rc = vboxNetFltWinFiniIdc();
+ if (RT_SUCCESS(rc))
+ {
+ vboxNetFltWinFiniNetFltBase();
+ }
+ return rc;
+}
+
+/**
+ * base netflt initialization
+ */
+static int vboxNetFltWinInitNetFltBase()
+{
+ int rc;
+
+ do
+ {
+ Assert(!g_bVBoxIdcInitialized);
+
+ rc = RTR0Init(0);
+ if (!RT_SUCCESS(rc))
+ {
+ break;
+ }
+
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
+ if (!RT_SUCCESS(rc))
+ {
+ RTR0Term();
+ break;
+ }
+ }while (0);
+
+ return rc;
+}
+
+/**
+ * initialize IDC
+ */
+static int vboxNetFltWinInitIdc()
+{
+ int rc;
+
+ do
+ {
+ if (g_bVBoxIdcInitialized)
+ {
+ rc = VINF_ALREADY_INITIALIZED;
+ break;
+ }
+
+ /*
+ * connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
+ if (!RT_SUCCESS(rc))
+ {
+ break;
+ }
+
+ g_bVBoxIdcInitialized = true;
+ } while (0);
+
+ return rc;
+}
+
+static VOID vboxNetFltWinInitIdcProbingWorker(PVOID pvContext)
+{
+ PINIT_IDC_INFO pInitIdcInfo = (PINIT_IDC_INFO)pvContext;
+ int rc = vboxNetFltWinInitIdc();
+ if (RT_FAILURE(rc))
+ {
+ bool bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
+ if (!bInterupted)
+ {
+ RTThreadSleep(1000); /* 1 s */
+ bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
+ if (!bInterupted)
+ {
+ vboxNetFltWinJobEnqueueJob(&g_VBoxJobQueue, &pInitIdcInfo->Job, false);
+ return;
+ }
+ }
+
+ /* it's interrupted */
+ rc = VERR_INTERRUPTED;
+ }
+
+ ASMAtomicUoWriteS32(&pInitIdcInfo->rc, rc);
+ KeSetEvent(&pInitIdcInfo->hCompletionEvent, 0, FALSE);
+}
+
+static int vboxNetFltWinStopInitIdcProbing()
+{
+ if (!g_VBoxInitIdcInfo.bInitialized)
+ return VERR_INVALID_STATE;
+
+ ASMAtomicUoWriteBool(&g_VBoxInitIdcInfo.bStop, true);
+ KeWaitForSingleObject(&g_VBoxInitIdcInfo.hCompletionEvent, Executive, KernelMode, FALSE, NULL);
+
+ return g_VBoxInitIdcInfo.rc;
+}
+
+static int vboxNetFltWinStartInitIdcProbing()
+{
+ Assert(!g_bVBoxIdcInitialized);
+ KeInitializeEvent(&g_VBoxInitIdcInfo.hCompletionEvent, NotificationEvent, FALSE);
+ g_VBoxInitIdcInfo.bStop = false;
+ g_VBoxInitIdcInfo.bInitialized = true;
+ vboxNetFltWinJobInit(&g_VBoxInitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_VBoxInitIdcInfo, false);
+ vboxNetFltWinJobEnqueueJob(&g_VBoxJobQueue, &g_VBoxInitIdcInfo.Job, false);
+ return VINF_SUCCESS;
+}
+
+static int vboxNetFltWinInitNetFlt()
+{
+ int rc;
+
+ do
+ {
+ rc = vboxNetFltWinInitNetFltBase();
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ break;
+ }
+
+ /*
+ * connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ rc = vboxNetFltWinInitIdc();
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ vboxNetFltWinFiniNetFltBase();
+ break;
+ }
+ } while (0);
+
+ return rc;
+}
+
+/* detach*/
+static int vboxNetFltWinDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("vboxNetFltWinDeleteInstance: pThis=0x%p \n", pThis));
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+ Assert(pThis);
+ Assert(pThis->fDisconnectedFromHost);
+ Assert(!pThis->fRediscoveryPending);
+ Assert(pThis->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE);
+#ifndef VBOXNETADP
+ Assert(pThis->u.s.WinIf.PtState.OpState == kVBoxNetDevOpState_Deinitialized);
+ Assert(!pThis->u.s.WinIf.hBinding);
+#endif
+ Assert(pThis->u.s.WinIf.MpState.OpState == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ Assert(!pThis->u.s.PacketQueueWorker.pSG);
+#endif
+
+ RTSemMutexDestroy(pThis->u.s.hWinIfMutex);
+
+ vboxNetFltWinDrvDereference();
+
+ return VINF_SUCCESS;
+}
+
+static NDIS_STATUS vboxNetFltWinDisconnectIt(PVBOXNETFLTINS pInstance)
+{
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ vboxNetFltWinQuFiniPacketQueue(pInstance);
+#else
+ RT_NOREF1(pInstance);
+#endif
+ return NDIS_STATUS_SUCCESS;
+}
+
+/* detach*/
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PVBOXNETFLTINS pNetFlt, bool bOnUnbind)
+{
+ NDIS_STATUS Status;
+ int rc;
+ LogFlowFunc(("ENTER: pThis=%0xp\n", pNetFlt));
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+ Assert(pNetFlt);
+
+ /* paranoia to ensure the instance is not removed while we're waiting on the mutex
+ * in case ndis does something unpredictable, e.g. calls our miniport halt independently
+ * from protocol unbind and concurrently with it*/
+ vboxNetFltRetain(pNetFlt, false);
+
+ rc = RTSemMutexRequest(pNetFlt->u.s.hWinIfMutex, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(vboxNetFltWinGetWinIfState(pNetFlt) == kVBoxWinIfState_Connected);
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Initialized);
+#endif
+ if (vboxNetFltWinGetWinIfState(pNetFlt) == kVBoxWinIfState_Connected)
+ {
+ vboxNetFltWinSetWinIfState(pNetFlt, kVBoxWinIfState_Disconnecting);
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtDoUnbinding(pNetFlt, bOnUnbind);
+#else
+ Status = vboxNetFltWinMpDoDeinitialization(pNetFlt);
+#endif
+ Assert(Status == NDIS_STATUS_SUCCESS);
+
+ vboxNetFltWinSetWinIfState(pNetFlt, kVBoxWinIfState_Disconnected);
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+ vboxNetFltWinPtFiniWinIf(&pNetFlt->u.s.WinIf);
+
+ /* we're unbinding, make an unbind-related release */
+ vboxNetFltRelease(pNetFlt, false);
+ }
+ else
+ {
+ AssertBreakpoint();
+#ifndef VBOXNETADP
+ pNetFlt->u.s.WinIf.OpenCloseStatus = NDIS_STATUS_FAILURE;
+#endif
+ if (!bOnUnbind)
+ {
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ Status = NDIS_STATUS_FAILURE;
+ }
+ RTSemMutexRelease(pNetFlt->u.s.hWinIfMutex);
+ }
+ else
+ {
+ AssertBreakpoint();
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ /* release for the retain we made before waining on the mutex */
+ vboxNetFltRelease(pNetFlt, false);
+
+ LogFlowFunc(("LEAVE: Status 0x%x\n", Status));
+
+ return Status;
+}
+
+
+/**
+ * Checks if the host (not us) has put the adapter in promiscuous mode.
+ *
+ * @returns true if promiscuous, false if not.
+ * @param pThis The instance.
+ */
+static bool vboxNetFltWinIsPromiscuous2(PVBOXNETFLTINS pThis)
+{
+#ifndef VBOXNETADP
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pThis))
+ {
+ bool bPromiscuous;
+ if (!vboxNetFltWinReferenceWinIf(pThis))
+ return false;
+
+ bPromiscuous = (pThis->u.s.WinIf.fUpperProtocolSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
+ /*vboxNetFltWinIsPromiscuous(pAdapt);*/
+
+ vboxNetFltWinDereferenceWinIf(pThis);
+ return bPromiscuous;
+ }
+ return false;
+#else
+ RT_NOREF1(pThis);
+ return true;
+#endif
+}
+
+
+/**
+ * Report the MAC address, promiscuous mode setting, GSO capabilities and
+ * no-preempt destinations to the internal network.
+ *
+ * Does nothing if we're not currently connected to an internal network.
+ *
+ * @param pThis The instance data.
+ */
+static void vboxNetFltWinReportStuff(PVBOXNETFLTINS pThis)
+{
+ /** @todo Keep these up to date, esp. the promiscuous mode bit. */
+ if (pThis->pSwitchPort
+ && vboxNetFltTryRetainBusyNotDisconnected(pThis))
+ {
+ pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
+ pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort,
+ vboxNetFltWinIsPromiscuous2(pThis));
+ pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
+ INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
+ /** @todo We should be able to do pfnXmit at DISPATCH_LEVEL... */
+ pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
+ vboxNetFltRelease(pThis, true /*fBusy*/);
+ }
+}
+
+/**
+ * Worker for vboxNetFltWinAttachToInterface.
+ *
+ * @param pAttachInfo Structure for communicating with
+ * vboxNetFltWinAttachToInterface.
+ */
+static void vboxNetFltWinAttachToInterfaceWorker(PATTACH_INFO pAttachInfo)
+{
+ PVBOXNETFLTINS pThis = pAttachInfo->pNetFltIf;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ int rc;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ /* to ensure we're not removed while we're here */
+ vboxNetFltRetain(pThis, false);
+
+ rc = RTSemMutexRequest(pThis->u.s.hWinIfMutex, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(vboxNetFltWinGetWinIfState(pThis) == kVBoxWinIfState_Disconnected);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+ if (vboxNetFltWinGetWinIfState(pThis) == kVBoxWinIfState_Disconnected)
+ {
+ if (pAttachInfo->fRediscovery)
+ {
+ /* rediscovery means adaptor bind is performed while intnet is already using it
+ * i.e. adaptor was unbound while being used by intnet and now being bound back again */
+ Assert( ((VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState))
+ == kVBoxNetFltInsState_Connected);
+ }
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtInitWinIf(&pThis->u.s.WinIf, pAttachInfo->pCreateContext->pOurName);
+#else
+ Status = vboxNetFltWinPtInitWinIf(&pThis->u.s.WinIf);
+#endif
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Connecting);
+
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtDoBinding(pThis, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
+#else
+ Status = vboxNetFltWinMpDoInitialization(pThis, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
+#endif
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (!pAttachInfo->fRediscovery)
+ vboxNetFltWinDrvReference();
+#ifndef VBOXNETADP
+ if (pThis->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+#endif
+ {
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Connected);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.PtState) == kVBoxNetDevOpState_Initialized);
+#endif
+ /* 4. mark as connected */
+ RTSpinlockAcquire(pThis->hSpinlock);
+ ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ RTSpinlockRelease(pThis->hSpinlock);
+
+ pAttachInfo->Status = VINF_SUCCESS;
+ pAttachInfo->pCreateContext->Status = NDIS_STATUS_SUCCESS;
+
+ RTSemMutexRelease(pThis->u.s.hWinIfMutex);
+
+ vboxNetFltRelease(pThis, false);
+
+ /* 5. Report MAC address, promiscuousness and GSO capabilities. */
+ vboxNetFltWinReportStuff(pThis);
+
+ return;
+ }
+#ifndef VBOXNETADP /* unreachable for VBOXNETADP because of the return above */
+ AssertBreakpoint();
+
+ if (!pAttachInfo->fRediscovery)
+ {
+ vboxNetFltWinDrvDereference();
+ }
+# ifndef VBOXNETADP
+ vboxNetFltWinPtDoUnbinding(pThis, true);
+/*# else - unreachable
+ vboxNetFltWinMpDoDeinitialization(pThis); */
+# endif
+#endif
+ }
+ AssertBreakpoint();
+ vboxNetFltWinPtFiniWinIf(&pThis->u.s.WinIf);
+ }
+ AssertBreakpoint();
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Disconnected);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+ }
+ AssertBreakpoint();
+
+ pAttachInfo->Status = VERR_GENERAL_FAILURE;
+ pAttachInfo->pCreateContext->Status = Status;
+ RTSemMutexRelease(pThis->u.s.hWinIfMutex);
+ }
+ else
+ {
+ AssertBreakpoint();
+ pAttachInfo->Status = rc;
+ }
+
+ vboxNetFltRelease(pThis, false);
+
+ return;
+}
+
+/**
+ * Common code for vboxNetFltOsInitInstance and
+ * vboxNetFltOsMaybeRediscovered.
+ *
+ * @returns IPRT status code.
+ * @param pThis The instance.
+ * @param fRediscovery True if vboxNetFltOsMaybeRediscovered is calling,
+ * false if it's vboxNetFltOsInitInstance.
+ */
+static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery)
+{
+ ATTACH_INFO Info;
+ Info.pNetFltIf = pThis;
+ Info.fRediscovery = fRediscovery;
+ Info.pCreateContext = (PCREATE_INSTANCE_CONTEXT)pContext;
+
+ vboxNetFltWinAttachToInterfaceWorker(&Info);
+
+ return Info.Status;
+}
+static NTSTATUS vboxNetFltWinPtDevDispatch(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
+{
+ RT_NOREF1(pDevObj);
+ PIO_STACK_LOCATION pIrpSl = IoGetCurrentIrpStackLocation(pIrp);;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ switch (pIrpSl->MajorFunction)
+ {
+ case IRP_MJ_DEVICE_CONTROL:
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ case IRP_MJ_CREATE:
+ case IRP_MJ_CLEANUP:
+ case IRP_MJ_CLOSE:
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+
+ pIrp->IoStatus.Status = Status;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevCreate(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ NDIS_STRING DevName, LinkName;
+ PDRIVER_DISPATCH aMajorFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
+ NdisInitUnicodeString(&DevName, VBOXNETFLT_NAME_DEVICE);
+ NdisInitUnicodeString(&LinkName, VBOXNETFLT_NAME_LINK);
+
+ Assert(!pGlobals->hDevice);
+ Assert(!pGlobals->pDevObj);
+ NdisZeroMemory(aMajorFunctions, sizeof (aMajorFunctions));
+ aMajorFunctions[IRP_MJ_CREATE] = vboxNetFltWinPtDevDispatch;
+ aMajorFunctions[IRP_MJ_CLEANUP] = vboxNetFltWinPtDevDispatch;
+ aMajorFunctions[IRP_MJ_CLOSE] = vboxNetFltWinPtDevDispatch;
+ aMajorFunctions[IRP_MJ_DEVICE_CONTROL] = vboxNetFltWinPtDevDispatch;
+
+ NDIS_STATUS Status = NdisMRegisterDevice(pGlobals->Mp.hNdisWrapper,
+ &DevName, &LinkName,
+ aMajorFunctions,
+ &pGlobals->pDevObj,
+ &pGlobals->hDevice);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevDestroy(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ Assert(pGlobals->hDevice);
+ Assert(pGlobals->pDevObj);
+ NDIS_STATUS Status = NdisMDeregisterDevice(pGlobals->hDevice);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pGlobals->hDevice = NULL;
+ pGlobals->pDevObj = NULL;
+ }
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevCreateReference(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ NDIS_STATUS Status = KeWaitForSingleObject(&pGlobals->SynchEvent, Executive, KernelMode, FALSE, NULL);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Assert(pGlobals->cDeviceRefs >= 0);
+ if (++pGlobals->cDeviceRefs == 1)
+ {
+ Status = vboxNetFltWinDevCreate(pGlobals);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ObReferenceObject(pGlobals->pDevObj);
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ KeSetEvent(&pGlobals->SynchEvent, 0, FALSE);
+ }
+ else
+ {
+ /* should never happen actually */
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ }
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevDereference(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ NDIS_STATUS Status = KeWaitForSingleObject(&pGlobals->SynchEvent, Executive, KernelMode, FALSE, NULL);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Assert(pGlobals->cDeviceRefs > 0);
+ if (!(--pGlobals->cDeviceRefs))
+ {
+ ObDereferenceObject(pGlobals->pDevObj);
+ Status = vboxNetFltWinDevDestroy(pGlobals);
+ }
+ else
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ KeSetEvent(&pGlobals->SynchEvent, 0, FALSE);
+ }
+ else
+ {
+ /* should never happen actually */
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ }
+ return Status;
+}
+
+/* reference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvReference()
+{
+ vboxNetFltWinDevCreateReference(&g_VBoxNetFltGlobalsWin);
+}
+
+/* dereference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvDereference()
+{
+ vboxNetFltWinDevDereference(&g_VBoxNetFltGlobalsWin);
+}
+
+/*
+ *
+ * The OS specific interface definition
+ *
+ */
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ /* AttachToInterface true if disconnected */
+ return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
+}
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
+{
+ RT_NOREF1(pvIfData);
+ int rc = VINF_SUCCESS;
+ uint32_t cRefs = 0;
+#ifndef VBOXNETADP
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ cRefs++;
+ if (fDst & INTNETTRUNKDIR_HOST)
+ cRefs++;
+#else
+ if ((fDst & INTNETTRUNKDIR_WIRE) || (fDst & INTNETTRUNKDIR_HOST))
+ cRefs = 1;
+#endif
+
+ AssertReturn(cRefs, VINF_SUCCESS);
+
+ if (!vboxNetFltWinIncReferenceWinIf(pThis, cRefs))
+ {
+ return VERR_GENERAL_FAILURE;
+ }
+#ifndef VBOXNETADP
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ {
+ PNDIS_PACKET pPacket;
+
+ pPacket = vboxNetFltWinNdisPacketFromSG(pThis, pSG, NULL /*pBufToFree*/,
+ true /*fToWire*/, true /*fCopyMemory*/);
+
+ if (pPacket)
+ {
+ NDIS_STATUS fStatus;
+
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ /* force "don't loopback" flags to prevent loopback branch invocation in any case
+ * to avoid ndis misbehave */
+ NdisGetPacketFlags(pPacket) |= g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#else
+ /* this is done by default in vboxNetFltWinNdisPacketFromSG */
+#endif
+
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ vboxNetFltWinLbPutSendPacket(pThis, pPacket, true /* bFromIntNet */);
+#endif
+ NdisSend(&fStatus, pThis->u.s.WinIf.hBinding, pPacket);
+ if (fStatus != NDIS_STATUS_PENDING)
+ {
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ /* the status is NOT pending, complete the packet */
+ bool fTmp = vboxNetFltWinLbRemoveSendPacket(pThis, pPacket);
+ Assert(fTmp); NOREF(fTmp);
+#endif
+ if (!NT_SUCCESS(fStatus))
+ rc = VERR_GENERAL_FAILURE; /** @todo convert status to VERR_xxx */
+
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ }
+ else
+ {
+ /* pending, dereference on packet complete */
+ cRefs--;
+ }
+ }
+ else
+ {
+ AssertFailed();
+ rc = VERR_NO_MEMORY;
+ }
+ }
+#endif
+
+#ifndef VBOXNETADP
+ if (fDst & INTNETTRUNKDIR_HOST)
+#else
+ if (cRefs)
+#endif
+ {
+ PNDIS_PACKET pPacket = vboxNetFltWinNdisPacketFromSG(pThis, pSG, NULL /*pBufToFree*/,
+ false /*fToWire*/, true /*fCopyMemory*/);
+ if (pPacket)
+ {
+ NdisMIndicateReceivePacket(pThis->u.s.WinIf.hMiniport, &pPacket, 1);
+ cRefs--;
+#ifdef VBOXNETADP
+ STATISTIC_INCREASE(pThis->u.s.WinIf.cRxSuccess);
+#endif
+ }
+ else
+ {
+ AssertFailed();
+#ifdef VBOXNETADP
+ STATISTIC_INCREASE(pThis->u.s.WinIf.cRxError);
+#endif
+ rc = VERR_NO_MEMORY;
+ }
+ }
+
+ Assert(cRefs <= 2);
+
+ if (cRefs)
+ {
+ vboxNetFltWinDecReferenceWinIf(pThis, cRefs);
+ }
+
+ return rc;
+}
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+#ifndef VBOXNETADP
+ NDIS_STATUS Status;
+#endif
+ /* we first wait for all pending ops to complete
+ * this might include all packets queued for processing */
+ for (;;)
+ {
+ if (fActive)
+ {
+ if (!pThis->u.s.cModePassThruRefs)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if (!pThis->u.s.cModeNetFltRefs)
+ {
+ break;
+ }
+ }
+ vboxNetFltWinSleep(2);
+ }
+
+ if (!vboxNetFltWinReferenceWinIf(pThis))
+ return;
+#ifndef VBOXNETADP
+
+ if (fActive)
+ {
+#ifdef DEBUG_misha
+ NDIS_PHYSICAL_MEDIUM PhMedium;
+ bool bPromiscSupported;
+
+ Status = vboxNetFltWinQueryPhysicalMedium(pThis, &PhMedium);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+
+ LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
+ Assert(Status == NDIS_STATUS_NOT_SUPPORTED);
+ if (Status != NDIS_STATUS_NOT_SUPPORTED)
+ {
+ LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
+ }
+ PhMedium = NdisPhysicalMediumUnspecified;
+ }
+ else
+ {
+ LogRel(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
+ }
+
+ bPromiscSupported = (!(PhMedium == NdisPhysicalMediumWirelessWan
+ || PhMedium == NdisPhysicalMediumWirelessLan
+ || PhMedium == NdisPhysicalMediumNative802_11
+ || PhMedium == NdisPhysicalMediumBluetooth
+ /*|| PhMedium == NdisPhysicalMediumWiMax */
+ ));
+
+ Assert(bPromiscSupported == VBOXNETFLT_PROMISCUOUS_SUPPORTED(pThis));
+#endif
+ }
+
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pThis))
+ {
+ Status = vboxNetFltWinSetPromiscuous(pThis, fActive);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogRel(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
+ AssertFailed();
+ }
+ }
+#else
+# ifdef VBOXNETADP_REPORT_DISCONNECTED
+ if (fActive)
+ {
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_CONNECT,
+ (PVOID)NULL,
+ 0);
+ }
+ else
+ {
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_DISCONNECT,
+ (PVOID)NULL,
+ 0);
+ }
+#else
+ if (fActive)
+ {
+ /* indicate status change to make the ip settings be re-picked for dhcp */
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_DISCONNECT,
+ (PVOID)NULL,
+ 0);
+
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_CONNECT,
+ (PVOID)NULL,
+ 0);
+ }
+# endif
+#endif
+ vboxNetFltWinDereferenceWinIf(pThis);
+
+ return;
+}
+
+#ifndef VBOXNETADP
+
+DECLINLINE(bool) vboxNetFltWinIsAddrLinkLocal4(PCRTNETADDRIPV4 pAddr)
+{
+ return (pAddr->s.Lo == 0xfea9); /* 169.254 */
+}
+
+DECLINLINE(bool) vboxNetFltWinIsAddrLinkLocal6(PCRTNETADDRIPV6 pAddr)
+{
+ return ((pAddr->au8[0] == 0xfe) && ((pAddr->au8[1] & 0xc0) == 0x80));
+}
+
+void vboxNetFltWinNotifyHostAddress(PTA_ADDRESS pAddress, bool fAdded)
+{
+ void *pvAddr = NULL;
+ INTNETADDRTYPE enmAddrType = kIntNetAddrType_Invalid;
+
+ LogFlow(("==>vboxNetFltWinNotifyHostAddress: AddrType=%d %s\n",
+ pAddress->AddressType, fAdded ? "added" : "deleted"));
+ if (pAddress->AddressType == TDI_ADDRESS_TYPE_IP)
+ {
+ PTDI_ADDRESS_IP pTdiAddrIp = (PTDI_ADDRESS_IP)pAddress->Address;
+ /*
+ * Note that we do not get loopback addresses here. If we did we should
+ * have checked and ignored them too.
+ */
+ if (!vboxNetFltWinIsAddrLinkLocal4((PCRTNETADDRIPV4)(&pTdiAddrIp->in_addr)))
+ {
+ pvAddr = &pTdiAddrIp->in_addr;
+ enmAddrType = kIntNetAddrType_IPv4;
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: ignoring link-local address %RTnaipv4\n",
+ pTdiAddrIp->in_addr));
+ }
+ else if (pAddress->AddressType == TDI_ADDRESS_TYPE_IP6)
+ {
+ PTDI_ADDRESS_IP6 pTdiAddrIp6 = (PTDI_ADDRESS_IP6)pAddress->Address;
+ if (!vboxNetFltWinIsAddrLinkLocal6((PCRTNETADDRIPV6)(pTdiAddrIp6->sin6_addr)))
+ {
+ pvAddr = pTdiAddrIp6->sin6_addr;
+ enmAddrType = kIntNetAddrType_IPv6;
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: ignoring link-local address %RTnaipv6\n",
+ pTdiAddrIp6->sin6_addr));
+ }
+ else
+ {
+ Log2(("vboxNetFltWinNotifyHostAddress: ignoring irrelevant address type %d\n",
+ pAddress->AddressType));
+ LogFlow(("<==vboxNetFltWinNotifyHostAddress\n"));
+ return;
+ }
+ if (pvAddr)
+ {
+ NdisAcquireSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ /* At this point the list must contain at least one element. */
+ PVBOXNETFLTINS pInstance = NULL;
+ PVBOXNETFLTWIN pFilter;
+ RTListForEach(&g_VBoxNetFltGlobalsWin.listFilters, pFilter, VBOXNETFLTWIN, node)
+ {
+ pInstance = RT_FROM_MEMBER(pFilter, VBOXNETFLTINS, u.s.WinIf);
+ if (vboxNetFltWinReferenceWinIf(pInstance))
+ {
+ if (pInstance->pSwitchPort && pInstance->pSwitchPort->pfnNotifyHostAddress)
+ break;
+ vboxNetFltWinDereferenceWinIf(pInstance);
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: failed to retain filter instance %p\n", pInstance));
+ pInstance = NULL;
+ }
+ NdisReleaseSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ if (pInstance)
+ {
+ if (enmAddrType == kIntNetAddrType_IPv4)
+ Log2(("vboxNetFltWin%sAddressHandler: %RTnaipv4\n",
+ fAdded ? "Add" : "Del", *(PCRTNETADDRIPV4)pvAddr));
+ else
+ Log2(("vboxNetFltWin%sAddressHandler: %RTnaipv6\n",
+ fAdded ? "Add" : "Del", pvAddr));
+ pInstance->pSwitchPort->pfnNotifyHostAddress(pInstance->pSwitchPort, fAdded,
+ enmAddrType, pvAddr);
+ vboxNetFltWinDereferenceWinIf(pInstance);
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: no filters require notification\n"));
+ }
+ LogFlow(("<==vboxNetFltWinNotifyHostAddress\n"));
+}
+
+void vboxNetFltWinAddAddressHandler(PTA_ADDRESS Address,
+ PUNICODE_STRING DeviceName,
+ PTDI_PNP_CONTEXT Context)
+{
+ RT_NOREF2(DeviceName, Context);
+ vboxNetFltWinNotifyHostAddress(Address, true);
+}
+
+void vboxNetFltWinDelAddressHandler(PTA_ADDRESS Address,
+ PUNICODE_STRING DeviceName,
+ PTDI_PNP_CONTEXT Context)
+{
+ RT_NOREF2(DeviceName, Context);
+ vboxNetFltWinNotifyHostAddress(Address, false);
+}
+
+void vboxNetFltWinRegisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltWinRegisterIpAddrNotifier: instance=%p pThis->pSwitchPort=%p pThis->pSwitchPort->pfnNotifyHostAddress=%p\n",
+ pThis, pThis->pSwitchPort, pThis->pSwitchPort ? pThis->pSwitchPort->pfnNotifyHostAddress : NULL));
+ if (pThis->pSwitchPort && pThis->pSwitchPort->pfnNotifyHostAddress)
+ {
+ NdisAcquireSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ bool fRegisterHandlers = RTListIsEmpty(&g_VBoxNetFltGlobalsWin.listFilters);
+ RTListPrepend(&g_VBoxNetFltGlobalsWin.listFilters, &pThis->u.s.WinIf.node);
+ NdisReleaseSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+
+ if (fRegisterHandlers)
+ {
+ TDI_CLIENT_INTERFACE_INFO Info;
+ UNICODE_STRING ClientName = RTL_CONSTANT_STRING(L"VBoxNetFlt");
+ memset(&Info, 0, sizeof(Info));
+ Info.MajorTdiVersion = 2;
+ Info.MinorTdiVersion = 0;
+ Info.ClientName = &ClientName;
+ Info.AddAddressHandlerV2 = vboxNetFltWinAddAddressHandler;
+ Info.DelAddressHandlerV2 = vboxNetFltWinDelAddressHandler;
+ Assert(!g_VBoxNetFltGlobalsWin.hNotifier);
+ NTSTATUS Status = TdiRegisterPnPHandlers(&Info, sizeof(Info), &g_VBoxNetFltGlobalsWin.hNotifier);
+ Log2(("vboxNetFltWinRegisterIpAddrNotifier: TdiRegisterPnPHandlers returned %d\n", Status)); NOREF(Status);
+ }
+ else
+ Log2(("vboxNetFltWinRegisterIpAddrNotifier: already registed\n"));
+ }
+ else
+ Log2(("vboxNetFltWinRegisterIpAddrNotifier: this instance does not require notifications, ignoring...\n"));
+ LogFlow(("<==vboxNetFltWinRegisterIpAddrNotifier: notifier=%p\n", g_VBoxNetFltGlobalsWin.hNotifier));
+}
+
+void vboxNetFltWinUnregisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltWinUnregisterIpAddrNotifier: notifier=%p\n", g_VBoxNetFltGlobalsWin.hNotifier));
+ if (pThis->pSwitchPort && pThis->pSwitchPort->pfnNotifyHostAddress)
+ {
+ NdisAcquireSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ /* At this point the list must contain at least one element. */
+ Assert(!RTListIsEmpty(&g_VBoxNetFltGlobalsWin.listFilters));
+ RTListNodeRemove(&pThis->u.s.WinIf.node);
+ HANDLE hNotifier = NULL;
+ if (RTListIsEmpty(&g_VBoxNetFltGlobalsWin.listFilters))
+ {
+ /*
+ * The list has become empty, so we need to deregister handlers. We
+ * grab hNotifier and reset it while still holding the lock. This
+ * guaranties that we won't interfere with setting it in
+ * vboxNetFltWinRegisterIpAddrNotifier(). It is inconceivable that
+ * vboxNetFltWinUnregisterIpAddrNotifier() will be called for the
+ * same filter instance while it is still being processed by
+ * vboxNetFltWinRegisterIpAddrNotifier(). This would require trunk
+ * destruction in the middle of its creation. It is possible that
+ * vboxNetFltWinUnregisterIpAddrNotifier() is called for another
+ * filter instance, but in such case we won't even get here as the
+ * list won't be empty.
+ */
+ hNotifier = g_VBoxNetFltGlobalsWin.hNotifier;
+ g_VBoxNetFltGlobalsWin.hNotifier = NULL;
+ }
+ NdisReleaseSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ if (hNotifier)
+ {
+ NTSTATUS Status = TdiDeregisterPnPHandlers(hNotifier);
+ Log2(("vboxNetFltWinUnregisterIpAddrNotifier: TdiDeregisterPnPHandlers(%p) returned %d\n",
+ hNotifier, Status)); NOREF(Status);
+ }
+ else
+ Log2(("vboxNetFltWinUnregisterIpAddrNotifier: filters remain, do not deregister handlers yet\n"));
+ }
+ else
+ Log2(("vboxNetFltWinUnregisterIpAddrNotifier: this instance did not require notifications, ignoring...\n"));
+ LogFlow(("<==vboxNetFltWinUnregisterIpAddrNotifier\n"));
+}
+#else /* VBOXNETADP */
+#define vboxNetFltWinRegisterIpAddrNotifier(x)
+#define vboxNetFltWinUnregisterIpAddrNotifier(x)
+#endif /* VBOXNETADP */
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ NDIS_STATUS Status = vboxNetFltWinDisconnectIt(pThis);
+ Log2(("vboxNetFltOsDisconnectIt: pThis=%p pThis->pSwitchPort=%p pThis->pSwitchPort->pfnNotifyHostAddress=%p\n",
+ pThis, pThis->pSwitchPort, pThis->pSwitchPort ? pThis->pSwitchPort->pfnNotifyHostAddress : NULL));
+ vboxNetFltWinUnregisterIpAddrNotifier(pThis);
+ return Status == NDIS_STATUS_SUCCESS ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
+}
+
+static void vboxNetFltWinConnectItWorker(PVOID pvContext)
+{
+ PWORKER_INFO pInfo = (PWORKER_INFO)pvContext;
+#if !defined(VBOXNETADP) || !defined(VBOXNETFLT_NO_PACKET_QUEUE)
+ NDIS_STATUS Status;
+#endif
+ PVBOXNETFLTINS pInstance = pInfo->pNetFltIf;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ /* this is not a rediscovery, initialize Mac cache */
+ if (vboxNetFltWinReferenceWinIf(pInstance))
+ {
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinGetMacAddress(pInstance, &pInstance->u.s.MacAddr);
+ if (Status == NDIS_STATUS_SUCCESS)
+#endif
+ {
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ pInfo->Status = VINF_SUCCESS;
+#else
+ Status = vboxNetFltWinQuInitPacketQueue(pInstance);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pInfo->Status = VINF_SUCCESS;
+ }
+ else
+ {
+ pInfo->Status = VERR_GENERAL_FAILURE;
+ }
+#endif
+ }
+#ifndef VBOXNETADP
+ else
+ {
+ pInfo->Status = VERR_INTNET_FLT_IF_FAILED;
+ }
+#endif
+
+ vboxNetFltWinDereferenceWinIf(pInstance);
+ }
+ else
+ {
+ pInfo->Status = VERR_INTNET_FLT_IF_NOT_FOUND;
+ }
+}
+
+static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis)
+{
+ WORKER_INFO Info;
+ Info.pNetFltIf = pThis;
+
+ vboxNetFltWinJobSynchExecAtPassive(vboxNetFltWinConnectItWorker, &Info);
+
+ if (RT_SUCCESS(Info.Status))
+ vboxNetFltWinReportStuff(pThis);
+
+ return Info.Status;
+}
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ Log2(("vboxNetFltOsConnectIt: pThis=%p pThis->pSwitchPort=%p pThis->pSwitchPort->pfnNotifyHostAddress=%p\n",
+ pThis, pThis->pSwitchPort, pThis->pSwitchPort ? pThis->pSwitchPort->pfnNotifyHostAddress : NULL));
+ vboxNetFltWinRegisterIpAddrNotifier(pThis);
+ return vboxNetFltWinConnectIt(pThis);
+}
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ vboxNetFltWinDeleteInstance(pThis);
+}
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
+{
+ int rc = RTSemMutexCreate(&pThis->u.s.hWinIfMutex);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxNetFltWinAttachToInterface(pThis, pvContext, false /*fRediscovery*/ );
+ if (RT_SUCCESS(rc))
+ {
+ return rc;
+ }
+ RTSemMutexDestroy(pThis->u.s.hWinIfMutex);
+ }
+ return rc;
+}
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ pThis->u.s.cModeNetFltRefs = 0;
+ pThis->u.s.cModePassThruRefs = 0;
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Disconnected);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+#endif
+ return VINF_SUCCESS;
+}
+
+void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
+{
+ RT_NOREF3(pThis, pvIfData, pMac);
+}
+
+int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
+{
+ /* Nothing to do */
+ RT_NOREF3(pThis, pvIf, ppvIfData);
+ return VINF_SUCCESS;
+}
+
+int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
+{
+ /* Nothing to do */
+ RT_NOREF2(pThis, pvIfData);
+ return VINF_SUCCESS;
+}