summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp1595
1 files changed, 1595 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp
new file mode 100644
index 00000000..3e06f3c2
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp
@@ -0,0 +1,1595 @@
+/* $Id: VBoxNetFltP-win.cpp $ */
+/** @file
+ * VBoxNetFltP-win.cpp - Bridged Networking Driver, Windows Specific Code.
+ * Protocol edge
+ */
+/*
+ * 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
+ */
+#include "VBoxNetFltCmn-win.h"
+
+#ifdef VBOXNETADP
+# error "No protocol edge"
+#endif
+
+#define VBOXNETFLT_PT_STATUS_IS_FILTERED(_s) (\
+ (_s) == NDIS_STATUS_MEDIA_CONNECT \
+ || (_s) == NDIS_STATUS_MEDIA_DISCONNECT \
+ )
+
+/**
+ * performs binding to the given adapter
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(PVBOXNETFLTINS pThis, PNDIS_STRING pOurDeviceName, PNDIS_STRING pBindToDeviceName)
+{
+ Assert(pThis->u.s.WinIf.PtState.PowerState == NdisDeviceStateD3);
+ Assert(pThis->u.s.WinIf.PtState.OpState == kVBoxNetDevOpState_Deinitialized);
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Initializing);
+
+ NDIS_STATUS Status = vboxNetFltWinCopyString(&pThis->u.s.WinIf.MpDeviceName, pOurDeviceName);
+ Assert (Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ vboxNetFltWinSetPowerState(&pThis->u.s.WinIf.PtState, NdisDeviceStateD0);
+ pThis->u.s.WinIf.OpenCloseStatus = NDIS_STATUS_SUCCESS;
+
+ UINT iMedium;
+ NDIS_STATUS TmpStatus;
+ NDIS_MEDIUM aenmNdisMedium[] =
+ {
+ /* Ethernet */
+ NdisMedium802_3,
+ /* Wan */
+ NdisMediumWan
+ };
+
+ NdisResetEvent(&pThis->u.s.WinIf.OpenCloseEvent);
+
+ NdisOpenAdapter(&Status, &TmpStatus, &pThis->u.s.WinIf.hBinding, &iMedium,
+ aenmNdisMedium, RT_ELEMENTS(aenmNdisMedium),
+ g_VBoxNetFltGlobalsWin.Pt.hProtocol,
+ pThis,
+ pBindToDeviceName,
+ 0, /* IN UINT OpenOptions, (reserved, should be NULL) */
+ NULL /* IN PSTRING AddressingInformation OPTIONAL */
+ );
+ Assert(Status == NDIS_STATUS_PENDING || Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pThis->u.s.WinIf.OpenCloseEvent, 0);
+ Status = pThis->u.s.WinIf.OpenCloseStatus;
+ }
+
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Assert(pThis->u.s.WinIf.hBinding);
+ pThis->u.s.WinIf.enmMedium = aenmNdisMedium[iMedium];
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Initialized);
+
+ Status = vboxNetFltWinMpInitializeDevideInstance(pThis);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ LogRelFunc(("vboxNetFltWinMpInitializeDevideInstance failed, Status 0x%x\n", Status));
+ }
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinPtCloseInterface(pThis, &TmpStatus);
+ Assert(TmpStatus == NDIS_STATUS_SUCCESS);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+ {
+ LogRelFunc(("NdisOpenAdapter failed, Status (0x%x)", Status));
+ }
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+ pThis->u.s.WinIf.hBinding = NULL;
+ }
+
+ return Status;
+}
+
+static VOID vboxNetFltWinPtBindAdapter(OUT PNDIS_STATUS pStatus,
+ IN NDIS_HANDLE hBindContext,
+ IN PNDIS_STRING pDeviceNameStr,
+ IN PVOID pvSystemSpecific1,
+ IN PVOID pvSystemSpecific2)
+{
+ LogFlowFuncEnter();
+ RT_NOREF2(hBindContext, pvSystemSpecific2);
+
+ NDIS_STATUS Status;
+ NDIS_HANDLE hConfig = NULL;
+
+ NdisOpenProtocolConfiguration(&Status, &hConfig, (PNDIS_STRING)pvSystemSpecific1);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PNDIS_CONFIGURATION_PARAMETER pParam;
+ NDIS_STRING UppedBindStr = NDIS_STRING_CONST("UpperBindings");
+ NdisReadConfiguration(&Status, &pParam, hConfig, &UppedBindStr, NdisParameterString);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLTINS pNetFlt;
+ Status = vboxNetFltWinPtInitBind(&pNetFlt, &pParam->ParameterData.StringData, pDeviceNameStr);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ }
+
+ NdisCloseConfiguration(hConfig);
+ }
+
+ *pStatus = Status;
+
+ LogFlowFunc(("LEAVE: Status 0x%x\n", Status));
+}
+
+static VOID vboxNetFltWinPtOpenAdapterComplete(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ RT_NOREF1(OpenErrorStatus);
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Status (0x%x), OpenErrorStatus(0x%x)\n", pNetFlt, Status, OpenErrorStatus));
+ Assert(pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+ {
+ pNetFlt->u.s.WinIf.OpenCloseStatus = Status;
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ LogRelFunc(("Open Complete status is 0x%x", Status));
+ }
+ else
+ LogRelFunc(("Adapter maintained status is 0x%x", pNetFlt->u.s.WinIf.OpenCloseStatus));
+ NdisSetEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent);
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x), OpenErrorStatus(0x%x)\n", pNetFlt, Status, OpenErrorStatus));
+}
+
+static void vboxNetFltWinPtRequestsWaitComplete(PVBOXNETFLTINS pNetFlt)
+{
+ /* wait for request to complete */
+ while (vboxNetFltWinAtomicUoReadWinState(pNetFlt->u.s.WinIf.StateFlags).fRequestInfo == VBOXNDISREQUEST_INPROGRESS)
+ {
+ vboxNetFltWinSleep(2);
+ }
+
+ /*
+ * If the below miniport is going to low power state, complete the queued request
+ */
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ if (pNetFlt->u.s.WinIf.StateFlags.fRequestInfo & VBOXNDISREQUEST_QUEUED)
+ {
+ /* mark the request as InProgress before posting it to RequestComplete */
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ vboxNetFltWinPtRequestComplete(pNetFlt, &pNetFlt->u.s.WinIf.PassDownRequest, NDIS_STATUS_FAILURE);
+ }
+ else
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ }
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoUnbinding(PVBOXNETFLTINS pNetFlt, bool bOnUnbind)
+{
+ NDIS_STATUS Status;
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+ int cPPUsage;
+
+ LogFlowFunc(("ENTER: pNetFlt 0x%p\n", pNetFlt));
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Initialized);
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+
+ ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true);
+ ASMAtomicUoWriteBool(&pNetFlt->fRediscoveryPending, false);
+ ASMAtomicUoWriteU64(&pNetFlt->NanoTSLastRediscovery, NanoTS);
+
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitializing);
+ if (!bOnUnbind)
+ {
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+ }
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ vboxNetFltWinPtRequestsWaitComplete(pNetFlt);
+
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.MpState);
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.PtState);
+
+ /* check packet pool is empty */
+ cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hSendPacketPool);
+ Assert(cPPUsage == 0);
+ cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(cPPUsage == 0);
+ /* for debugging only, ignore the err in release */
+ NOREF(cPPUsage);
+
+ if (!bOnUnbind || !vboxNetFltWinMpDeInitializeDeviceInstance(pNetFlt, &Status))
+ {
+ vboxNetFltWinPtCloseInterface(pNetFlt, &Status);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+
+ if (!bOnUnbind)
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ }
+ }
+ else
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt 0x%p\n", pNetFlt));
+
+ return Status;
+}
+
+static VOID vboxNetFltWinPtUnbindAdapter(OUT PNDIS_STATUS pStatus,
+ IN NDIS_HANDLE hContext,
+ IN NDIS_HANDLE hUnbindContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ RT_NOREF1(hUnbindContext);
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ *pStatus = vboxNetFltWinDetachFromInterface(pNetFlt, true);
+ Assert(*pStatus == NDIS_STATUS_SUCCESS);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static VOID vboxNetFltWinPtUnloadProtocol()
+{
+ LogFlowFuncEnter();
+ NDIS_STATUS Status = vboxNetFltWinPtDeregister(&g_VBoxNetFltGlobalsWin.Pt);
+ Assert(Status == NDIS_STATUS_SUCCESS); NOREF(Status);
+ LogFlowFunc(("LEAVE: PtDeregister Status (0x%x)\n", Status));
+}
+
+
+static VOID vboxNetFltWinPtCloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)ProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+ Assert(pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ Assert(pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS);
+ if (pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+ {
+ pNetFlt->u.s.WinIf.OpenCloseStatus = Status;
+ }
+ NdisSetEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent);
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+}
+
+static VOID vboxNetFltWinPtResetComplete(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS Status)
+{
+ RT_NOREF2(hProtocolBindingContext, Status);
+ LogFlowFunc(("ENTER: pNetFlt 0x%p, Status 0x%x\n", hProtocolBindingContext, Status));
+ /*
+ * should never be here
+ */
+ AssertFailed();
+ LogFlowFunc(("LEAVE: pNetFlt 0x%p, Status 0x%x\n", hProtocolBindingContext, Status));
+}
+
+static NDIS_STATUS vboxNetFltWinPtHandleQueryInfoComplete(PVBOXNETFLTINS pNetFlt, NDIS_STATUS Status)
+{
+ PNDIS_REQUEST pRequest = &pNetFlt->u.s.WinIf.PassDownRequest;
+
+ switch (pRequest->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_PNP_CAPABILITIES:
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof (NDIS_PNP_CAPABILITIES))
+ {
+ PNDIS_PNP_CAPABILITIES pPnPCaps = (PNDIS_PNP_CAPABILITIES)(pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ PNDIS_PM_WAKE_UP_CAPABILITIES pPmWuCaps = &pPnPCaps->WakeUpCapabilities;
+ pPmWuCaps->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pPmWuCaps->MinPatternWakeUp = NdisDeviceStateUnspecified;
+ pPmWuCaps->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+ *pNetFlt->u.s.WinIf.pcPDRBytesRW = sizeof (NDIS_PNP_CAPABILITIES);
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = 0;
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof(NDIS_PNP_CAPABILITIES);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ break;
+ }
+
+ case OID_GEN_MAC_OPTIONS:
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ pNetFlt->u.s.WinIf.fMacOptions = *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ /* clearing this flag tells ndis we'll handle loopback ourselves
+ * the ndis layer or nic driver below us would loopback packets as necessary */
+ *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
+#else
+ /* we have to catch loopbacks from the underlying driver, so no duplications will occur,
+ * just indicate NDIS to handle loopbacks for the packets coming from the protocol */
+ *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer |= NDIS_MAC_OPTION_NO_LOOPBACK;
+#endif
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ break;
+ }
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ {
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ /* we're here _ONLY_ in the passthru mode */
+ Assert(pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter && !pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt);
+ if (pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter && !pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt)
+ {
+ Assert(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE);
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ /* the filter request is issued below only in case netflt is not active,
+ * simply update the cache here */
+ /* cache the filter used by upper protocols */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ Assert(pRequest->DATA.QUERY_INFORMATION.Oid != OID_PNP_QUERY_POWER);
+ break;
+ }
+
+ *pNetFlt->u.s.WinIf.pcPDRBytesRW = pRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = pRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinPtHandleSetInfoComplete(PVBOXNETFLTINS pNetFlt, NDIS_STATUS Status)
+{
+ PNDIS_REQUEST pRequest = &pNetFlt->u.s.WinIf.PassDownRequest;
+
+ switch (pRequest->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ {
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter)
+ {
+ if (pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt)
+ {
+ Assert(pNetFlt->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE);
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 0;
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.SET_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ pNetFlt->u.s.WinIf.fOurSetFilter = *((PULONG)pRequest->DATA.SET_INFORMATION.InformationBuffer);
+ Assert(pNetFlt->u.s.WinIf.fOurSetFilter == NDIS_PACKET_TYPE_PROMISCUOUS);
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else
+ {
+ Assert(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.SET_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ /* the request was issued when the netflt was not active, simply update the cache here */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *((PULONG)pRequest->DATA.SET_INFORMATION.InformationBuffer);
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 0;
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+#ifdef DEBUG_misha
+ else
+ {
+ AssertFailed();
+ }
+#endif
+ }
+ break;
+ }
+
+ default:
+ Assert(pRequest->DATA.SET_INFORMATION.Oid != OID_PNP_SET_POWER);
+ break;
+ }
+
+ *pNetFlt->u.s.WinIf.pcPDRBytesRW = pRequest->DATA.SET_INFORMATION.BytesRead;
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = pRequest->DATA.SET_INFORMATION.BytesNeeded;
+
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetFltWinPtRequestComplete(NDIS_HANDLE hContext, PNDIS_REQUEST pNdisRequest, NDIS_STATUS Status)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ PNDIS_REQUEST pSynchRequest = pNetFlt->u.s.WinIf.pSynchRequest;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
+
+ if (pSynchRequest == pNdisRequest)
+ {
+ /* asynchronous completion of our sync request */
+ /*1.set the status */
+ pNetFlt->u.s.WinIf.SynchCompletionStatus = Status;
+ /* 2. set event */
+ KeSetEvent(&pNetFlt->u.s.WinIf.hSynchCompletionEvent, 0, FALSE);
+ /* 3. return; */
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
+ return;
+ }
+
+ Assert(&pNetFlt->u.s.WinIf.PassDownRequest == pNdisRequest);
+ Assert(pNetFlt->u.s.WinIf.StateFlags.fRequestInfo == VBOXNDISREQUEST_INPROGRESS);
+ vboxNetFltWinMpRequestStateComplete(pNetFlt);
+
+ switch (pNdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+ Status = vboxNetFltWinPtHandleQueryInfoComplete(pNetFlt, Status);
+ NdisMQueryInformationComplete(pNetFlt->u.s.WinIf.hMiniport, Status);
+ break;
+
+ case NdisRequestSetInformation:
+ Status = vboxNetFltWinPtHandleSetInfoComplete(pNetFlt, Status);
+ NdisMSetInformationComplete(pNetFlt->u.s.WinIf.hMiniport, Status);
+ break;
+
+ default:
+ AssertFailed();
+ break;
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
+}
+
+static VOID vboxNetFltWinPtStatus(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID pvStatusBuffer, IN UINT cbStatusBuffer)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), GeneralStatus (0x%x)\n", pNetFlt, GeneralStatus));
+
+ if (vboxNetFltWinReferenceWinIf(pNetFlt))
+ {
+ Assert(pNetFlt->u.s.WinIf.hMiniport);
+
+ if (VBOXNETFLT_PT_STATUS_IS_FILTERED(GeneralStatus))
+ {
+ pNetFlt->u.s.WinIf.MpIndicatedMediaStatus = GeneralStatus;
+ }
+ NdisMIndicateStatus(pNetFlt->u.s.WinIf.hMiniport,
+ GeneralStatus,
+ pvStatusBuffer,
+ cbStatusBuffer);
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ else
+ {
+ if (pNetFlt->u.s.WinIf.hMiniport != NULL
+ && VBOXNETFLT_PT_STATUS_IS_FILTERED(GeneralStatus)
+ )
+ {
+ pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus = GeneralStatus;
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), GeneralStatus (0x%x)\n", pNetFlt, GeneralStatus));
+}
+
+
+static VOID vboxNetFltWinPtStatusComplete(IN NDIS_HANDLE hProtocolBindingContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (vboxNetFltWinReferenceWinIf(pNetFlt))
+ {
+ NdisMIndicateStatusComplete(pNetFlt->u.s.WinIf.hMiniport);
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static VOID vboxNetFltWinPtSendComplete(IN NDIS_HANDLE hProtocolBindingContext, IN PNDIS_PACKET pPacket, IN NDIS_STATUS Status)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ PVBOXNETFLT_PKTRSVD_PT pSendInfo = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ PNDIS_PACKET pOrigPacket = pSendInfo->pOrigPacket;
+ PVOID pBufToFree = pSendInfo->pBufToFree;
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x)\n", pNetFlt, pPacket, Status));
+
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ /** @todo for optimization we could check only for netflt-mode packets
+ * do it for all for now */
+ vboxNetFltWinLbRemoveSendPacket(pNetFlt, pPacket);
+#endif
+
+ if (pOrigPacket)
+ {
+ NdisIMCopySendCompletePerPacketInfo(pOrigPacket, pPacket);
+ NdisFreePacket(pPacket);
+ /* the ptk was posted from the upperlying protocol */
+ NdisMSendComplete(pNetFlt->u.s.WinIf.hMiniport, pOrigPacket, Status);
+ }
+ else
+ {
+ /* if the pOrigPacket is zero - the ptk was originated by netFlt send/receive
+ * need to free packet buffers */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, !pBufToFree);
+ }
+
+ if (pBufToFree)
+ {
+ vboxNetFltWinMemFree(pBufToFree);
+ }
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x)\n", pNetFlt, pPacket, Status));
+}
+
+/**
+ * removes searches for the packet in the list and removes it if found
+ * @return true if the packet was found and removed, false - otherwise
+ */
+static bool vboxNetFltWinRemovePacketFromList(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
+ return vboxNetFltWinInterlockedSearchListEntry(pList, &pTDR->ListEntry, true /* remove*/);
+}
+
+/**
+ * puts the packet to the tail of the list
+ */
+static void vboxNetFltWinPutPacketToList(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket, PNDIS_BUFFER pOrigBuffer)
+{
+ PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
+ pTDR->pOrigBuffer = pOrigBuffer;
+ vboxNetFltWinInterlockedPutTail(pList, &pTDR->ListEntry);
+}
+
+static bool vboxNetFltWinPtTransferDataCompleteActive(PVBOXNETFLTINS pNetFltIf, PNDIS_PACKET pPacket, NDIS_STATUS Status)
+{
+ PNDIS_BUFFER pBuffer;
+ PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR;
+
+ if (!vboxNetFltWinRemovePacketFromList(&pNetFltIf->u.s.WinIf.TransferDataList, pPacket))
+ return false;
+
+ pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
+ Assert(pTDR);
+ Assert(pTDR->pOrigBuffer);
+
+ do
+ {
+ NdisUnchainBufferAtFront(pPacket, &pBuffer);
+
+ Assert(pBuffer);
+
+ NdisFreeBuffer(pBuffer);
+
+ pBuffer = pTDR->pOrigBuffer;
+
+ NdisChainBufferAtBack(pPacket, pBuffer);
+
+ /* data transfer was initiated when the netFlt was active
+ * the netFlt is still retained by us
+ * 1. check if loopback
+ * 2. enqueue packet
+ * 3. release netFlt */
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ if (vboxNetFltWinIsLoopedBackPacket(pPacket))
+ {
+ /* should not be here */
+ AssertFailed();
+ }
+#else
+ PNDIS_PACKET pLb = vboxNetFltWinLbSearchLoopBack(pNetFltIf, pPacket, false);
+ if (pLb)
+ {
+#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
+ /* should not be here */
+ AssertFailed();
+#endif
+ if (!vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ /* the packet is not from int net, need to pass it up to the host */
+ NdisMIndicateReceivePacket(pNetFltIf->u.s.WinIf.hMiniport, &pPacket, 1);
+ /* dereference NetFlt, WinIf will be dereferenced on Packet return */
+ vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+ break;
+ }
+ }
+#endif
+ else
+ {
+ /* 2. enqueue */
+ /* use the same packet info to put the packet in the processing packet queue */
+ PVBOXNETFLT_PKTRSVD_MP pRecvInfo = (PVBOXNETFLT_PKTRSVD_MP)pPacket->MiniportReserved;
+
+ VBOXNETFLT_LBVERIFY(pNetFltIf, pPacket);
+
+ pRecvInfo->pOrigPacket = NULL;
+ pRecvInfo->pBufToFree = NULL;
+
+ NdisGetPacketFlags(pPacket) = 0;
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFltIf, pPacket, 0))
+ {
+ /* drop it */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ vboxNetFltWinDereferenceWinIf(pNetFltIf);
+ }
+ else
+ {
+ NdisMIndicateReceivePacket(pNetFltIf->u.s.WinIf.hMiniport, &pPacket, 1);
+ }
+ vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+ break;
+# else
+ Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, PACKET_MINE);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ AssertFailed();
+# endif
+ }
+ }
+ else
+ {
+ AssertFailed();
+ }
+ /* we are here because of error either in data transfer or in enqueueing the packet */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+ vboxNetFltWinDereferenceWinIf(pNetFltIf);
+ } while (0);
+
+ return true;
+}
+
+static VOID vboxNetFltWinPtTransferDataComplete(IN NDIS_HANDLE hProtocolBindingContext,
+ IN PNDIS_PACKET pPacket,
+ IN NDIS_STATUS Status,
+ IN UINT cbTransferred)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x), cbTransfered (%d)\n", pNetFlt, pPacket, Status, cbTransferred));
+ if (!vboxNetFltWinPtTransferDataCompleteActive(pNetFlt, pPacket, Status))
+ {
+ if (pNetFlt->u.s.WinIf.hMiniport)
+ {
+ NdisMTransferDataComplete(pNetFlt->u.s.WinIf.hMiniport,
+ pPacket,
+ Status,
+ cbTransferred);
+ }
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ /* else - all processing is done with vboxNetFltWinPtTransferDataCompleteActive already */
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x), cbTransfered (%d)\n", pNetFlt, pPacket, Status, cbTransferred));
+}
+
+static INT vboxNetFltWinRecvPacketPassThru(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket)
+{
+ Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ PNDIS_PACKET pMyPacket;
+ NDIS_STATUS Status = vboxNetFltWinPrepareRecvPacket(pNetFlt, pPacket, &pMyPacket, true);
+ /* the Status holds the current packet status it will be checked for NDIS_STATUS_RESOURCES later
+ * (see below) */
+ Assert(pMyPacket);
+ if (pMyPacket)
+ {
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+ if (Status == NDIS_STATUS_RESOURCES)
+ {
+ NdisDprFreePacket(pMyPacket);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * process the packet receive in a "passthru" mode
+ */
+static NDIS_STATUS vboxNetFltWinRecvPassThru(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket)
+{
+ Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NDIS_STATUS Status;
+ PNDIS_PACKET pMyPacket;
+
+ NdisDprAllocatePacket(&Status, &pMyPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ vboxNetFltWinCopyPacketInfoOnRecv(pMyPacket, pPacket, true /* force NDIS_STATUS_RESOURCES */);
+ Assert(NDIS_GET_PACKET_STATUS(pMyPacket) == NDIS_STATUS_RESOURCES);
+
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+
+ NdisDprFreePacket(pMyPacket);
+ }
+ return Status;
+}
+
+static VOID vboxNetFltWinRecvIndicatePassThru(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE MacReceiveContext,
+ PVOID pHeaderBuffer, UINT cbHeaderBuffer, PVOID pLookAheadBuffer, UINT cbLookAheadBuffer, UINT cbPacket)
+{
+ /* Note: we're using KeGetCurrentProcessorNumber, which is not entirely correct in case
+ * we're running on 64bit win7+, which can handle > 64 CPUs, however since KeGetCurrentProcessorNumber
+ * always returns the number < than the number of CPUs in the first group, we're guaranteed to have CPU index < 64
+ * @todo: use KeGetCurrentProcessorNumberEx for Win7+ 64 and dynamically extended array */
+ ULONG Proc = KeGetCurrentProcessorNumber();
+ Assert(Proc < RT_ELEMENTS(pNetFlt->u.s.WinIf.abIndicateRxComplete));
+ pNetFlt->u.s.WinIf.abIndicateRxComplete[Proc] = TRUE;
+ switch (pNetFlt->u.s.WinIf.enmMedium)
+ {
+ case NdisMedium802_3:
+ case NdisMediumWan:
+ NdisMEthIndicateReceive(pNetFlt->u.s.WinIf.hMiniport,
+ MacReceiveContext,
+ (PCHAR)pHeaderBuffer,
+ cbHeaderBuffer,
+ pLookAheadBuffer,
+ cbLookAheadBuffer,
+ cbPacket);
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+}
+
+/**
+ * process the ProtocolReceive in an "active" mode
+ *
+ * @return NDIS_STATUS_SUCCESS - the packet is processed
+ * NDIS_STATUS_PENDING - the packet is being processed, we are waiting for the ProtocolTransferDataComplete to be called
+ * NDIS_STATUS_NOT_ACCEPTED - the packet is not needed - typically this is because this is a loopback packet
+ * NDIS_STATUS_FAILURE - packet processing failed
+ */
+static NDIS_STATUS vboxNetFltWinPtReceiveActive(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE MacReceiveContext, PVOID pHeaderBuffer, UINT cbHeaderBuffer,
+ PVOID pLookaheadBuffer, UINT cbLookaheadBuffer, UINT cbPacket)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ if (cbHeaderBuffer != VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+
+#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
+ if (cbPacket == cbLookaheadBuffer)
+ {
+ PINTNETSG pSG;
+ PUCHAR pRcvData;
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ PNDIS_PACKET pLb;
+#endif
+
+ /* allocate SG buffer */
+ Status = vboxNetFltWinAllocSG(cbPacket + cbHeaderBuffer, &pSG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ break;
+ }
+
+ pRcvData = (PUCHAR)pSG->aSegs[0].pv;
+
+ NdisMoveMappedMemory(pRcvData, pHeaderBuffer, cbHeaderBuffer);
+
+ NdisCopyLookaheadData(pRcvData+cbHeaderBuffer,
+ pLookaheadBuffer,
+ cbLookaheadBuffer,
+ pNetFlt->u.s.WinIf.fMacOptions);
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ pLb = vboxNetFltWinLbSearchLoopBackBySG(pNetFlt, pSG, false);
+ if (pLb)
+ {
+#ifndef DEBUG_NETFLT_RECV_NOPACKET
+ /* should not be here */
+ AssertFailed();
+#endif
+ if (!vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ PNDIS_PACKET pMyPacket;
+ pMyPacket = vboxNetFltWinNdisPacketFromSG(pNetFlt, /* PVBOXNETFLTINS */
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ false, /* bool bToWire */
+ false); /* bool bCopyMemory */
+ if (pMyPacket)
+ {
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+ /* dereference the NetFlt here & indicate SUCCESS, which would mean the caller would not do a dereference
+ * the WinIf dereference will be done on packet return */
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ vboxNetFltWinMemFree(pSG);
+ Status = NDIS_STATUS_FAILURE;
+ }
+ }
+ else
+ {
+ vboxNetFltWinMemFree(pSG);
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ break;
+ }
+#endif
+ VBOXNETFLT_LBVERIFYSG(pNetFlt, pSG);
+
+ /* enqueue SG */
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFlt, pSG, VBOXNETFLT_PACKET_SG))
+ {
+ /* drop it */
+ vboxNetFltWinMemFree(pSG);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ else
+ {
+ PNDIS_PACKET pMyPacket = vboxNetFltWinNdisPacketFromSG(pNetFlt, /* PVBOXNETFLTINS */
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ false, /* bool bToWire */
+ false); /* bool bCopyMemory */
+ Assert(pMyPacket);
+ if (pMyPacket)
+ {
+ NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_SUCCESS);
+
+ DBG_CHECK_PACKET_AND_SG(pMyPacket, pSG);
+
+ LogFlow(("non-ndis packet info, packet created (%p)\n", pMyPacket));
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+ }
+ else
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+# else
+ Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, PACKET_SG | PACKET_MINE);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ vboxNetFltWinMemFree(pSG);
+ break;
+ }
+# endif
+#endif
+ }
+ else
+ {
+ PNDIS_PACKET pPacket;
+ PNDIS_BUFFER pTransferBuffer;
+ PNDIS_BUFFER pOrigBuffer;
+ PUCHAR pMemBuf;
+ UINT cbBuf = cbPacket + cbHeaderBuffer;
+ UINT cbTransferred;
+
+ /* allocate NDIS Packet buffer */
+ NdisAllocatePacket(&Status, &pPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ break;
+ }
+
+ VBOXNETFLT_OOB_INIT(pPacket);
+
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ /* set "don't loopback" flags */
+ NdisGetPacketFlags(pPacket) = g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#else
+ NdisGetPacketFlags(pPacket) = 0;
+#endif
+
+ Status = vboxNetFltWinMemAlloc((PVOID*)(&pMemBuf), cbBuf);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ NdisFreePacket(pPacket);
+ break;
+ }
+ NdisAllocateBuffer(&Status, &pTransferBuffer, pNetFlt->u.s.WinIf.hRecvBufferPool, pMemBuf + cbHeaderBuffer, cbPacket);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreePacket(pPacket);
+ vboxNetFltWinMemFree(pMemBuf);
+ break;
+ }
+
+ NdisAllocateBuffer(&Status, &pOrigBuffer, pNetFlt->u.s.WinIf.hRecvBufferPool, pMemBuf, cbBuf);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreeBuffer(pTransferBuffer);
+ NdisFreePacket(pPacket);
+ vboxNetFltWinMemFree(pMemBuf);
+ break;
+ }
+
+ NdisChainBufferAtBack(pPacket, pTransferBuffer);
+
+ NdisMoveMappedMemory(pMemBuf, pHeaderBuffer, cbHeaderBuffer);
+
+ vboxNetFltWinPutPacketToList(&pNetFlt->u.s.WinIf.TransferDataList, pPacket, pOrigBuffer);
+
+#ifdef DEBUG_NETFLT_RECV_TRANSFERDATA
+ if (cbPacket == cbLookaheadBuffer)
+ {
+ NdisCopyLookaheadData(pMemBuf+cbHeaderBuffer,
+ pLookaheadBuffer,
+ cbLookaheadBuffer,
+ pNetFlt->u.s.WinIf.fMacOptions);
+ }
+ else
+#endif
+ {
+ Assert(cbPacket > cbLookaheadBuffer);
+
+ NdisTransferData(&Status, pNetFlt->u.s.WinIf.hBinding, MacReceiveContext,
+ 0, /* ByteOffset */
+ cbPacket, pPacket, &cbTransferred);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ vboxNetFltWinPtTransferDataComplete(pNetFlt, pPacket, Status, cbTransferred);
+ }
+ }
+ } while (0);
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinPtReceive(IN NDIS_HANDLE hProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID pHeaderBuffer,
+ IN UINT cbHeaderBuffer,
+ IN PVOID pLookAheadBuffer,
+ IN UINT cbLookAheadBuffer,
+ IN UINT cbPacket)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ PNDIS_PACKET pPacket = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ bool bNetFltActive;
+ bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &bNetFltActive);
+ const bool bPassThruActive = !bNetFltActive;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (fWinIfActive)
+ {
+ do
+ {
+#ifndef DEBUG_NETFLT_RECV_NOPACKET
+ pPacket = NdisGetReceivedPacket(pNetFlt->u.s.WinIf.hBinding, MacReceiveContext);
+ if (pPacket)
+ {
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ PNDIS_PACKET pLb = NULL;
+# else
+ if (vboxNetFltWinIsLoopedBackPacket(pPacket))
+ {
+ AssertFailed();
+ /* nothing else to do here, just return the packet */
+ //NdisReturnPackets(&pPacket, 1);
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+# endif
+
+ if (bNetFltActive)
+ {
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ pLb = vboxNetFltWinLbSearchLoopBack(pNetFlt, pPacket, false);
+ if (!pLb)
+# endif
+ {
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFlt, pPacket, 0))
+ {
+ /* drop it */
+ break;
+ }
+# else
+ Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, PACKET_COPY);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //NdisReturnPackets(&pPacket, 1);
+ fWinIfActive = false;
+ bNetFltActive = false;
+ break;
+ }
+# endif
+ }
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ else if (vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ /* nothing else to do here, just return the packet */
+ //NdisReturnPackets(&pPacket, 1);
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+ /* we are here because this is a looped back packet set not from intnet
+ * we will post it to the upper protocol */
+# endif
+ }
+
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ Assert(!pLb || !vboxNetFltWinLbIsFromIntNet(pLb));
+# endif
+ Status = vboxNetFltWinRecvPassThru(pNetFlt, pPacket);
+ Assert(Status == STATUS_SUCCESS);
+ /* we are done with packet processing, and we will
+ * not receive packet return event for this packet,
+ * fWinIfActive should be true to ensure we release WinIf*/
+ Assert(fWinIfActive);
+ if (Status == STATUS_SUCCESS)
+ break;
+ }
+ else
+ {
+ /* intnet processing failed - fall back to no-packet mode */
+ Assert(bNetFltActive);
+ Assert(fWinIfActive);
+ }
+
+ }
+#endif /* #ifndef DEBUG_NETFLT_RECV_NOPACKET */
+
+ if (bNetFltActive)
+ {
+ Status = vboxNetFltWinPtReceiveActive(pNetFlt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
+ pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
+ if (NT_SUCCESS(Status))
+ {
+ if (Status != NDIS_STATUS_NOT_ACCEPTED)
+ {
+ fWinIfActive = false;
+ bNetFltActive = false;
+ }
+ else
+ {
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ /* this is a loopback packet, nothing to do here */
+#else
+ AssertFailed();
+ /* should not be here */
+#endif
+ }
+ break;
+ }
+ }
+
+ /* we are done with packet processing, and we will
+ * not receive packet return event for this packet,
+ * fWinIfActive should be true to ensure we release WinIf*/
+ Assert(fWinIfActive);
+
+ vboxNetFltWinRecvIndicatePassThru(pNetFlt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer, pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
+ /* the status could contain an error value here in case the IntNet recv failed,
+ * ensure we return back success status */
+ Status = NDIS_STATUS_SUCCESS;
+
+ } while (0);
+
+ if (bNetFltActive)
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else if (bPassThruActive)
+ {
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+ if (fWinIfActive)
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+
+ return Status;
+
+}
+
+static VOID vboxNetFltWinPtReceiveComplete(NDIS_HANDLE hProtocolBindingContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ bool fNetFltActive;
+ bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &fNetFltActive);
+ NDIS_HANDLE hMiniport = pNetFlt->u.s.WinIf.hMiniport;
+ /* Note: we're using KeGetCurrentProcessorNumber, which is not entirely correct in case
+ * we're running on 64bit win7+, which can handle > 64 CPUs, however since KeGetCurrentProcessorNumber
+ * always returns the number < than the number of CPUs in the first group, we're guaranteed to have CPU index < 64
+ * @todo: use KeGetCurrentProcessorNumberEx for Win7+ 64 and dynamically extended array */
+ ULONG iProc = KeGetCurrentProcessorNumber();
+ Assert(iProc < RT_ELEMENTS(pNetFlt->u.s.WinIf.abIndicateRxComplete));
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (hMiniport != NULL && pNetFlt->u.s.WinIf.abIndicateRxComplete[iProc])
+ {
+ switch (pNetFlt->u.s.WinIf.enmMedium)
+ {
+ case NdisMedium802_3:
+ case NdisMediumWan:
+ NdisMEthIndicateReceiveComplete(hMiniport);
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+ }
+
+ pNetFlt->u.s.WinIf.abIndicateRxComplete[iProc] = FALSE;
+
+ if (fWinIfActive)
+ {
+ if (fNetFltActive)
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ else
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static INT vboxNetFltWinPtReceivePacket(NDIS_HANDLE hProtocolBindingContext, PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ INT cRefCount = 0;
+ bool bNetFltActive;
+ bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &bNetFltActive);
+ const bool bPassThruActive = !bNetFltActive;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (fWinIfActive)
+ {
+ do
+ {
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ if (vboxNetFltWinIsLoopedBackPacket(pPacket))
+ {
+ AssertFailed();
+ Log(("lb_rp"));
+
+ /* nothing else to do here, just return the packet */
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ break;
+ }
+
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+#endif
+
+ if (bNetFltActive)
+ {
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ PNDIS_PACKET pLb = vboxNetFltWinLbSearchLoopBack(pNetFlt, pPacket, false);
+ if (!pLb)
+#endif
+ {
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ NDIS_STATUS fStatus;
+#endif
+ bool fResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES; NOREF(fResources);
+
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+#ifdef DEBUG_misha
+ /** @todo remove this assert.
+ * this is a temporary assert for debugging purposes:
+ * we're probably doing something wrong with the packets if the miniport reports NDIS_STATUS_RESOURCES */
+ Assert(!fResources);
+#endif
+
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFlt, pPacket, 0))
+ {
+ /* drop it */
+ cRefCount = 0;
+ break;
+ }
+
+#else
+ fStatus = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, fResources ? PACKET_COPY : 0);
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ bNetFltActive = false;
+ fWinIfActive = false;
+ if (fResources)
+ {
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ }
+ else
+ cRefCount = 1;
+ break;
+ }
+ else
+ {
+ AssertFailed();
+ }
+#endif
+ }
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ else if (vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ /* the packet is from intnet, it has already been set to the host,
+ * no need for loopng it back to the host again */
+ /* nothing else to do here, just return the packet */
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ break;
+ }
+#endif
+ }
+
+ cRefCount = vboxNetFltWinRecvPacketPassThru(pNetFlt, pPacket);
+ if (cRefCount)
+ {
+ Assert(cRefCount == 1);
+ fWinIfActive = false;
+ }
+
+ } while (FALSE);
+
+ if (bNetFltActive)
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else if (bPassThruActive)
+ {
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+ if (fWinIfActive)
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ }
+ else
+ {
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), cRefCount (%d)\n", pNetFlt, cRefCount));
+
+ return cRefCount;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinPtCloseInterface(PVBOXNETFLTINS pNetFlt, PNDIS_STATUS pStatus)
+{
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+
+ if (pNetFlt->u.s.WinIf.StateFlags.fInterfaceClosing)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ AssertFailed();
+ return false;
+ }
+ if (pNetFlt->u.s.WinIf.hBinding == NULL)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ AssertFailed();
+ return false;
+ }
+
+ pNetFlt->u.s.WinIf.StateFlags.fInterfaceClosing = TRUE;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ NdisResetEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent);
+ NdisCloseAdapter(pStatus, pNetFlt->u.s.WinIf.hBinding);
+ if (*pStatus == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent, 0);
+ *pStatus = pNetFlt->u.s.WinIf.OpenCloseStatus;
+ }
+
+ Assert (*pStatus == NDIS_STATUS_SUCCESS);
+
+ pNetFlt->u.s.WinIf.hBinding = NULL;
+
+ return true;
+}
+
+static NDIS_STATUS vboxNetFltWinPtPnPSetPower(PVBOXNETFLTINS pNetFlt, NDIS_DEVICE_POWER_STATE enmPowerState)
+{
+ NDIS_DEVICE_POWER_STATE enmPrevPowerState = vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState);
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.PtState, enmPowerState);
+
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState) > NdisDeviceStateD0)
+ {
+ if (enmPrevPowerState == NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = TRUE;
+ }
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ vboxNetFltWinPtRequestsWaitComplete(pNetFlt);
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.MpState);
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.PtState);
+
+ /* check packet pool is empty */
+ UINT cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hSendPacketPool);
+ Assert(cPPUsage == 0);
+ cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(cPPUsage == 0);
+ /* for debugging only, ignore the err in release */
+ NOREF(cPPUsage);
+
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fRequestInfo);
+ }
+ else
+ {
+ if (enmPrevPowerState > NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = FALSE;
+ }
+
+ if (pNetFlt->u.s.WinIf.StateFlags.fRequestInfo & VBOXNDISREQUEST_QUEUED)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ vboxNetFltWinMpRequestPost(pNetFlt);
+ }
+ else
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ }
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+static NDIS_STATUS vboxNetFltWinPtPnPEvent(IN NDIS_HANDLE hProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), NetEvent (%d)\n", pNetFlt, pNetPnPEvent->NetEvent));
+
+ switch (pNetPnPEvent->NetEvent)
+ {
+ case NetEventSetPower:
+ {
+ NDIS_DEVICE_POWER_STATE enmPowerState = *((PNDIS_DEVICE_POWER_STATE)pNetPnPEvent->Buffer);
+ NDIS_STATUS rcNdis = vboxNetFltWinPtPnPSetPower(pNetFlt, enmPowerState);
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), NetEvent (%d), rcNdis=%#x\n", pNetFlt, pNetPnPEvent->NetEvent, rcNdis));
+ return rcNdis;
+ }
+
+ case NetEventReconfigure:
+ {
+ if (!pNetFlt)
+ {
+ NdisReEnumerateProtocolBindings(g_VBoxNetFltGlobalsWin.Pt.hProtocol);
+ }
+ }
+ /** @todo r=bird: Is the fall thru intentional?? */
+ default:
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), NetEvent (%d)\n", pNetFlt, pNetPnPEvent->NetEvent));
+ return NDIS_STATUS_SUCCESS;
+ }
+
+}
+
+#ifdef __cplusplus
+# define PTCHARS_40(_p) ((_p).Ndis40Chars)
+#else
+# define PTCHARS_40(_p) (_p)
+#endif
+
+/**
+ * register the protocol edge
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtRegister(PVBOXNETFLTGLOBALS_PT pGlobalsPt, PDRIVER_OBJECT pDriverObject,
+ PUNICODE_STRING pRegistryPathStr)
+{
+ RT_NOREF2(pDriverObject, pRegistryPathStr);
+ NDIS_PROTOCOL_CHARACTERISTICS PtChars;
+ NDIS_STRING NameStr;
+
+ NdisInitUnicodeString(&NameStr, VBOXNETFLT_NAME_PROTOCOL);
+
+ NdisZeroMemory(&PtChars, sizeof (PtChars));
+ PTCHARS_40(PtChars).MajorNdisVersion = VBOXNETFLT_VERSION_PT_NDIS_MAJOR;
+ PTCHARS_40(PtChars).MinorNdisVersion = VBOXNETFLT_VERSION_PT_NDIS_MINOR;
+
+ PTCHARS_40(PtChars).Name = NameStr;
+ PTCHARS_40(PtChars).OpenAdapterCompleteHandler = vboxNetFltWinPtOpenAdapterComplete;
+ PTCHARS_40(PtChars).CloseAdapterCompleteHandler = vboxNetFltWinPtCloseAdapterComplete;
+ PTCHARS_40(PtChars).SendCompleteHandler = vboxNetFltWinPtSendComplete;
+ PTCHARS_40(PtChars).TransferDataCompleteHandler = vboxNetFltWinPtTransferDataComplete;
+ PTCHARS_40(PtChars).ResetCompleteHandler = vboxNetFltWinPtResetComplete;
+ PTCHARS_40(PtChars).RequestCompleteHandler = vboxNetFltWinPtRequestComplete;
+ PTCHARS_40(PtChars).ReceiveHandler = vboxNetFltWinPtReceive;
+ PTCHARS_40(PtChars).ReceiveCompleteHandler = vboxNetFltWinPtReceiveComplete;
+ PTCHARS_40(PtChars).StatusHandler = vboxNetFltWinPtStatus;
+ PTCHARS_40(PtChars).StatusCompleteHandler = vboxNetFltWinPtStatusComplete;
+ PTCHARS_40(PtChars).BindAdapterHandler = vboxNetFltWinPtBindAdapter;
+ PTCHARS_40(PtChars).UnbindAdapterHandler = vboxNetFltWinPtUnbindAdapter;
+ PTCHARS_40(PtChars).UnloadHandler = vboxNetFltWinPtUnloadProtocol;
+#if !defined(DEBUG_NETFLT_RECV)
+ PTCHARS_40(PtChars).ReceivePacketHandler = vboxNetFltWinPtReceivePacket;
+#endif
+ PTCHARS_40(PtChars).PnPEventHandler = vboxNetFltWinPtPnPEvent;
+
+ NDIS_STATUS Status;
+ NdisRegisterProtocol(&Status, &pGlobalsPt->hProtocol, &PtChars, sizeof (PtChars));
+ Assert(Status == STATUS_SUCCESS);
+ return Status;
+}
+
+/**
+ * deregister the protocol edge
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDeregister(PVBOXNETFLTGLOBALS_PT pGlobalsPt)
+{
+ if (!pGlobalsPt->hProtocol)
+ return NDIS_STATUS_SUCCESS;
+
+ NDIS_STATUS Status;
+
+ NdisDeregisterProtocol(&Status, pGlobalsPt->hProtocol);
+ Assert (Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisZeroMemory(pGlobalsPt, sizeof (*pGlobalsPt));
+ }
+ return Status;
+}