summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetFlt/win
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
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')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/cfg/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp3770
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf95
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc77
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt.inf117
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h533
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp1570
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h67
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf82
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp1595
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h52
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp3650
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h972
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp2736
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h55
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf120
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp747
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.def42
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.h96
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rc78
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rgs13
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjRc.h46
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjT.idl55
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/tools/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpInstall.cpp341
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpUninstall.cpp107
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltInstall.cpp201
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltUninstall.cpp133
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfInstall.cpp186
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfUninstall.cpp130
33 files changed, 17666 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/win/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp
new file mode 100644
index 00000000..a686196f
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp
@@ -0,0 +1,3770 @@
+/* $Id: VBoxNetCfg.cpp $ */
+/** @file
+ * VBoxNetCfg.cpp - Network Configuration API.
+ */
+
+/*
+ * 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 *
+*********************************************************************************************************************************/
+#define _WIN32_DCOM
+
+#include "VBox/VBoxNetCfg-win.h"
+#include "VBox/VBoxDrvCfg-win.h"
+
+#include <devguid.h>
+#include <regstr.h>
+#include <iprt/win/shlobj.h>
+#include <cfgmgr32.h>
+#include <iprt/win/objbase.h>
+
+#include <Wbemidl.h>
+
+#include <iprt/win/winsock2.h>
+#include <iprt/win/ws2tcpip.h>
+#include <ws2ipdef.h>
+#include <iprt/win/netioapi.h>
+#include <iprt/win/iphlpapi.h>
+
+#include <iprt/asm.h>
+#include <iprt/assertcompile.h>
+#include <iprt/mem.h>
+#include <iprt/list.h>
+#include <iprt/rand.h>
+#include <iprt/string.h>
+#include <iprt/utf16.h>
+#include <VBox/com/string.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifndef Assert /** @todo r=bird: where would this be defined? */
+//# ifdef DEBUG
+//# define Assert(_expr) assert(_expr)
+//# else
+//# define Assert(_expr) do{ }while (0)
+//# endif
+# define Assert _ASSERT
+# define AssertMsg(expr, msg) do{}while (0)
+#endif
+
+#define NonStandardLog DoLogging
+#define NonStandardLogFlow(x) DoLogging x
+
+#define SetErrBreak(strAndArgs) \
+ if (1) { \
+ hrc = E_FAIL; \
+ NonStandardLog strAndArgs; \
+ bstrError.printfNoThrow strAndArgs; \
+ break; \
+ } else do {} while (0)
+
+
+#define VBOXNETCFGWIN_NETADP_ID_SZ "sun_VBoxNetAdp"
+#define VBOXNETCFGWIN_NETADP_ID_WSZ RT_CONCAT(L,VBOXNETCFGWIN_NETADP_ID_SZ)
+#define DRIVERHWID VBOXNETCFGWIN_NETADP_ID_WSZ
+
+/* We assume the following name matches the device description in vboxnetadp6.inf */
+#define HOSTONLY_ADAPTER_NAME_SZ "VirtualBox Host-Only Ethernet Adapter"
+#define HOSTONLY_ADAPTER_NAME_WSZ RT_CONCAT(L,HOSTONLY_ADAPTER_NAME_SZ)
+
+#define VBOX_CONNECTION_NAME_SZ "VirtualBox Host-Only Network"
+#define VBOX_CONNECTION_NAME_WSZ RT_CONCAT(L,VBOX_CONNECTION_NAME_SZ)
+
+#define VBOXNETCFGWIN_NETLWF_ID L"oracle_VBoxNetLwf"
+
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static PFNVBOXNETCFGLOGGER volatile g_pfnLogger = NULL;
+
+/*
+ * Wrappers for HelpAPI functions
+ */
+typedef void FNINITIALIZEIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
+typedef FNINITIALIZEIPINTERFACEENTRY *PFNINITIALIZEIPINTERFACEENTRY;
+
+typedef NETIOAPI_API FNGETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
+typedef FNGETIPINTERFACEENTRY *PFNGETIPINTERFACEENTRY;
+
+typedef NETIOAPI_API FNSETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
+typedef FNSETIPINTERFACEENTRY *PFNSETIPINTERFACEENTRY;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static PFNINITIALIZEIPINTERFACEENTRY g_pfnInitializeIpInterfaceEntry = NULL;
+static PFNGETIPINTERFACEENTRY g_pfnGetIpInterfaceEntry = NULL;
+static PFNSETIPINTERFACEENTRY g_pfnSetIpInterfaceEntry = NULL;
+
+static void DoLogging(const char *pszString, ...);
+
+/*
+ * Forward declaration for using vboxNetCfgWinSetupMetric()
+ */
+static HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID *pLuid);
+static HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID *pLUID);
+
+
+
+static HRESULT vboxNetCfgWinINetCfgLock(IN INetCfg *pNetCfg,
+ IN LPCWSTR pszwClientDescription,
+ IN DWORD cmsTimeout,
+ OUT LPWSTR *ppszwClientDescription)
+{
+ INetCfgLock *pLock;
+ HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID *)&pLock);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("QueryInterface failed: %Rhrc\n", hr));
+ return hr;
+ }
+
+ hr = pLock->AcquireWriteLock(cmsTimeout, pszwClientDescription, ppszwClientDescription);
+ if (hr == S_FALSE)
+ NonStandardLogFlow(("Write lock busy\n"));
+ else if (FAILED(hr))
+ NonStandardLogFlow(("AcquireWriteLock failed: %Rhrc\n", hr));
+
+ pLock->Release();
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinINetCfgUnlock(IN INetCfg *pNetCfg)
+{
+ INetCfgLock *pLock;
+ HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID *)&pLock);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("QueryInterface failed: %Rhrc\n", hr));
+ return hr;
+ }
+
+ hr = pLock->ReleaseWriteLock();
+ if (FAILED(hr))
+ NonStandardLogFlow(("ReleaseWriteLock failed: %Rhrc\n", hr));
+
+ pLock->Release();
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(OUT INetCfg **ppNetCfg,
+ IN BOOL fGetWriteLock,
+ IN LPCWSTR pszwClientDescription,
+ IN DWORD cmsTimeout,
+ OUT LPWSTR *ppszwClientDescription)
+{
+ INetCfg *pNetCfg = NULL;
+ HRESULT hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (PVOID *)&pNetCfg);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("CoCreateInstance failed: %Rhrc\n", hr));
+ return hr;
+ }
+
+ if (fGetWriteLock)
+ {
+ hr = vboxNetCfgWinINetCfgLock(pNetCfg, pszwClientDescription, cmsTimeout, ppszwClientDescription);
+ if (hr == S_FALSE)
+ {
+ NonStandardLogFlow(("Write lock is busy\n", hr));
+ hr = NETCFG_E_NO_WRITE_LOCK;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pNetCfg->Initialize(NULL);
+ if (SUCCEEDED(hr))
+ {
+ *ppNetCfg = pNetCfg;
+ return S_OK;
+ }
+ NonStandardLogFlow(("Initialize failed: %Rhrc\n", hr));
+ }
+
+ pNetCfg->Release();
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pNetCfg, IN BOOL fHasWriteLock)
+{
+ if (!pNetCfg) /* If network config has been released already, just bail out. */
+ {
+ NonStandardLogFlow(("Warning: No network config given but write lock is set to TRUE\n"));
+ return S_OK;
+ }
+
+ HRESULT hr = pNetCfg->Uninitialize();
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("Uninitialize failed: %Rhrc\n", hr));
+ /* Try to release the write lock below. */
+ }
+
+ if (fHasWriteLock)
+ {
+ HRESULT hr2 = vboxNetCfgWinINetCfgUnlock(pNetCfg);
+ if (FAILED(hr2))
+ NonStandardLogFlow(("vboxNetCfgWinINetCfgUnlock failed: %Rhrc\n", hr2));
+ if (SUCCEEDED(hr))
+ hr = hr2;
+ }
+
+ pNetCfg->Release();
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinGetComponentByGuidEnum(IEnumNetCfgComponent *pEnumNcc,
+ IN const GUID *pGuid,
+ OUT INetCfgComponent **ppNcc)
+{
+ HRESULT hr = pEnumNcc->Reset();
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("Reset failed: %Rhrc\n", hr));
+ return hr;
+ }
+
+ INetCfgComponent *pNcc = NULL;
+ while ((hr = pEnumNcc->Next(1, &pNcc, NULL)) == S_OK)
+ {
+ ULONG uComponentStatus = 0;
+ hr = pNcc->GetDeviceStatus(&uComponentStatus);
+ if (SUCCEEDED(hr))
+ {
+ if (uComponentStatus == 0)
+ {
+ GUID NccGuid;
+ hr = pNcc->GetInstanceGuid(&NccGuid);
+
+ if (SUCCEEDED(hr))
+ {
+ if (NccGuid == *pGuid)
+ {
+ /* found the needed device */
+ *ppNcc = pNcc;
+ break;
+ }
+ }
+ else
+ NonStandardLogFlow(("GetInstanceGuid failed: %Rhrc\n", hr));
+ }
+ }
+
+ pNcc->Release();
+ }
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc,
+ IN const GUID *pguidClass,
+ IN const GUID * pComponentGuid,
+ OUT INetCfgComponent **ppncc)
+{
+ IEnumNetCfgComponent *pEnumNcc = NULL;
+ HRESULT hr = pNc->EnumComponents(pguidClass, &pEnumNcc);
+ if (SUCCEEDED(hr))
+ {
+ hr = vboxNetCfgWinGetComponentByGuidEnum(pEnumNcc, pComponentGuid, ppncc);
+ if (hr == S_FALSE)
+ NonStandardLogFlow(("Component not found\n"));
+ else if (FAILED(hr))
+ NonStandardLogFlow(("vboxNetCfgWinGetComponentByGuidEnum failed: %Rhrc\n", hr));
+ pEnumNcc->Release();
+ }
+ else
+ NonStandardLogFlow(("EnumComponents failed: %Rhrc\n", hr));
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinQueryInstaller(IN INetCfg *pNetCfg, IN const GUID *pguidClass, INetCfgClassSetup **ppSetup)
+{
+ HRESULT hr = pNetCfg->QueryNetCfgClass(pguidClass, IID_INetCfgClassSetup, (void **)ppSetup);
+ if (FAILED(hr))
+ NonStandardLogFlow(("QueryNetCfgClass failed: %Rhrc\n", hr));
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId,
+ IN const GUID *pguidClass, OUT INetCfgComponent **ppComponent)
+{
+ INetCfgClassSetup *pSetup;
+ HRESULT hr = vboxNetCfgWinQueryInstaller(pNetCfg, pguidClass, &pSetup);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed: %Rhrc\n", hr));
+ return hr;
+ }
+
+ OBO_TOKEN Token;
+ RT_ZERO(Token);
+ Token.Type = OBO_USER;
+
+ INetCfgComponent *pTempComponent = NULL;
+ hr = pSetup->Install(pszwComponentId, &Token,
+ 0, /* IN DWORD dwSetupFlags */
+ 0, /* IN DWORD dwUpgradeFromBuildNo */
+ NULL, /* IN LPCWSTR pszwAnswerFile */
+ NULL, /* IN LPCWSTR pszwAnswerSections */
+ &pTempComponent);
+ if (SUCCEEDED(hr))
+ {
+ if (pTempComponent != NULL)
+ {
+ /*
+ * Set default metric value of interface to fix multicast issue
+ * See @bugref{6379} for details.
+ */
+ HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
+ HRESULT hrc2 = pTempComponent->OpenParamKey(&hKey);
+
+ /* Set default metric value for host-only interface only */
+ if ( SUCCEEDED(hrc2)
+ && hKey != (HKEY)INVALID_HANDLE_VALUE
+ /* Original was weird: && wcsnicmp(pszwComponentId, VBOXNETCFGWIN_NETADP_ID_WSZ, 256) == 0) */
+ && RTUtf16ICmpAscii(pszwComponentId, VBOXNETCFGWIN_NETADP_ID_SZ) == 0)
+ {
+ NET_LUID luid;
+ hrc2 = vboxNetCfgWinGetInterfaceLUID(hKey, &luid);
+
+ /* Close the key as soon as possible. See @bugref{7973}. */
+ RegCloseKey(hKey);
+ hKey = (HKEY)INVALID_HANDLE_VALUE;
+
+ if (FAILED(hrc2))
+ {
+ /*
+ * The setting of Metric is not very important functionality,
+ * So we will not break installation process due to this error.
+ */
+ NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! vboxNetCfgWinGetInterfaceLUID failed, default metric for new interface will not be set: %Rhrc\n", hrc2));
+ }
+ else
+ {
+ hrc2 = vboxNetCfgWinSetupMetric(&luid);
+ if (FAILED(hrc2))
+ {
+ /*
+ * The setting of Metric is not very important functionality,
+ * So we will not break installation process due to this error.
+ */
+ NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! vboxNetCfgWinSetupMetric failed, default metric for new interface will not be set: %Rhrc\n", hrc2));
+ }
+ }
+ }
+ if (hKey != (HKEY)INVALID_HANDLE_VALUE)
+ RegCloseKey(hKey);
+ if (ppComponent != NULL)
+ *ppComponent = pTempComponent;
+ else
+ pTempComponent->Release();
+ }
+
+ /* ignore the apply failure */
+ HRESULT hrc3 = pNetCfg->Apply();
+ Assert(hrc3 == S_OK);
+ if (hrc3 != S_OK)
+ NonStandardLogFlow(("Apply failed: %Rhrc\n", hrc3));
+ }
+ else
+ NonStandardLogFlow(("Install failed: %Rhrc\n", hr));
+
+ pSetup->Release();
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinInstallInfAndComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
+ IN LPCWSTR const *apwszInfPaths, IN UINT cInfPaths,
+ OUT INetCfgComponent **ppComponent)
+{
+ NonStandardLogFlow(("Installing %u INF files ...\n", cInfPaths));
+
+ HRESULT hr = S_OK;
+ UINT cFilesProcessed = 0;
+ for (; cFilesProcessed < cInfPaths; cFilesProcessed++)
+ {
+ NonStandardLogFlow(("Installing INF file \"%ls\" ...\n", apwszInfPaths[cFilesProcessed]));
+ hr = VBoxDrvCfgInfInstall(apwszInfPaths[cFilesProcessed]);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("VBoxNetCfgWinInfInstall failed: %Rhrc\n", hr));
+ break;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = VBoxNetCfgWinInstallComponent(pNetCfg, pszwComponentId, pguidClass, ppComponent);
+ if (FAILED(hr))
+ NonStandardLogFlow(("VBoxNetCfgWinInstallComponent failed: %Rhrc\n", hr));
+ }
+
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("Installation failed, rolling back installation set ...\n"));
+
+ do
+ {
+ HRESULT hr2 = VBoxDrvCfgInfUninstall(apwszInfPaths[cFilesProcessed], 0);
+ if (FAILED(hr2))
+ NonStandardLogFlow(("VBoxDrvCfgInfUninstall failed: %Rhrc\n", hr2));
+ /* Keep going. */
+ if (!cFilesProcessed)
+ break;
+ } while (cFilesProcessed--);
+
+ NonStandardLogFlow(("Rollback complete\n"));
+ }
+
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUninstallComponent(IN INetCfg *pNetCfg, IN INetCfgComponent *pComponent)
+{
+ GUID GuidClass;
+ HRESULT hr = pComponent->GetClassGuid(&GuidClass);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("GetClassGuid failed: %Rhrc\n", hr));
+ return hr;
+ }
+
+ INetCfgClassSetup *pSetup = NULL;
+ hr = vboxNetCfgWinQueryInstaller(pNetCfg, &GuidClass, &pSetup);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed: %Rhrc\n", hr));
+ return hr;
+ }
+
+ OBO_TOKEN Token;
+ RT_ZERO(Token);
+ Token.Type = OBO_USER;
+
+ hr = pSetup->DeInstall(pComponent, &Token, NULL /* OUT LPWSTR *pmszwRefs */);
+ if (SUCCEEDED(hr))
+ {
+ hr = pNetCfg->Apply();
+ if (FAILED(hr))
+ NonStandardLogFlow(("Apply failed: %Rhrc\n", hr));
+ }
+ else
+ NonStandardLogFlow(("DeInstall failed: %Rhrc\n", hr));
+
+ if (pSetup)
+ pSetup->Release();
+ return hr;
+}
+
+typedef BOOL (*PFN_VBOXNETCFGWIN_NETCFGENUM_CALLBACK_T)(IN INetCfg *pNetCfg, IN INetCfgComponent *pNetCfgComponent,
+ PVOID pvContext);
+
+static HRESULT vboxNetCfgWinEnumNetCfgComponents(IN INetCfg *pNetCfg,
+ IN const GUID *pguidClass,
+ PFN_VBOXNETCFGWIN_NETCFGENUM_CALLBACK_T pfnCallback,
+ PVOID pContext)
+{
+ IEnumNetCfgComponent *pEnumComponent = NULL;
+ HRESULT hr = pNetCfg->EnumComponents(pguidClass, &pEnumComponent);
+ if (SUCCEEDED(hr))
+ {
+ INetCfgComponent *pNetCfgComponent;
+ hr = pEnumComponent->Reset();
+ for (;;)
+ {
+ hr = pEnumComponent->Next(1, &pNetCfgComponent, NULL);
+ if (hr == S_OK)
+ {
+// ULONG uComponentStatus;
+// hr = pNcc->GetDeviceStatus(&uComponentStatus);
+// if (SUCCEEDED(hr))
+ BOOL fResult = FALSE;
+ if (pNetCfgComponent)
+ {
+ fResult = pfnCallback(pNetCfg, pNetCfgComponent, pContext);
+ pNetCfgComponent->Release();
+ }
+
+ if (!fResult)
+ break;
+ }
+ else
+ {
+ if (hr == S_FALSE)
+ hr = S_OK; /* no more components */
+ else
+ NonStandardLogFlow(("Next failed: %Rhrc\n", hr));
+ break;
+ }
+ }
+ pEnumComponent->Release();
+ }
+ return hr;
+}
+
+/** PFNVBOXNETCFGWINNETENUMCALLBACK */
+static BOOL vboxNetCfgWinRemoveAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pvContext)
+{
+ RT_NOREF1(pvContext);
+
+ SP_REMOVEDEVICE_PARAMS rmdParams;
+ RT_ZERO(rmdParams);
+ rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+ rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
+ rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
+
+ if (SetupDiSetClassInstallParams(hDevInfo,pDev,
+ &rmdParams.ClassInstallHeader, sizeof(rmdParams)))
+ {
+ if (SetupDiSetSelectedDevice(hDevInfo, pDev))
+ {
+#ifndef VBOXNETCFG_DELAYEDRENAME
+ /* Figure out NetCfgInstanceId. */
+ HKEY hKey = SetupDiOpenDevRegKey(hDevInfo,
+ pDev,
+ DICS_FLAG_GLOBAL,
+ 0,
+ DIREG_DRV,
+ KEY_READ);
+ if (hKey == INVALID_HANDLE_VALUE)
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiOpenDevRegKey failed with error %u\n",
+ GetLastError()));
+ else
+ {
+ WCHAR wszCfgGuidString[50] = { L'' };
+ DWORD cbSize = sizeof(wszCfgGuidString) - sizeof(WCHAR); /* make sure we get a terminated string back */
+ DWORD dwValueType = 0;
+ LSTATUS lrc = RegQueryValueExW(hKey, L"NetCfgInstanceId", NULL, &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
+ if (lrc == ERROR_SUCCESS)
+ {
+ /** @todo r=bird: original didn't check the type here, just assumed it was a
+ * valid zero terminated string. (zero term handled by -sizeof(WHCAR) above now). */
+ if (dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ || dwValueType == REG_EXPAND_SZ)
+ {
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Processing device ID \"%ls\"\n",
+ wszCfgGuidString));
+
+ /* Figure out device name. */
+ WCHAR wszDevName[256 + 1] = {0};
+ if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev, SPDRP_FRIENDLYNAME, NULL, (PBYTE)wszDevName,
+ sizeof(wszDevName) - sizeof(WCHAR) /* yes, in bytes */, NULL))
+ {
+ /*
+ * Rename the connection before removing the device. This will
+ * hopefully prevent an error when we will be attempting
+ * to rename a newly created connection (see @bugref{6740}).
+ */
+ WCHAR wszNewName[RT_ELEMENTS(wszDevName) + 128 /* ensure sufficient buffer */];
+ HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszNewName,
+ RT_ELEMENTS(wszNewName) - 10 /*removed++*/,
+ NULL);
+ RTUtf16CatAscii(wszNewName, sizeof(wszNewName), " removed");
+ if (SUCCEEDED(hr))
+ hr = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszNewName);
+ //NonStandardLogFlow(("VBoxNetCfgWinRenameConnection(%S,%S) => 0x%x\n", wszCfgGuidString, TempName, hr_tmp));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Failed to get friendly name for device \"%ls\"\n",
+ wszCfgGuidString));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Friendly name for \"%S\" isn't a string: %d\n",
+ wszCfgGuidString, dwValueType
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Querying instance ID failed with %u (%#x)\n",
+ lrc, lrc));
+
+ RegCloseKey(hKey);
+ }
+#endif /* VBOXNETCFG_DELAYEDRENAME */
+
+ if (SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, pDev))
+ {
+ SP_DEVINSTALL_PARAMS_W DevParams = { sizeof(DevParams) };
+ if (SetupDiGetDeviceInstallParams(hDevInfo, pDev, &DevParams))
+ {
+ if ( (DevParams.Flags & DI_NEEDRESTART)
+ || (DevParams.Flags & DI_NEEDREBOOT))
+ NonStandardLog(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: A reboot is required\n"));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %u\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %u\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetSelectedDevice failed with %u\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetClassInstallParams failed with %u\n",
+ GetLastError()));
+
+ /* Continue enumeration. */
+ return TRUE;
+}
+
+typedef struct VBOXNECTFGWINPROPCHANGE
+{
+ VBOXNECTFGWINPROPCHANGE_TYPE_T enmPcType;
+ HRESULT hr;
+} VBOXNECTFGWINPROPCHANGE, *PVBOXNECTFGWINPROPCHANGE;
+
+static BOOL vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
+{
+ PVBOXNECTFGWINPROPCHANGE pPc = (PVBOXNECTFGWINPROPCHANGE)pContext;
+
+ SP_PROPCHANGE_PARAMS PcParams;
+ RT_ZERO(PcParams);
+ PcParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+ PcParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
+ PcParams.Scope = DICS_FLAG_GLOBAL;
+
+ switch (pPc->enmPcType)
+ {
+ case VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE:
+ PcParams.StateChange = DICS_DISABLE;
+ NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_DISABLE): %d\n", pPc->enmPcType));
+ break;
+ case VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE:
+ PcParams.StateChange = DICS_ENABLE;
+ NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_ENABLE): %d\n", pPc->enmPcType));
+ break;
+ default:
+ NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Unexpected prop change type: %d\n", pPc->enmPcType));
+ pPc->hr = E_INVALIDARG;
+ return FALSE;
+ }
+
+ if (SetupDiSetClassInstallParamsW(hDevInfo, pDev, &PcParams.ClassInstallHeader, sizeof(PcParams)))
+ {
+ if (SetupDiSetSelectedDevice(hDevInfo, pDev))
+ {
+ if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, pDev))
+ {
+ SP_DEVINSTALL_PARAMS_W DevParams = { sizeof(DevParams) };
+ if (SetupDiGetDeviceInstallParamsW(hDevInfo, pDev, &DevParams))
+ {
+ if ( (DevParams.Flags & DI_NEEDRESTART)
+ || (DevParams.Flags & DI_NEEDREBOOT))
+ NonStandardLog(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: A reboot is required\n"));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %u\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %u\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("SetupDiSetSelectedDevice failed with %u\n", GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("SetupDiSetClassInstallParams failed with %u\n", GetLastError()));
+
+ /* Continue enumeration. */
+ return TRUE;
+}
+
+typedef BOOL (*PFNVBOXNETCFGWINNETENUMCALLBACK)(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext);
+
+static HRESULT vboxNetCfgWinEnumNetDevices(LPCWSTR pwszPnPId, PFNVBOXNETCFGWINNETENUMCALLBACK pfnCallback, PVOID pvContext)
+{
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Searching for: %ls\n", pwszPnPId));
+
+ HRESULT hr;
+ HDEVINFO hDevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET,
+ NULL, /* IN PCTSTR Enumerator, OPTIONAL */
+ NULL, /* IN HWND hwndParent, OPTIONAL */
+ DIGCF_PRESENT, /* IN DWORD Flags,*/
+ NULL, /* IN HDEVINFO DeviceInfoSet, OPTIONAL */
+ NULL, /* IN PCTSTR MachineName, OPTIONAL */
+ NULL /* IN PVOID Reserved */);
+ if (hDevInfo != INVALID_HANDLE_VALUE)
+ {
+ size_t const cwcPnPId = RTUtf16Len(pwszPnPId);
+ DWORD winEr = NO_ERROR;
+ DWORD dwDevId = 0;
+ DWORD cbBuffer = 0;
+ PBYTE pbBuffer = NULL;
+ for (;;)
+ {
+ SP_DEVINFO_DATA Dev;
+ memset(&Dev, 0, sizeof(SP_DEVINFO_DATA));
+ Dev.cbSize = sizeof(SP_DEVINFO_DATA);
+
+ if (!SetupDiEnumDeviceInfo(hDevInfo, dwDevId, &Dev))
+ {
+ winEr = GetLastError();
+ if (winEr == ERROR_NO_MORE_ITEMS)
+ winEr = NO_ERROR;
+ break;
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Enumerating device %u ... \n", dwDevId));
+ dwDevId++;
+
+ DWORD cbRequired = 0;
+ SetLastError(0);
+ if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
+ SPDRP_HARDWAREID, /* IN DWORD Property */
+ NULL, /* OUT PDWORD PropertyRegDataType OPTIONAL */
+ pbBuffer, /* OUT PBYTE PropertyBuffer */
+ cbBuffer, /* IN DWORD PropertyBufferSize */
+ &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
+ {
+ winEr = GetLastError();
+ if (winEr != ERROR_INSUFFICIENT_BUFFER)
+ {
+ if (winEr == ERROR_INVALID_DATA)
+ {
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with ERROR_INVALID_DATA - ignoring, skipping to next device\n"));
+ continue;
+ }
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with %u\n", winEr));
+ break;
+ }
+ winEr = NO_ERROR;
+
+ cbBuffer = RT_ALIGN_32(cbRequired, 64);
+ void *pvNew = RTMemRealloc(pbBuffer, cbBuffer);
+ if (pvNew)
+ pbBuffer = (PBYTE)pvNew;
+ else
+ {
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Out of memory allocating %u bytes\n", cbBuffer));
+ winEr = ERROR_OUTOFMEMORY;
+ break;
+ }
+
+ if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
+ SPDRP_HARDWAREID, /* IN DWORD Property */
+ NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL */
+ pbBuffer, /* OUT PBYTE PropertyBuffer */
+ cbBuffer, /* IN DWORD PropertyBufferSize */
+ &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
+ {
+ winEr = GetLastError();
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (2) failed with %u\n",
+ winEr));
+ break;
+ }
+ }
+
+ PWSTR pwszCurId = (PWSTR)pbBuffer;
+ size_t cwcCurId = RTUtf16Len(pwszCurId);
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Device %u: %ls\n", dwDevId, pwszCurId));
+
+ if (cwcCurId >= cwcPnPId)
+ {
+ NonStandardLogFlow(("!RTUtf16NICmp(pwszCurId = (%ls), pwszPnPId = (%ls), cwcPnPId = (%d))\n", pwszCurId, pwszPnPId, cwcPnPId));
+
+ pwszCurId += cwcCurId - cwcPnPId;
+ if (!RTUtf16NICmp(pwszCurId, pwszPnPId, cwcPnPId))
+ {
+ if (!pfnCallback(hDevInfo, &Dev, pvContext))
+ break;
+ }
+ }
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Found %u devices total\n", dwDevId));
+
+ if (pbBuffer)
+ RTMemFree(pbBuffer);
+
+ hr = HRESULT_FROM_WIN32(winEr);
+
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ }
+ else
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetClassDevsExW failed with %u\n", winEr));
+ hr = HRESULT_FROM_WIN32(winEr);
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Ended with hr (0x%x)\n", hr));
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR pwszPnPId)
+{
+ return vboxNetCfgWinEnumNetDevices(pwszPnPId, vboxNetCfgWinRemoveAllNetDevicesOfIdCallback, NULL);
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR pwszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE_T enmPcType)
+{
+ VBOXNECTFGWINPROPCHANGE Pc;
+ Pc.enmPcType = enmPcType;
+ Pc.hr = S_OK;
+ NonStandardLogFlow(("Calling VBoxNetCfgWinEnumNetDevices with pwszPnPId (= %ls) and vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback\n", pwszPnPId));
+
+ HRESULT hr = vboxNetCfgWinEnumNetDevices(pwszPnPId, vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback, &Pc);
+ if (!SUCCEEDED(hr))
+ {
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices failed 0x%x\n", hr));
+ return hr;
+ }
+
+ if (!SUCCEEDED(Pc.hr))
+ {
+ NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback failed 0x%x\n", Pc.hr));
+ return Pc.hr;
+ }
+
+ return S_OK;
+}
+
+
+
+/*********************************************************************************************************************************
+* Logging *
+*********************************************************************************************************************************/
+
+static void DoLogging(const char *pszString, ...)
+{
+ PFNVBOXNETCFGLOGGER pfnLogger = g_pfnLogger;
+ if (pfnLogger)
+ {
+ char szBuffer[4096];
+ va_list va;
+ va_start(va, pszString);
+ RTStrPrintfV(szBuffer, RT_ELEMENTS(szBuffer), pszString, va);
+ va_end(va);
+
+ pfnLogger(szBuffer);
+ }
+}
+
+VBOXNETCFGWIN_DECL(void) VBoxNetCfgWinSetLogging(IN PFNVBOXNETCFGLOGGER pfnLogger)
+{
+ g_pfnLogger = pfnLogger;
+}
+
+
+
+/*********************************************************************************************************************************
+* IP configuration API *
+*********************************************************************************************************************************/
+/* network settings config */
+#if 1 /** @todo r=bird: Can't we replace this with VBox/com/ptr.h? */
+/**
+ * Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
+ */
+template<class C>
+class ComStrongRef
+{
+protected:
+
+ static void addref(C *p) { p->AddRef(); }
+ static void release(C *p) { p->Release(); }
+};
+
+
+/**
+ * Base template for smart COM pointers. Not intended to be used directly.
+ */
+template<class C, template<class> class RefOps = ComStrongRef>
+class ComPtrBase : protected RefOps<C>
+{
+public:
+
+ /* special template to disable AddRef()/Release() */
+ template<class I>
+ class NoAddRefRelease : public I
+ {
+ public:
+ virtual ~NoAddRefRelease() { /* Make VC++ 19.2 happy. */ }
+ private:
+#ifndef VBOX_WITH_XPCOM
+ STDMETHOD_(ULONG, AddRef)() = 0;
+ STDMETHOD_(ULONG, Release)() = 0;
+#else
+ NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
+ NS_IMETHOD_(nsrefcnt) Release(void) = 0;
+#endif
+ };
+
+protected:
+
+ ComPtrBase() : p(NULL) {}
+ ComPtrBase(const ComPtrBase &that) : p(that.p) { addref(); }
+ ComPtrBase(C *that_p) : p(that_p) { addref(); }
+
+ ~ComPtrBase() { release(); }
+
+ ComPtrBase &operator=(const ComPtrBase &that)
+ {
+ safe_assign(that.p);
+ return *this;
+ }
+
+ ComPtrBase &operator=(C *that_p)
+ {
+ safe_assign(that_p);
+ return *this;
+ }
+
+public:
+
+ void setNull()
+ {
+ release();
+ p = NULL;
+ }
+
+ bool isNull() const
+ {
+ return (p == NULL);
+ }
+
+ bool operator!() const { return isNull(); }
+
+ bool operator<(C* that_p) const { return p < that_p; }
+ bool operator==(C* that_p) const { return p == that_p; }
+
+ template<class I>
+ bool equalsTo(I *aThat) const
+ {
+ return ComPtrEquals(p, aThat);
+ }
+
+ template<class OC>
+ bool equalsTo(const ComPtrBase<OC> &oc) const
+ {
+ return equalsTo((OC *) oc);
+ }
+
+ /** Intended to pass instances as in parameters to interface methods */
+ operator C *() const { return p; }
+
+ /**
+ * Dereferences the instance (redirects the -> operator to the managed
+ * pointer).
+ */
+ NoAddRefRelease<C> *operator->() const
+ {
+ AssertMsg (p, ("Managed pointer must not be null\n"));
+ return (NoAddRefRelease <C> *) p;
+ }
+
+ template<class I>
+ HRESULT queryInterfaceTo(I **pp) const
+ {
+ if (pp)
+ {
+ if (p)
+ return p->QueryInterface(COM_IIDOF(I), (void **)pp);
+ *pp = NULL;
+ return S_OK;
+ }
+ return E_INVALIDARG;
+ }
+
+ /** Intended to pass instances as out parameters to interface methods */
+ C **asOutParam()
+ {
+ setNull();
+ return &p;
+ }
+
+private:
+
+ void addref()
+ {
+ if (p)
+ RefOps<C>::addref(p);
+ }
+
+ void release()
+ {
+ if (p)
+ RefOps<C>::release(p);
+ }
+
+ void safe_assign(C *that_p)
+ {
+ /* be aware of self-assignment */
+ if (that_p)
+ RefOps<C>::addref(that_p);
+ release();
+ p = that_p;
+ }
+
+ C *p;
+};
+
+/**
+ * Smart COM pointer wrapper that automatically manages refcounting of
+ * interface pointers.
+ *
+ * @param I COM interface class
+ */
+template<class I, template<class> class RefOps = ComStrongRef>
+class ComPtr : public ComPtrBase<I, RefOps>
+{
+ typedef ComPtrBase<I, RefOps> Base;
+
+public:
+
+ ComPtr() : Base() {}
+ ComPtr(const ComPtr &that) : Base(that) {}
+ ComPtr&operator= (const ComPtr &that)
+ {
+ Base::operator=(that);
+ return *this;
+ }
+
+ template<class OI>
+ ComPtr(OI *that_p) : Base () { operator=(that_p); }
+
+ /* specialization for I */
+ ComPtr(I *that_p) : Base (that_p) {}
+
+ template <class OC>
+ ComPtr(const ComPtr<OC, RefOps> &oc) : Base() { operator=((OC *) oc); }
+
+ template<class OI>
+ ComPtr &operator=(OI *that_p)
+ {
+ if (that_p)
+ that_p->QueryInterface(COM_IIDOF(I), (void **)Base::asOutParam());
+ else
+ Base::setNull();
+ return *this;
+ }
+
+ /* specialization for I */
+ ComPtr &operator=(I *that_p)
+ {
+ Base::operator=(that_p);
+ return *this;
+ }
+
+ template<class OC>
+ ComPtr &operator=(const ComPtr<OC, RefOps> &oc)
+ {
+ return operator=((OC *) oc);
+ }
+};
+#endif
+
+static HRESULT netIfWinFindAdapterClassById(IWbemServices *pSvc, const GUID *pGuid, IWbemClassObject **pAdapterConfig)
+{
+ HRESULT hr;
+
+ WCHAR wszGuid[50];
+ int cwcGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
+ if (cwcGuid)
+ {
+ com::BstrFmt bstrQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"%ls\"", wszGuid);
+ IEnumWbemClassObject* pEnumerator = NULL;
+ hr = pSvc->ExecQuery(com::Bstr("WQL").raw(), bstrQuery.raw(), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (SUCCEEDED(hr))
+ {
+ if (pEnumerator)
+ {
+ IWbemClassObject *pclsObj = NULL;
+ ULONG uReturn = 0;
+ hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
+ NonStandardLogFlow(("netIfWinFindAdapterClassById: IEnumWbemClassObject::Next -> hr=0x%x pclsObj=%p uReturn=%u 42=%u\n",
+ hr, (void *)pclsObj, uReturn, 42));
+ if (SUCCEEDED(hr))
+ {
+ if (uReturn && pclsObj != NULL)
+ {
+ *pAdapterConfig = pclsObj;
+ pEnumerator->Release();
+ NonStandardLogFlow(("netIfWinFindAdapterClassById: S_OK and %p\n", *pAdapterConfig));
+ return S_OK;
+ }
+ hr = E_FAIL;
+ }
+ pEnumerator->Release();
+ }
+ else
+ {
+ NonStandardLogFlow(("ExecQuery returned no enumerator\n"));
+ hr = E_FAIL;
+ }
+ }
+ else
+ NonStandardLogFlow(("ExecQuery failed (0x%x)\n", hr));
+ }
+ else
+ {
+ DWORD winEr = GetLastError();
+ hr = HRESULT_FROM_WIN32(winEr);
+ if (SUCCEEDED(hr))
+ hr = E_FAIL;
+ NonStandardLogFlow(("StringFromGUID2 failed winEr=%u, hr=0x%x\n", winEr, hr));
+ }
+
+ NonStandardLogFlow(("netIfWinFindAdapterClassById: 0x%x and %p\n", hr, *pAdapterConfig));
+ return hr;
+}
+
+static HRESULT netIfWinIsHostOnly(IWbemClassObject *pAdapterConfig, BOOL *pfIsHostOnly)
+{
+ VARIANT vtServiceName;
+ VariantInit(&vtServiceName);
+
+ HRESULT hr = pAdapterConfig->Get(L"ServiceName", 0 /*lFlags*/, &vtServiceName, NULL /*pvtType*/, NULL /*plFlavor*/);
+ if (SUCCEEDED(hr))
+ {
+ *pfIsHostOnly = RTUtf16CmpAscii(vtServiceName.bstrVal, "VBoxNetAdp") == 0;
+
+ VariantClear(&vtServiceName);
+ }
+
+ return hr;
+}
+
+static HRESULT netIfWinGetIpSettings(IWbemClassObject * pAdapterConfig, ULONG *pIpv4, ULONG *pMaskv4)
+{
+ *pIpv4 = 0;
+ *pMaskv4 = 0;
+
+ VARIANT vtIp;
+ VariantInit(&vtIp);
+ HRESULT hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
+ if (SUCCEEDED(hr))
+ {
+ if (vtIp.vt == (VT_ARRAY | VT_BSTR))
+ {
+ VARIANT vtMask;
+ VariantInit(&vtMask);
+ hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
+ if (SUCCEEDED(hr))
+ {
+ if (vtMask.vt == (VT_ARRAY | VT_BSTR))
+ {
+ SAFEARRAY *pIpArray = vtIp.parray;
+ SAFEARRAY *pMaskArray = vtMask.parray;
+ if (pIpArray && pMaskArray)
+ {
+ BSTR pBstrCurIp;
+ BSTR pBstrCurMask;
+ for (LONG i = 0;
+ SafeArrayGetElement(pIpArray, &i, (PVOID)&pBstrCurIp) == S_OK
+ && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pBstrCurMask) == S_OK;
+ i++)
+ {
+ com::Utf8Str strIp(pBstrCurIp);
+ ULONG Ipv4 = inet_addr(strIp.c_str());
+ if (Ipv4 != INADDR_NONE)
+ {
+ *pIpv4 = Ipv4;
+
+ com::Utf8Str strMask(pBstrCurMask);
+ *pMaskv4 = inet_addr(strMask.c_str());
+ break;
+ }
+ }
+ }
+ }
+ VariantClear(&vtMask);
+ }
+ }
+ VariantClear(&vtIp);
+ }
+
+ return hr;
+}
+
+#if 0 /* unused */
+
+static HRESULT netIfWinHasIpSettings(IWbemClassObject * pAdapterConfig, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, bool *pFound)
+{
+ VARIANT vtIp;
+ HRESULT hr;
+ VariantInit(&vtIp);
+
+ *pFound = false;
+
+ hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
+ if (SUCCEEDED(hr))
+ {
+ VARIANT vtMask;
+ VariantInit(&vtMask);
+ hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
+ if (SUCCEEDED(hr))
+ {
+ SAFEARRAY * pIpArray = vtIp.parray;
+ SAFEARRAY * pMaskArray = vtMask.parray;
+ if (pIpArray && pMaskArray)
+ {
+ BSTR pIp, pMask;
+ for (LONG k = 0;
+ SafeArrayGetElement(pCheckIp, &k, (PVOID)&pIp) == S_OK
+ && SafeArrayGetElement(pCheckMask, &k, (PVOID)&pMask) == S_OK;
+ k++)
+ {
+ BSTR pCurIp;
+ BSTR pCurMask;
+ for (LONG i = 0;
+ SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
+ && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
+ i++)
+ {
+ if (!wcsicmp(pCurIp, pIp))
+ {
+ if (!wcsicmp(pCurMask, pMask))
+ *pFound = true;
+ break;
+ }
+ }
+ }
+ }
+
+
+ VariantClear(&vtMask);
+ }
+
+ VariantClear(&vtIp);
+ }
+
+ return hr;
+}
+
+static HRESULT netIfWinWaitIpSettings(IWbemServices *pSvc, const GUID * pGuid, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, ULONG sec2Wait, bool *pFound)
+{
+ /* on Vista we need to wait for the address to get applied */
+ /* wait for the address to appear in the list */
+ HRESULT hr = S_OK;
+ ULONG i;
+ *pFound = false;
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ for (i = 0;
+ (hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam())) == S_OK
+ && (hr = netIfWinHasIpSettings(pAdapterConfig, pCheckIp, pCheckMask, pFound)) == S_OK
+ && !(*pFound)
+ && i < sec2Wait/6;
+ i++)
+ {
+ Sleep(6000);
+ }
+
+ return hr;
+}
+
+#endif /* unused */
+
+static HRESULT netIfWinCreateIWbemServices(IWbemServices **ppSvc)
+{
+ IWbemLocator *pLoc = NULL;
+ HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc);
+ if (SUCCEEDED(hr))
+ {
+ IWbemServices *pSvc = NULL;
+ hr = pLoc->ConnectServer(com::Bstr(L"ROOT\\CIMV2").raw(), /* [in] const BSTR strNetworkResource */
+ NULL, /* [in] const BSTR strUser */
+ NULL, /* [in] const BSTR strPassword */
+ 0, /* [in] const BSTR strLocale */
+ NULL, /* [in] LONG lSecurityFlags */
+ 0, /* [in] const BSTR strAuthority */
+ 0, /* [in] IWbemContext* pCtx */
+ &pSvc /* [out] IWbemServices** ppNamespace */);
+ if (SUCCEEDED(hr))
+ {
+ hr = CoSetProxyBlanket(pSvc, /* IUnknown * pProxy */
+ RPC_C_AUTHN_WINNT, /* DWORD dwAuthnSvc */
+ RPC_C_AUTHZ_NONE, /* DWORD dwAuthzSvc */
+ NULL, /* WCHAR * pServerPrincName */
+ RPC_C_AUTHN_LEVEL_CALL, /* DWORD dwAuthnLevel */
+ RPC_C_IMP_LEVEL_IMPERSONATE, /* DWORD dwImpLevel */
+ NULL, /* RPC_AUTH_IDENTITY_HANDLE pAuthInfo */
+ EOAC_NONE /* DWORD dwCapabilities */
+ );
+ if (SUCCEEDED(hr))
+ {
+ *ppSvc = pSvc;
+ /* do not need it any more */
+ pLoc->Release();
+ return hr;
+ }
+
+ NonStandardLogFlow(("CoSetProxyBlanket failed: %Rhrc\n", hr));
+ pSvc->Release();
+ }
+ else
+ NonStandardLogFlow(("ConnectServer failed: %Rhrc\n", hr));
+ pLoc->Release();
+ }
+ else
+ NonStandardLogFlow(("CoCreateInstance failed: %Rhrc\n", hr));
+ return hr;
+}
+
+static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, com::Bstr *pRet)
+{
+ VARIANT index;
+ VariantInit(&index);
+ HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
+ if (SUCCEEDED(hr))
+ hr = pRet->printfNoThrow("Win32_NetworkAdapterConfiguration.Index='%u'", index.uintVal);
+ else
+ {
+ pRet->setNull();
+ NonStandardLogFlow(("Get failed: %Rhrc\n", hr));
+ }
+ return hr;
+}
+
+static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, com::Bstr const &rObjPath,
+ const char *pszMethodName, LPWSTR *papwszArgNames, LPVARIANT *pArgs, UINT cArgs,
+ IWbemClassObject **ppOutParams)
+{
+ *ppOutParams = NULL;
+ com::Bstr bstrMethodName;
+ HRESULT hr = bstrMethodName.assignEx(pszMethodName);
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pInParamsDefinition;
+ ComPtr<IWbemClassObject> pClassInstance;
+ if (cArgs)
+ {
+ hr = pClass->GetMethod(bstrMethodName.raw(), 0, pInParamsDefinition.asOutParam(), NULL);
+ if (SUCCEEDED(hr))
+ {
+ hr = pInParamsDefinition->SpawnInstance(0, pClassInstance.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ for (UINT i = 0; i < cArgs; i++)
+ {
+ hr = pClassInstance->Put(papwszArgNames[i], 0, pArgs[i], 0);
+ if (FAILED(hr))
+ break;
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ IWbemClassObject *pOutParams = NULL;
+ hr = pSvc->ExecMethod(rObjPath.raw(), bstrMethodName.raw(), 0, NULL, pClassInstance, &pOutParams, NULL);
+ if (SUCCEEDED(hr))
+ *ppOutParams = pOutParams;
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr const *paIps, UINT cIps)
+{
+ HRESULT hr = S_OK;
+ SAFEARRAY *pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIps);
+ if (pIpArray)
+ {
+ for (UINT i = 0; i < cIps; i++)
+ {
+ com::Bstr bstrVal;
+ hr = bstrVal.printfNoThrow("%RTnaipv4", paIps[i].s_addr);
+ if (SUCCEEDED(hr))
+ {
+ Assert(bstrVal.equals(inet_ntoa(paIps[i])));
+
+ BSTR pRawVal;
+ hr = bstrVal.detachToEx(&pRawVal);
+ if (SUCCEEDED(hr))
+ {
+ LONG aIndex[1] = { (LONG)i };
+ hr = SafeArrayPutElement(pIpArray, aIndex, pRawVal);
+ if (SUCCEEDED(hr))
+ continue;
+ SysFreeString(pRawVal);
+ }
+ }
+ break;
+ }
+
+ if (SUCCEEDED(hr))
+ *ppArray = pIpArray;
+ else
+ SafeArrayDestroy(pIpArray);
+ }
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ return hr;
+}
+
+#if 0 /* unused */
+static HRESULT netIfWinCreateIpArrayV4V6(SAFEARRAY **ppArray, BSTR Ip)
+{
+ HRESULT hr;
+ SAFEARRAY *pIpArray = SafeArrayCreateVector(VT_BSTR, 0, 1);
+ if (pIpArray)
+ {
+ BSTR val = com::Bstr(Ip, false).copy();
+ long aIndex[1];
+ aIndex[0] = 0;
+ hr = SafeArrayPutElement(pIpArray, aIndex, val);
+ if (FAILED(hr))
+ {
+ SysFreeString(val);
+ SafeArrayDestroy(pIpArray);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *ppArray = pIpArray;
+ }
+ }
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
+
+ return hr;
+}
+#endif
+
+
+static HRESULT netIfWinCreateIpArrayVariantV4(VARIANT *pIpAddresses, in_addr const *paIps, UINT cIps)
+{
+ VariantInit(pIpAddresses);
+ pIpAddresses->vt = VT_ARRAY | VT_BSTR;
+
+ SAFEARRAY *pIpArray;
+ HRESULT hr = netIfWinCreateIpArray(&pIpArray, paIps, cIps);
+ if (SUCCEEDED(hr))
+ pIpAddresses->parray = pIpArray;
+ return hr;
+}
+
+#if 0 /* unused */
+static HRESULT netIfWinCreateIpArrayVariantV4V6(VARIANT * pIpAddresses, BSTR Ip)
+{
+ HRESULT hr;
+ VariantInit(pIpAddresses);
+ pIpAddresses->vt = VT_ARRAY | VT_BSTR;
+ SAFEARRAY *pIpArray;
+ hr = netIfWinCreateIpArrayV4V6(&pIpArray, Ip);
+ if (SUCCEEDED(hr))
+ {
+ pIpAddresses->parray = pIpArray;
+ }
+ return hr;
+}
+#endif
+
+static HRESULT netIfWinEnableStatic(IWbemServices *pSvc, const GUID *pGuid, com::Bstr &rObjPath, VARIANT *pIp, VARIANT *pMask)
+{
+ com::Bstr bstrClassName;
+ HRESULT hr = bstrClassName.assignEx("Win32_NetworkAdapterConfiguration");
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pClass;
+ hr = pSvc->GetObject(bstrClassName.raw(), 0, NULL, pClass.asOutParam(), NULL);
+ if (SUCCEEDED(hr))
+ {
+ LPWSTR argNames[] = {L"IPAddress", L"SubnetMask"};
+ LPVARIANT args[] = { pIp, pMask };
+
+ ComPtr<IWbemClassObject> pOutParams;
+ hr = netIfExecMethod(pSvc, pClass, rObjPath.raw(), "EnableStatic", argNames, args,
+ 2, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ com::Bstr bstrReturnValue;
+ hr = bstrReturnValue.assignEx("ReturnValue");
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ VariantInit(&varReturnValue);
+ hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
+ Assert(SUCCEEDED(hr));
+ if (SUCCEEDED(hr))
+ {
+ //Assert(varReturnValue.vt == VT_UINT);
+ int winEr = varReturnValue.uintVal;
+ switch (winEr)
+ {
+ case 0:
+ {
+ hr = S_OK;
+ //bool bFound;
+ //HRESULT tmpHr = netIfWinWaitIpSettings(pSvc, pGuid, pIp->parray, pMask->parray, 180, &bFound);
+ NOREF(pGuid);
+ break;
+ }
+ default:
+ hr = HRESULT_FROM_WIN32( winEr );
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return hr;
+}
+
+
+static HRESULT netIfWinEnableStaticV4(IWbemServices *pSvc, const GUID *pGuid, com::Bstr &rObjPath,
+ in_addr const *paIps, in_addr const *paMasks, UINT cIpAndMasks)
+{
+ VARIANT ipAddresses;
+ HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, paIps, cIpAndMasks);
+ if (SUCCEEDED(hr))
+ {
+ VARIANT ipMasks;
+ hr = netIfWinCreateIpArrayVariantV4(&ipMasks, paMasks, cIpAndMasks);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableStatic(pSvc, pGuid, rObjPath, &ipAddresses, &ipMasks);
+ VariantClear(&ipMasks);
+ }
+ VariantClear(&ipAddresses);
+ }
+ return hr;
+}
+
+#if 0 /* unused */
+
+static HRESULT netIfWinEnableStaticV4V6(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, BSTR Ip, BSTR Mask)
+{
+ VARIANT ipAddresses;
+ HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&ipAddresses, Ip);
+ if (SUCCEEDED(hr))
+ {
+ VARIANT ipMasks;
+ hr = netIfWinCreateIpArrayVariantV4V6(&ipMasks, Mask);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
+ VariantClear(&ipMasks);
+ }
+ VariantClear(&ipAddresses);
+ }
+ return hr;
+}
+
+/* win API allows to set gw metrics as well, we are not setting them */
+static HRESULT netIfWinSetGateways(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pGw)
+{
+ ComPtr<IWbemClassObject> pClass;
+ BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
+ HRESULT hr;
+ if (ClassName)
+ {
+ hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
+ if (SUCCEEDED(hr))
+ {
+ LPWSTR argNames[] = {L"DefaultIPGateway"};
+ LPVARIANT args[] = {pGw};
+ ComPtr<IWbemClassObject> pOutParams;
+
+ hr = netIfExecMethod(pSvc, pClass, ObjPath, com::Bstr(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ hr = pOutParams->Get(com::Bstr(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
+ Assert(SUCCEEDED(hr));
+ if (SUCCEEDED(hr))
+ {
+// Assert(varReturnValue.vt == VT_UINT);
+ int winEr = varReturnValue.uintVal;
+ switch (winEr)
+ {
+ case 0:
+ hr = S_OK;
+ break;
+ default:
+ hr = HRESULT_FROM_WIN32( winEr );
+ break;
+ }
+ }
+ }
+ }
+ SysFreeString(ClassName);
+ }
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
+
+ return hr;
+}
+
+/* win API allows to set gw metrics as well, we are not setting them */
+static HRESULT netIfWinSetGatewaysV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aGw, UINT cGw)
+{
+ VARIANT gwais;
+ HRESULT hr = netIfWinCreateIpArrayVariantV4(&gwais, aGw, cGw);
+ if (SUCCEEDED(hr))
+ {
+ netIfWinSetGateways(pSvc, ObjPath, &gwais);
+ VariantClear(&gwais);
+ }
+ return hr;
+}
+
+/* win API allows to set gw metrics as well, we are not setting them */
+static HRESULT netIfWinSetGatewaysV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Gw)
+{
+ VARIANT vGw;
+ HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&vGw, Gw);
+ if (SUCCEEDED(hr))
+ {
+ netIfWinSetGateways(pSvc, ObjPath, &vGw);
+ VariantClear(&vGw);
+ }
+ return hr;
+}
+
+#endif /* unused */
+
+static HRESULT netIfWinEnableDHCP(IWbemServices * pSvc, const com::Bstr &rObjPath)
+{
+ com::Bstr bstrClassName;
+ HRESULT hr = bstrClassName.assignEx("Win32_NetworkAdapterConfiguration");
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pClass;
+ hr = pSvc->GetObject(bstrClassName.raw(), 0, NULL, pClass.asOutParam(), NULL);
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pOutParams;
+ hr = netIfExecMethod(pSvc, pClass, rObjPath, "EnableDHCP", NULL, NULL, 0, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ com::Bstr bstrReturnValue;
+ hr = bstrReturnValue.assignEx("ReturnValue");
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ VariantInit(&varReturnValue);
+ hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
+ Assert(SUCCEEDED(hr));
+ if (SUCCEEDED(hr))
+ {
+ //Assert(varReturnValue.vt == VT_UINT);
+ int winEr = varReturnValue.uintVal;
+ switch (winEr)
+ {
+ case 0:
+ hr = S_OK;
+ break;
+ default:
+ hr = HRESULT_FROM_WIN32( winEr );
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return hr;
+}
+
+static HRESULT netIfWinDhcpRediscover(IWbemServices * pSvc, const com::Bstr &rObjPath)
+{
+ com::Bstr bstrClassName;
+ HRESULT hr = bstrClassName.assignEx("Win32_NetworkAdapterConfiguration");
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pClass;
+ hr = pSvc->GetObject(bstrClassName.raw(), 0, NULL, pClass.asOutParam(), NULL);
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pOutParams;
+ hr = netIfExecMethod(pSvc, pClass, rObjPath, "ReleaseDHCPLease", NULL, NULL, 0, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ com::Bstr bstrReturnValue;
+ hr = bstrReturnValue.assignEx("ReturnValue");
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ VariantInit(&varReturnValue);
+ hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
+ Assert(SUCCEEDED(hr));
+ if (SUCCEEDED(hr))
+ {
+ //Assert(varReturnValue.vt == VT_UINT);
+ int winEr = varReturnValue.uintVal;
+ if (winEr == 0)
+ {
+ hr = netIfExecMethod(pSvc, pClass, rObjPath, "RenewDHCPLease", NULL, NULL, 0, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
+ Assert(SUCCEEDED(hr));
+ if (SUCCEEDED(hr))
+ {
+ //Assert(varReturnValue.vt == VT_UINT);
+ winEr = varReturnValue.uintVal;
+ if (winEr == 0)
+ hr = S_OK;
+ else
+ hr = HRESULT_FROM_WIN32( winEr );
+ }
+ }
+ }
+ else
+ hr = HRESULT_FROM_WIN32( winEr );
+ }
+ }
+ }
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinIsDhcpEnabled(IWbemClassObject *pAdapterConfig, BOOL *pfEnabled)
+{
+ VARIANT vtEnabled;
+ VariantInit(&vtEnabled);
+ HRESULT hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
+ if (SUCCEEDED(hr))
+ *pfEnabled = vtEnabled.boolVal;
+ else
+ *pfEnabled = FALSE;
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(IN const GUID *pGuid, OUT PADAPTER_SETTINGS pSettings)
+{
+ ComPtr<IWbemServices> pSvc;
+ HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ hr = vboxNetCfgWinIsDhcpEnabled(pAdapterConfig, &pSettings->bDhcp);
+ if (SUCCEEDED(hr))
+ hr = netIfWinGetIpSettings(pAdapterConfig, &pSettings->ip, &pSettings->mask);
+ }
+ }
+
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinIsDhcpEnabled(const GUID * pGuid, BOOL *pEnabled)
+{
+ ComPtr<IWbemServices> pSvc;
+ HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ VARIANT vtEnabled;
+ hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
+ if (SUCCEEDED(hr))
+ *pEnabled = vtEnabled.boolVal;
+ }
+ }
+
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(IN const GUID *pGuid, IN ULONG ip, IN ULONG mask)
+{
+ NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: ip=0x%x mask=0x%x\n", ip, mask));
+ ComPtr<IWbemServices> pSvc;
+ HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ BOOL fIsHostOnly;
+ hr = netIfWinIsHostOnly(pAdapterConfig, &fIsHostOnly);
+ if (SUCCEEDED(hr))
+ {
+ if (fIsHostOnly)
+ {
+ in_addr aIp[1];
+ in_addr aMask[1];
+ aIp[0].S_un.S_addr = ip;
+ aMask[0].S_un.S_addr = mask;
+
+ com::Bstr bstrObjPath;
+ hr = netIfWinAdapterConfigPath(pAdapterConfig, &bstrObjPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableStaticV4(pSvc, pGuid, bstrObjPath, aIp, aMask, ip != 0 ? 1 : 0);
+ if (SUCCEEDED(hr))
+ {
+#if 0
+ in_addr aGw[1];
+ aGw[0].S_un.S_addr = gw;
+ hr = netIfWinSetGatewaysV4(pSvc, bstrObjPath, aGw, 1);
+ if (SUCCEEDED(hr))
+#endif
+ {
+ }
+ }
+ }
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ }
+ }
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: returns %Rhrc\n", hr));
+ return hr;
+}
+
+#if 0
+static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, IN_BSTR aIPV6Mask, IN_BSTR aIPV6DefaultGateway)
+{
+ HRESULT hr;
+ ComPtr<IWbemServices> pSvc;
+ hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ BSTR ObjPath;
+ hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableStaticV4V6(pSvc, pAdapterConfig, ObjPath, aIPV6Address, aIPV6Mask);
+ if (SUCCEEDED(hr))
+ {
+ if (aIPV6DefaultGateway)
+ {
+ hr = netIfWinSetGatewaysV4V6(pSvc, ObjPath, aIPV6DefaultGateway);
+ }
+ if (SUCCEEDED(hr))
+ {
+// hr = netIfWinUpdateConfig(pIf);
+ }
+ }
+ SysFreeString(ObjPath);
+ }
+ }
+ }
+
+ return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
+}
+
+static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
+{
+ RTNETADDRIPV6 Mask;
+ int rc = RTNetPrefixToMaskIPv6(aIPV6MaskPrefixLength, &Mask);
+ if (RT_SUCCESS(rc))
+ {
+ Bstr maskStr = composeIPv6Address(&Mask);
+ rc = netIfEnableStaticIpConfigV6(pGuid, aIPV6Address, maskStr, NULL);
+ }
+ return rc;
+}
+#endif
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(IN const GUID *pGuid)
+{
+ ComPtr<IWbemServices> pSvc;
+ HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ BOOL fIsHostOnly;
+ hr = netIfWinIsHostOnly(pAdapterConfig, &fIsHostOnly);
+ if (SUCCEEDED(hr))
+ {
+ if (fIsHostOnly)
+ {
+ com::Bstr bstrObjPath;
+ hr = netIfWinAdapterConfigPath(pAdapterConfig, &bstrObjPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableDHCP(pSvc, bstrObjPath);
+ if (SUCCEEDED(hr))
+ {
+ //hr = netIfWinUpdateConfig(pIf);
+ }
+ }
+ }
+ else
+ hr = E_FAIL;
+ }
+ }
+ }
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(IN const GUID *pGuid)
+{
+ ComPtr<IWbemServices> pSvc;
+ HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ BOOL fIsHostOnly;
+ hr = netIfWinIsHostOnly(pAdapterConfig, &fIsHostOnly);
+ if (SUCCEEDED(hr))
+ {
+ if (fIsHostOnly)
+ {
+ com::Bstr bstrObjPath;
+ hr = netIfWinAdapterConfigPath(pAdapterConfig, &bstrObjPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinDhcpRediscover(pSvc, bstrObjPath);
+ if (SUCCEEDED(hr))
+ {
+ //hr = netIfWinUpdateConfig(pIf);
+ }
+ }
+ }
+ else
+ hr = E_FAIL;
+ }
+ }
+ }
+
+
+ return hr;
+}
+
+static const char *vboxNetCfgWinAddrToStr(char *pszBuf, size_t cbBuf, LPSOCKADDR pAddr)
+{
+ switch (pAddr->sa_family)
+ {
+ case AF_INET:
+ RTStrPrintf(pszBuf, cbBuf, "%d.%d.%d.%d",
+ ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b1,
+ ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b2,
+ ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b3,
+ ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b4);
+ break;
+ case AF_INET6:
+ RTStrPrintf(pszBuf, cbBuf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[0], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[1],
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[2], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[3],
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[4], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[5],
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[6], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[7],
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[8], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[9],
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[10], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[11],
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[12], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[13],
+ ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[14], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[15]);
+ break;
+ default:
+ RTStrCopy(pszBuf, cbBuf, "unknown");
+ break;
+ }
+ return pszBuf;
+}
+
+typedef bool (*PFNVBOXNETCFG_IPSETTINGS_CALLBACK) (ULONG ip, ULONG mask, PVOID pContext);
+
+static void vboxNetCfgWinEnumIpConfig(PIP_ADAPTER_ADDRESSES pAddresses, PFNVBOXNETCFG_IPSETTINGS_CALLBACK pfnCallback, PVOID pContext)
+{
+ PIP_ADAPTER_ADDRESSES pAdapter;
+ for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next)
+ {
+ NonStandardLogFlow(("+- Enumerating adapter '%ls' %s\n", pAdapter->FriendlyName, pAdapter->AdapterName));
+ for (PIP_ADAPTER_PREFIX pPrefix = pAdapter->FirstPrefix; pPrefix; pPrefix = pPrefix->Next)
+ {
+ char szBuf[80];
+ const char *pcszAddress = vboxNetCfgWinAddrToStr(szBuf, sizeof(szBuf), pPrefix->Address.lpSockaddr);
+
+ /* We are concerned with IPv4 only, ignore the rest. */
+ if (pPrefix->Address.lpSockaddr->sa_family != AF_INET)
+ {
+ NonStandardLogFlow(("| +- %s %d: not IPv4, ignoring\n", pcszAddress, pPrefix->PrefixLength));
+ continue;
+ }
+
+ /* Ignore invalid prefixes as well as host addresses. */
+ if (pPrefix->PrefixLength < 1 || pPrefix->PrefixLength > 31)
+ {
+ NonStandardLogFlow(("| +- %s %d: host or broadcast, ignoring\n", pcszAddress, pPrefix->PrefixLength));
+ continue;
+ }
+
+ /* Ignore multicast and beyond. */
+ ULONG ip = ((struct sockaddr_in *)pPrefix->Address.lpSockaddr)->sin_addr.s_addr;
+ if ((ip & 0xF0) > 224)
+ {
+ NonStandardLogFlow(("| +- %s %d: multicast, ignoring\n", pcszAddress, pPrefix->PrefixLength));
+ continue;
+ }
+
+ ULONG mask = htonl((~(((ULONG)~0) >> pPrefix->PrefixLength)));
+ bool fContinue = pfnCallback(ip, mask, pContext);
+ if (!fContinue)
+ {
+ NonStandardLogFlow(("| +- %s %d: CONFLICT!\n", pcszAddress, pPrefix->PrefixLength));
+ return;
+ }
+
+ NonStandardLogFlow(("| +- %s %d: no conflict, moving on\n", pcszAddress, pPrefix->PrefixLength));
+ }
+ }
+}
+
+typedef struct _IPPROBE_CONTEXT
+{
+ ULONG Prefix;
+ bool fConflict;
+}IPPROBE_CONTEXT, *PIPPROBE_CONTEXT;
+
+#define IPPROBE_INIT(a_pContext, a_addr) \
+ do { (a_pContext)->fConflict = false; (a_pContext)->Prefix = (a_addr); } while (0)
+
+#define IPPROBE_INIT_STR(a_pContext, a_straddr) \
+ IPROBE_INIT(a_pContext, inet_addr(_straddr))
+
+static bool vboxNetCfgWinIpProbeCallback (ULONG ip, ULONG mask, PVOID pContext)
+{
+ PIPPROBE_CONTEXT pProbe = (PIPPROBE_CONTEXT)pContext;
+
+ if ((ip & mask) == (pProbe->Prefix & mask))
+ {
+ pProbe->fConflict = true;
+ return false;
+ }
+
+ return true;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(OUT PULONG pNetIp, OUT PULONG pNetMask)
+{
+ HRESULT hr = S_OK;
+
+ *pNetIp = 0;
+ *pNetMask = 0;
+
+ /*
+ * MSDN recommends to pre-allocate a 15KB buffer.
+ */
+ ULONG cbBuf = 15 * _1K;
+ PIP_ADAPTER_ADDRESSES paAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAllocZ(cbBuf);
+ if (!paAddresses)
+ return E_OUTOFMEMORY;
+ DWORD dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, paAddresses, &cbBuf);
+ if (dwRc == ERROR_BUFFER_OVERFLOW)
+ {
+ /* Impressive! More than 10 adapters! Get more memory and try again. */
+ RTMemFree(paAddresses);
+ paAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAllocZ(cbBuf);
+ if (!paAddresses)
+ return E_OUTOFMEMORY;
+ dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, paAddresses, &cbBuf);
+ }
+ if (dwRc == NO_ERROR)
+ {
+ const ULONG ip192168 = inet_addr("192.168.0.0");
+ for (int i = 0; i < 384; i++)
+ {
+#if 0
+ ULONG ipProbe = rand()*255 / RAND_MAX;
+#else
+ uint32_t ipProbe = RTRandU32Ex(0, 255);
+#endif
+ ipProbe = ip192168 | (ipProbe << 16);
+ NonStandardLogFlow(("probing %RTnaipv4\n", ipProbe));
+
+ IPPROBE_CONTEXT Context;
+ IPPROBE_INIT(&Context, ipProbe);
+ vboxNetCfgWinEnumIpConfig(paAddresses, vboxNetCfgWinIpProbeCallback, &Context);
+ if (!Context.fConflict)
+ {
+ NonStandardLogFlow(("found unused net %RTnaipv4\n", ipProbe));
+ *pNetIp = ipProbe;
+ *pNetMask = inet_addr("255.255.255.0");
+ break;
+ }
+ }
+ if (*pNetIp == 0)
+ dwRc = ERROR_DHCP_ADDRESS_CONFLICT;
+ }
+ else
+ NonStandardLogFlow(("GetAdaptersAddresses err (%u)\n", dwRc));
+
+ RTMemFree(paAddresses);
+
+ if (dwRc != NO_ERROR)
+ hr = HRESULT_FROM_WIN32(dwRc);
+ return hr;
+}
+
+/*
+ * convenience functions to perform netflt/adp manipulations
+ */
+#define VBOXNETCFGWIN_NETFLT_ID L"sun_VBoxNetFlt"
+#define VBOXNETCFGWIN_NETFLT_MP_ID L"sun_VBoxNetFltmp"
+
+static HRESULT vboxNetCfgWinNetFltUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
+{
+ INetCfgComponent *pNcc = NULL;
+ HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETFLT_ID, &pNcc);
+ if (hr == S_OK)
+ {
+ NonStandardLog("NetFlt is installed currently, uninstalling ...\n");
+
+ hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
+ NonStandardLogFlow(("NetFlt component uninstallation ended with hr (%Rhrc)\n", hr));
+
+ pNcc->Release();
+ }
+ else if (hr == S_FALSE)
+ NonStandardLog("NetFlt is not installed currently\n");
+ else
+ NonStandardLogFlow(("FindComponent failed: %Rhrc\n", hr));
+
+ VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETFLT_ID, InfRmFlags);
+ VBoxDrvCfgInfUninstallAllF(L"Net", VBOXNETCFGWIN_NETFLT_MP_ID, InfRmFlags);
+
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc)
+{
+ return vboxNetCfgWinNetFltUninstall(pNc, 0);
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc, IN LPCWSTR const *pwszInfFullPath, IN UINT cInfFullPaths)
+{
+ HRESULT hr = vboxNetCfgWinNetFltUninstall(pNc, SUOI_FORCEDELETE);
+ if (SUCCEEDED(hr))
+ {
+ NonStandardLog("NetFlt will be installed ...\n");
+ hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETFLT_ID,
+ &GUID_DEVCLASS_NETSERVICE,
+ pwszInfFullPath,
+ cInfFullPaths,
+ NULL);
+ }
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, LPCWSTR pwszId, DWORD InfRmFlags)
+{
+ NOREF(pNc);
+ NonStandardLog("Finding NetAdp driver package and trying to uninstall it ...\n");
+
+ VBoxDrvCfgInfUninstallAllF(L"Net", pwszId, InfRmFlags);
+ NonStandardLog("NetAdp is not installed currently\n");
+ return S_OK;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, IN LPCWSTR pwszId)
+{
+ return vboxNetCfgWinNetAdpUninstall(pNc, pwszId, SUOI_FORCEDELETE);
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpInstall(IN INetCfg *pNc,
+ IN LPCWSTR const pwszInfFullPath)
+{
+ NonStandardLog("NetAdp will be installed ...\n");
+ HRESULT hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETADP_ID_WSZ,
+ &GUID_DEVCLASS_NET,
+ &pwszInfFullPath,
+ 1,
+ NULL);
+ return hr;
+}
+
+
+static HRESULT vboxNetCfgWinNetLwfUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
+{
+ INetCfgComponent * pNcc = NULL;
+ HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETLWF_ID, &pNcc);
+ if (hr == S_OK)
+ {
+ NonStandardLog("NetLwf is installed currently, uninstalling ...\n");
+
+ hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
+
+ pNcc->Release();
+ }
+ else if (hr == S_FALSE)
+ {
+ NonStandardLog("NetLwf is not installed currently\n");
+ hr = S_OK;
+ }
+ else
+ {
+ NonStandardLogFlow(("FindComponent failed: %Rhrc\n", hr));
+ hr = S_OK;
+ }
+
+ VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETLWF_ID, InfRmFlags);
+
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfUninstall(IN INetCfg *pNc)
+{
+ return vboxNetCfgWinNetLwfUninstall(pNc, 0);
+}
+
+static void VBoxNetCfgWinFilterLimitWorkaround(void)
+{
+ /*
+ * Need to check if the system has a limit of installed filter drivers. If it
+ * has, bump the limit to 14, which the maximum value supported by Windows 7.
+ * Note that we only touch the limit if it is set to the default value (8).
+ * See @bugref{7899}.
+ */
+ /** @todo r=bird: This code was mixing HRESULT and LSTATUS, checking the return
+ * codes using SUCCEEDED(lrc) instead of lrc == ERROR_SUCCESS. So, it might
+ * have misbehaved on bogus registry content, but worked fine on sane values. */
+ HKEY hKeyNet = NULL;
+ LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Network", 0,
+ KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyNet);
+ if (lrc == ERROR_SUCCESS)
+ {
+ DWORD dwMaxNumFilters = 0;
+ DWORD cbMaxNumFilters = sizeof(dwMaxNumFilters);
+ lrc = RegQueryValueExW(hKeyNet, L"MaxNumFilters", NULL, NULL, (LPBYTE)&dwMaxNumFilters, &cbMaxNumFilters);
+ if (lrc == ERROR_SUCCESS && cbMaxNumFilters == sizeof(dwMaxNumFilters) && dwMaxNumFilters == 8)
+ {
+ dwMaxNumFilters = 14;
+ lrc = RegSetValueExW(hKeyNet, L"MaxNumFilters", 0, REG_DWORD, (LPBYTE)&dwMaxNumFilters, sizeof(dwMaxNumFilters));
+ if (lrc == ERROR_SUCCESS)
+ NonStandardLog("Adjusted the installed filter limit to 14...\n");
+ else
+ NonStandardLog("Failed to set MaxNumFilters, error code %d\n", lrc);
+ }
+ RegCloseKey(hKeyNet);
+ }
+ else
+ NonStandardLog("Failed to open network key, error code %d\n", lrc);
+
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc, IN LPCWSTR const pwszInfFullPath)
+{
+ HRESULT hr = vboxNetCfgWinNetLwfUninstall(pNc, SUOI_FORCEDELETE);
+ if (SUCCEEDED(hr))
+ {
+ VBoxNetCfgWinFilterLimitWorkaround();
+ NonStandardLog("NetLwf will be installed ...\n");
+ hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETLWF_ID,
+ &GUID_DEVCLASS_NETSERVICE,
+ &pwszInfFullPath,
+ 1,
+ NULL);
+ }
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(IN PCWSTR pwszDevName, OUT WCHAR *pwszBuf,
+ IN ULONG cwcBuf, OUT PULONG pcwcNeeded)
+{
+ /* Look for a suffix that we need to preserve. */
+ size_t const cwcDevName = RTUtf16Len(pwszDevName);
+ size_t offSuffix = cwcDevName;
+ while (offSuffix > 0 && pwszDevName[offSuffix - 1] != '#')
+ offSuffix--;
+ size_t const cwcSuffix = pwszDevName[offSuffix] != '#' ? 0 : cwcDevName - offSuffix;
+
+ /* Calculate required buffer size: */
+ size_t cwcNeeded = sizeof(VBOX_CONNECTION_NAME_WSZ) / sizeof(wchar_t) /* includes terminator */
+ + !!cwcSuffix /*space*/ + cwcSuffix;
+ if (pcwcNeeded)
+ *pcwcNeeded = (ULONG)cwcNeeded;
+
+ if (cwcNeeded <= cwcBuf)
+ {
+ memcpy(pwszBuf, VBOX_CONNECTION_NAME_WSZ, sizeof(VBOX_CONNECTION_NAME_WSZ));
+ if (cwcSuffix > 0)
+ {
+ size_t offDst = sizeof(VBOX_CONNECTION_NAME_WSZ) / sizeof(wchar_t) - 1;
+ pwszBuf[offDst++] = ' ';
+ memcpy(&pwszBuf[offDst], &pwszDevName[offSuffix], cwcSuffix * sizeof(wchar_t));
+ pwszBuf[offDst + cwcSuffix] = '\0';
+ }
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+static BOOL vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
+{
+ GUID * const pGuid = (GUID*)pContext;
+ RT_NOREF1(pNc);
+
+ /* Get component's binding. */
+ INetCfgComponentBindings *pNetCfgBindings = NULL;
+ HRESULT hr = pNcc->QueryInterface(IID_INetCfgComponentBindings, (PVOID *)&pNetCfgBindings);
+ if (SUCCEEDED(hr))
+ {
+ /* Get binding path enumerator reference. */
+ IEnumNetCfgBindingPath *pEnumNetCfgBindPath = NULL;
+ hr = pNetCfgBindings->EnumBindingPaths(EBP_BELOW, &pEnumNetCfgBindPath);
+ if (SUCCEEDED(hr))
+ {
+ bool fFoundIface = false;
+ hr = pEnumNetCfgBindPath->Reset();
+ do
+ {
+ INetCfgBindingPath *pNetCfgBindPath = NULL;
+ hr = pEnumNetCfgBindPath->Next(1, &pNetCfgBindPath, NULL);
+ if (hr == S_OK)
+ {
+ IEnumNetCfgBindingInterface *pEnumNetCfgBindIface;
+ hr = pNetCfgBindPath->EnumBindingInterfaces(&pEnumNetCfgBindIface);
+ if (hr == S_OK)
+ {
+ pEnumNetCfgBindIface->Reset();
+ do
+ {
+ INetCfgBindingInterface *pNetCfgBindIfce;
+ hr = pEnumNetCfgBindIface->Next(1, &pNetCfgBindIfce, NULL);
+ if (hr == S_OK)
+ {
+ INetCfgComponent *pNetCfgCompo;
+ hr = pNetCfgBindIfce->GetLowerComponent(&pNetCfgCompo);
+ if (hr == S_OK)
+ {
+ ULONG uComponentStatus;
+ hr = pNetCfgCompo->GetDeviceStatus(&uComponentStatus);
+ if (hr == S_OK)
+ {
+ GUID guid;
+ hr = pNetCfgCompo->GetInstanceGuid(&guid);
+ if ( hr == S_OK
+ && guid == *pGuid)
+ {
+ hr = pNetCfgBindings->MoveAfter(pNetCfgBindPath, NULL);
+ if (FAILED(hr))
+ NonStandardLogFlow(("Unable to move interface: %Rhrc\n", hr));
+ fFoundIface = true;
+
+ /*
+ * Enable binding paths for host-only adapters bound to bridged filter
+ * (see @bugref{8140}).
+ */
+ HRESULT hr2;
+ LPWSTR pwszHwId = NULL;
+ if ((hr2 = pNcc->GetId(&pwszHwId)) != S_OK)
+ NonStandardLogFlow(("Failed to get HW ID: %Rhrc\n", hr2));
+ else
+ {
+ /** @todo r=bird: Original was:
+ * _wcsnicmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID, sizeof(VBOXNETCFGWIN_NETLWF_ID)/2)
+ * which is the same as _wcsicmp. Not sure if this was accidental, but it's not the
+ * only one in this code area (VBoxNetFltNobj.cpp had some too IIRC). */
+ if (RTUtf16ICmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID) != 0)
+ NonStandardLogFlow(("Ignoring component %ls\n", pwszHwId));
+ else if ((hr2 = pNetCfgBindPath->IsEnabled()) != S_FALSE)
+ NonStandardLogFlow(("Already enabled binding path: %Rhrc\n", hr2));
+ else if ((hr2 = pNetCfgBindPath->Enable(TRUE)) != S_OK)
+ NonStandardLogFlow(("Failed to enable binding path: %Rhrc\n", hr2));
+ else
+ NonStandardLogFlow(("Enabled binding path\n"));
+ CoTaskMemFree(pwszHwId);
+ }
+ }
+ }
+ pNetCfgCompo->Release();
+ }
+ else
+ NonStandardLogFlow(("GetLowerComponent failed: %Rhrc\n", hr));
+ pNetCfgBindIfce->Release();
+ }
+ else
+ {
+ if (hr == S_FALSE) /* No more binding interfaces? */
+ hr = S_OK;
+ else
+ NonStandardLogFlow(("Next binding interface failed: %Rhrc\n", hr));
+ break;
+ }
+ } while (!fFoundIface);
+ pEnumNetCfgBindIface->Release();
+ }
+ else
+ NonStandardLogFlow(("EnumBindingInterfaces failed: %Rhrc\n", hr));
+ pNetCfgBindPath->Release();
+ }
+ else
+ {
+ if (hr == S_FALSE) /* No more binding paths? */
+ hr = S_OK;
+ else
+ NonStandardLogFlow(("Next bind path failed: %Rhrc\n", hr));
+ break;
+ }
+ } while (!fFoundIface);
+ pEnumNetCfgBindPath->Release();
+ }
+ else
+ NonStandardLogFlow(("EnumBindingPaths failed: %Rhrc\n", hr));
+ pNetCfgBindings->Release();
+ }
+ else
+ NonStandardLogFlow(("QueryInterface for IID_INetCfgComponentBindings failed: %Rhrc\n", hr));
+ return TRUE;
+}
+
+/** Callback for SetupDiSetDeviceInstallParams used by
+ * vboxNetCfgWinCreateHostOnlyNetworkInterface */
+static UINT WINAPI vboxNetCfgWinPspFileCallback(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
+{
+ switch (Notification)
+ {
+ case SPFILENOTIFY_TARGETNEWER:
+ case SPFILENOTIFY_TARGETEXISTS:
+ return TRUE;
+ }
+ return SetupDefaultQueueCallbackW(Context, Notification, Param1, Param2);
+}
+
+
+
+
+/* The original source of the VBoxNetAdp adapter creation/destruction code has the following copyright: */
+/*
+ Copyright 2004 by the Massachusetts Institute of Technology
+
+ All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation, and that the name of the Massachusetts
+ Institute of Technology (M.I.T.) not be used in advertising or publicity
+ pertaining to distribution of the software without specific, written
+ prior permission.
+
+ M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ SOFTWARE.
+*/
+
+
+/**
+ * Use the IShellFolder API to rename the connection.
+ */
+static HRESULT rename_shellfolder(PCWSTR pwszGuid, PCWSTR pwszNewName)
+{
+ /* Build the display name in the form "::{GUID}". Do this first in case it overflows. */
+ WCHAR wszAdapterGuid[MAX_PATH + 2] = {0};
+ ssize_t cwc = RTUtf16Printf(wszAdapterGuid, RT_ELEMENTS(wszAdapterGuid), "::%ls", pwszGuid);
+ if (cwc < 0)
+ return E_INVALIDARG;
+
+ /* This is the GUID for the network connections folder. It is constant.
+ * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
+ const GUID MY_CLSID_NetworkConnections = {
+ 0x7007ACC7, 0x3202, 0x11D1, {
+ 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
+ }
+ };
+
+ /* Create an instance of the network connections folder. */
+ IShellFolder *pShellFolder = NULL;
+ HRESULT hr = CoCreateInstance(MY_CLSID_NetworkConnections, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder,
+ reinterpret_cast<LPVOID *>(&pShellFolder));
+ if (SUCCEEDED(hr))
+ {
+ /* Parse the display name. */
+ LPITEMIDLIST pidl = NULL;
+ hr = pShellFolder->ParseDisplayName(NULL, NULL, wszAdapterGuid, NULL, &pidl, NULL);
+ if (SUCCEEDED(hr))
+ hr = pShellFolder->SetNameOf(NULL, pidl, pwszNewName, SHGDN_NORMAL, &pidl);
+ CoTaskMemFree(pidl);
+ pShellFolder->Release();
+ }
+ return hr;
+}
+
+/**
+ * Loads a system DLL.
+ *
+ * @returns Module handle or NULL
+ * @param pwszName The DLL name.
+ */
+static HMODULE loadSystemDll(const wchar_t *pwszName)
+{
+ WCHAR wszPath[MAX_PATH];
+ UINT cwcPath = GetSystemDirectoryW(wszPath, RT_ELEMENTS(wszPath));
+ size_t cwcName = RTUtf16Len(pwszName) + 1;
+ if (cwcPath + 1 + cwcName > RT_ELEMENTS(wszPath))
+ return NULL;
+
+ wszPath[cwcPath++] = '\\';
+ memcpy(&wszPath[cwcPath], pwszName, cwcName * sizeof(wszPath[0]));
+ return LoadLibraryW(wszPath);
+}
+
+static bool vboxNetCfgWinDetectStaleConnection(PCWSTR pwszName)
+{
+ HKEY hKeyAdapters = NULL;
+ LSTATUS lrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
+ 0 /*ulOptions*/, KEY_ALL_ACCESS, &hKeyAdapters);
+ if (lrc != ERROR_SUCCESS)
+ return false;
+
+ bool fFailureImminent = false;
+ for (DWORD i = 0; !fFailureImminent; ++i)
+ {
+ WCHAR wszAdapterSubKeyName[MAX_PATH];
+ DWORD cwcAdapterSubKeyName = MAX_PATH;
+ lrc = RegEnumKeyEx(hKeyAdapters, i, wszAdapterSubKeyName, &cwcAdapterSubKeyName, NULL, NULL, NULL, NULL);
+ if (lrc != ERROR_SUCCESS)
+ break;
+
+ HKEY hKeyAdapter = NULL;
+ lrc = RegOpenKeyEx(hKeyAdapters, wszAdapterSubKeyName, 0, KEY_ALL_ACCESS, &hKeyAdapter);
+ if (lrc == ERROR_SUCCESS)
+ {
+ HKEY hKeyConnection = NULL;
+ lrc = RegOpenKeyEx(hKeyAdapter, L"Connection", 0, KEY_ALL_ACCESS, &hKeyConnection);
+ if (lrc == ERROR_SUCCESS)
+ {
+ WCHAR wszCurName[MAX_PATH + 1];
+ DWORD cbCurName = sizeof(wszCurName) - sizeof(WCHAR);
+ DWORD dwType = REG_SZ;
+ lrc = RegQueryValueEx(hKeyConnection, L"Name", NULL, NULL, (LPBYTE)wszCurName, &cbCurName);
+ if ( lrc == ERROR_SUCCESS
+ /** @todo r=bird: The original code didn't do any value type checks, thus allowing all SZ types. */
+ && (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ))
+ {
+ wszCurName[MAX_PATH] = '\0'; /* returned values doesn't necessarily need to be terminated */
+
+ if (RTUtf16ICmp(pwszName, pwszName) == 0)
+ fFailureImminent = true;
+ }
+ RegCloseKey(hKeyConnection);
+ }
+ RegCloseKey(hKeyAdapter);
+ }
+ }
+ RegCloseKey(hKeyAdapters);
+
+ return fFailureImminent;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(LPWSTR pwszGuid, PCWSTR NewName)
+{
+ /*
+ * Before attempting to rename the connection, check if there is a stale
+ * connection with the same name. We must return ok, so the rest of
+ * configuration process proceeds normally.
+ */
+ if (vboxNetCfgWinDetectStaleConnection(NewName))
+ return S_OK;
+
+ /* First try the IShellFolder interface, which was unimplemented
+ * for the network connections folder before XP. */
+ HRESULT hrc = rename_shellfolder(pwszGuid, NewName);
+ if (hrc == E_NOTIMPL)
+ {
+/** @todo that code doesn't seem to work! */
+ /* The IShellFolder interface is not implemented on this platform.
+ * Try the (undocumented) HrRenameConnection API in the netshell
+ * library. */
+ CLSID clsid;
+ hrc = CLSIDFromString((LPOLESTR)pwszGuid, &clsid);
+ if (FAILED(hrc))
+ return E_FAIL;
+
+ HINSTANCE hNetShell = loadSystemDll(L"netshell.dll");
+ if (hNetShell == NULL)
+ return E_FAIL;
+
+ typedef HRESULT (WINAPI *PFNHRRENAMECONNECTION)(const GUID *, PCWSTR);
+ PFNHRRENAMECONNECTION pfnRenameConnection = (PFNHRRENAMECONNECTION)GetProcAddress(hNetShell, "HrRenameConnection");
+ if (pfnRenameConnection != NULL)
+ hrc = pfnRenameConnection(&clsid, NewName);
+ else
+ hrc = E_FAIL;
+
+ FreeLibrary(hNetShell);
+ }
+ if (FAILED(hrc))
+ return hrc;
+ return S_OK;
+}
+
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pBstrErrMsg)
+{
+ HRESULT hrc = S_OK;
+ com::Bstr bstrError;
+
+ do /* break non-loop */
+ {
+ WCHAR wszPnPInstanceId[512] = {0};
+
+ /*
+ * We have to find the device instance ID through a registry search
+ */
+ HKEY hkeyNetwork = NULL;
+ HKEY hkeyConnection = NULL;
+ do /* another non-loop for breaking out of */
+ {
+ WCHAR wszGuid[50];
+ int cwcGuid = StringFromGUID2(*pGUID, wszGuid, RT_ELEMENTS(wszGuid));
+ if (!cwcGuid)
+ SetErrBreak(("Failed to create a Guid string"));
+
+ WCHAR wszRegLocation[128 + RT_ELEMENTS(wszGuid)];
+ RTUtf16Printf(wszRegLocation, RT_ELEMENTS(wszRegLocation),
+ "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%ls", wszGuid);
+
+ LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegLocation, 0, KEY_READ, &hkeyNetwork);
+ if (lrc != ERROR_SUCCESS || !hkeyNetwork)
+ SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u [1]", wszRegLocation, lrc));
+
+ lrc = RegOpenKeyExW(hkeyNetwork, L"Connection", 0, KEY_READ, &hkeyConnection);
+ if (lrc != ERROR_SUCCESS || !hkeyConnection)
+ SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u [2]", wszRegLocation, lrc));
+
+ DWORD cbValue = sizeof(wszPnPInstanceId) - sizeof(WCHAR);
+ DWORD dwType = ~0U;
+ lrc = RegQueryValueExW(hkeyConnection, L"PnPInstanceID", NULL, &dwType, (LPBYTE)wszPnPInstanceId, &cbValue);
+ if (lrc != ERROR_SUCCESS || dwType != REG_SZ)
+ SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u, dwType=%u [3]",
+ wszRegLocation, lrc, dwType));
+ } while (0);
+
+ if (hkeyConnection)
+ RegCloseKey(hkeyConnection);
+ if (hkeyNetwork)
+ RegCloseKey(hkeyNetwork);
+ if (FAILED(hrc))
+ break;
+
+ /*
+ * Now we are going to enumerate all network devices and
+ * wait until we encounter the right device instance ID
+ */
+ HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
+ do /* break-only, not-a-loop */
+ {
+ BOOL ok;
+
+ /* initialize the structure size */
+ SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
+
+ /* copy the net class GUID */
+ GUID netGuid;
+ memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
+
+ /* return a device info set contains all installed devices of the Net class */
+ hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
+ if (hDeviceInfo == INVALID_HANDLE_VALUE)
+ SetErrBreak(("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
+
+ /* Enumerate the driver info list. */
+ bool fFound = false;
+ for (DWORD index = 0; !fFound; index++)
+ {
+ if (!SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+
+ /* try to get the hardware ID registry property */
+ DWORD cbValue = 0;
+ if (SetupDiGetDeviceRegistryPropertyW(hDeviceInfo,
+ &DeviceInfoData,
+ SPDRP_HARDWAREID,
+ NULL,
+ NULL,
+ 0,
+ &cbValue))
+ continue; /* Something is wrong. This shouldn't have worked with a NULL buffer! */
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ continue;
+
+ WCHAR *pwszzDeviceHwId = (WCHAR *)RTMemAllocZ(cbValue + sizeof(WCHAR) * 2);
+ if (!pwszzDeviceHwId)
+ break;
+ if (SetupDiGetDeviceRegistryPropertyW(hDeviceInfo,
+ &DeviceInfoData,
+ SPDRP_HARDWAREID,
+ NULL,
+ (PBYTE)pwszzDeviceHwId,
+ cbValue,
+ &cbValue))
+ {
+ /* search the string list. */
+ for (WCHAR *pwszCurHwId = pwszzDeviceHwId;
+ (uintptr_t)pwszCurHwId - (uintptr_t)pwszzDeviceHwId < cbValue && *pwszCurHwId != L'\0';
+ pwszCurHwId += RTUtf16Len(pwszCurHwId) + 1)
+ if (RTUtf16ICmp(DRIVERHWID, pwszCurHwId) == 0)
+ {
+ /* get the device instance ID */
+ WCHAR wszDevId[MAX_DEVICE_ID_LEN];
+ if (CM_Get_Device_IDW(DeviceInfoData.DevInst, wszDevId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
+ {
+ /* compare to what we determined before */
+ if (RTUtf16Cmp(wszDevId, wszPnPInstanceId) == 0)
+ {
+ fFound = true;
+ break;
+ }
+ }
+ }
+ }
+ RTMemFree(pwszzDeviceHwId);
+ }
+
+ if (!fFound)
+ SetErrBreak(("Host Interface Network driver not found (0x%08X)", GetLastError()));
+
+ ok = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
+ if (!ok)
+ SetErrBreak(("SetupDiSetSelectedDevice failed (0x%08X)", GetLastError()));
+
+ ok = SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
+ if (!ok)
+ SetErrBreak(("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)", GetLastError()));
+ } while (0);
+
+ /* clean up the device info set */
+ if (hDeviceInfo != INVALID_HANDLE_VALUE)
+ SetupDiDestroyDeviceInfoList (hDeviceInfo);
+ } while (0);
+
+ if (pBstrErrMsg)
+ {
+ *pBstrErrMsg = NULL;
+ if (bstrError.isNotEmpty())
+ bstrError.detachToEx(pBstrErrMsg);
+ }
+ return hrc;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pfRebootRequired, LPCWSTR pcsxwId)
+{
+ return VBoxDrvCfgDrvUpdate(pcsxwId, pcsxwInf, pfRebootRequired);
+}
+
+static const char *vboxNetCfgWinGetStateText(DWORD dwState)
+{
+ switch (dwState)
+ {
+ case SERVICE_STOPPED: return "is not running";
+ case SERVICE_STOP_PENDING: return "is stopping";
+ case SERVICE_CONTINUE_PENDING: return "continue is pending";
+ case SERVICE_PAUSE_PENDING: return "pause is pending";
+ case SERVICE_PAUSED: return "is paused";
+ case SERVICE_RUNNING: return "is running";
+ case SERVICE_START_PENDING: return "is starting";
+ }
+ return "state is invalid";
+}
+
+static DWORD vboxNetCfgWinGetNetSetupState(SC_HANDLE hService)
+{
+ SERVICE_STATUS status;
+ status.dwCurrentState = SERVICE_RUNNING;
+ if (hService) {
+ if (QueryServiceStatus(hService, &status))
+ NonStandardLogFlow(("NetSetupSvc %s\n", vboxNetCfgWinGetStateText(status.dwCurrentState)));
+ else
+ NonStandardLogFlow(("QueryServiceStatus failed (0x%x)\n", GetLastError()));
+ }
+ return status.dwCurrentState;
+}
+
+DECLINLINE(bool) vboxNetCfgWinIsNetSetupRunning(SC_HANDLE hService)
+{
+ return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_RUNNING;
+}
+
+DECLINLINE(bool) vboxNetCfgWinIsNetSetupStopped(SC_HANDLE hService)
+{
+ return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_STOPPED;
+}
+
+typedef struct
+{
+ BSTR bstrName;
+ GUID *pGuid;
+ HRESULT hr;
+} RENAMING_CONTEXT;
+
+static BOOL vboxNetCfgWinRenameHostOnlyNetworkInterface(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
+{
+ RT_NOREF1(pNc);
+ RENAMING_CONTEXT *pParams = (RENAMING_CONTEXT *)pContext;
+
+ GUID guid;
+ pParams->hr = pNcc->GetInstanceGuid(&guid);
+ if ( pParams->hr == S_OK && guid == *pParams->pGuid)
+ {
+ /* Located our component, rename it */
+ pParams->hr = pNcc->SetDisplayName(pParams->bstrName);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Enumerate all host-only adapters collecting their names into a set, then
+ * come up with the next available name by taking the first unoccupied index.
+ */
+static HRESULT vboxNetCfgWinNextAvailableDevName(com::Bstr *pbstrName)
+{
+ SP_DEVINFO_DATA DeviceInfoData = { sizeof(SP_DEVINFO_DATA) };
+ HDEVINFO hDeviceInfoSet = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT);
+ if (hDeviceInfoSet == INVALID_HANDLE_VALUE)
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ typedef struct VBOXDEVNAMEENTRY
+ {
+ RTLISTNODE ListEntry;
+ WCHAR wszDevName[64];
+ WCHAR wcZeroParanoia;
+ } VBOXDEVNAMEENTRY;
+
+#if 0
+ /*
+ * Build a list of names starting with HOSTONLY_ADAPTER_NAME_WSZ belonging to our device.
+ */
+ RTLISTANCHOR Head; /* VBOXDEVNAMEENTRY */
+ RTListInit(&Head);
+ HRESULT hrc = S_OK;
+#else
+ /*
+ * Build a bitmap of in-use index values of devices starting with HOSTONLY_ADAPTER_NAME_WSZ.
+ * Reserving 0 for one w/o a suffix, and marking 1 as unusable.
+ */
+ uint64_t bmIndexes[_32K / 64]; /* 4KB - 32767 device should be sufficient. */
+ RT_ZERO(bmIndexes);
+ ASMBitSet(&bmIndexes, 1);
+#endif
+ for (DWORD i = 0; SetupDiEnumDeviceInfo(hDeviceInfoSet, i, &DeviceInfoData); ++i)
+ {
+ /* Should be more than enough for both our device id and our device name, we do not care about the rest */
+ VBOXDEVNAMEENTRY Entry = { { 0, 0 }, L"", 0 }; /* (initialize it to avoid the wrath of asan) */
+ if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID,
+ NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL))
+ continue;
+
+ /* Ignore everything except our host-only adapters */
+ if (RTUtf16ICmp(Entry.wszDevName, DRIVERHWID) == 0)
+ {
+ if ( SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_FRIENDLYNAME,
+ NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL)
+ || SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_DEVICEDESC,
+ NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL))
+ {
+ /* We can ignore any host-only adapter with a non-standard name. */
+ if (RTUtf16NICmp(Entry.wszDevName, HOSTONLY_ADAPTER_NAME_WSZ,
+ RT_ELEMENTS(HOSTONLY_ADAPTER_NAME_WSZ) - 1) == 0)
+ {
+#if 0
+ VBOXDEVNAMEENTRY *pEntry = (VBOXDEVNAMEENTRY *)RTMemDup(&Entry, sizeof(Entry));
+ if (pEntry)
+ RTListAppend(&Head, &pEntry->ListEntry);
+ else
+ {
+ hrc = E_OUTOFMEMORY;
+ break;
+ }
+#else
+ WCHAR const *pwc = &Entry.wszDevName[RT_ELEMENTS(HOSTONLY_ADAPTER_NAME_WSZ) - 1];
+
+ /* skip leading space */
+ WCHAR wc = *pwc;
+ while (wc == L' ' || wc == L'\t' || wc == L'\n' || wc == L'\r')
+ wc = *++pwc;
+
+ /* If end of string, use index 0. */
+ if (wc == L'\0')
+ ASMBitSet(bmIndexes, 0);
+
+ /* Hash and digit? */
+ else if (wc == L'#')
+ {
+ wc = *++pwc;
+ while (wc == L' ' || wc == L'\t' || wc == L'\n' || wc == L'\r') /* just in case */
+ wc = *++pwc;
+ if (wc >= L'0' && wc <= L'9')
+ {
+ /* Convert what we can to a number and mark it as allocated in the bitmap. */
+ uint64_t uIndex = wc - L'0';
+ while ((wc = *++pwc) >= L'0' && wc <= L'9')
+ uIndex = uIndex * 10 + wc - L'0';
+ if (uIndex < sizeof(bmIndexes) * 8 && uIndex > 0)
+ ASMBitSet(bmIndexes, (int32_t)uIndex);
+ }
+ }
+#endif
+ }
+ }
+ }
+ }
+#if 0
+ if (SUCCEEDED(hrc))
+ {
+ /*
+ * First try a name w/o an index, then try index #2 and up.
+ *
+ * Note! We have to use ASCII/UTF-8 strings here as Bstr will confuse WCHAR
+ * with BSTR/OLECHAR strings and use SysAllocString to duplicate it .
+ */
+ char szName[sizeof(HOSTONLY_ADAPTER_NAME_SZ " #4294967296") + 32] = HOSTONLY_ADAPTER_NAME_SZ;
+ size_t const cchBase = sizeof(HOSTONLY_ADAPTER_NAME_SZ) - 1;
+ for (DWORD idx = 2;; idx++)
+ {
+ bool fFound = false;
+ VBOXDEVNAMEENTRY *pCur;
+ RTListForEach(&Head, pCur, VBOXDEVNAMEENTRY, ListEntry)
+ {
+ fFound = RTUtf16ICmpAscii(pCur->wszDevName, szName) == 0;
+ if (fFound)
+ {
+ hrc = pbstrName->assignEx(szName);
+ break;
+ }
+ }
+ if (fFound)
+ break;
+ RTStrPrintf(&szName[cchBase], sizeof(szName) - cchBase, " #%u", idx);
+ }
+ }
+
+ VBOXDEVNAMEENTRY *pFirst;
+ while ((pFirst = RTListRemoveFirst(&Head, VBOXDEVNAMEENTRY, ListEntry)) != NULL)
+ RTMemFree(pFirst);
+
+#else
+ /*
+ * Find an unused index value and format the corresponding name.
+ */
+ HRESULT hrc;
+ int32_t iBit = ASMBitFirstClear(bmIndexes, sizeof(bmIndexes) * 8);
+ if (iBit >= 0)
+ {
+ if (iBit == 0)
+ hrc = pbstrName->assignEx(HOSTONLY_ADAPTER_NAME_SZ); /* Not _WSZ! */
+ else
+ hrc = pbstrName->printfNoThrow(HOSTONLY_ADAPTER_NAME_SZ " #%u", iBit);
+ }
+ else
+ {
+ NonStandardLogFlow(("vboxNetCfgWinNextAvailableDevName: no unused index in the first 32K!\n"));
+ hrc = E_FAIL;
+ }
+#endif
+
+ if (hDeviceInfoSet)
+ SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
+ return hrc;
+}
+
+static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile,
+ IN BSTR pBstrDesiredName,
+ OUT GUID *pGuid, OUT BSTR *pBstrName, OUT BSTR *pBstrErrMsg)
+{
+ com::Bstr bstrError;
+
+ /* Determine the interface name. We make a copy of the input here for
+ renaming reasons, see futher down. */
+ com::Bstr bstrNewInterfaceName;
+ HRESULT hrc;
+ if (SysStringLen(pBstrDesiredName) != 0)
+ hrc = bstrNewInterfaceName.assignEx(pBstrDesiredName);
+ else
+ {
+ hrc = vboxNetCfgWinNextAvailableDevName(&bstrNewInterfaceName);
+ if (FAILED(hrc))
+ NonStandardLogFlow(("vboxNetCfgWinNextAvailableDevName failed with 0x%x\n", hrc));
+ }
+ if (FAILED(hrc))
+ return hrc;
+
+ WCHAR wszCfgGuidString[50] = {0};
+ WCHAR wszDevName[256 + 1] = {0};
+ SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
+ HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
+ PVOID pQueueCallbackContext = NULL;
+ BOOL fRegistered = FALSE;
+ BOOL destroyList = FALSE;
+ HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
+ LSTATUS lrcRet = ERROR_SUCCESS; /* the */
+
+ do /* non-loop, for breaking. */
+ {
+ /* copy the net class GUID */
+ GUID netGuid;
+ memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
+
+ /* Create an empty device info set associated with the net class GUID: */
+ hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
+ if (hDeviceInfo == INVALID_HANDLE_VALUE)
+ SetErrBreak(("SetupDiCreateDeviceInfoList failed (%Rwc)", GetLastError()));
+
+ /* Translate the GUID to a class name: */
+ WCHAR wszClassName[MAX_PATH];
+ if (!SetupDiClassNameFromGuid(&netGuid, wszClassName, MAX_PATH, NULL))
+ SetErrBreak(("SetupDiClassNameFromGuid failed (%Rwc)", GetLastError()));
+
+ /* Create a device info element and add the new device instance key to registry: */
+ if (!SetupDiCreateDeviceInfo(hDeviceInfo, wszClassName, &netGuid, NULL, NULL, DICD_GENERATE_ID, &DeviceInfoData))
+ SetErrBreak(("SetupDiCreateDeviceInfo failed (%Rwc)", GetLastError()));
+
+ /* Select the newly created device info to be the currently selected member: */
+ if (!SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData))
+ SetErrBreak(("SetupDiSetSelectedDevice failed (%Rwc)", GetLastError()));
+
+ SP_DEVINSTALL_PARAMS DeviceInstallParams;
+ if (pwszInfPath)
+ {
+ /* get the device install parameters and disable filecopy */
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
+ {
+ memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
+ size_t pathLenght = wcslen(pwszInfPath) + 1/* null terminator */;
+ if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
+ {
+ memcpy(DeviceInstallParams.DriverPath, pwszInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
+
+ if (fIsInfPathFile)
+ DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
+
+ if (!SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
+ {
+ NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed (%Rwc)\n", GetLastError()));
+ break;
+ }
+ }
+ else
+ {
+ NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
+ break;
+ }
+ }
+ else
+ NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed (%Rwc)\n", GetLastError()));
+ }
+
+ /* build a list of class drivers */
+ if (!SetupDiBuildDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER))
+ SetErrBreak(("SetupDiBuildDriverInfoList failed (%Rwc)", GetLastError()));
+
+ destroyList = TRUE;
+
+ /*
+ * Enumerate the driver info list.
+ */
+ /* For our purposes, 2k buffer is more than enough to obtain the
+ hardware ID of the VBoxNetAdp driver. */ /** @todo r=bird: The buffer isn't 2KB, it's 8KB, but whatever. */
+ DWORD detailBuf[2048];
+ SP_DRVINFO_DATA DriverInfoData = { sizeof(DriverInfoData) };
+ bool fFound = false;
+ for (DWORD index = 0; !fFound; index++)
+ {
+ /* If the function fails with last error set to ERROR_NO_MORE_ITEMS,
+ then we have reached the end of the list. Otherwise there was
+ something wrong with this particular driver. */
+ if (!SetupDiEnumDriverInfo(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER, index, &DriverInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+
+ /* if we successfully find the hardware ID and it turns out to
+ * be the one for the loopback driver, then we are done. */
+ PSP_DRVINFO_DETAIL_DATA_W pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA_W)detailBuf;
+ pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+ DWORD cbValue = 0;
+ if (SetupDiGetDriverInfoDetailW(hDeviceInfo,
+ &DeviceInfoData,
+ &DriverInfoData,
+ pDriverInfoDetail,
+ sizeof(detailBuf) - sizeof(detailBuf[0]),
+ &cbValue))
+ {
+ /* Sure that the HardwareID string list is properly zero terminated (paranoia). */
+ detailBuf[RT_ELEMENTS(detailBuf) - 1] = 0; AssertCompile(sizeof(detailBuf[0]) == sizeof(WCHAR) * 2);
+
+ /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the whole
+ list and see if there is a match somewhere: */
+ for (WCHAR *pwszCurHwId = pDriverInfoDetail->HardwareID;
+ (uintptr_t)pwszCurHwId - (uintptr_t)pDriverInfoDetail < cbValue && *pwszCurHwId != L'\0';
+ pwszCurHwId += RTUtf16Len(pwszCurHwId) + 1)
+ if (RTUtf16ICmp(DRIVERHWID, pwszCurHwId) == 0)
+ {
+ fFound = true;
+ break;
+ }
+ }
+ }
+
+ if (!fFound)
+ SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
+
+ /* set the loopback driver to be the currently selected */
+ if (!SetupDiSetSelectedDriver(hDeviceInfo, &DeviceInfoData, &DriverInfoData))
+ SetErrBreak(("SetupDiSetSelectedDriver failed (%u)", GetLastError()));
+
+ /* register the phantom device to prepare for install */
+ if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDeviceInfo, &DeviceInfoData))
+ SetErrBreak(("SetupDiCallClassInstaller failed (%u)", GetLastError()));
+
+ /* registered, but remove if errors occur in the following code */
+ fRegistered = TRUE;
+
+ /* ask the installer if we can install the device */
+ if (!SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, hDeviceInfo, &DeviceInfoData))
+ {
+ if (GetLastError() != ERROR_DI_DO_DEFAULT)
+ SetErrBreak(("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (%u)", GetLastError()));
+ /* that's fine */
+ }
+
+ /* get the device install parameters and disable filecopy */
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
+ {
+ pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
+ if (pQueueCallbackContext)
+ {
+ DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
+ DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
+ if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("SetupDiSetDeviceInstallParamsW failed, winEr (%d)\n", winEr));
+ Assert(0);
+ }
+ }
+ else
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr));
+ }
+ }
+ else
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
+ }
+
+ /* install the files first */
+ if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, hDeviceInfo, &DeviceInfoData))
+ SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (%Rwc)", GetLastError()));
+
+ /* get the device install parameters and disable filecopy */
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
+ {
+ DeviceInstallParams.Flags |= DI_NOFILECOPY;
+ if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
+ SetErrBreak(("SetupDiSetDeviceInstallParamsW failed (%Rwc)", GetLastError()));
+ }
+ /** @todo r=bird: Why isn't SetupDiGetDeviceInstallParams failure fatal here? */
+
+ /*
+ * Register any device-specific co-installers for this device,
+ */
+ if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, hDeviceInfo, &DeviceInfoData))
+ SetErrBreak(("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (%Rwc)", GetLastError()));
+
+ /*
+ * install any installer-specified interfaces.
+ * and then do the real install
+ */
+ if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, hDeviceInfo, &DeviceInfoData))
+ SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (%Rwc)", GetLastError()));
+
+ if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, hDeviceInfo, &DeviceInfoData))
+ SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (%Rwc)", GetLastError()));
+
+ /*
+ * Query the instance ID; on Windows 10, the registry key may take a short
+ * while to appear. Microsoft recommends waiting for up to 5 seconds, but
+ * we want to be on the safe side, so let's wait for 20 seconds. Waiting
+ * longer is harmful as network setup service will shut down after a period
+ * of inactivity.
+ */
+ for (int retries = 0; retries < 2 * 20; ++retries)
+ {
+ Sleep(500); /* half second */
+
+ /* Figure out NetCfgInstanceId */
+ hkey = SetupDiOpenDevRegKey(hDeviceInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ);
+ if (hkey == INVALID_HANDLE_VALUE)
+ break;
+
+ DWORD cbSize = sizeof(wszCfgGuidString);
+ DWORD dwValueType = 0;
+ lrcRet = RegQueryValueExW(hkey, L"NetCfgInstanceId", NULL, &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
+ /* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
+ if (lrcRet != ERROR_FILE_NOT_FOUND)
+ break;
+
+ RegCloseKey(hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+ }
+
+ if (lrcRet == ERROR_FILE_NOT_FOUND)
+ {
+ hrc = E_ABORT;
+ break;
+ }
+
+ /*
+ * We need to check 'hkey' after we check 'lrcRet' to distinguish the case
+ * of failed SetupDiOpenDevRegKey from the case when we timed out.
+ */
+ if (hkey == INVALID_HANDLE_VALUE)
+ SetErrBreak(("SetupDiOpenDevRegKey failed (%Rwc)", GetLastError()));
+
+ if (lrcRet != ERROR_SUCCESS)
+ SetErrBreak(("Querying NetCfgInstanceId failed (%Rwc)", lrcRet));
+
+ NET_LUID luid;
+ HRESULT hrcSMRes = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
+
+ /* Close the key as soon as possible. See @bugref{7973}. */
+ RegCloseKey(hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+
+ if (FAILED(hrcSMRes))
+ {
+ /*
+ * The setting of Metric is not very important functionality,
+ * So we will not break installation process due to this error.
+ */
+ NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface: Warning! "
+ "vboxNetCfgWinGetInterfaceLUID failed, default metric for new interface will not be set: %Rhrc\n",
+ hrcSMRes));
+ }
+ else
+ {
+ /*
+ * Set default metric value of interface to fix multicast issue
+ * See @bugref{6379} for details.
+ */
+ hrcSMRes = vboxNetCfgWinSetupMetric(&luid);
+ if (FAILED(hrcSMRes))
+ {
+ /*
+ * The setting of Metric is not very important functionality,
+ * So we will not break installation process due to this error.
+ */
+ NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface: Warning! "
+ "vboxNetCfgWinSetupMetric failed, default metric for new interface will not be set: %Rhrc\n",
+ hrcSMRes));
+ }
+ }
+
+ /*
+ * We need to query the device name after we have succeeded in querying its
+ * instance ID to avoid similar waiting-and-retrying loop (see @bugref{7973}).
+ */
+ if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
+ SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
+ NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
+ (PBYTE)wszDevName, /*OUT PBYTE PropertyBuffer,*/
+ sizeof(wszDevName) - sizeof(WCHAR), /* IN DWORD PropertyBufferSize,*/
+ NULL /*OUT PDWORD RequiredSize OPTIONAL*/ ))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr != ERROR_INVALID_DATA)
+ SetErrBreak(("SetupDiGetDeviceRegistryProperty failed (%Rwc)", dwErr));
+
+ RT_ZERO(wszDevName);
+ if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
+ SPDRP_DEVICEDESC, /* IN DWORD Property,*/
+ NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
+ (PBYTE)wszDevName, /*OUT PBYTE PropertyBuffer,*/
+ sizeof(wszDevName) - sizeof(WCHAR), /* IN DWORD PropertyBufferSize,*/
+ NULL /*OUT PDWORD RequiredSize OPTIONAL*/ ))
+ SetErrBreak(("SetupDiGetDeviceRegistryProperty failed (%Rwc)", GetLastError()));
+ }
+
+ /* No need to rename the device if the names match. */
+ if (RTUtf16Cmp(bstrNewInterfaceName.raw(), wszDevName) == 0)
+ bstrNewInterfaceName.setNull();
+
+#ifdef VBOXNETCFG_DELAYEDRENAME
+ /* Re-use wszDevName for device instance id retrieval. */
+ DWORD cwcReturned = 0;
+ RT_ZERO(wszDevName);
+ if (!SetupDiGetDeviceInstanceIdW(hDeviceInfo, &DeviceInfoData, wszDevName, RT_ELEMENTS(wszDevName) - 1, &cwcReturned))
+ SetErrBreak(("SetupDiGetDeviceInstanceId failed (%Rwc)", GetLastError()));
+#endif /* VBOXNETCFG_DELAYEDRENAME */
+ } while (0);
+
+ /*
+ * Cleanup.
+ */
+ if (hkey != INVALID_HANDLE_VALUE)
+ RegCloseKey(hkey);
+
+ if (pQueueCallbackContext)
+ SetupTermDefaultQueueCallback(pQueueCallbackContext);
+
+ if (hDeviceInfo != INVALID_HANDLE_VALUE)
+ {
+ /* an error has occurred, but the device is registered, we must remove it */
+ if (lrcRet != ERROR_SUCCESS && fRegistered)
+ SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
+
+ SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
+
+ /* destroy the driver info list */
+#if 0
+ /* I've remove this, as I was consistently getting crashes in
+ * SetupDiDestroyDeviceInfoList otherwise during MSI installation
+ * (W10 build 19044, VBox r153431 + nocrt changes).
+ *
+ * Some details from windbg:
+ *
+ * (175e8.1596c): Access violation - code c0000005 (first chance)
+ * First chance exceptions are reported before any exception handling.
+ * This exception may be expected and handled.
+ * SETUPAPI!DereferenceClassDriverList+0x4e:
+ * 00007ffa`83e2a42a 834008ff add dword ptr [rax+8],0FFFFFFFFh ds:00000000`00000008=????????
+ * 0:006> k
+ * # Child-SP RetAddr Call Site
+ * 00 0000007e`ccd7c070 00007ffa`83e2a287 SETUPAPI!DereferenceClassDriverList+0x4e
+ * 01 0000007e`ccd7c0a0 00007ffa`56b96bd3 SETUPAPI!SetupDiDestroyDriverInfoList+0x117
+ * 02 0000007e`ccd7c0f0 00007ffa`56b982a3 MSIF170!vboxNetCfgWinCreateHostOnlyNetworkInterface+0xb23 [E:\vbox\svn\trunk\src\VBox\HostDrivers\VBoxNetFlt\win\cfg\VBoxNetCfg.cpp @ 3378]
+ * 03 0000007e`ccd7ef10 00007ffa`56b92cb8 MSIF170!VBoxNetCfgWinCreateHostOnlyNetworkInterface+0x53 [E:\vbox\svn\trunk\src\VBox\HostDrivers\VBoxNetFlt\win\cfg\VBoxNetCfg.cpp @ 3479]
+ * 04 0000007e`ccd7efc0 00007ffa`610f59d3 MSIF170!_createHostOnlyInterface+0x218 [E:\vbox\svn\trunk\src\VBox\Installer\win\InstallHelper\VBoxInstallHelper.cpp @ 1453]
+ * 05 0000007e`ccd7f260 00007ffa`610d80ac msi!CallCustomDllEntrypoint+0x2b
+ * 06 0000007e`ccd7f2d0 00007ffa`84567034 msi!CMsiCustomAction::CustomActionThread+0x34c
+ * 07 0000007e`ccd7f8c0 00007ffa`849a2651 KERNEL32!BaseThreadInitThunk+0x14
+ * 08 0000007e`ccd7f8f0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
+ * 0:006> r
+ * rax=0000000000000000 rbx=0000025f4f03af90 rcx=00007ffa83f23b40
+ * rdx=0000025f4f03af90 rsi=0000025f5108be50 rdi=0000025f4f066f10
+ * rip=00007ffa83e2a42a rsp=0000007eccd7c070 rbp=00007ffa83f23000
+ * r8=0000007eccd7c0a8 r9=0000007eccd7c1f0 r10=0000000000000000
+ * r11=0000007eccd7c020 r12=0000007eccd7c3d0 r13=00007ffa83f23000
+ * r14=0000000000000000 r15=0000025f4f03af90
+ * iopl=0 nv up ei pl nz na po nc
+ * cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
+ * SETUPAPI!DereferenceClassDriverList+0x4e:
+ * 00007ffa`83e2a42a 834008ff add dword ptr [rax+8],0FFFFFFFFh ds:00000000`00000008=????????
+ *
+ */
+ if (destroyList)
+ SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER);
+#else
+ RT_NOREF(destroyList);
+#endif
+
+ /* clean up the device info set */
+ SetupDiDestroyDeviceInfoList(hDeviceInfo);
+ }
+
+ /*
+ * Return the network connection GUID on success.
+ */
+ if (SUCCEEDED(hrc))
+ {
+ /** @todo r=bird: Some please explain this mess. It's not just returning a
+ * GUID here, it's a bit more than that. */
+ RENAMING_CONTEXT context;
+ context.hr = E_FAIL;
+
+ if (pGuid)
+ {
+ hrc = CLSIDFromString(wszCfgGuidString, (LPCLSID)pGuid);
+ if (FAILED(hrc))
+ NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
+ }
+
+ INetCfg *pNetCfg = NULL;
+ LPWSTR pwszApp = NULL;
+ HRESULT hrc2 = VBoxNetCfgWinQueryINetCfg(&pNetCfg, TRUE, L"VirtualBox Host-Only Creation",
+ 30 * 1000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec. */
+ /** @todo special handling for 6to4svc.dll ???, i.e. several retrieves */
+ &pwszApp);
+ if (hrc2 == S_OK)
+ {
+ if (bstrNewInterfaceName.isNotEmpty())
+ {
+ /* The assigned name does not match the desired one, rename the device */
+ context.bstrName = bstrNewInterfaceName.raw();
+ context.pGuid = pGuid;
+ hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NET,
+ vboxNetCfgWinRenameHostOnlyNetworkInterface, &context);
+ }
+ if (SUCCEEDED(hrc2))
+ hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETSERVICE,
+ vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
+ if (SUCCEEDED(hrc2))
+ hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETTRANS,
+ vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
+ if (SUCCEEDED(hrc2))
+ hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETCLIENT,
+ vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
+ if (SUCCEEDED(hrc2))
+ hrc2 = pNetCfg->Apply();
+ else
+ NonStandardLogFlow(("Enumeration failed, hrc2=%Rhrc\n", hrc2));
+
+ VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
+ }
+ else if (hrc2 == NETCFG_E_NO_WRITE_LOCK && pwszApp)
+ {
+ NonStandardLogFlow(("Application '%ls' is holding the lock, failed\n", pwszApp));
+ CoTaskMemFree(pwszApp);
+ pwszApp = NULL;
+ }
+ else
+ NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hrc2=%Rhrc\n", hrc2));
+
+#ifndef VBOXNETCFG_DELAYEDRENAME
+ /* If the device has been successfully renamed, replace the name now. */
+ if (SUCCEEDED(hrc2) && SUCCEEDED(context.hr))
+ RTUtf16Copy(wszDevName, RT_ELEMENTS(wszDevName), pBstrDesiredName);
+
+ WCHAR wszConnectionName[128];
+ hrc2 = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionName, RT_ELEMENTS(wszConnectionName), NULL);
+ if (SUCCEEDED(hrc2))
+ hrc2 = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszConnectionName);
+#endif
+
+ /*
+ * Now, return the network connection GUID/name.
+ */
+ if (pBstrName)
+ {
+ *pBstrName = SysAllocString((const OLECHAR *)wszDevName);
+ if (!*pBstrName)
+ {
+ NonStandardLogFlow(("SysAllocString failed\n"));
+ hrc = E_OUTOFMEMORY;
+ }
+ }
+ }
+
+ if (pBstrErrMsg)
+ {
+ *pBstrErrMsg = NULL;
+ if (bstrError.isNotEmpty())
+ bstrError.detachToEx(pBstrErrMsg);
+ }
+ return hrc;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile,
+ IN BSTR pwszDesiredName, OUT GUID *pGuid,
+ OUT BSTR *pBstrName, OUT BSTR *pBstrErrMsg)
+{
+ HRESULT hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
+ pGuid, pBstrName, pBstrErrMsg);
+ if (hrc == E_ABORT)
+ {
+ NonStandardLogFlow(("Timed out while waiting for NetCfgInstanceId, try again immediately...\n"));
+
+ /*
+ * This is the first time we fail to obtain NetCfgInstanceId, let us
+ * retry it once. It is needed to handle the situation when network
+ * setup fails to recognize the arrival of our device node while it
+ * is busy removing another host-only interface, and it gets stuck
+ * with no matching network interface created for our device node.
+ * See @bugref{7973} for details.
+ */
+ hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
+ pGuid, pBstrName, pBstrErrMsg);
+ if (hrc == E_ABORT)
+ {
+ NonStandardLogFlow(("Timed out again while waiting for NetCfgInstanceId, try again after a while...\n"));
+
+ /*
+ * This is the second time we fail to obtain NetCfgInstanceId, let us
+ * retry it once more. This time we wait to network setup service
+ * to go down before retrying. Hopefully it will resolve all error
+ * conditions. See @bugref{7973} for details.
+ */
+ SC_HANDLE hSCM = OpenSCManagerW(NULL, NULL, GENERIC_READ);
+ if (hSCM)
+ {
+ SC_HANDLE hService = OpenServiceW(hSCM, L"NetSetupSvc", GENERIC_READ);
+ if (hService)
+ {
+ for (int retries = 0; retries < 60 && !vboxNetCfgWinIsNetSetupStopped(hService); ++retries)
+ Sleep(1000);
+ CloseServiceHandle(hService);
+ hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
+ pGuid, pBstrName, pBstrErrMsg);
+ }
+ else
+ NonStandardLogFlow(("OpenService failed (%Rwc)\n", GetLastError()));
+ CloseServiceHandle(hSCM);
+ }
+ else
+ NonStandardLogFlow(("OpenSCManager failed (%Rwc)", GetLastError()));
+
+ /* Give up and report the error. */
+ if (hrc == E_ABORT)
+ {
+ if (pBstrErrMsg)
+ {
+ com::Bstr bstrError;
+ bstrError.printfNoThrow("Querying NetCfgInstanceId failed (ERROR_FILE_NOT_FOUND)");
+ bstrError.detachToEx(pBstrErrMsg);
+ }
+ hrc = E_FAIL;
+ }
+ }
+ }
+ return hrc;
+}
+
+static HRESULT vboxNetCfgWinGetLoopbackMetric(OUT DWORD *Metric)
+{
+ Assert(g_pfnInitializeIpInterfaceEntry != NULL);
+ Assert(g_pfnGetIpInterfaceEntry != NULL);
+
+ MIB_IPINTERFACE_ROW row;
+ RT_ZERO(row); /* paranoia */
+ g_pfnInitializeIpInterfaceEntry(&row);
+
+ row.Family = AF_INET;
+ row.InterfaceLuid.Info.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
+
+ NETIO_STATUS dwErr = g_pfnGetIpInterfaceEntry(&row);
+ if (dwErr == NO_ERROR)
+ {
+ *Metric = row.Metric;
+ return S_OK;
+ }
+ return HRESULT_FROM_WIN32(dwErr);
+}
+
+static HRESULT vboxNetCfgWinSetInterfaceMetric(IN NET_LUID *pInterfaceLuid, IN DWORD metric)
+{
+ Assert(g_pfnInitializeIpInterfaceEntry != NULL);
+ Assert(g_pfnSetIpInterfaceEntry != NULL);
+
+ MIB_IPINTERFACE_ROW newRow;
+ RT_ZERO(newRow); /* paranoia */
+ g_pfnInitializeIpInterfaceEntry(&newRow);
+
+ // identificate the interface to change
+ newRow.InterfaceLuid = *pInterfaceLuid;
+ newRow.Family = AF_INET;
+
+ // changed settings
+ newRow.UseAutomaticMetric = false;
+ newRow.Metric = metric;
+
+ // change settings
+ NETIO_STATUS dwErr = g_pfnSetIpInterfaceEntry(&newRow);
+ if (dwErr == NO_ERROR)
+ return S_OK;
+ return HRESULT_FROM_WIN32(dwErr);
+}
+
+static HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid)
+{
+ HRESULT hrc = E_FAIL;
+ HMODULE hmod = loadSystemDll(L"Iphlpapi.dll");
+ if (hmod)
+ {
+ g_pfnInitializeIpInterfaceEntry = (PFNINITIALIZEIPINTERFACEENTRY)GetProcAddress(hmod, "InitializeIpInterfaceEntry");
+ g_pfnGetIpInterfaceEntry = (PFNGETIPINTERFACEENTRY) GetProcAddress(hmod, "GetIpInterfaceEntry");
+ g_pfnSetIpInterfaceEntry = (PFNSETIPINTERFACEENTRY) GetProcAddress(hmod, "SetIpInterfaceEntry");
+ Assert(g_pfnInitializeIpInterfaceEntry);
+ Assert(g_pfnGetIpInterfaceEntry);
+ Assert(g_pfnSetIpInterfaceEntry);
+
+ if ( g_pfnInitializeIpInterfaceEntry
+ && g_pfnGetIpInterfaceEntry
+ && g_pfnSetIpInterfaceEntry)
+ {
+ DWORD loopbackMetric = 0;
+ hrc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
+ if (SUCCEEDED(hrc))
+ hrc = vboxNetCfgWinSetInterfaceMetric(pLuid, loopbackMetric - 1);
+ }
+
+ g_pfnInitializeIpInterfaceEntry = NULL;
+ g_pfnSetIpInterfaceEntry = NULL;
+ g_pfnGetIpInterfaceEntry = NULL;
+
+ FreeLibrary(hmod);
+ }
+ return hrc;
+}
+
+static HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID *pLUID)
+{
+ if (pLUID == NULL)
+ return E_INVALIDARG;
+
+ DWORD dwLuidIndex = 0;
+ DWORD cbSize = sizeof(dwLuidIndex);
+ DWORD dwValueType = REG_DWORD; /** @todo r=bird: This is output only. No checked after the call. So, only for debugging? */
+ LSTATUS lrc = RegQueryValueExW(hKey, L"NetLuidIndex", NULL, &dwValueType, (LPBYTE)&dwLuidIndex, &cbSize);
+ if (lrc == ERROR_SUCCESS)
+ {
+ DWORD dwIfType = 0;
+ cbSize = sizeof(dwIfType);
+ dwValueType = REG_DWORD; /** @todo r=bird: This is output only. No checked after the call. So, only for debugging? */
+ lrc = RegQueryValueExW(hKey, L"*IfType", NULL, &dwValueType, (LPBYTE)&dwIfType, &cbSize);
+ if (lrc == ERROR_SUCCESS)
+ {
+ RT_ZERO(*pLUID);
+ pLUID->Info.IfType = dwIfType;
+ pLUID->Info.NetLuidIndex = dwLuidIndex;
+ return S_OK;
+ }
+ }
+
+ RT_ZERO(*pLUID);
+ return HRESULT_FROM_WIN32(lrc);
+}
+
+
+#ifdef VBOXNETCFG_DELAYEDRENAME
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pwszId, OUT BSTR *pDevName)
+{
+ if (pDevName)
+ *pDevName = NULL;
+
+ HRESULT hr = S_OK; /** @todo r=bird: ODD return status for SetupDiCreateDeviceInfoList failures! */
+ HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
+ if (hDevInfo != INVALID_HANDLE_VALUE)
+ {
+ SP_DEVINFO_DATA DevInfoData = { sizeof(SP_DEVINFO_DATA) };
+ if (SetupDiOpenDeviceInfo(hDevInfo, pwszId, NULL, 0, &DevInfoData))
+ {
+ WCHAR wszDevName[256 + 1] = {0};
+ DWORD err = ERROR_SUCCESS;
+ if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, SPDRP_FRIENDLYNAME, NULL /*PropertyRegDataType*/,
+ (PBYTE)wszDevName, sizeof(wszDevName) - sizeof(WCHAR) /*yes, bytes*/,
+ NULL /*RequiredSize*/))
+ {
+ err = GetLastError();
+ if (err == ERROR_INVALID_DATA)
+ {
+ RT_ZERO(wszDevName);
+ if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, SPDRP_DEVICEDESC, NULL /*PropertyRegDataType*/,
+ (PBYTE)wszDevName, sizeof(wszDevName) - sizeof(WCHAR) /*yes, bytes*/,
+ NULL /*RequiredSize*/))
+ err = ERROR_SUCCESS;
+ else
+ err = GetLastError();
+ }
+ }
+ if (err == ERROR_SUCCESS)
+ {
+ WCHAR wszConnectionNewName[128] = {0};
+ hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionNewName,
+ RT_ELEMENTS(wszConnectionNewName), NULL);
+ if (SUCCEEDED(hr))
+ {
+ WCHAR wszGuid[50];
+ int cbWGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
+ if (cbWGuid)
+ {
+ hr = VBoxNetCfgWinRenameConnection(wszGuid, wszConnectionNewName);
+ if (FAILED(hr))
+ NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinRenameConnection failed (0x%x)\n", hr));
+ }
+ else
+ {
+ err = GetLastError();
+ hr = HRESULT_FROM_WIN32(err);
+ if (SUCCEEDED(hr))
+ hr = E_FAIL;
+ NonStandardLogFlow(("StringFromGUID2 failed err=%u, hr=0x%x\n", err, hr));
+ }
+ }
+ else
+ NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinGenHostonlyConnectionName failed (0x%x)\n", hr));
+ if (SUCCEEDED(hr) && pDevName)
+ {
+ *pDevName = SysAllocString((const OLECHAR *)wszDevName);
+ if (!*pDevName)
+ {
+ NonStandardLogFlow(("SysAllocString failed\n"));
+ hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(err);
+ NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiGetDeviceRegistryPropertyW failed (0x%x)\n", err));
+ }
+ }
+ else
+ {
+ DWORD err = GetLastError();
+ hr = HRESULT_FROM_WIN32(err);
+ NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiOpenDeviceInfo failed (0x%x)\n", err));
+ }
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ }
+
+ return hr;
+}
+#endif /* VBOXNETCFG_DELAYEDRENAME */
+
+#undef SetErrBreak
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf
new file mode 100644
index 00000000..9e13a198
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf
@@ -0,0 +1,95 @@
+; $Id: VBoxNetAdp.inf $
+;; @file
+; VBoxNetAdp.inf - VirtualBox Host-Only Driver inf file
+;
+
+;
+; 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
+;
+
+[Version]
+signature = "$Windows NT$"
+;cat CatalogFile = VBoxNetAdp.cat
+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %ORACLE%
+; DriverPackageType=Network
+; DriverPackageDisplayName=%VBoxNetAdp_Desc%
+;edit-DriverVer=08/13/2008,1.1.0.1
+
+[ControlFlags]
+;ExcludeFromSelect = sun_VBoxNetAdp
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetAdp.sys=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetAdp.Files.Sys = 12 ; %windir%\System32\drivers
+
+[Manufacturer]
+%ORACLE% = VBoxNetAdp@COMMA-NT-ARCH@
+
+[VBoxNetAdp@DOT-NT-ARCH@]
+%VBoxNetAdp_Desc% = VBoxNetAdp.ndi, sun_VBoxNetAdp
+
+[VBoxNetAdp.ndi]
+Characteristics = 0x1 ; NCF_VIRTUAL
+CopyFiles = VBoxNetAdp.Files.Sys
+AddReg = VBoxNetAdp.AddReg
+
+[VBoxNetAdp.Files.Sys]
+VBoxNetAdp.sys,,,2
+
+[VBoxNetAdp.ndi.Services]
+AddService = VBoxNetAdp,0x2, VBoxNetAdp.AddService
+
+[VBoxNetAdp.AddService]
+DisplayName = %VBoxNetAdp_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetAdp.sys
+LoadOrderGroup = NDIS
+
+[VBoxNetAdp.AddReg]
+HKR, , *NdisDeviceType, 0x00010001, 1 ; NDIS_DEVICE_TYPE_ENDPOINT
+HKR, Ndi, Service, 0, "VBoxNetAdp"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+
+[Strings]
+ORACLE = "Oracle Corporation"
+VBoxNetAdp_Desc = "VirtualBox Host-Only Ethernet Adapter"
+DiskDescription = "VirtualBox Host-Only Ethernet Adapter"
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc
new file mode 100644
index 00000000..979fb6dd
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc
@@ -0,0 +1,77 @@
+/* $Id: VBoxNetFlt-win.rc $ */
+/** @file
+ * VBoxNetFlt - Resource file containing version info and icon.
+ */
+/*
+ * 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 <windows.h>
+#include <VBox/version.h>
+
+#ifndef VBOXNETADP
+# define DESCRIPTION_STR "VirtualBox Bridged Networking Driver\0"
+# define FILENAME_STR "VBoxNetFlt"
+#else
+# define DESCRIPTION_STR "VirtualBox Host-Only Network Adapter Driver\0"
+# define FILENAME_STR "VBoxNetAdp"
+#endif
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DRV
+ FILESUBTYPE VFT2_DRV_NETWORK
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileDescription", DESCRIPTION_STR
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "InternalName", FILENAME_STR "\0"
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", FILENAME_STR ".sys\0"
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt.inf
new file mode 100644
index 00000000..22425793
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt.inf
@@ -0,0 +1,117 @@
+; $Id: VBoxNetFlt.inf $
+;; @file
+; VBoxNetFlt.inf - VirtualBox Bridged Networking Driver inf file 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
+;
+
+[Version]
+Signature = "$Windows NT$"
+;cat CatalogFile = VBoxNetFlt.cat
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+Provider = %ORACLE%
+;DriverPackageType=Network
+;DriverPackageDisplayName=%VBoxNetFlt_Desc%
+;edit-DriverVer=08/13/2008,1.1.0.1
+
+
+[Manufacturer]
+%ORACLE% = VBoxNetFlt@COMMA-NT-ARCH@
+
+[ControlFlags]
+
+[VBoxNetFlt@DOT-NT-ARCH@]
+%VBoxNetFlt_Desc% = VBoxNetFlt.ndi, sun_VBoxNetFlt
+
+[VBoxNetFlt.ndi]
+AddReg = VBoxNetFlt.ndi.AddReg, VBoxNetFlt.AddReg
+Characteristics = 0x4410 ; NCF_FILTER | NCF_NDIS_PROTOCOL
+CopyFiles = VBoxNetFlt.Files.DLL, VBoxNetFlt.Files.Sys
+CopyInf = VBoxNetFltM.inf
+
+[VBoxNetFlt.ndi.Remove]
+DelFiles = VBoxNetFlt.Files.DLL, VBoxNetFlt.Files.Sys
+
+[VBoxNetFlt.ndi.Services]
+AddService = VBoxNetFlt,, VBoxNetFlt.AddService
+
+[VBoxNetFlt.AddService]
+DisplayName = %VBoxNetFltService_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetFlt.sys
+LoadOrderGroup = PNP_TDI
+AddReg = VBoxNetFlt.AddService.AddReg
+
+
+[VBoxNetFlt.AddService.AddReg]
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetFlt.sys=1
+VBoxNetFltNobj.dll=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetFlt.Files.DLL = 11 ; %windir%\System32
+VBoxNetFlt.Files.Sys = 12 ; %windir%\System32\drivers
+
+[VBoxNetFlt.Files.Sys]
+VBoxNetFlt.sys,,,2
+
+[VBoxNetFlt.Files.DLL]
+VBoxNetFltNobj.dll,,,2
+
+[VBoxNetFlt.ndi.AddReg]
+HKR, Ndi, HelpText, , %VBoxNetFlt_HELP%
+HKR, Ndi, ClsID, 0, {f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}
+HKR, Ndi, ComponentDll, , VBoxNetFltNobj.dll
+HKR, Ndi, FilterClass, , failover
+HKR, Ndi, FilterDeviceInfId, , sun_VBoxNetFltmp
+HKR, Ndi, Service, , VBoxNetFlt
+HKR, Ndi\Interfaces, UpperRange, , noupper
+HKR, Ndi\Interfaces, LowerRange, , nolower
+HKR, Ndi\Interfaces, FilterMediaTypes, , "ethernet, nolower"
+
+[VBoxNetFlt.AddReg]
+HKR, Parameters, Param1, 0, 4
+
+[Strings]
+ORACLE = "Oracle Corporation"
+DiskDescription = "VirtualBox Bridged Networking Driver"
+VBoxNetFlt_Desc = "VirtualBox Bridged Networking Driver"
+VBoxNetFlt_HELP = "VirtualBox Bridged Networking Driver"
+VBoxNetFltService_Desc = "VirtualBox Bridged Networking Service"
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h
new file mode 100644
index 00000000..520a7d7c
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h
@@ -0,0 +1,533 @@
+/* $Id: VBoxNetFltCmn-win.h $ */
+/** @file
+ * VBoxNetFltCmn-win.h - Bridged Networking Driver, Windows Specific Code.
+ * Common header with configuration defines and global defs
+ */
+
+/*
+ * 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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltCmn_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltCmn_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+
+/* debugging flags */
+#ifdef DEBUG
+//# define DEBUG_NETFLT_PACKETS
+# ifndef DEBUG_misha
+# define RT_NO_STRICT
+# endif
+/* # define DEBUG_NETFLT_LOOPBACK */
+/* receive logic has several branches */
+/* the DEBUG_NETFLT_RECV* macros used to debug the ProtocolReceive callback
+ * which is typically not used in case the underlying miniport indicates the packets with NdisMIndicateReceivePacket
+ * the best way to debug the ProtocolReceive (which in turn has several branches) is to enable the DEBUG_NETFLT_RECV
+ * one by one in the below order, i.e.
+ * first DEBUG_NETFLT_RECV
+ * then DEBUG_NETFLT_RECV + DEBUG_NETFLT_RECV_NOPACKET */
+//# define DEBUG_NETFLT_RECV
+//# define DEBUG_NETFLT_RECV_NOPACKET
+//# define DEBUG_NETFLT_RECV_TRANSFERDATA
+/* use ExAllocatePoolWithTag instead of NdisAllocateMemoryWithTag */
+// #define DEBUG_NETFLT_USE_EXALLOC
+#endif
+
+#include <VBox/intnet.h>
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/version.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/process.h>
+#include <iprt/alloc.h>
+#include <iprt/alloca.h>
+#include <iprt/time.h>
+#include <iprt/net.h>
+#include <iprt/list.h>
+
+#include <iprt/nt/ntddk.h>
+#include <iprt/nt/ndis.h>
+
+#define VBOXNETFLT_OS_SPECFIC 1
+
+/** version
+ * NOTE: we are NOT using NDIS 5.1 features now */
+#ifdef NDIS51_MINIPORT
+# define VBOXNETFLT_VERSION_MP_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_MP_NDIS_MINOR 1
+#else
+# define VBOXNETFLT_VERSION_MP_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_MP_NDIS_MINOR 0
+#endif
+
+#ifndef VBOXNETADP
+#ifdef NDIS51
+# define VBOXNETFLT_VERSION_PT_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_PT_NDIS_MINOR 1 /* todo: use 0 here as well ? */
+#else
+# define VBOXNETFLT_VERSION_PT_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_PT_NDIS_MINOR 0
+#endif
+
+# define VBOXNETFLT_NAME_PROTOCOL L"VBoxNetFlt"
+/** device to be used to prevent the driver unload & ioctl interface (if necessary in the future) */
+# define VBOXNETFLT_NAME_LINK L"\\DosDevices\\Global\\VBoxNetFlt"
+# define VBOXNETFLT_NAME_DEVICE L"\\Device\\VBoxNetFlt"
+#else
+# define VBOXNETFLT_NAME_LINK L"\\DosDevices\\Global\\VBoxNetAdp"
+# define VBOXNETFLT_NAME_DEVICE L"\\Device\\VBoxNetAdp"
+#endif
+
+typedef struct VBOXNETFLTINS *PVBOXNETFLTINS;
+
+/** configuration */
+
+/** Ndis Packet pool settings
+ * these are applied to both receive and send packet pools */
+/* number of packets for normal used */
+#define VBOXNETFLT_PACKET_POOL_SIZE_NORMAL 0x000000FF
+/* number of additional overflow packets */
+#define VBOXNETFLT_PACKET_POOL_SIZE_OVERFLOW 0x0000FF00
+
+/** packet queue size used when the driver is working in the "active" mode */
+#define VBOXNETFLT_PACKET_INFO_POOL_SIZE 0x0000FFFF
+
+#ifndef VBOXNETADP
+/** memory tag used for memory allocations
+ * (VBNF stands for VBox NetFlt) */
+# define VBOXNETFLT_MEM_TAG 'FNBV'
+#else
+/** memory tag used for memory allocations
+ * (VBNA stands for VBox NetAdp) */
+# define VBOXNETFLT_MEM_TAG 'ANBV'
+#endif
+
+/** receive and transmit Ndis buffer pool size */
+#define VBOXNETFLT_BUFFER_POOL_SIZE_TX 128
+#define VBOXNETFLT_BUFFER_POOL_SIZE_RX 128
+
+#define VBOXNETFLT_PACKET_ETHEADER_SIZE 14
+#define VBOXNETFLT_PACKET_HEADER_MATCH_SIZE 24
+#define VBOXNETFLT_PACKET_QUEUE_SG_SEGS_ALLOC 32
+
+
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+# define VBOXNETFLT_PACKETMATCH_LENGTH (VBOXNETFLT_PACKET_ETHEADER_SIZE + 2)
+#endif
+
+#ifdef VBOXNETADP
+#define VBOXNETADP_HEADER_SIZE 14
+#define VBOXNETADP_MAX_DATA_SIZE 1500
+#define VBOXNETADP_MAX_PACKET_SIZE (VBOXNETADP_HEADER_SIZE + VBOXNETADP_MAX_DATA_SIZE)
+#define VBOXNETADP_MIN_PACKET_SIZE 60
+/* link speed 100Mbps (measured in 100 bps) */
+#define VBOXNETADP_LINK_SPEED 1000000
+#define VBOXNETADP_MAX_LOOKAHEAD_SIZE VBOXNETADP_MAX_DATA_SIZE
+#define VBOXNETADP_VENDOR_ID 0x080027
+#define VBOXNETADP_VENDOR_DRIVER_VERSION 0x00010000
+#define VBOXNETADP_VENDOR_DESC "Sun"
+#define VBOXNETADP_MAX_MCAST_LIST 32
+#define VBOXNETADP_ETH_ADDRESS_LENGTH 6
+
+//#define VBOXNETADP_REPORT_DISCONNECTED
+#endif
+/* type defs */
+
+/** Flag specifying that the type of enqueued packet
+ * if set the info contains the PINTNETSG packet
+ * if clear the packet info contains the PNDIS_PACKET packet
+ * Typically the packet queue we are maintaining contains PNDIS_PACKETs only,
+ * however in case the underlying miniport indicates a packet with the NDIS_STATUS_RESOURCES status
+ * we MUST return the packet back to the miniport immediately
+ * this is why we are creating the INTNETSG, copying the ndis packet info there and enqueueing it */
+#define VBOXNETFLT_PACKET_SG 0x00000001
+
+/** the flag specifying that the packet source
+ * if set the packet comes from the host (upperlying protocol)
+ * if clear the packet comes from the wire (underlying miniport) */
+#define VBOXNETFLT_PACKET_SRC_HOST 0x00000002
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+/** flag specifying the packet was originated by our driver
+ * i.e. we could use it on our needs and should not return it
+ * we are enqueueing "our" packets on ProtocolReceive call-back when
+ * Ndis does not give us a receive packet (the driver below us has called NdisM..IndicateReceive)
+ * this is supported for Ndis Packet only */
+#define VBOXNETFLT_PACKET_MINE 0x00000004
+
+/** flag passed to vboxNetFltWinQuEnqueuePacket specifying that the packet should be copied
+ * this is supported for Ndis Packet only */
+#define VBOXNETFLT_PACKET_COPY 0x00000008
+#endif
+
+/** packet queue element containing the packet info */
+typedef struct VBOXNETFLT_PACKET_INFO
+{
+ /** list entry used for enqueueing the info */
+ LIST_ENTRY ListEntry;
+ /** pointer to the pool containing this packet info */
+ struct VBOXNETFLT_PACKET_INFO_POOL *pPool;
+ /** flags describing the referenced packet. Contains PACKET_xxx flags (i.e. PACKET_SG, PACKET_SRC_HOST) */
+ uint32_t fFlags;
+ /** pointer to the packet this info represents */
+ PVOID pPacket;
+} VBOXNETFLT_PACKET_INFO, *PVBOXNETFLT_PACKET_INFO;
+
+/* paranoid check to make sure the elements in the packet info array are properly aligned */
+AssertCompile((sizeof(VBOXNETFLT_PACKET_INFO) & (sizeof(PVOID) - 1)) == 0);
+
+/** represents the packet queue */
+typedef LIST_ENTRY PVBOXNETFLT_ACKET_QUEUE, *PVBOXNETFLT_PACKET_QUEUE;
+
+/*
+ * we are using non-interlocked versions of LIST_ENTRY-related operations macros and synchronize
+ * access to the queue and its elements by acquiring/releasing a spinlock using Ndis[Acquire,Release]Spinlock
+ *
+ * we are NOT using interlocked versions of insert/remove head/tail list functions because we need to iterate though
+ * the queue elements as well as remove elements from the midle of the queue
+ *
+ * * @todo: it seems that we can switch to using interlocked versions of list-entry functions
+ * since we have removed all functionality (mentioned above, i.e. queue elements iteration, etc.) that might prevent us from doing this
+ */
+typedef struct VBOXNETFLT_INTERLOCKED_PACKET_QUEUE
+{
+ /** queue */
+ PVBOXNETFLT_ACKET_QUEUE Queue;
+ /** queue lock */
+ NDIS_SPIN_LOCK Lock;
+} VBOXNETFLT_INTERLOCKED_PACKET_QUEUE, *PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE;
+
+typedef struct VBOXNETFLT_SINGLE_LIST
+{
+ /** queue */
+ SINGLE_LIST_ENTRY Head;
+ /** pointer to the list tail. used to enqueue elements to the tail of the list */
+ PSINGLE_LIST_ENTRY pTail;
+} VBOXNETFLT_SINGLE_LIST, *PVBOXNETFLT_SINGLE_LIST;
+
+typedef struct VBOXNETFLT_INTERLOCKED_SINGLE_LIST
+{
+ /** queue */
+ VBOXNETFLT_SINGLE_LIST List;
+ /** queue lock */
+ NDIS_SPIN_LOCK Lock;
+} VBOXNETFLT_INTERLOCKED_SINGLE_LIST, *PVBOXNETFLT_INTERLOCKED_SINGLE_LIST;
+
+/** packet info pool contains free packet info elements to be used for the packet queue
+ * we are using the pool mechanism to allocate packet queue elements
+ * the pool mechanism is pretty simple now, we are allocating a bunch of memory
+ * for maintaining VBOXNETFLT_PACKET_INFO_POOL_SIZE queue elements and just returning null when the pool is exhausted
+ * This mechanism seems to be enough for now since we are using VBOXNETFLT_PACKET_INFO_POOL_SIZE = 0xffff which is
+ * the maximum size of packets the ndis packet pool supports */
+typedef struct VBOXNETFLT_PACKET_INFO_POOL
+{
+ /** free packet info queue */
+ VBOXNETFLT_INTERLOCKED_PACKET_QUEUE Queue;
+ /** memory bugger used by the pool */
+ PVOID pBuffer;
+} VBOXNETFLT_PACKET_INFO_POOL, *PVBOXNETFLT_PACKET_INFO_POOL;
+
+typedef enum VBOXNETDEVOPSTATE
+{
+ kVBoxNetDevOpState_InvalidValue = 0,
+ kVBoxNetDevOpState_Initializing,
+ kVBoxNetDevOpState_Initialized,
+ kVBoxNetDevOpState_Deinitializing,
+ kVBoxNetDevOpState_Deinitialized,
+
+} VBOXNETDEVOPSTATE;
+
+typedef enum VBOXNETFLT_WINIFSTATE
+{
+ /** The usual invalid state. */
+ kVBoxWinIfState_Invalid = 0,
+ /** Initialization. */
+ kVBoxWinIfState_Connecting,
+ /** Connected fuly functional state */
+ kVBoxWinIfState_Connected,
+ /** Disconnecting */
+ kVBoxWinIfState_Disconnecting,
+ /** Disconnected */
+ kVBoxWinIfState_Disconnected,
+} VBOXNETFLT_WINIFSTATE;
+
+/** structure used to maintain the state and reference count of the miniport and protocol */
+typedef struct VBOXNETFLT_WINIF_DEVICE
+{
+ /** initialize state */
+ VBOXNETDEVOPSTATE OpState;
+ /** ndis power state */
+ NDIS_DEVICE_POWER_STATE PowerState;
+ /** reference count */
+ uint32_t cReferences;
+} VBOXNETFLT_WINIF_DEVICE, *PVBOXNETFLT_WINIF_DEVICE;
+
+#define VBOXNDISREQUEST_INPROGRESS 1
+#define VBOXNDISREQUEST_QUEUED 2
+
+typedef struct VBOXNETFLTWIN_STATE
+{
+ union
+ {
+ struct
+ {
+ UINT fRequestInfo : 2;
+ UINT fInterfaceClosing : 1;
+ UINT fStandBy : 1;
+ UINT fProcessingPacketFilter : 1;
+ UINT fPPFNetFlt : 1;
+ UINT fUpperProtSetFilterInitialized : 1;
+ UINT Reserved : 25;
+ };
+ UINT Value;
+ };
+} VBOXNETFLTWIN_STATE, *PVBOXNETFLTWIN_STATE;
+
+DECLINLINE(VBOXNETFLTWIN_STATE) vboxNetFltWinAtomicUoReadWinState(VBOXNETFLTWIN_STATE State)
+{
+ UINT fValue = ASMAtomicUoReadU32((volatile uint32_t *)&State.Value);
+ return *((PVBOXNETFLTWIN_STATE)((void*)&fValue));
+}
+
+/* miniport layer globals */
+typedef struct VBOXNETFLTGLOBALS_MP
+{
+ /** our miniport handle */
+ NDIS_HANDLE hMiniport;
+ /** ddis wrapper handle */
+ NDIS_HANDLE hNdisWrapper;
+} VBOXNETFLTGLOBALS_MP, *PVBOXNETFLTGLOBALS_MP;
+
+#ifndef VBOXNETADP
+/* protocol layer globals */
+typedef struct VBOXNETFLTGLOBALS_PT
+{
+ /** our protocol handle */
+ NDIS_HANDLE hProtocol;
+} VBOXNETFLTGLOBALS_PT, *PVBOXNETFLTGLOBALS_PT;
+#endif /* #ifndef VBOXNETADP */
+
+typedef struct VBOXNETFLTGLOBALS_WIN
+{
+ /** synch event used for device creation synchronization */
+ KEVENT SynchEvent;
+ /** Device reference count */
+ int cDeviceRefs;
+ /** ndis device */
+ NDIS_HANDLE hDevice;
+ /** device object */
+ PDEVICE_OBJECT pDevObj;
+ /* loopback flags */
+ /* ndis packet flags to disable packet loopback */
+ UINT fPacketDontLoopBack;
+ /* ndis packet flags specifying whether the packet is looped back */
+ UINT fPacketIsLoopedBack;
+ /* Minport info */
+ VBOXNETFLTGLOBALS_MP Mp;
+#ifndef VBOXNETADP
+ /* Protocol info */
+ VBOXNETFLTGLOBALS_PT Pt;
+ /** lock protecting the filter list */
+ NDIS_SPIN_LOCK lockFilters;
+ /** the head of filter list */
+ RTLISTANCHOR listFilters;
+ /** IP address change notifier handle */
+ HANDLE hNotifier;
+#endif
+} VBOXNETFLTGLOBALS_WIN, *PVBOXNETFLTGLOBALS_WIN;
+
+extern VBOXNETFLTGLOBALS_WIN g_VBoxNetFltGlobalsWin;
+
+/** represents filter driver device context*/
+typedef struct VBOXNETFLTWIN
+{
+ /** handle used by miniport edge for ndis calls */
+ NDIS_HANDLE hMiniport;
+ /** miniport edge state */
+ VBOXNETFLT_WINIF_DEVICE MpState;
+ /** ndis packet pool used for receives */
+ NDIS_HANDLE hRecvPacketPool;
+ /** ndis buffer pool used for receives */
+ NDIS_HANDLE hRecvBufferPool;
+ /** driver bind adapter state. */
+ VBOXNETFLT_WINIFSTATE enmState;
+#ifndef VBOXNETADP
+ /* misc state flags */
+ VBOXNETFLTWIN_STATE StateFlags;
+ /** handle used by protocol edge for ndis calls */
+ NDIS_HANDLE hBinding;
+ /** protocol edge state */
+ VBOXNETFLT_WINIF_DEVICE PtState;
+ /** ndis packet pool used for receives */
+ NDIS_HANDLE hSendPacketPool;
+ /** ndis buffer pool used for receives */
+ NDIS_HANDLE hSendBufferPool;
+ /** used for maintaining the pending send packets for handling packet loopback */
+ VBOXNETFLT_INTERLOCKED_SINGLE_LIST SendPacketQueue;
+ /** used for serializing calls to the NdisRequest in the vboxNetFltWinSynchNdisRequest */
+ RTSEMFASTMUTEX hSynchRequestMutex;
+ /** event used to synchronize with the Ndis Request completion in the vboxNetFltWinSynchNdisRequest */
+ KEVENT hSynchCompletionEvent;
+ /** status of the Ndis Request initiated by the vboxNetFltWinSynchNdisRequest */
+ NDIS_STATUS volatile SynchCompletionStatus;
+ /** pointer to the Ndis Request being executed by the vboxNetFltWinSynchNdisRequest */
+ PNDIS_REQUEST volatile pSynchRequest;
+ /** open/close adapter status.
+ * Since ndis adapter open and close requests may complete asynchronously,
+ * we are using event mechanism to wait for open/close completion
+ * the status field is being set by the completion call-back */
+ NDIS_STATUS OpenCloseStatus;
+ /** open/close adaptor completion event */
+ NDIS_EVENT OpenCloseEvent;
+ /** medium we are attached to */
+ NDIS_MEDIUM enmMedium;
+ /**
+ * Passdown request info
+ */
+ /** ndis request we pass down to the miniport below */
+ NDIS_REQUEST PassDownRequest;
+ /** Ndis pass down request bytes read or written original pointer */
+ PULONG pcPDRBytesRW;
+ /** Ndis pass down request bytes needed original pointer */
+ PULONG pcPDRBytesNeeded;
+ /** true if we should indicate the receive complete used by the ProtocolReceive mechanism.
+ * We need to indicate it only with the ProtocolReceive + NdisMEthIndicateReceive path.
+ * 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 */
+ bool abIndicateRxComplete[64];
+ /** Pending transfer data packet queue (i.e. packets that were indicated as pending on NdisTransferData call */
+ VBOXNETFLT_INTERLOCKED_SINGLE_LIST TransferDataList;
+ /* mac options initialized on OID_GEN_MAC_OPTIONS */
+ ULONG fMacOptions;
+ /** our miniport devuice name */
+ NDIS_STRING MpDeviceName;
+ /** synchronize with unbind with Miniport initialization */
+ NDIS_EVENT MpInitCompleteEvent;
+ /** media connect status that we indicated */
+ NDIS_STATUS MpIndicatedMediaStatus;
+ /** media connect status pending to indicate */
+ NDIS_STATUS MpUnindicatedMediaStatus;
+ /** packet filter flags set by the upper protocols */
+ ULONG fUpperProtocolSetFilter;
+ /** packet filter flags set by the upper protocols */
+ ULONG fSetFilterBuffer;
+ /** packet filter flags set by us */
+ ULONG fOurSetFilter;
+ /** our own list of filters, needed by notifier */
+ RTLISTNODE node;
+#else
+ volatile ULONG cTxSuccess;
+ volatile ULONG cRxSuccess;
+ volatile ULONG cTxError;
+ volatile ULONG cRxError;
+#endif
+} VBOXNETFLTWIN, *PVBOXNETFLTWIN;
+
+typedef struct VBOXNETFLT_PACKET_QUEUE_WORKER
+{
+ /** this event is used to initiate a packet queue worker thread kill */
+ KEVENT KillEvent;
+ /** this event is used to notify a worker thread that the packets are added to the queue */
+ KEVENT NotifyEvent;
+ /** pointer to the packet queue worker thread object */
+ PKTHREAD pThread;
+ /** pointer to the SG used by the packet queue for IntNet receive notifications */
+ PINTNETSG pSG;
+ /** Packet queue */
+ VBOXNETFLT_INTERLOCKED_PACKET_QUEUE PacketQueue;
+ /** Packet info pool, i.e. the pool for the packet queue elements */
+ VBOXNETFLT_PACKET_INFO_POOL PacketInfoPool;
+} VBOXNETFLT_PACKET_QUEUE_WORKER, *PVBOXNETFLT_PACKET_QUEUE_WORKER;
+
+/* protocol reserved data held in ndis packet */
+typedef struct VBOXNETFLT_PKTRSVD_PT
+{
+ /** original packet received from the upperlying protocol
+ * can be null if the packet was originated by intnet */
+ PNDIS_PACKET pOrigPacket;
+ /** pointer to the buffer to be freed on send completion
+ * can be null if no buffer is to be freed */
+ PVOID pBufToFree;
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+ SINGLE_LIST_ENTRY ListEntry;
+ /* true if the packet is from IntNet */
+ bool bFromIntNet;
+#endif
+} VBOXNETFLT_PKTRSVD_PT, *PVBOXNETFLT_PKTRSVD_PT;
+
+/** miniport reserved data held in ndis packet */
+typedef struct VBOXNETFLT_PKTRSVD_MP
+{
+ /** original packet received from the underling miniport
+ * can be null if the packet was originated by intnet */
+ PNDIS_PACKET pOrigPacket;
+ /** pointer to the buffer to be freed on receive completion
+ * can be null if no buffer is to be freed */
+ PVOID pBufToFree;
+} VBOXNETFLT_PKTRSVD_MP, *PVBOXNETFLT_PKTRSVD_MP;
+
+/** represents the data stored in the protocol reserved field of ndis packet on NdisTransferData processing */
+typedef struct VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT
+{
+ /** next packet in a list */
+ SINGLE_LIST_ENTRY ListEntry;
+ /* packet buffer start */
+ PNDIS_BUFFER pOrigBuffer;
+} VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT, *PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT;
+
+/* VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT should fit into PROTOCOL_RESERVED_SIZE_IN_PACKET because we use protocol reserved part
+ * of our miniport edge on transfer data processing for honding our own info */
+AssertCompile(sizeof (VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT) <= PROTOCOL_RESERVED_SIZE_IN_PACKET);
+/* this should fit in MiniportReserved */
+AssertCompile(sizeof (VBOXNETFLT_PKTRSVD_MP) <= RT_SIZEOFMEMB(NDIS_PACKET, MiniportReserved));
+/* we use RTAsmAtomic*U32 for those, make sure we're correct */
+AssertCompile(sizeof (NDIS_DEVICE_POWER_STATE) == sizeof (uint32_t));
+AssertCompile(sizeof (UINT) == sizeof (uint32_t));
+
+
+#define NDIS_FLAGS_SKIP_LOOPBACK_W2K 0x400
+
+#include "../../VBoxNetFltInternal.h"
+#include "VBoxNetFltRt-win.h"
+#ifndef VBOXNETADP
+# include "VBoxNetFltP-win.h"
+#endif
+#include "VBoxNetFltM-win.h"
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltCmn_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp
new file mode 100644
index 00000000..65bde454
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp
@@ -0,0 +1,1570 @@
+/* $Id: VBoxNetFltM-win.cpp $ */
+/** @file
+ * VBoxNetFltM-win.cpp - Bridged Networking Driver, Windows Specific Code.
+ * Miniport 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"
+
+static const char* vboxNetFltWinMpDumpOid(ULONG oid);
+
+#ifndef VBOXNETADP
+static NDIS_STATUS vboxNetFltWinMpInitialize(OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext)
+{
+ RT_NOREF1(WrapperConfigurationContext);
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)NdisIMGetDeviceContext(MiniportAdapterHandle);
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ pNetFlt->u.s.WinIf.hMiniport = MiniportAdapterHandle;
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initializing);
+ /* the MP state should be already set to kVBoxNetDevOpState_Initializing, just a paranoia
+ * in case NDIS for some reason calls us in some irregular way */
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initializing);
+
+ NDIS_MEDIUM enmMedium = pNetFlt->u.s.WinIf.enmMedium;
+ if (enmMedium == NdisMediumWan)
+ enmMedium = NdisMedium802_3;
+
+ UINT i = 0;
+ for (; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == enmMedium)
+ {
+ *SelectedMediumIndex = i;
+ break;
+ }
+ }
+
+ do
+ {
+ if (i != MediumArraySize)
+ {
+ NdisMSetAttributesEx(MiniportAdapterHandle, pNetFlt, 0,
+ NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
+ NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT|
+ NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
+ NDIS_ATTRIBUTE_DESERIALIZE |
+ NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+ NdisInterfaceInternal /* 0 */);
+
+ pNetFlt->u.s.WinIf.MpIndicatedMediaStatus = NDIS_STATUS_MEDIA_CONNECT;
+ Assert(vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD3);
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.MpState, NdisDeviceStateD0);
+ Assert(pNetFlt->u.s.WinIf.MpState.OpState == kVBoxNetDevOpState_Initializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initialized);
+
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+ else
+ {
+ Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ Assert(Status != NDIS_STATUS_SUCCESS);
+ Assert(vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD3);
+ Assert(pNetFlt->u.s.WinIf.MpState.OpState == kVBoxNetDevOpState_Initializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ } while (0);
+
+ NdisSetEvent(&pNetFlt->u.s.WinIf.MpInitCompleteEvent);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+
+ *OpenErrorStatus = Status;
+
+ return Status;
+}
+
+/**
+ * process the packet send in a "passthru" mode
+ */
+static NDIS_STATUS vboxNetFltWinSendPassThru(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ , bool bNetFltActive
+#endif
+ )
+{
+ PNDIS_PACKET pMyPacket;
+ NDIS_STATUS Status = vboxNetFltWinPrepareSendPacket(pNetFlt, pPacket, &pMyPacket);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+#if !defined(VBOX_LOOPBACK_USEFLAGS) /* || defined(DEBUG_NETFLT_PACKETS) */
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (bNetFltActive)
+ vboxNetFltWinLbPutSendPacket(pNetFlt, pMyPacket, false /* bFromIntNet */);
+# else
+ /* no need for the loop enqueue & check in a passthru mode , ndis will do everything for us */
+# endif
+#endif
+ NdisSend(&Status, pNetFlt->u.s.WinIf.hBinding, pMyPacket);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisIMCopySendCompletePerPacketInfo(pPacket, pMyPacket);
+#if defined(VBOXNETFLT_NO_PACKET_QUEUE) && !defined(VBOX_LOOPBACK_USEFLAGS)
+ if (bNetFltActive)
+ vboxNetFltWinLbRemoveSendPacket(pNetFlt, pMyPacket);
+#endif
+ NdisFreePacket(pMyPacket);
+ }
+ }
+ return Status;
+}
+
+#else /* defined VBOXNETADP */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoDeinitialization(PVBOXNETFLTINS pNetFlt)
+{
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true);
+ ASMAtomicUoWriteBool(&pNetFlt->fRediscoveryPending, false);
+ ASMAtomicUoWriteU64(&pNetFlt->NanoTSLastRediscovery, NanoTS);
+
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.MpState);
+
+ /* check packet pool is empty */
+ int cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(cPPUsage == 0);
+ /* for debugging only, ignore the err in release */
+ NOREF(cPPUsage);
+
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static NDIS_STATUS vboxNetFltWinMpReadApplyConfig(PVBOXNETFLTINS pThis, NDIS_HANDLE hMiniportAdapter,
+ NDIS_HANDLE hWrapperConfigurationContext)
+{
+ RT_NOREF1(hMiniportAdapter);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HANDLE hConfiguration;
+ PNDIS_CONFIGURATION_PARAMETER pParameterValue;
+ NDIS_STRING strMAC = NDIS_STRING_CONST("MAC");
+ RTMAC mac;
+
+ NdisOpenConfiguration(
+ &Status,
+ &hConfiguration,
+ hWrapperConfigurationContext);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ do
+ {
+ int rc;
+ NDIS_CONFIGURATION_PARAMETER param;
+ WCHAR MacBuf[13];
+
+ NdisReadConfiguration(&Status,
+ &pParameterValue,
+ hConfiguration,
+ &strMAC,
+ NdisParameterString);
+// Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+
+ rc = vboxNetFltWinMACFromNdisString(&mac, &pParameterValue->ParameterData.StringData);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ break;
+ }
+ }
+
+ vboxNetFltWinGenerateMACAddress(&mac);
+ param.ParameterType = NdisParameterString;
+ param.ParameterData.StringData.Buffer = MacBuf;
+ param.ParameterData.StringData.MaximumLength = sizeof(MacBuf);
+
+ rc = vboxNetFltWinMAC2NdisString(&mac, &param.ParameterData.StringData);
+ Assert(RT_SUCCESS(rc));
+ if (RT_SUCCESS(rc))
+ {
+ NdisWriteConfiguration(&Status,
+ hConfiguration,
+ &strMAC,
+ &param);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ /* ignore the failure */
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ }
+ } while (0);
+
+ NdisCloseConfiguration(hConfiguration);
+ }
+ else
+ {
+ vboxNetFltWinGenerateMACAddress(&mac);
+ }
+
+ pThis->u.s.MacAddr = mac;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoInitialization(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE hMiniportAdapter, NDIS_HANDLE hWrapperConfigurationContext)
+{
+ NDIS_STATUS Status;
+ pNetFlt->u.s.WinIf.hMiniport = hMiniportAdapter;
+
+ LogFlowFunc(("ENTER: pNetFlt 0x%p\n", pNetFlt));
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initializing);
+
+ vboxNetFltWinMpReadApplyConfig(pNetFlt, hMiniportAdapter, hWrapperConfigurationContext);
+
+ NdisMSetAttributesEx(hMiniportAdapter, pNetFlt,
+ 0, /* CheckForHangTimeInSeconds */
+ NDIS_ATTRIBUTE_DESERIALIZE |
+ NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+ NdisInterfaceInternal/* 0 */);
+
+ Assert(vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD3);
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.MpState, NdisDeviceStateD0);
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initialized);
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ LogFlowFunc(("pNetFlt 0x%p, Status 0x%x\n", pNetFlt, Status));
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinMpInitialize(OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext)
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+ UINT i = 0;
+
+ LogFlowFuncEnter();
+
+ for (; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == NdisMedium802_3)
+ {
+ *SelectedMediumIndex = i;
+ break;
+ }
+ }
+
+ if (i != MediumArraySize)
+ {
+ PDEVICE_OBJECT pPdo, pFdo;
+#define KEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
+ UCHAR Buf[512];
+ PUCHAR pSuffix;
+ ULONG cbBuf;
+ NDIS_STRING RtlStr;
+
+ wcscpy((WCHAR*)Buf, KEY_PREFIX);
+ pSuffix = Buf + (sizeof(KEY_PREFIX)-2);
+
+ NdisMGetDeviceProperty(MiniportAdapterHandle,
+ &pPdo,
+ &pFdo,
+ NULL, //Next Device Object
+ NULL,
+ NULL);
+
+ Status = IoGetDeviceProperty (pPdo,
+ DevicePropertyDriverKeyName,
+ sizeof(Buf) - (sizeof(KEY_PREFIX)-2),
+ pSuffix,
+ &cbBuf);
+ if (Status == STATUS_SUCCESS)
+ {
+ OBJECT_ATTRIBUTES ObjAttr;
+ HANDLE hDrvKey;
+ RtlStr.Buffer=(WCHAR*)Buf;
+ RtlStr.Length=(USHORT)cbBuf - 2 + sizeof(KEY_PREFIX) - 2;
+ RtlStr.MaximumLength=sizeof(Buf);
+
+ InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ Status = ZwOpenKey(&hDrvKey, KEY_READ, &ObjAttr);
+ if (Status == STATUS_SUCCESS)
+ {
+ static UNICODE_STRING NetCfgInstanceIdValue = NDIS_STRING_CONST("NetCfgInstanceId");
+// UCHAR valBuf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + RTUUID_STR_LENGTH*2 + 10];
+// ULONG cLength = sizeof(valBuf);
+#define NAME_PREFIX L"\\DEVICE\\"
+ PKEY_VALUE_PARTIAL_INFORMATION pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buf;
+ Status = ZwQueryValueKey(hDrvKey,
+ &NetCfgInstanceIdValue,
+ KeyValuePartialInformation,
+ pInfo,
+ sizeof(Buf),
+ &cbBuf);
+ if (Status == STATUS_SUCCESS)
+ {
+ if (pInfo->Type == REG_SZ && pInfo->DataLength > 2)
+ {
+ WCHAR *pName;
+ Status = vboxNetFltWinMemAlloc((PVOID*)&pName, pInfo->DataLength + sizeof(NAME_PREFIX));
+ if (Status == STATUS_SUCCESS)
+ {
+ PVBOXNETFLTINS pNetFlt;
+ wcscpy(pName, NAME_PREFIX);
+ wcscpy(pName+(sizeof(NAME_PREFIX)-2)/2, (WCHAR*)pInfo->Data);
+ RtlStr.Buffer=pName;
+ RtlStr.Length = (USHORT)pInfo->DataLength - 2 + sizeof(NAME_PREFIX) - 2;
+ RtlStr.MaximumLength = (USHORT)pInfo->DataLength + sizeof(NAME_PREFIX);
+
+ Status = vboxNetFltWinPtInitBind(&pNetFlt, MiniportAdapterHandle, &RtlStr, WrapperConfigurationContext);
+
+ if (Status == STATUS_SUCCESS)
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initialized);
+#if 0
+ NdisMIndicateStatus(pNetFlt->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_CONNECT,
+ (PVOID)NULL,
+ 0);
+#endif
+ }
+ else
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+
+ vboxNetFltWinMemFree(pName);
+
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ /** @todo */
+ *OpenErrorStatus = Status;
+
+ LogFlowFunc(("LEAVE: Status (0x%x)\n", Status));
+
+ return Status;
+}
+#endif
+
+static VOID vboxNetFltWinMpSendPackets(IN NDIS_HANDLE hMiniportAdapterContext,
+ IN PPNDIS_PACKET pPacketArray,
+ IN UINT cNumberOfPackets)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hMiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ bool bNetFltActive;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ Assert(cNumberOfPackets);
+
+ if (vboxNetFltWinIncReferenceWinIfNetFlt(pNetFlt, cNumberOfPackets, &bNetFltActive))
+ {
+ uint32_t cAdaptRefs = cNumberOfPackets;
+ uint32_t cNetFltRefs;
+ uint32_t cPassThruRefs;
+ if (bNetFltActive)
+ {
+ cNetFltRefs = cNumberOfPackets;
+ cPassThruRefs = 0;
+ }
+ else
+ {
+ cPassThruRefs = cNumberOfPackets;
+ cNetFltRefs = 0;
+ }
+
+ for (UINT i = 0; i < cNumberOfPackets; i++)
+ {
+ PNDIS_PACKET pPacket;
+
+ pPacket = pPacketArray[i];
+
+ if (!cNetFltRefs
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ || !vboxNetFltWinPostIntnet(pNetFlt, pPacket, VBOXNETFLT_PACKET_SRC_HOST)
+#else
+ || (fStatus = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, VBOXNETFLT_PACKET_SRC_HOST)) != NDIS_STATUS_SUCCESS
+#endif
+ )
+ {
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinSendPassThru(pNetFlt, pPacket
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ , !!cNetFltRefs
+#endif
+ );
+#else
+ if (!cNetFltRefs)
+ {
+# ifdef VBOXNETADP_REPORT_DISCONNECTED
+ Status = NDIS_STATUS_MEDIA_DISCONNECT;
+ STATISTIC_INCREASE(pNetFlt->u.s.WinIf.cTxError);
+# else
+ Status = NDIS_STATUS_SUCCESS;
+# endif
+ }
+#endif
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMSendComplete(pNetFlt->u.s.WinIf.hMiniport, pPacket, Status);
+ }
+ else
+ {
+ cAdaptRefs--;
+ }
+ }
+ else
+ {
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ NdisMSendComplete(pNetFlt->u.s.WinIf.hMiniport, pPacket, NDIS_STATUS_SUCCESS);
+#else
+ cAdaptRefs--;
+ cNetFltRefs--;
+#endif
+ }
+ }
+
+ if (cNetFltRefs)
+ {
+ vboxNetFltWinDecReferenceNetFlt(pNetFlt, cNetFltRefs);
+ }
+ else if (cPassThruRefs)
+ {
+ vboxNetFltWinDecReferenceModePassThru(pNetFlt, cPassThruRefs);
+ }
+ if (cAdaptRefs)
+ {
+ vboxNetFltWinDecReferenceWinIf(pNetFlt, cAdaptRefs);
+ }
+ }
+ else
+ {
+ NDIS_HANDLE h = pNetFlt->u.s.WinIf.hMiniport;
+ AssertFailed();
+ if (h)
+ {
+ for (UINT i = 0; i < cNumberOfPackets; i++)
+ {
+ PNDIS_PACKET pPacket;
+ pPacket = pPacketArray[i];
+ NdisMSendComplete(h, pPacket, NDIS_STATUS_FAILURE);
+ }
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+#ifndef VBOXNETADP
+static UINT vboxNetFltWinMpRequestStatePrep(PVBOXNETFLTINS pNetFlt, NDIS_STATUS *pStatus)
+{
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fRequestInfo);
+
+ if (vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) > kVBoxNetDevOpState_Initialized /* protocol unbind in progress */
+ || vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0)
+ {
+ *pStatus = NDIS_STATUS_FAILURE;
+ return 0;
+ }
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fRequestInfo);
+ if (vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) > kVBoxNetDevOpState_Initialized /* protocol unbind in progress */
+ || vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pStatus = NDIS_STATUS_FAILURE;
+ return 0;
+ }
+
+ if ((vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState) > NdisDeviceStateD0)
+ && !pNetFlt->u.s.WinIf.StateFlags.fStandBy)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS | VBOXNDISREQUEST_QUEUED;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pStatus = NDIS_STATUS_PENDING;
+ return VBOXNDISREQUEST_INPROGRESS | VBOXNDISREQUEST_QUEUED;
+ }
+
+ if (pNetFlt->u.s.WinIf.StateFlags.fStandBy)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pStatus = NDIS_STATUS_FAILURE;
+ return 0;
+ }
+
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS;
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ *pStatus = NDIS_STATUS_SUCCESS;
+ return VBOXNDISREQUEST_INPROGRESS;
+}
+
+static NDIS_STATUS vboxNetFltWinMpRequestPostQuery(PVBOXNETFLTINS pNetFlt)
+{
+ if (pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ bool fNetFltActive;
+ const bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &fNetFltActive);
+
+ Assert(pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBuffer);
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter);
+
+ if (fNetFltActive)
+ {
+ /* netflt is active, simply return the cached value */
+ *((PULONG)pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBuffer) = pNetFlt->u.s.WinIf.fUpperProtocolSetFilter;
+
+ /* we've intercepted the query and completed it */
+ vboxNetFltWinMpRequestStateComplete(pNetFlt);
+
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ return NDIS_STATUS_SUCCESS;
+ }
+ else if (fWinIfActive)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 1;
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 0;
+ /* we're cleaning it in RequestComplete */
+ }
+ }
+
+ NDIS_STATUS Status;
+ /* issue the request */
+ NdisRequest(&Status, pNetFlt->u.s.WinIf.hBinding, &pNetFlt->u.s.WinIf.PassDownRequest);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ vboxNetFltWinPtRequestComplete(pNetFlt, &pNetFlt->u.s.WinIf.PassDownRequest, Status);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinMpQueryInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ /* fist check if this is the oid we want to pass down */
+ switch (Oid)
+ {
+ case OID_PNP_QUERY_POWER:
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ case OID_TCP_TASK_OFFLOAD:
+ case OID_GEN_SUPPORTED_GUIDS:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ default:
+ {
+ /* the oid is to be passed down,
+ * check the device state if we can do it
+ * and update device state accordingly */
+ UINT uOp = vboxNetFltWinMpRequestStatePrep(pNetFlt, &Status);
+ if (uOp)
+ {
+ /* save the request info */
+ pNetFlt->u.s.WinIf.PassDownRequest.RequestType = NdisRequestQueryInformation;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.Oid = Oid;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;
+ pNetFlt->u.s.WinIf.pcPDRBytesNeeded = BytesNeeded;
+ pNetFlt->u.s.WinIf.pcPDRBytesRW = BytesWritten;
+
+ /* the oid can be processed */
+ if (!(uOp & VBOXNDISREQUEST_QUEUED))
+ {
+ Status = vboxNetFltWinMpRequestPostQuery(pNetFlt);
+ }
+ }
+ break;
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+
+#endif /* ifndef VBOXNETADP*/
+
+static NDIS_STATUS vboxNetFltWinMpHandlePowerState(PVBOXNETFLTINS pNetFlt, NDIS_DEVICE_POWER_STATE enmState)
+{
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0
+ && enmState != NdisDeviceStateD0)
+ {
+ /* invalid state transformation */
+ AssertFailed();
+ return NDIS_STATUS_FAILURE;
+ }
+
+#ifndef VBOXNETADP
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD0
+ && enmState > NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = TRUE;
+ }
+
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0
+ && enmState == NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = FALSE;
+ }
+#endif
+
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.MpState, enmState);
+
+#ifndef VBOXNETADP
+ if (pNetFlt->u.s.WinIf.StateFlags.fStandBy == FALSE)
+ {
+ if (pNetFlt->u.s.WinIf.MpIndicatedMediaStatus != pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus)
+ {
+ NdisMIndicateStatus(pNetFlt->u.s.WinIf.hMiniport, pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus, NULL, 0);
+ NdisMIndicateStatusComplete(pNetFlt->u.s.WinIf.hMiniport);
+ pNetFlt->u.s.WinIf.MpIndicatedMediaStatus = pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus;
+ }
+ }
+ else
+ {
+ pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus = pNetFlt->u.s.WinIf.MpIndicatedMediaStatus;
+ }
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+#ifndef VBOXNETADP
+static NDIS_STATUS vboxNetFltWinMpRequestPostSet(PVBOXNETFLTINS pNetFlt)
+{
+ if (pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ /* need to disable cleaning promiscuous here ?? */
+ bool fNetFltActive;
+ const bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &fNetFltActive);
+
+ Assert(pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer);
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter);
+
+ if (fNetFltActive)
+ {
+ Assert(fWinIfActive);
+
+ /* netflt is active, update the cached value */
+ /** @todo in case we are are not in promiscuous now, we are issuing a request.
+ * what should we do in case of a failure?
+ * i.e. should we update the fUpperProtocolSetFilter in completion routine in this case? etc. */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *((PULONG)pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer);
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+
+ if (!(pNetFlt->u.s.WinIf.fOurSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS))
+ {
+ pNetFlt->u.s.WinIf.fSetFilterBuffer = NDIS_PACKET_TYPE_PROMISCUOUS;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer = &pNetFlt->u.s.WinIf.fSetFilterBuffer;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof (pNetFlt->u.s.WinIf.fSetFilterBuffer);
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 1;
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 1;
+ /* we'll do dereferencing in request complete */
+ }
+ else
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ /* we've intercepted the query and completed it */
+ vboxNetFltWinMpRequestStateComplete(pNetFlt);
+ return NDIS_STATUS_SUCCESS;
+ }
+ }
+ else if (fWinIfActive)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 1;
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 0;
+ /* dereference on completion */
+ }
+ }
+
+ NDIS_STATUS Status;
+
+ NdisRequest(&Status, pNetFlt->u.s.WinIf.hBinding, &pNetFlt->u.s.WinIf.PassDownRequest);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ vboxNetFltWinPtRequestComplete(pNetFlt, &pNetFlt->u.s.WinIf.PassDownRequest, Status);
+ }
+
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRequestPost(PVBOXNETFLTINS pNetFlt)
+{
+ switch (pNetFlt->u.s.WinIf.PassDownRequest.RequestType)
+ {
+ case NdisRequestQueryInformation:
+ return vboxNetFltWinMpRequestPostQuery(pNetFlt);
+ case NdisRequestSetInformation:
+ return vboxNetFltWinMpRequestPostSet(pNetFlt);
+ default:
+ AssertBreakpoint();
+ return NDIS_STATUS_FAILURE;
+ }
+}
+
+static NDIS_STATUS vboxNetFltWinMpSetInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ switch (Oid)
+ {
+ case OID_PNP_SET_POWER:
+ {
+ if (InformationBufferLength >= sizeof (NDIS_DEVICE_POWER_STATE))
+ {
+ NDIS_DEVICE_POWER_STATE *penmState = (NDIS_DEVICE_POWER_STATE*)InformationBuffer;
+ Status = vboxNetFltWinMpHandlePowerState(pNetFlt, *penmState);
+ }
+ else
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
+ *BytesNeeded = 0;
+ }
+ else
+ {
+ *BytesRead = 0;
+ *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+ }
+ break;
+ }
+ default:
+ {
+ /* the oid is to be passed down,
+ * check the device state if we can do it
+ * and update device state accordingly */
+ UINT uOp = vboxNetFltWinMpRequestStatePrep(pNetFlt, &Status);
+ if (uOp)
+ {
+ /* save the request info */
+ pNetFlt->u.s.WinIf.PassDownRequest.RequestType = NdisRequestSetInformation;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.Oid = Oid;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;
+ pNetFlt->u.s.WinIf.pcPDRBytesNeeded = BytesNeeded;
+ pNetFlt->u.s.WinIf.pcPDRBytesRW = BytesRead;
+
+ /* the oid can be processed */
+ if (!(uOp & VBOXNDISREQUEST_QUEUED))
+ {
+ Status = vboxNetFltWinMpRequestPostSet(pNetFlt);
+ }
+ }
+ break;
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+#else
+static NDIS_OID g_vboxNetFltWinMpSupportedOids[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_PNP_CAPABILITIES,
+ OID_PNP_QUERY_POWER,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_PNP_SET_POWER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAC_OPTIONS,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS,
+};
+
+static NDIS_STATUS vboxNetFltWinMpQueryInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded)
+{
+ /* static data */
+ static const NDIS_HARDWARE_STATUS enmHwStatus = NdisHardwareStatusReady;
+ static const NDIS_MEDIUM enmMedium = NdisMedium802_3;
+ static NDIS_PNP_CAPABILITIES PnPCaps = {0};
+ static BOOLEAN bPnPCapsInited = FALSE;
+
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG64 u64Info = 0;
+ ULONG u32Info = 0;
+ USHORT u16Info = 0;
+ /* default is 4bytes */
+ const void* pvInfo = (void*)&u32Info;
+ ULONG cbInfo = sizeof (u32Info);
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ switch (Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+ pvInfo = g_vboxNetFltWinMpSupportedOids;
+ cbInfo = sizeof (g_vboxNetFltWinMpSupportedOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ pvInfo = &enmHwStatus;
+ cbInfo = sizeof (NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ pvInfo = &enmMedium;
+ cbInfo = sizeof (NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ u32Info = VBOXNETADP_MAX_LOOKAHEAD_SIZE;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ u32Info = VBOXNETADP_MAX_PACKET_SIZE - VBOXNETADP_HEADER_SIZE;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ u32Info = VBOXNETADP_MAX_PACKET_SIZE;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ u32Info = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_NO_LOOPBACK;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ u32Info = VBOXNETADP_LINK_SPEED;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ u32Info = VBOXNETADP_MAX_PACKET_SIZE * VBOXNETFLT_PACKET_INFO_POOL_SIZE;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ u32Info = VBOXNETADP_VENDOR_ID;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ pvInfo = VBOXNETADP_VENDOR_DESC;
+ cbInfo = sizeof (VBOXNETADP_VENDOR_DESC);
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ u32Info = VBOXNETADP_VENDOR_DRIVER_VERSION;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ u16Info = (USHORT)((VBOXNETFLT_VERSION_MP_NDIS_MAJOR << 8) + VBOXNETFLT_VERSION_MP_NDIS_MINOR);
+ pvInfo = (PVOID)&u16Info;
+ cbInfo = sizeof (USHORT);
+ break;
+
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ u32Info = VBOXNETFLT_PACKET_INFO_POOL_SIZE;
+ break;
+
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+#ifdef VBOXNETADP_REPORT_DISCONNECTED
+ {
+ bool bNetFltActive;
+ bool bActive = vboxNetFltWinReferenceWinIfNetFltFromAdapt(pNetFlt, bNetFltActive);
+ if (bActive && bNetFltActive)
+ {
+ u32Info = NdisMediaStateConnected;
+ }
+ else
+ {
+ u32Info = NdisMediaStateDisconnected;
+ }
+
+ if (bActive)
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ if (bNetFltActive)
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else
+ {
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+ }
+#else
+ u32Info = NdisMediaStateConnected;
+#endif
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ u32Info = NDIS_PACKET_TYPE_BROADCAST
+ | NDIS_PACKET_TYPE_DIRECTED
+ | NDIS_PACKET_TYPE_ALL_FUNCTIONAL
+ | NDIS_PACKET_TYPE_ALL_LOCAL
+ | NDIS_PACKET_TYPE_GROUP
+ | NDIS_PACKET_TYPE_MULTICAST;
+ break;
+
+ case OID_PNP_CAPABILITIES:
+ if (!bPnPCapsInited)
+ {
+ PnPCaps.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ PnPCaps.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
+ bPnPCapsInited = TRUE;
+ }
+ cbInfo = sizeof (NDIS_PNP_CAPABILITIES);
+ pvInfo = &PnPCaps;
+
+ break;
+
+ case OID_PNP_QUERY_POWER:
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ u64Info = pNetFlt->u.s.WinIf.cTxSuccess;
+ pvInfo = &u64Info;
+ if (InformationBufferLength >= sizeof (ULONG64) || InformationBufferLength == 0)
+ {
+ cbInfo = sizeof (ULONG64);
+ }
+ else
+ {
+ cbInfo = sizeof (ULONG);
+ }
+ *BytesNeeded = sizeof (ULONG64);
+ break;
+
+ case OID_GEN_RCV_OK:
+ u64Info = pNetFlt->u.s.WinIf.cRxSuccess;
+ pvInfo = &u64Info;
+ if (InformationBufferLength >= sizeof (ULONG64) || InformationBufferLength == 0)
+ {
+ cbInfo = sizeof (ULONG64);
+ }
+ else
+ {
+ cbInfo = sizeof (ULONG);
+ }
+ *BytesNeeded = sizeof (ULONG64);
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ u32Info = pNetFlt->u.s.WinIf.cTxError;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ u32Info = pNetFlt->u.s.WinIf.cRxError;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_GEN_RCV_CRC_ERROR:
+ u32Info = 0;
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ u32Info = VBOXNETFLT_PACKET_INFO_POOL_SIZE;
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ pvInfo = &pNetFlt->u.s.MacAddr;
+ cbInfo = VBOXNETADP_ETH_ADDRESS_LENGTH;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ pvInfo = &pNetFlt->u.s.MacAddr;
+ cbInfo = VBOXNETADP_ETH_ADDRESS_LENGTH;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ u32Info = VBOXNETADP_MAX_MCAST_LIST;
+ break;
+
+ case OID_802_3_MAC_OPTIONS:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ case OID_802_3_XMIT_DEFERRED:
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ case OID_802_3_RCV_OVERRUN:
+ case OID_802_3_XMIT_UNDERRUN:
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ u32Info = 0;
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (cbInfo <= InformationBufferLength)
+ {
+ *BytesWritten = cbInfo;
+ if (cbInfo)
+ NdisMoveMemory(InformationBuffer, pvInfo, cbInfo);
+ }
+ else
+ {
+ *BytesNeeded = cbInfo;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ }
+
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinMpSetInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS) MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ switch (Oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ *BytesRead = InformationBufferLength;
+ if (InformationBufferLength % VBOXNETADP_ETH_ADDRESS_LENGTH)
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ if (InformationBufferLength > (VBOXNETADP_MAX_MCAST_LIST * VBOXNETADP_ETH_ADDRESS_LENGTH))
+ {
+ Status = NDIS_STATUS_MULTICAST_FULL;
+ *BytesNeeded = VBOXNETADP_MAX_MCAST_LIST * VBOXNETADP_ETH_ADDRESS_LENGTH;
+ break;
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (InformationBufferLength != sizeof (ULONG))
+ {
+ *BytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ *BytesRead = InformationBufferLength;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (InformationBufferLength != sizeof (ULONG)){
+ *BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ break;
+
+ case OID_PNP_SET_POWER:
+ if (InformationBufferLength >= sizeof(NDIS_DEVICE_POWER_STATE))
+ {
+ NDIS_DEVICE_POWER_STATE *penmState = (NDIS_DEVICE_POWER_STATE*)InformationBuffer;
+ Status = vboxNetFltWinMpHandlePowerState(pNetFlt, *penmState);
+ }
+ else
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
+ *BytesNeeded = 0;
+ }
+ else
+ {
+ *BytesRead = 0;
+ *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+ }
+ break;
+
+ default:
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+
+#endif
+
+#define VBOXNETFLTDUMP_STRCASE(_t) \
+ case _t: return #_t;
+#define VBOXNETFLTDUMP_STRCASE_UNKNOWN() \
+ default: /*AssertFailed();*/ return "Unknown";
+
+static const char* vboxNetFltWinMpDumpOid(ULONG oid)
+{
+ switch (oid)
+ {
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_SUPPORTED_LIST)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_HARDWARE_STATUS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_SUPPORTED)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_IN_USE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_LOOKAHEAD)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_FRAME_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_LINK_SPEED)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSMIT_BUFFER_SPACE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RECEIVE_BUFFER_SPACE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSMIT_BLOCK_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RECEIVE_BLOCK_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VENDOR_ID)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VENDOR_DESCRIPTION)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_CURRENT_PACKET_FILTER)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_CURRENT_LOOKAHEAD)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DRIVER_VERSION)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_TOTAL_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_PROTOCOL_OPTIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAC_OPTIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_CONNECT_STATUS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_SEND_PACKETS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VENDOR_DRIVER_VERSION)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_SUPPORTED_GUIDS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_NETWORK_LAYER_ADDRESSES)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSPORT_HEADER_OFFSET)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MACHINE_NAME)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RNDIS_CONFIG_PARAMETER)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VLAN_ID)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_CAPABILITIES)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_PHYSICAL_MEDIUM)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_XMIT_OK)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_OK)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_XMIT_ERROR)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_ERROR)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_NO_BUFFER)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_BYTES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_FRAMES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_BYTES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_FRAMES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_BYTES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_FRAMES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_BYTES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_FRAMES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_BYTES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_FRAMES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_BYTES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_FRAMES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_CRC_ERROR)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSMIT_QUEUE_LENGTH)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_GET_TIME_CAPS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_GET_NETCARD_TIME)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_NETCARD_LOAD)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DEVICE_PROFILE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_INIT_TIME_MS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RESET_COUNTS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_SENSE_COUNTS)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_CAPABILITIES)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_SET_POWER)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_QUERY_POWER)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_ADD_WAKE_UP_PATTERN)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_REMOVE_WAKE_UP_PATTERN)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_ENABLE_WAKE_UP)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_PERMANENT_ADDRESS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_CURRENT_ADDRESS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_MULTICAST_LIST)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_MAXIMUM_LIST_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_MAC_OPTIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_RCV_ERROR_ALIGNMENT)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_ONE_COLLISION)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_MORE_COLLISIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_DEFERRED)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_MAX_COLLISIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_RCV_OVERRUN)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_UNDERRUN)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_HEARTBEAT_FAILURE)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_TIMES_CRS_LOST)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_LATE_COLLISIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_OFFLOAD)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_ADD_SA)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_DELETE_SA)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_SAN_SUPPORT)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA)
+ VBOXNETFLTDUMP_STRCASE_UNKNOWN()
+ }
+}
+
+DECLHIDDEN(VOID) vboxNetFltWinMpReturnPacket(IN NDIS_HANDLE hMiniportAdapterContext, IN PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hMiniportAdapterContext;
+ PVBOXNETFLT_PKTRSVD_MP pInfo = (PVBOXNETFLT_PKTRSVD_MP)pPacket->MiniportReserved;
+ PNDIS_PACKET pOrigPacket = pInfo->pOrigPacket;
+ PVOID pBufToFree = pInfo->pBufToFree;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (pOrigPacket)
+ {
+ /* the packet was sent from underlying miniport */
+ NdisFreePacket(pPacket);
+ NdisReturnPackets(&pOrigPacket, 1);
+ }
+ else
+ {
+ /* the packet was sent from IntNet or it is a packet we allocated on PtReceive for TransferData processing */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, !pBufToFree /* bFreeMem */);
+ }
+
+ if (pBufToFree)
+ {
+ vboxNetFltWinMemFree(pBufToFree);
+ }
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static NDIS_STATUS vboxNetFltWinMpTransferData(OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE hContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer)
+{
+#ifndef VBOXNETADP
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ NDIS_STATUS Status;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if ( vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState) != NdisDeviceStateD0
+ || vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) != NdisDeviceStateD0)
+ {
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, NDIS_STATUS_FAILURE));
+ return NDIS_STATUS_FAILURE;
+ }
+
+ NdisTransferData(&Status, pNetFlt->u.s.WinIf.hBinding, MiniportReceiveContext,
+ ByteOffset, BytesToTransfer, Packet, BytesTransferred);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+ return Status;
+
+#else
+ RT_NOREF6(Packet, BytesTransferred, hContext, MiniportReceiveContext, ByteOffset, BytesToTransfer);
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", hContext));
+ /* should never be here */
+ AssertFailed();
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", hContext, NDIS_STATUS_FAILURE));
+ return NDIS_STATUS_FAILURE;
+#endif
+}
+
+static void vboxNetFltWinMpHalt(IN NDIS_HANDLE hContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ NDIS_STATUS Status;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+#ifndef VBOXNETADP
+ if (vboxNetFltWinGetWinIfState(pNetFlt) == kVBoxWinIfState_Disconnecting)
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+
+ vboxNetFltWinPtCloseInterface(pNetFlt, &Status);
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+#endif
+ {
+ /* we're NOT called from protocolUnbinAdapter, perform a full disconnect */
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+#ifndef VBOXNETADP
+ AssertBreakpoint();
+#endif
+ Status = vboxNetFltWinDetachFromInterface(pNetFlt, false);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+/**
+ * register the miniport edge
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRegister(PVBOXNETFLTGLOBALS_MP pGlobalsMp, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
+{
+ NDIS_MINIPORT_CHARACTERISTICS MpChars;
+
+ NdisMInitializeWrapper(&pGlobalsMp->hNdisWrapper, pDriverObject, pRegistryPathStr, NULL);
+
+ NdisZeroMemory(&MpChars, sizeof (MpChars));
+
+ MpChars.MajorNdisVersion = VBOXNETFLT_VERSION_MP_NDIS_MAJOR;
+ MpChars.MinorNdisVersion = VBOXNETFLT_VERSION_MP_NDIS_MINOR;
+
+ MpChars.HaltHandler = vboxNetFltWinMpHalt;
+ MpChars.InitializeHandler = vboxNetFltWinMpInitialize;
+ MpChars.QueryInformationHandler = vboxNetFltWinMpQueryInformation;
+ MpChars.SetInformationHandler = vboxNetFltWinMpSetInformation;
+ MpChars.TransferDataHandler = vboxNetFltWinMpTransferData;
+ MpChars.ReturnPacketHandler = vboxNetFltWinMpReturnPacket;
+ MpChars.SendPacketsHandler = vboxNetFltWinMpSendPackets;
+
+#ifndef VBOXNETADP
+ NDIS_STATUS Status = NdisIMRegisterLayeredMiniport(pGlobalsMp->hNdisWrapper, &MpChars, sizeof (MpChars), &pGlobalsMp->hMiniport);
+#else
+ NDIS_STATUS Status = NdisMRegisterMiniport(pGlobalsMp->hNdisWrapper, &MpChars, sizeof (MpChars));
+#endif
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisMRegisterUnloadHandler(pGlobalsMp->hNdisWrapper, vboxNetFltWinUnload);
+ }
+
+ return Status;
+}
+
+/**
+ * deregister the miniport edge
+ */
+DECLHIDDEN(VOID) vboxNetFltWinMpDeregister(PVBOXNETFLTGLOBALS_MP pGlobalsMp)
+{
+#ifndef VBOXNETADP
+ NdisIMDeregisterLayeredMiniport(pGlobalsMp->hMiniport);
+#endif
+ NdisTerminateWrapper(pGlobalsMp->hNdisWrapper, NULL);
+
+ NdisZeroMemory(pGlobalsMp, sizeof (*pGlobalsMp));
+}
+
+#ifndef VBOXNETADP
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpInitializeDevideInstance(PVBOXNETFLTINS pThis)
+{
+ NDIS_STATUS Status;
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Initializing);
+
+ Status = NdisIMInitializeDeviceInstanceEx(g_VBoxNetFltGlobalsWin.Mp.hMiniport,
+ &pThis->u.s.WinIf.MpDeviceName,
+ pThis);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pThis->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+ AssertBreakpoint();
+ vboxNetFltWinMpDeInitializeDeviceInstance(pThis, &Status);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ return pThis->u.s.WinIf.OpenCloseStatus;
+ }
+
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+
+ return Status;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinMpDeInitializeDeviceInstance(PVBOXNETFLTINS pThis, PNDIS_STATUS pStatus)
+{
+ NDIS_STATUS Status;
+
+ if (vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initializing)
+ {
+ Status = NdisIMCancelInitializeDeviceInstance(g_VBoxNetFltGlobalsWin.Mp.hMiniport, &pThis->u.s.WinIf.MpDeviceName);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ /* we've canceled the initialization successfully */
+ Assert(pThis->u.s.WinIf.hMiniport == NULL);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+ NdisWaitEvent(&pThis->u.s.WinIf.MpInitCompleteEvent, 0);
+ }
+ else
+ Status = NDIS_STATUS_SUCCESS;
+
+ Assert( vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized
+ || vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ if (vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized)
+ {
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+
+ Status = NdisIMDeInitializeDeviceInstance(pThis->u.s.WinIf.hMiniport);
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ if (Status != NDIS_STATUS_SUCCESS)
+ Status = NDIS_STATUS_FAILURE;
+
+ *pStatus = Status;
+ return true;
+ }
+
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+
+ *pStatus = Status;
+ return false;
+}
+
+#endif /* !VBOXNETADP */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h
new file mode 100644
index 00000000..7a904aa8
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h
@@ -0,0 +1,67 @@
+/* $Id: VBoxNetFltM-win.h $ */
+/** @file
+ * VBoxNetFltM-win.h - Bridged Networking Driver, Windows Specific Code - Miniport edge API
+ */
+
+/*
+ * 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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltM_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltM_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRegister(PVBOXNETFLTGLOBALS_MP pGlobalsMp, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr);
+DECLHIDDEN(VOID) vboxNetFltWinMpDeregister(PVBOXNETFLTGLOBALS_MP pGlobalsMp);
+DECLHIDDEN(VOID) vboxNetFltWinMpReturnPacket(IN NDIS_HANDLE hMiniportAdapterContext, IN PNDIS_PACKET pPacket);
+
+#ifdef VBOXNETADP
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoInitialization(PVBOXNETFLTINS pThis, NDIS_HANDLE hMiniportAdapter, NDIS_HANDLE hWrapperConfigurationContext);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoDeinitialization(PVBOXNETFLTINS pThis);
+
+#else
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpInitializeDevideInstance(PVBOXNETFLTINS pThis);
+DECLHIDDEN(bool) vboxNetFltWinMpDeInitializeDeviceInstance(PVBOXNETFLTINS pThis, PNDIS_STATUS pStatus);
+
+DECLINLINE(VOID) vboxNetFltWinMpRequestStateComplete(PVBOXNETFLTINS pNetFlt)
+{
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = 0;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRequestPost(PVBOXNETFLTINS pNetFlt);
+#endif
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltM_win_h */
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf
new file mode 100644
index 00000000..fcf30fc8
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf
@@ -0,0 +1,82 @@
+; $Id: VBoxNetFltM.inf $
+;; @file
+; VBoxNetFltM.inf - VirtualBox Bridged Networking Driver inf file Miniport 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
+;
+
+[Version]
+signature = "$Windows NT$"
+;cat CatalogFile = VBoxNetFlt.cat
+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %ORACLE%
+;DriverPackageType=NdisImMiniport
+;DriverPackageDisplayName=%VBoxNetFltMP_Desc%
+;edit-DriverVer=08/13/2008,1.1.0.1
+
+[ControlFlags]
+ExcludeFromSelect = sun_VBoxNetFltmp
+
+[DestinationDirs]
+DefaultDestDir=12
+; No files to copy
+
+[Manufacturer]
+%ORACLE% = VBoxNetFltMP@COMMA-NT-ARCH@
+
+[VBoxNetFltMP@DOT-NT-ARCH@]
+%VBoxNetFltMP_Desc% = VBoxNetFltMP.ndi, sun_VBoxNetFltmp
+
+[VBoxNetFltMP.ndi]
+Characteristics = 0x29 ;NCF_NOT_USER_REMOVABLE | NCF_VIRTUAL | NCF_HIDDEN
+CopyFiles =
+
+[VBoxNetFltMP.ndi.Services]
+AddService = VBoxNetFlt,0x2, VBoxNetFltMP.AddService
+
+[VBoxNetFltMP.AddService]
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetFlt.sys
+
+[VBoxNetFltMP.AddService.AddReg]
+
+[Strings]
+ORACLE = "Oracle Corporation"
+VBoxNetFltMP_Desc = "VirtualBox Bridged Networking Driver Miniport"
+
+[SourceDisksNames]
+
+[SourceDisksFiles]
+
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;
+}
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h
new file mode 100644
index 00000000..11910676
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h
@@ -0,0 +1,52 @@
+/* $Id: VBoxNetFltP-win.h $ */
+/** @file
+ * VBoxNetFltP-win.h - Bridged Networking Driver, Windows Specific Code.
+ * Protocol edge API
+ */
+/*
+ * 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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltP_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltP_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#ifdef VBOXNETADP
+# error "No protocol edge"
+#endif
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtRegister(PVBOXNETFLTGLOBALS_PT pGlobalsPt, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDeregister(PVBOXNETFLTGLOBALS_PT pGlobalsPt);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoUnbinding(PVBOXNETFLTINS pNetFlt, bool bOnUnbind);
+DECLHIDDEN(VOID) vboxNetFltWinPtRequestComplete(NDIS_HANDLE hContext, PNDIS_REQUEST pNdisRequest, NDIS_STATUS Status);
+DECLHIDDEN(bool) vboxNetFltWinPtCloseInterface(PVBOXNETFLTINS pNetFlt, PNDIS_STATUS pStatus);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(PVBOXNETFLTINS pThis, PNDIS_STRING pOurDeviceName, PNDIS_STRING pBindToDeviceName);
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltP_win_h */
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;
+}
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h
new file mode 100644
index 00000000..36235409
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h
@@ -0,0 +1,972 @@
+/* $Id: VBoxNetFltRt-win.h $ */
+/** @file
+ * VBoxNetFltRt-win.h - Bridged Networking Driver, Windows Specific Code.
+ * NetFlt Runtime API
+ */
+/*
+ * 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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltRt_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltRt_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+DECLHIDDEN(VOID) vboxNetFltWinUnload(IN PDRIVER_OBJECT DriverObject);
+
+#ifndef VBOXNETADP
+# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch);
+DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch);
+# endif
+#endif
+
+/*************************
+ * packet queue API *
+ *************************/
+
+
+#define LIST_ENTRY_2_PACKET_INFO(pListEntry) \
+ ( (PVBOXNETFLT_PACKET_INFO)((uint8_t *)(pListEntry) - RT_UOFFSETOF(VBOXNETFLT_PACKET_INFO, ListEntry)) )
+
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+
+#define VBOX_SLE_2_PKTRSVD_PT(_pEntry) \
+ ( (PVBOXNETFLT_PKTRSVD_PT)((uint8_t *)(_pEntry) - RT_UOFFSETOF(VBOXNETFLT_PKTRSVD_PT, ListEntry)) )
+
+#define VBOX_SLE_2_SENDPACKET(_pEntry) \
+ ( (PNDIS_PACKET)((uint8_t *)(VBOX_SLE_2_PKTRSVD_PT(_pEntry)) - RT_UOFFSETOF(NDIS_PACKET, ProtocolReserved)) )
+
+#endif
+/**
+ * enqueus the packet info to the tail of the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuEnqueueTail(PVBOXNETFLT_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ InsertTailList(pQueue, &pPacketInfo->ListEntry);
+}
+
+DECLINLINE(void) vboxNetFltWinQuEnqueueHead(PVBOXNETFLT_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ Assert(pPacketInfo->pPool);
+ InsertHeadList(pQueue, &pPacketInfo->ListEntry);
+}
+
+/**
+ * enqueus the packet info to the tail of the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuInterlockedEnqueueTail(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ Assert(pPacketInfo->pPool);
+ NdisAcquireSpinLock(&pQueue->Lock);
+ vboxNetFltWinQuEnqueueTail(&pQueue->Queue, pPacketInfo);
+ NdisReleaseSpinLock(&pQueue->Lock);
+}
+
+DECLINLINE(void) vboxNetFltWinQuInterlockedEnqueueHead(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ NdisAcquireSpinLock(&pQueue->Lock);
+ vboxNetFltWinQuEnqueueHead(&pQueue->Queue, pPacketInfo);
+ NdisReleaseSpinLock(&pQueue->Lock);
+}
+
+/**
+ * dequeus the packet info from the head of the queue
+ */
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuDequeueHead(PVBOXNETFLT_PACKET_QUEUE pQueue)
+{
+ PLIST_ENTRY pListEntry = RemoveHeadList(pQueue);
+ if (pListEntry != pQueue)
+ {
+ PVBOXNETFLT_PACKET_INFO pInfo = LIST_ENTRY_2_PACKET_INFO(pListEntry);
+ Assert(pInfo->pPool);
+ return pInfo;
+ }
+ return NULL;
+}
+
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuDequeueTail(PVBOXNETFLT_PACKET_QUEUE pQueue)
+{
+ PLIST_ENTRY pListEntry = RemoveTailList(pQueue);
+ if (pListEntry != pQueue)
+ {
+ PVBOXNETFLT_PACKET_INFO pInfo = LIST_ENTRY_2_PACKET_INFO(pListEntry);
+ Assert(pInfo->pPool);
+ return pInfo;
+ }
+ return NULL;
+}
+
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuInterlockedDequeueHead(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pInterlockedQueue)
+{
+ PVBOXNETFLT_PACKET_INFO pInfo;
+ NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+ pInfo = vboxNetFltWinQuDequeueHead(&pInterlockedQueue->Queue);
+ NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+ return pInfo;
+}
+
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuInterlockedDequeueTail(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pInterlockedQueue)
+{
+ PVBOXNETFLT_PACKET_INFO pInfo;
+ NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+ pInfo = vboxNetFltWinQuDequeueTail(&pInterlockedQueue->Queue);
+ NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+ return pInfo;
+}
+
+DECLINLINE(void) vboxNetFltWinQuDequeue(PVBOXNETFLT_PACKET_INFO pInfo)
+{
+ RemoveEntryList(&pInfo->ListEntry);
+}
+
+DECLINLINE(void) vboxNetFltWinQuInterlockedDequeue(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pInterlockedQueue, PVBOXNETFLT_PACKET_INFO pInfo)
+{
+ NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+ vboxNetFltWinQuDequeue(pInfo);
+ NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+}
+
+/**
+ * allocates the packet info from the pool
+ */
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinPpAllocPacketInfo(PVBOXNETFLT_PACKET_INFO_POOL pPool)
+{
+ return vboxNetFltWinQuInterlockedDequeueHead(&pPool->Queue);
+}
+
+/**
+ * returns the packet info to the pool
+ */
+DECLINLINE(void) vboxNetFltWinPpFreePacketInfo(PVBOXNETFLT_PACKET_INFO pInfo)
+{
+ PVBOXNETFLT_PACKET_INFO_POOL pPool = pInfo->pPool;
+ vboxNetFltWinQuInterlockedEnqueueHead(&pPool->Queue, pInfo);
+}
+
+/** initializes the packet queue */
+#define INIT_PACKET_QUEUE(_pQueue) InitializeListHead((_pQueue))
+
+/** initializes the packet queue */
+#define INIT_INTERLOCKED_PACKET_QUEUE(_pQueue) \
+ { \
+ INIT_PACKET_QUEUE(&(_pQueue)->Queue); \
+ NdisAllocateSpinLock(&(_pQueue)->Lock); \
+ }
+
+/** delete the packet queue */
+#define FINI_INTERLOCKED_PACKET_QUEUE(_pQueue) NdisFreeSpinLock(&(_pQueue)->Lock)
+
+/** returns the packet the packet info contains */
+#define GET_PACKET_FROM_INFO(_pPacketInfo) (ASMAtomicUoReadPtr((void * volatile *)&(_pPacketInfo)->pPacket))
+
+/** assignes the packet to the packet info */
+#define SET_PACKET_TO_INFO(_pPacketInfo, _pPacket) (ASMAtomicUoWritePtr(&(_pPacketInfo)->pPacket, (_pPacket)))
+
+/** returns the flags the packet info contains */
+#define GET_FLAGS_FROM_INFO(_pPacketInfo) (ASMAtomicUoReadU32((volatile uint32_t *)&(_pPacketInfo)->fFlags))
+
+/** sets flags to the packet info */
+#define SET_FLAGS_TO_INFO(_pPacketInfo, _fFlags) (ASMAtomicUoWriteU32((volatile uint32_t *)&(_pPacketInfo)->fFlags, (_fFlags)))
+
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+DECLHIDDEN(bool) vboxNetFltWinPostIntnet(PVBOXNETFLTINS pInstance, PVOID pvPacket, const UINT fFlags);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQuEnqueuePacket(PVBOXNETFLTINS pInstance, PVOID pPacket, const UINT fPacketFlags);
+DECLHIDDEN(void) vboxNetFltWinQuFiniPacketQueue(PVBOXNETFLTINS pInstance);
+DECLHIDDEN(NTSTATUS) vboxNetFltWinQuInitPacketQueue(PVBOXNETFLTINS pInstance);
+#endif /* #ifndef VBOXNETFLT_NO_PACKET_QUEUE */
+
+
+#ifndef VBOXNETADP
+/**
+ * searches the list entry in a single-linked list
+ */
+DECLINLINE(bool) vboxNetFltWinSearchListEntry(PVBOXNETFLT_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry2Search, bool bRemove)
+{
+ PSINGLE_LIST_ENTRY pHead = &pList->Head;
+ PSINGLE_LIST_ENTRY pCur;
+ PSINGLE_LIST_ENTRY pPrev;
+ for (pCur = pHead->Next, pPrev = pHead; pCur; pPrev = pCur, pCur = pCur->Next)
+ {
+ if (pEntry2Search == pCur)
+ {
+ if (bRemove)
+ {
+ pPrev->Next = pCur->Next;
+ if (pCur == pList->pTail)
+ {
+ pList->pTail = pPrev;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinSearchPacket(PVBOXNETFLT_SINGLE_LIST pList, PNDIS_PACKET pPacket2Search, int cbMatch, bool bRemove)
+{
+ PSINGLE_LIST_ENTRY pHead = &pList->Head;
+ PSINGLE_LIST_ENTRY pCur;
+ PSINGLE_LIST_ENTRY pPrev;
+ PNDIS_PACKET pCurPacket;
+ for (pCur = pHead->Next, pPrev = pHead; pCur; pPrev = pCur, pCur = pCur->Next)
+ {
+ pCurPacket = VBOX_SLE_2_SENDPACKET(pCur);
+ if (pCurPacket == pPacket2Search || vboxNetFltWinMatchPackets(pPacket2Search, pCurPacket, cbMatch))
+ {
+ if (bRemove)
+ {
+ pPrev->Next = pCur->Next;
+ if (pCur == pList->pTail)
+ {
+ pList->pTail = pPrev;
+ }
+ }
+ return pCurPacket;
+ }
+ }
+ return NULL;
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinSearchPacketBySG(PVBOXNETFLT_SINGLE_LIST pList, PINTNETSG pSG, int cbMatch, bool bRemove)
+{
+ PSINGLE_LIST_ENTRY pHead = &pList->Head;
+ PSINGLE_LIST_ENTRY pCur;
+ PSINGLE_LIST_ENTRY pPrev;
+ PNDIS_PACKET pCurPacket;
+ for (pCur = pHead->Next, pPrev = pHead; pCur; pPrev = pCur, pCur = pCur->Next)
+ {
+ pCurPacket = VBOX_SLE_2_SENDPACKET(pCur);
+ if (vboxNetFltWinMatchPacketAndSG(pCurPacket, pSG, cbMatch))
+ {
+ if (bRemove)
+ {
+ pPrev->Next = pCur->Next;
+ if (pCur == pList->pTail)
+ {
+ pList->pTail = pPrev;
+ }
+ }
+ return pCurPacket;
+ }
+ }
+ return NULL;
+}
+
+#endif /* #if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS) */
+
+DECLINLINE(bool) vboxNetFltWinSListIsEmpty(PVBOXNETFLT_SINGLE_LIST pList)
+{
+ return !pList->Head.Next;
+}
+
+DECLINLINE(void) vboxNetFltWinPutTail(PVBOXNETFLT_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ pList->pTail->Next = pEntry;
+ pList->pTail = pEntry;
+ pEntry->Next = NULL;
+}
+
+DECLINLINE(void) vboxNetFltWinPutHead(PVBOXNETFLT_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ pEntry->Next = pList->Head.Next;
+ pList->Head.Next = pEntry;
+ if (!pEntry->Next)
+ pList->pTail = pEntry;
+}
+
+DECLINLINE(PSINGLE_LIST_ENTRY) vboxNetFltWinGetHead(PVBOXNETFLT_SINGLE_LIST pList)
+{
+ PSINGLE_LIST_ENTRY pEntry = pList->Head.Next;
+ if (pEntry && pEntry == pList->pTail)
+ {
+ pList->Head.Next = NULL;
+ pList->pTail = &pList->Head;
+ }
+ return pEntry;
+}
+
+DECLINLINE(bool) vboxNetFltWinInterlockedSearchListEntry(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry2Search, bool bRemove)
+{
+ bool bFound;
+ NdisAcquireSpinLock(&pList->Lock);
+ bFound = vboxNetFltWinSearchListEntry(&pList->List, pEntry2Search, bRemove);
+ NdisReleaseSpinLock(&pList->Lock);
+ return bFound;
+}
+
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinInterlockedSearchPacket(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket2Search, int cbMatch, bool bRemove)
+{
+ PNDIS_PACKET pFound;
+ NdisAcquireSpinLock(&pList->Lock);
+ pFound = vboxNetFltWinSearchPacket(&pList->List, pPacket2Search, cbMatch, bRemove);
+ NdisReleaseSpinLock(&pList->Lock);
+ return pFound;
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinInterlockedSearchPacketBySG(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PINTNETSG pSG, int cbMatch, bool bRemove)
+{
+ PNDIS_PACKET pFound;
+ NdisAcquireSpinLock(&pList->Lock);
+ pFound = vboxNetFltWinSearchPacketBySG(&pList->List, pSG, cbMatch, bRemove);
+ NdisReleaseSpinLock(&pList->Lock);
+ return pFound;
+}
+#endif /* #if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS) */
+
+DECLINLINE(void) vboxNetFltWinInterlockedPutTail(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ NdisAcquireSpinLock(&pList->Lock);
+ vboxNetFltWinPutTail(&pList->List, pEntry);
+ NdisReleaseSpinLock(&pList->Lock);
+}
+
+DECLINLINE(void) vboxNetFltWinInterlockedPutHead(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ NdisAcquireSpinLock(&pList->Lock);
+ vboxNetFltWinPutHead(&pList->List, pEntry);
+ NdisReleaseSpinLock(&pList->Lock);
+}
+
+DECLINLINE(PSINGLE_LIST_ENTRY) vboxNetFltWinInterlockedGetHead(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList)
+{
+ PSINGLE_LIST_ENTRY pEntry;
+ NdisAcquireSpinLock(&pList->Lock);
+ pEntry = vboxNetFltWinGetHead(&pList->List);
+ NdisReleaseSpinLock(&pList->Lock);
+ return pEntry;
+}
+
+# if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+DECLINLINE(void) vboxNetFltWinLbPutSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, bool bFromIntNet)
+{
+ PVBOXNETFLT_PKTRSVD_PT pSrv = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ pSrv->bFromIntNet = bFromIntNet;
+ vboxNetFltWinInterlockedPutHead(&pNetFlt->u.s.WinIf.SendPacketQueue, &pSrv->ListEntry);
+}
+
+DECLINLINE(bool) vboxNetFltWinLbIsFromIntNet(PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLT_PKTRSVD_PT pSrv = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ return pSrv->bFromIntNet;
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinLbSearchLoopBack(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, bool bRemove)
+{
+ return vboxNetFltWinInterlockedSearchPacket(&pNetFlt->u.s.WinIf.SendPacketQueue, pPacket, VBOXNETFLT_PACKETMATCH_LENGTH, bRemove);
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinLbSearchLoopBackBySG(PVBOXNETFLTINS pNetFlt, PINTNETSG pSG, bool bRemove)
+{
+ return vboxNetFltWinInterlockedSearchPacketBySG(&pNetFlt->u.s.WinIf.SendPacketQueue, pSG, VBOXNETFLT_PACKETMATCH_LENGTH, bRemove);
+}
+
+DECLINLINE(bool) vboxNetFltWinLbRemoveSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLT_PKTRSVD_PT pSrv = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ bool bRet = vboxNetFltWinInterlockedSearchListEntry(&pNetFlt->u.s.WinIf.SendPacketQueue, &pSrv->ListEntry, true);
+#ifdef DEBUG_misha
+ Assert(bRet == (pNetFlt->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE));
+#endif
+ return bRet;
+}
+
+# endif
+
+#endif
+
+#ifdef DEBUG_misha
+DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc);
+DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc);
+extern RTMAC g_vboxNetFltWinVerifyMACBroadcast;
+extern RTMAC g_vboxNetFltWinVerifyMACGuest;
+
+# define VBOXNETFLT_LBVERIFY(_pnf, _p) \
+ do { \
+ Assert(!vboxNetFltWinCheckMACs(_p, NULL, &g_vboxNetFltWinVerifyMACGuest)); \
+ Assert(!vboxNetFltWinCheckMACs(_p, NULL, &(_pnf)->u.s.MacAddr)); \
+ } while (0)
+
+# define VBOXNETFLT_LBVERIFYSG(_pnf, _p) \
+ do { \
+ Assert(!vboxNetFltWinCheckMACsSG(_p, NULL, &g_vboxNetFltWinVerifyMACGuest)); \
+ Assert(!vboxNetFltWinCheckMACsSG(_p, NULL, &(_pnf)->u.s.MacAddr)); \
+ } while (0)
+
+#else
+# define VBOXNETFLT_LBVERIFY(_pnf, _p) do { } while (0)
+# define VBOXNETFLT_LBVERIFYSG(_pnf, _p) do { } while (0)
+#endif
+
+/** initializes the list */
+#define INIT_SINGLE_LIST(_pList) \
+ { \
+ (_pList)->Head.Next = NULL; \
+ (_pList)->pTail = &(_pList)->Head; \
+ }
+
+/** initializes the list */
+#define INIT_INTERLOCKED_SINGLE_LIST(_pList) \
+ do { \
+ INIT_SINGLE_LIST(&(_pList)->List); \
+ NdisAllocateSpinLock(&(_pList)->Lock); \
+ } while (0)
+
+/** delete the packet queue */
+#define FINI_INTERLOCKED_SINGLE_LIST(_pList) \
+ do { \
+ Assert(vboxNetFltWinSListIsEmpty(&(_pList)->List)); \
+ NdisFreeSpinLock(&(_pList)->Lock); \
+ } while (0)
+
+
+/**************************************************************************
+ * PVBOXNETFLTINS , WinIf reference/dereference (i.e. retain/release) API *
+ **************************************************************************/
+
+
+DECLHIDDEN(void) vboxNetFltWinWaitDereference(PVBOXNETFLT_WINIF_DEVICE pState);
+
+DECLINLINE(void) vboxNetFltWinReferenceModeNetFlt(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicIncU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinReferenceModePassThru(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicIncU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinIncReferenceModeNetFlt(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs, v);
+}
+
+DECLINLINE(void) vboxNetFltWinIncReferenceModePassThru(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs, v);
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceModeNetFlt(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicDecU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceModePassThru(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicDecU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceModeNetFlt(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ Assert(v);
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs, (uint32_t)(-((int32_t)v)));
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceModePassThru(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ Assert(v);
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs, (uint32_t)(-((int32_t)v)));
+}
+
+DECLINLINE(void) vboxNetFltWinSetPowerState(PVBOXNETFLT_WINIF_DEVICE pState, NDIS_DEVICE_POWER_STATE State)
+{
+ ASMAtomicUoWriteU32((volatile uint32_t *)&pState->PowerState, State);
+}
+
+DECLINLINE(NDIS_DEVICE_POWER_STATE) vboxNetFltWinGetPowerState(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ return (NDIS_DEVICE_POWER_STATE)ASMAtomicUoReadU32((volatile uint32_t *)&pState->PowerState);
+}
+
+DECLINLINE(void) vboxNetFltWinSetOpState(PVBOXNETFLT_WINIF_DEVICE pState, VBOXNETDEVOPSTATE State)
+{
+ ASMAtomicUoWriteU32((volatile uint32_t *)&pState->OpState, State);
+}
+
+DECLINLINE(VBOXNETDEVOPSTATE) vboxNetFltWinGetOpState(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ return (VBOXNETDEVOPSTATE)ASMAtomicUoReadU32((volatile uint32_t *)&pState->OpState);
+}
+
+DECLINLINE(bool) vboxNetFltWinDoReferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ if (vboxNetFltWinGetPowerState(pState) == NdisDeviceStateD0 && vboxNetFltWinGetOpState(pState) == kVBoxNetDevOpState_Initialized)
+ {
+ /** @todo r=bird: Since this is a volatile member, why don't you declare it as
+ * such and save yourself all the casting? */
+ ASMAtomicIncU32((uint32_t volatile *)&pState->cReferences);
+ return true;
+ }
+ return false;
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(bool) vboxNetFltWinDoReferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2)
+{
+ if (vboxNetFltWinGetPowerState(pState1) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState1) == kVBoxNetDevOpState_Initialized
+ && vboxNetFltWinGetPowerState(pState2) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState2) == kVBoxNetDevOpState_Initialized)
+ {
+ ASMAtomicIncU32((uint32_t volatile *)&pState1->cReferences);
+ ASMAtomicIncU32((uint32_t volatile *)&pState2->cReferences);
+ return true;
+ }
+ return false;
+}
+#endif
+
+DECLINLINE(void) vboxNetFltWinDereferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ ASMAtomicDecU32((uint32_t volatile *)&pState->cReferences);
+ /** @todo r=bird: Add comment explaining why these cannot hit 0 or why
+ * reference are counted */
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(void) vboxNetFltWinDereferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2)
+{
+ ASMAtomicDecU32((uint32_t volatile *)&pState1->cReferences);
+ ASMAtomicDecU32((uint32_t volatile *)&pState2->cReferences);
+}
+#endif
+
+DECLINLINE(void) vboxNetFltWinDecReferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState, uint32_t v)
+{
+ Assert(v);
+ ASMAtomicAddU32((uint32_t volatile *)&pState->cReferences, (uint32_t)(-((int32_t)v)));
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(void) vboxNetFltWinDecReferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2, uint32_t v)
+{
+ ASMAtomicAddU32((uint32_t volatile *)&pState1->cReferences, (uint32_t)(-((int32_t)v)));
+ ASMAtomicAddU32((uint32_t volatile *)&pState2->cReferences, (uint32_t)(-((int32_t)v)));
+}
+#endif
+
+DECLINLINE(bool) vboxNetFltWinDoIncReferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState, uint32_t v)
+{
+ Assert(v);
+ if (vboxNetFltWinGetPowerState(pState) == NdisDeviceStateD0 && vboxNetFltWinGetOpState(pState) == kVBoxNetDevOpState_Initialized)
+ {
+ ASMAtomicAddU32((uint32_t volatile *)&pState->cReferences, v);
+ return true;
+ }
+ return false;
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(bool) vboxNetFltWinDoIncReferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2, uint32_t v)
+{
+ if (vboxNetFltWinGetPowerState(pState1) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState1) == kVBoxNetDevOpState_Initialized
+ && vboxNetFltWinGetPowerState(pState2) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState2) == kVBoxNetDevOpState_Initialized)
+ {
+ ASMAtomicAddU32((uint32_t volatile *)&pState1->cReferences, v);
+ ASMAtomicAddU32((uint32_t volatile *)&pState2->cReferences, v);
+ return true;
+ }
+ return false;
+}
+#endif
+
+
+DECLINLINE(bool) vboxNetFltWinReferenceWinIfNetFlt(PVBOXNETFLTINS pNetFlt, bool * pbNetFltActive)
+{
+ RTSpinlockAcquire((pNetFlt)->hSpinlock);
+#ifndef VBOXNETADP
+ if (!vboxNetFltWinDoReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState))
+#else
+ if (!vboxNetFltWinDoReferenceDevice(&pNetFlt->u.s.WinIf.MpState))
+#endif
+ {
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+ *pbNetFltActive = false;
+ return false;
+ }
+
+ if (pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE)
+ {
+ vboxNetFltWinReferenceModePassThru(pNetFlt);
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+ *pbNetFltActive = false;
+ return true;
+ }
+
+ vboxNetFltRetain((pNetFlt), true /* fBusy */);
+ vboxNetFltWinReferenceModeNetFlt(pNetFlt);
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+
+ *pbNetFltActive = true;
+ return true;
+}
+
+DECLINLINE(bool) vboxNetFltWinIncReferenceWinIfNetFlt(PVBOXNETFLTINS pNetFlt, uint32_t v, bool *pbNetFltActive)
+{
+ uint32_t i;
+
+ Assert(v);
+ if (!v)
+ {
+ *pbNetFltActive = false;
+ return false;
+ }
+
+ RTSpinlockAcquire((pNetFlt)->hSpinlock);
+#ifndef VBOXNETADP
+ if (!vboxNetFltWinDoIncReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState, v))
+#else
+ if (!vboxNetFltWinDoIncReferenceDevice(&pNetFlt->u.s.WinIf.MpState, v))
+#endif
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pbNetFltActive = false;
+ return false;
+ }
+
+ if (pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE)
+ {
+ vboxNetFltWinIncReferenceModePassThru(pNetFlt, v);
+
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+ *pbNetFltActive = false;
+ return true;
+ }
+
+ vboxNetFltRetain(pNetFlt, true /* fBusy */);
+
+ vboxNetFltWinIncReferenceModeNetFlt(pNetFlt, v);
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ /* we have marked it as busy, so can do the res references outside the lock */
+ for (i = 0; i < v-1; i++)
+ {
+ vboxNetFltRetain(pNetFlt, true /* fBusy */);
+ }
+
+ *pbNetFltActive = true;
+
+ return true;
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceNetFlt(PVBOXNETFLTINS pNetFlt, uint32_t n)
+{
+ uint32_t i;
+ for (i = 0; i < n; i++)
+ {
+ vboxNetFltRelease(pNetFlt, true);
+ }
+
+ vboxNetFltWinDecReferenceModeNetFlt(pNetFlt, n);
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceNetFlt(PVBOXNETFLTINS pNetFlt)
+{
+ vboxNetFltRelease(pNetFlt, true);
+
+ vboxNetFltWinDereferenceModeNetFlt(pNetFlt);
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceWinIf(PVBOXNETFLTINS pNetFlt, uint32_t v)
+{
+#ifdef VBOXNETADP
+ vboxNetFltWinDecReferenceDevice(&pNetFlt->u.s.WinIf.MpState, v);
+#else
+ vboxNetFltWinDecReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState, v);
+#endif
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceWinIf(PVBOXNETFLTINS pNetFlt)
+{
+#ifdef VBOXNETADP
+ vboxNetFltWinDereferenceDevice(&pNetFlt->u.s.WinIf.MpState);
+#else
+ vboxNetFltWinDereferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState);
+#endif
+}
+
+DECLINLINE(bool) vboxNetFltWinIncReferenceWinIf(PVBOXNETFLTINS pNetFlt, uint32_t v)
+{
+ Assert(v);
+ if (!v)
+ {
+ return false;
+ }
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+#ifdef VBOXNETADP
+ if (vboxNetFltWinDoIncReferenceDevice(&pNetFlt->u.s.WinIf.MpState, v))
+#else
+ if (vboxNetFltWinDoIncReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState, v))
+#endif
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return true;
+ }
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return false;
+}
+
+DECLINLINE(bool) vboxNetFltWinReferenceWinIf(PVBOXNETFLTINS pNetFlt)
+{
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+#ifdef VBOXNETADP
+ if (vboxNetFltWinDoReferenceDevice(&pNetFlt->u.s.WinIf.MpState))
+#else
+ if (vboxNetFltWinDoReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState))
+#endif
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return true;
+ }
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return false;
+}
+
+/***********************************************
+ * methods for accessing the network card info *
+ ***********************************************/
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinGetMacAddress(PVBOXNETFLTINS pNetFlt, PRTMAC pMac);
+DECLHIDDEN(bool) vboxNetFltWinIsPromiscuous(PVBOXNETFLTINS pNetFlt);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinSetPromiscuous(PVBOXNETFLTINS pNetFlt, bool bYes);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PVBOXNETFLTINS pNetFlt, NDIS_PHYSICAL_MEDIUM * pMedium);
+
+/*********************
+ * mem alloc API *
+ *********************/
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMemAlloc(PVOID* ppMemBuf, UINT cbLength);
+
+DECLHIDDEN(void) vboxNetFltWinMemFree(PVOID pMemBuf);
+
+/* convenience method used which allocates and initializes the PINTNETSG containing one
+ * segment referring the buffer of size cbBufSize
+ * the allocated PINTNETSG should be freed with the vboxNetFltWinMemFree.
+ *
+ * This is used when our ProtocolReceive callback is called and we have to return the indicated NDIS_PACKET
+ * on a callback exit. This is why we allocate the PINTNETSG and put the packet info there and enqueue it
+ * for the packet queue */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinAllocSG(UINT cbBufSize, PINTNETSG *ppSG);
+
+/************************
+ * WinIf init/fini API *
+ ************************/
+#if defined(VBOXNETADP)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf, PNDIS_STRING pOurDeviceName);
+#endif
+
+DECLHIDDEN(VOID) vboxNetFltWinPtFiniWinIf(PVBOXNETFLTWIN pWinIf);
+
+/************************************
+ * Execute Job at passive level API *
+ ************************************/
+
+typedef VOID (*PFNVBOXNETFLT_JOB_ROUTINE) (PVOID pContext);
+
+DECLHIDDEN(VOID) vboxNetFltWinJobSynchExecAtPassive(PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext);
+
+/*******************************
+ * Ndis Packets processing API *
+ *******************************/
+DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PVBOXNETFLTINS pNetFlt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory);
+
+DECLHIDDEN(void) vboxNetFltWinFreeSGNdisPacket(PNDIS_PACKET pPacket, bool bFreeMem);
+
+#ifdef DEBUG_NETFLT_PACKETS
+#define DBG_CHECK_PACKETS(_p1, _p2) \
+ { \
+ bool _b = vboxNetFltWinMatchPackets(_p1, _p2, -1); \
+ Assert(_b); \
+ }
+
+#define DBG_CHECK_PACKET_AND_SG(_p, _sg) \
+ { \
+ bool _b = vboxNetFltWinMatchPacketAndSG(_p, _sg, -1); \
+ Assert(_b); \
+ }
+
+#define DBG_CHECK_SGS(_sg1, _sg2) \
+ { \
+ bool _b = vboxNetFltWinMatchSGs(_sg1, _sg2, -1); \
+ Assert(_b); \
+ }
+
+#else
+#define DBG_CHECK_PACKETS(_p1, _p2)
+#define DBG_CHECK_PACKET_AND_SG(_p, _sg)
+#define DBG_CHECK_SGS(_sg1, _sg2)
+#endif
+
+/**
+ * Ndis loops back broadcast packets posted to the wire by IntNet
+ * This routine is used in the mechanism of preventing this looping
+ *
+ * @param pAdapt
+ * @param pPacket
+ * @param bOnRecv true is we are receiving the packet from the wire
+ * false otherwise (i.e. the packet is from the host)
+ *
+ * @return true if the packet is a looped back one, false otherwise
+ */
+#ifdef VBOX_LOOPBACK_USEFLAGS
+DECLINLINE(bool) vboxNetFltWinIsLoopedBackPacket(PNDIS_PACKET pPacket)
+{
+ return (NdisGetPacketFlags(pPacket) & g_fPacketIsLoopedBack) == g_fPacketIsLoopedBack;
+}
+#endif
+
+/**************************************************************
+ * utility methods for ndis packet creation/initialization *
+ **************************************************************/
+
+#define VBOXNETFLT_OOB_INIT(_p) \
+ { \
+ NdisZeroMemory(NDIS_OOB_DATA_FROM_PACKET(_p), sizeof(NDIS_PACKET_OOB_DATA)); \
+ NDIS_SET_PACKET_HEADER_SIZE(_p, VBOXNETFLT_PACKET_ETHEADER_SIZE); \
+ }
+
+#ifndef VBOXNETADP
+
+DECLINLINE(NDIS_STATUS) vboxNetFltWinCopyPacketInfoOnRecv(PNDIS_PACKET pDstPacket, PNDIS_PACKET pSrcPacket, bool bForceStatusResources)
+{
+ NDIS_STATUS Status = bForceStatusResources ? NDIS_STATUS_RESOURCES : NDIS_GET_PACKET_STATUS(pSrcPacket);
+ NDIS_SET_PACKET_STATUS(pDstPacket, Status);
+
+ NDIS_PACKET_FIRST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pSrcPacket);
+ NDIS_PACKET_LAST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pSrcPacket);
+
+ NdisGetPacketFlags(pDstPacket) = NdisGetPacketFlags(pSrcPacket);
+
+ NDIS_SET_ORIGINAL_PACKET(pDstPacket, NDIS_GET_ORIGINAL_PACKET(pSrcPacket));
+ NDIS_SET_PACKET_HEADER_SIZE(pDstPacket, NDIS_GET_PACKET_HEADER_SIZE(pSrcPacket));
+
+ return Status;
+}
+
+DECLINLINE(void) vboxNetFltWinCopyPacketInfoOnSend(PNDIS_PACKET pDstPacket, PNDIS_PACKET pSrcPacket)
+{
+ NDIS_PACKET_FIRST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pSrcPacket);
+ NDIS_PACKET_LAST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pSrcPacket);
+
+ NdisGetPacketFlags(pDstPacket) = NdisGetPacketFlags(pSrcPacket);
+
+ NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(pDstPacket),
+ NDIS_OOB_DATA_FROM_PACKET(pSrcPacket),
+ sizeof (NDIS_PACKET_OOB_DATA));
+
+ NdisIMCopySendPerPacketInfo(pDstPacket, pSrcPacket);
+
+ PVOID pMediaSpecificInfo = NULL;
+ UINT fMediaSpecificInfoSize = 0;
+
+ NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(pSrcPacket, &pMediaSpecificInfo, &fMediaSpecificInfoSize);
+
+ if (pMediaSpecificInfo || fMediaSpecificInfoSize)
+ {
+ NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(pDstPacket, pMediaSpecificInfo, fMediaSpecificInfoSize);
+ }
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareRecvPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket, bool bDpr);
+#endif
+
+DECLHIDDEN(void) vboxNetFltWinSleep(ULONG milis);
+
+#define MACS_EQUAL(_m1, _m2) \
+ ((_m1).au16[0] == (_m2).au16[0] \
+ && (_m1).au16[1] == (_m2).au16[1] \
+ && (_m1).au16[2] == (_m2).au16[2])
+
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PVBOXNETFLTINS pNetFlt, bool bOnUnbind);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinCopyString(PNDIS_STRING pDst, PNDIS_STRING pSrc);
+
+
+/**
+ * Sets the enmState member atomically.
+ *
+ * Used for all updates.
+ *
+ * @param pThis The instance.
+ * @param enmNewState The new value.
+ */
+DECLINLINE(void) vboxNetFltWinSetWinIfState(PVBOXNETFLTINS pNetFlt, VBOXNETFLT_WINIFSTATE enmNewState)
+{
+ ASMAtomicWriteU32((uint32_t volatile *)&pNetFlt->u.s.WinIf.enmState, enmNewState);
+}
+
+/**
+ * Gets the enmState member atomically.
+ *
+ * Used for all reads.
+ *
+ * @returns The enmState value.
+ * @param pThis The instance.
+ */
+DECLINLINE(VBOXNETFLT_WINIFSTATE) vboxNetFltWinGetWinIfState(PVBOXNETFLTINS pNetFlt)
+{
+ return (VBOXNETFLT_WINIFSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pNetFlt->u.s.WinIf.enmState);
+}
+
+/* reference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvReference();
+/* dereference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvDereference();
+
+
+#ifndef VBOXNETADP
+# define VBOXNETFLT_PROMISCUOUS_SUPPORTED(_pNetFlt) (!(_pNetFlt)->fDisablePromiscuous)
+#else
+# define STATISTIC_INCREASE(_s) ASMAtomicIncU32((uint32_t volatile *)&(_s));
+
+DECLHIDDEN(void) vboxNetFltWinGenerateMACAddress(RTMAC *pMac);
+DECLHIDDEN(int) vboxNetFltWinMAC2NdisString(RTMAC *pMac, PNDIS_STRING pNdisString);
+DECLHIDDEN(int) vboxNetFltWinMACFromNdisString(RTMAC *pMac, PNDIS_STRING pNdisString);
+
+#endif
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltRt_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp
new file mode 100644
index 00000000..6520e909
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp
@@ -0,0 +1,2736 @@
+/* $Id: VBoxNetLwf-win.cpp $ */
+/** @file
+ * VBoxNetLwf-win.cpp - NDIS6 Bridged Networking Driver, Windows-specific code.
+ */
+/*
+ * Copyright (C) 2014-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
+ */
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+
+/*
+ * If VBOXNETLWF_SYNC_SEND is defined we won't allocate data buffers, but use
+ * the original buffers coming from IntNet to build MDLs around them. This
+ * also means that we need to wait for send operation to complete before
+ * returning the buffers, which hinders performance way too much.
+ */
+//#define VBOXNETLWF_SYNC_SEND
+
+/*
+ * If VBOXNETLWF_FIXED_SIZE_POOLS is defined we pre-allocate data buffers of
+ * fixed size in five pools. Each pool uses different size to accomodate packets
+ * of various sizes. We allocate these buffers once and re-use them when send
+ * operation is complete.
+ * If VBOXNETLWF_FIXED_SIZE_POOLS is not defined we allocate data buffers before
+ * each send operation and free then upon completion.
+ */
+#define VBOXNETLWF_FIXED_SIZE_POOLS
+
+/*
+ * Don't ask me why it is 42. Empirically this is what goes down the stack.
+ * OTOH, as we know from trustworthy sources, 42 is the answer, so be it.
+ */
+#define VBOXNETLWF_MAX_FRAME_SIZE(mtu) (mtu + 42)
+
+#include <VBox/version.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <iprt/net.h>
+#include <iprt/list.h>
+#include <VBox/intnetinline.h>
+
+#include <iprt/nt/ntddk.h>
+#include <iprt/nt/ndis.h>
+#include <iprt/win/netioapi.h>
+#include <mstcpip.h>
+
+#define LogError(x) DbgPrint x
+
+#if 0
+#undef Log
+#define Log(x) DbgPrint x
+#undef LogFlow
+#define LogFlow(x) DbgPrint x
+#endif
+
+/** We have an entirely different structure than the one defined in VBoxNetFltCmn-win.h */
+typedef struct VBOXNETFLTWIN
+{
+ /** filter module context handle */
+ NDIS_HANDLE hModuleCtx;
+ /** IP address change notifier handle */
+ HANDLE hNotifier; /* Must be here as hModuleCtx may already be NULL when vboxNetFltOsDeleteInstance is called */
+} VBOXNETFLTWIN, *PVBOXNETFLTWIN;
+#define VBOXNETFLT_NO_PACKET_QUEUE
+#define VBOXNETFLT_OS_SPECFIC 1
+#include "VBoxNetFltInternal.h"
+
+#include "VBoxNetLwf-win.h"
+#include "VBox/VBoxNetCmn-win.h"
+
+typedef enum {
+ LwfState_Detached = 0,
+ LwfState_Attaching,
+ LwfState_Paused,
+ LwfState_Restarting,
+ LwfState_Running,
+ LwfState_Pausing,
+ LwfState_32BitHack = 0x7fffffff
+} VBOXNETLWFSTATE;
+
+/*
+ * Valid state transitions are:
+ * 1) Disconnected -> Connecting : start the worker thread, attempting to init IDC;
+ * 2) Connecting -> Disconnected : failed to start IDC init worker thread;
+ * 3) Connecting -> Connected : IDC init successful, terminate the worker;
+ * 4) Connecting -> Stopping : IDC init incomplete, but the driver is being unloaded, terminate the worker;
+ * 5) Connected -> Stopping : IDC init was successful, no worker, the driver is being unloaded;
+ *
+ * Driver terminates in Stopping state.
+ */
+typedef enum {
+ LwfIdcState_Disconnected = 0, /* Initial state */
+ LwfIdcState_Connecting, /* Attemping to init IDC, worker thread running */
+ LwfIdcState_Connected, /* Successfully connected to IDC, worker thread terminated */
+ LwfIdcState_Stopping /* Terminating the worker thread and disconnecting IDC */
+} VBOXNETLWFIDCSTATE;
+
+struct _VBOXNETLWF_MODULE;
+
+typedef struct VBOXNETLWFGLOBALS
+{
+ /** synch event used for device creation synchronization */
+ //KEVENT SynchEvent;
+ /** Device reference count */
+ //int cDeviceRefs;
+ /** ndis device */
+ NDIS_HANDLE hDevice;
+ /** device object */
+ PDEVICE_OBJECT pDevObj;
+ /** our filter driver handle */
+ NDIS_HANDLE hFilterDriver;
+ /** lock protecting the module list */
+ NDIS_SPIN_LOCK Lock;
+ /** the head of module list */
+ RTLISTANCHOR listModules;
+ /** IDC initialization state */
+ volatile uint32_t enmIdcState;
+ /** IDC init thread handle */
+ HANDLE hInitIdcThread;
+} VBOXNETLWFGLOBALS, *PVBOXNETLWFGLOBALS;
+
+/**
+ * The (common) global data.
+ */
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+/* win-specific global data */
+VBOXNETLWFGLOBALS g_VBoxNetLwfGlobals;
+
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+static ULONG g_cbPool[] = { 576+56, 1556, 4096+56, 6192+56, 9056 };
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+
+typedef struct _VBOXNETLWF_MODULE {
+ RTLISTNODE node;
+
+ NDIS_HANDLE hFilter;
+#ifndef VBOXNETLWF_FIXED_SIZE_POOLS
+ NDIS_HANDLE hPool;
+#else /* VBOXNETLWF_FIXED_SIZE_POOLS */
+ NDIS_HANDLE hPool[RT_ELEMENTS(g_cbPool)];
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+ PVBOXNETLWFGLOBALS pGlobals;
+ /** Associated instance of NetFlt, one-to-one relationship */
+ PVBOXNETFLTINS pNetFlt; /// @todo Consider automic access!
+ /** Module state as described in http://msdn.microsoft.com/en-us/library/windows/hardware/ff550017(v=vs.85).aspx */
+ volatile uint32_t enmState; /* No lock needed yet, atomic should suffice. */
+ /** Mutex to prevent pausing while transmitting on behalf of NetFlt */
+ NDIS_MUTEX InTransmit;
+#ifdef VBOXNETLWF_SYNC_SEND
+ /** Event signalled when sending to the wire is complete */
+ KEVENT EventWire;
+ /** Event signalled when NDIS returns our receive notification */
+ KEVENT EventHost;
+#else /* !VBOXNETLWF_SYNC_SEND */
+ /** Event signalled when all pending sends (both to wire and host) have completed */
+ NDIS_EVENT EventSendComplete;
+ /** Counter for pending sends (both to wire and host) */
+ int32_t cPendingBuffers;
+ /** Work Item to deliver offloading indications at passive IRQL */
+ NDIS_HANDLE hWorkItem;
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ /** MAC address of underlying adapter */
+ RTMAC MacAddr;
+ /** Size of offload config structure */
+ USHORT cbOffloadConfig;
+ /** Saved offload configuration */
+ PNDIS_OFFLOAD pSavedOffloadConfig;
+ /** Temporary buffer for disabling offload configuration */
+ PNDIS_OFFLOAD pDisabledOffloadConfig;
+ /** the cloned request we have passed down */
+ PNDIS_OID_REQUEST pPendingRequest;
+ /** true if the underlying miniport supplied offloading config */
+ bool fOffloadConfigValid;
+ /** true if the trunk expects data from us */
+ bool fActive;
+ /** true if the host wants the adapter to be in promisc mode */
+ bool fHostPromisc;
+ /** true if the user wants packets being sent or received by VMs to be visible to the host in promisc mode */
+ bool fPassVmTrafficToHost;
+ /** Name of underlying adapter */
+ char szMiniportName[1];
+} VBOXNETLWF_MODULE;
+typedef VBOXNETLWF_MODULE *PVBOXNETLWF_MODULE;
+
+/*
+ * A structure to wrap OID requests in.
+ */
+typedef struct _VBOXNETLWF_OIDREQ {
+ NDIS_OID_REQUEST Request;
+ NDIS_STATUS Status;
+ NDIS_EVENT Event;
+} VBOXNETLWF_OIDREQ;
+typedef VBOXNETLWF_OIDREQ *PVBOXNETLWF_OIDREQ;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static FILTER_ATTACH vboxNetLwfWinAttach;
+static FILTER_DETACH vboxNetLwfWinDetach;
+static FILTER_RESTART vboxNetLwfWinRestart;
+static FILTER_PAUSE vboxNetLwfWinPause;
+static FILTER_OID_REQUEST vboxNetLwfWinOidRequest;
+static FILTER_OID_REQUEST_COMPLETE vboxNetLwfWinOidRequestComplete;
+//static FILTER_CANCEL_OID_REQUEST vboxNetLwfWinCancelOidRequest;
+static FILTER_STATUS vboxNetLwfWinStatus;
+//static FILTER_NET_PNP_EVENT vboxNetLwfWinPnPEvent;
+static FILTER_SEND_NET_BUFFER_LISTS vboxNetLwfWinSendNetBufferLists;
+static FILTER_SEND_NET_BUFFER_LISTS_COMPLETE vboxNetLwfWinSendNetBufferListsComplete;
+static FILTER_RECEIVE_NET_BUFFER_LISTS vboxNetLwfWinReceiveNetBufferLists;
+static FILTER_RETURN_NET_BUFFER_LISTS vboxNetLwfWinReturnNetBufferLists;
+static KSTART_ROUTINE vboxNetLwfWinInitIdcWorker;
+
+static VOID vboxNetLwfWinUnloadDriver(IN PDRIVER_OBJECT pDriver);
+static int vboxNetLwfWinInitBase(void);
+static int vboxNetLwfWinFini(void);
+
+
+
+/**
+ * Logs an error to the system event log.
+ *
+ * @param ErrCode Error to report to event log.
+ * @param ReturnedStatus Error that was reported by the driver to the caller.
+ * @param uErrId Unique error id representing the location in the driver.
+ * @param cbDumpData Number of bytes at pDumpData.
+ * @param pDumpData Pointer to data that will be added to the message (see 'details' tab).
+ */
+static void vboxNetLwfLogErrorEvent(NTSTATUS uErrCode, NTSTATUS uReturnedStatus, ULONG uErrId)
+{
+ /* Figure out how many modules are attached and if they are going to fit into the dump data. */
+ unsigned cMaxModules = (ERROR_LOG_MAXIMUM_SIZE - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)) / sizeof(RTMAC);
+ unsigned cModules = 0;
+ PVBOXNETLWF_MODULE pModuleCtx;
+ NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
+ ++cModules;
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ /* Prevent overflow */
+ if (cModules > cMaxModules)
+ cModules = cMaxModules;
+
+ /* DumpDataSize must be a multiple of sizeof(ULONG). */
+ unsigned cbDumpData = (cModules * sizeof(RTMAC) + 3) & ~3;
+ /* Prevent underflow */
+ unsigned cbTotal = RT_MAX(FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData,
+ sizeof(IO_ERROR_LOG_PACKET));
+
+ PIO_ERROR_LOG_PACKET pErrEntry;
+ pErrEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(g_VBoxNetLwfGlobals.pDevObj,
+ (UCHAR)cbTotal);
+ if (pErrEntry)
+ {
+ PRTMAC pDump = (PRTMAC)pErrEntry->DumpData;
+ /*
+ * Initialize the whole structure with zeros in case we are suddenly short
+ * of data because the list is empty or has become smaller.
+ */
+ memset(pErrEntry, 0, cbTotal);
+
+ NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
+ {
+ /* The list could have been modified while we were allocating the entry, rely on cModules instead! */
+ if (cModules-- == 0)
+ break;
+ *pDump++ = pModuleCtx->MacAddr;
+ }
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+
+ pErrEntry->DumpDataSize = cbDumpData;
+ pErrEntry->ErrorCode = uErrCode;
+ pErrEntry->UniqueErrorValue = uErrId;
+ pErrEntry->FinalStatus = uReturnedStatus;
+ IoWriteErrorLogEntry(pErrEntry);
+ }
+ else
+ {
+ DbgPrint("Failed to allocate error log entry (cb=%u)\n", cbTotal);
+ }
+}
+
+#ifdef DEBUG
+
+static const char *vboxNetLwfWinStatusToText(NDIS_STATUS code)
+{
+ switch (code)
+ {
+ case NDIS_STATUS_MEDIA_CONNECT: return "NDIS_STATUS_MEDIA_CONNECT";
+ case NDIS_STATUS_MEDIA_DISCONNECT: return "NDIS_STATUS_MEDIA_DISCONNECT";
+ case NDIS_STATUS_RESET_START: return "NDIS_STATUS_RESET_START";
+ case NDIS_STATUS_RESET_END: return "NDIS_STATUS_RESET_END";
+ case NDIS_STATUS_MEDIA_BUSY: return "NDIS_STATUS_MEDIA_BUSY";
+ case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: return "NDIS_STATUS_MEDIA_SPECIFIC_INDICATION";
+ case NDIS_STATUS_LINK_SPEED_CHANGE: return "NDIS_STATUS_LINK_SPEED_CHANGE";
+ case NDIS_STATUS_LINK_STATE: return "NDIS_STATUS_LINK_STATE";
+ case NDIS_STATUS_PORT_STATE: return "NDIS_STATUS_PORT_STATE";
+ case NDIS_STATUS_OPER_STATUS: return "NDIS_STATUS_OPER_STATUS";
+ case NDIS_STATUS_NETWORK_CHANGE: return "NDIS_STATUS_NETWORK_CHANGE";
+ case NDIS_STATUS_PACKET_FILTER: return "NDIS_STATUS_PACKET_FILTER";
+ case NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: return "NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG";
+ case NDIS_STATUS_TASK_OFFLOAD_HARDWARE_CAPABILITIES: return "NDIS_STATUS_TASK_OFFLOAD_HARDWARE_CAPABILITIES";
+ case NDIS_STATUS_OFFLOAD_ENCASPULATION_CHANGE: return "NDIS_STATUS_OFFLOAD_ENCASPULATION_CHANGE";
+ case NDIS_STATUS_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES: return "NDIS_STATUS_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES";
+ }
+ return "unknown";
+}
+
+static void vboxNetLwfWinDumpFilterTypes(ULONG uFlags)
+{
+ if (uFlags & NDIS_PACKET_TYPE_DIRECTED) Log5((" NDIS_PACKET_TYPE_DIRECTED\n"));
+ if (uFlags & NDIS_PACKET_TYPE_MULTICAST) Log5((" NDIS_PACKET_TYPE_MULTICAST\n"));
+ if (uFlags & NDIS_PACKET_TYPE_ALL_MULTICAST) Log5((" NDIS_PACKET_TYPE_ALL_MULTICAST\n"));
+ if (uFlags & NDIS_PACKET_TYPE_BROADCAST) Log5((" NDIS_PACKET_TYPE_BROADCAST\n"));
+ if (uFlags & NDIS_PACKET_TYPE_PROMISCUOUS) Log5((" NDIS_PACKET_TYPE_PROMISCUOUS\n"));
+ if (uFlags & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) Log5((" NDIS_PACKET_TYPE_ALL_FUNCTIONAL\n"));
+ if (uFlags & NDIS_PACKET_TYPE_ALL_LOCAL) Log5((" NDIS_PACKET_TYPE_ALL_LOCAL\n"));
+ if (uFlags & NDIS_PACKET_TYPE_FUNCTIONAL) Log5((" NDIS_PACKET_TYPE_FUNCTIONAL\n"));
+ if (uFlags & NDIS_PACKET_TYPE_GROUP) Log5((" NDIS_PACKET_TYPE_GROUP\n"));
+ if (uFlags & NDIS_PACKET_TYPE_MAC_FRAME) Log5((" NDIS_PACKET_TYPE_MAC_FRAME\n"));
+ if (uFlags & NDIS_PACKET_TYPE_SMT) Log5((" NDIS_PACKET_TYPE_SMT\n"));
+ if (uFlags & NDIS_PACKET_TYPE_SOURCE_ROUTING) Log5((" NDIS_PACKET_TYPE_SOURCE_ROUTING\n"));
+ if (uFlags == 0) Log5((" NONE\n"));
+}
+
+DECLINLINE(void) vboxNetLwfWinDumpEncapsulation(const char *pcszText, ULONG uEncapsulation)
+{
+ if (uEncapsulation == NDIS_ENCAPSULATION_NOT_SUPPORTED)
+ Log5(("%s not supported\n", pcszText));
+ else
+ {
+ Log5(("%s", pcszText));
+ if (uEncapsulation & NDIS_ENCAPSULATION_NULL)
+ Log5((" null"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3)
+ Log5((" 802.3"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q)
+ Log5((" 802.3pq"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q_IN_OOB)
+ Log5((" 802.3pq(oob)"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_LLC_SNAP_ROUTED)
+ Log5((" LLC"));
+ Log5(("\n"));
+ }
+}
+
+DECLINLINE(const char *) vboxNetLwfWinSetOnOffText(ULONG uOnOff)
+{
+ switch (uOnOff)
+ {
+ case NDIS_OFFLOAD_SET_NO_CHANGE: return "no change";
+ case NDIS_OFFLOAD_SET_ON: return "on";
+ case NDIS_OFFLOAD_SET_OFF: return "off";
+ }
+ return "unknown";
+}
+
+DECLINLINE(const char *) vboxNetLwfWinOnOffText(ULONG uOnOff)
+{
+ switch (uOnOff)
+ {
+ case NDIS_OFFLOAD_NOT_SUPPORTED: return "off";
+ case NDIS_OFFLOAD_SUPPORTED: return "on";
+ }
+ return "unknown";
+}
+
+DECLINLINE(const char *) vboxNetLwfWinSupportedText(ULONG uSupported)
+{
+ switch (uSupported)
+ {
+ case NDIS_OFFLOAD_NOT_SUPPORTED: return "not supported";
+ case NDIS_OFFLOAD_SUPPORTED: return "supported";
+ }
+ return "unknown";
+}
+
+static void vboxNetLwfWinDumpSetOffloadSettings(PNDIS_OFFLOAD pOffloadConfig)
+{
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv4Transmit.Encapsulation);
+ Log5((" Checksum.IPv4Transmit.IpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv4Transmit.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum)));
+ Log5((" Checksum.IPv4Transmit.IpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Receive.Encapsulation =", pOffloadConfig->Checksum.IPv4Receive.Encapsulation);
+ Log5((" Checksum.IPv4Receive.IpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpChecksum)));
+ Log5((" Checksum.IPv4Receive.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.UdpChecksum)));
+ Log5((" Checksum.IPv4Receive.IpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv6Transmit.Encapsulation);
+ Log5((" Checksum.IPv6Transmit.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv6Transmit.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Receive.Encapsulation =", pOffloadConfig->Checksum.IPv6Receive.Encapsulation);
+ Log5((" Checksum.IPv6Receive.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Receive.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpChecksum)));
+ Log5((" Checksum.IPv6Receive.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV1.IPv4.Encapsulation =", pOffloadConfig->LsoV1.IPv4.Encapsulation);
+ Log5((" LsoV1.IPv4.TcpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.TcpOptions)));
+ Log5((" LsoV1.IPv4.IpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.IpOptions)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv4.Encapsulation =", pOffloadConfig->LsoV2.IPv4.Encapsulation);
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv6.Encapsulation =", pOffloadConfig->LsoV2.IPv6.Encapsulation);
+ Log5((" LsoV2.IPv6.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported)));
+ Log5((" LsoV2.IPv6.TcpOptionsSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported)));
+}
+
+static void vboxNetLwfWinDumpOffloadSettings(PNDIS_OFFLOAD pOffloadConfig)
+{
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv4Transmit.Encapsulation);
+ Log5((" Checksum.IPv4Transmit.IpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv4Transmit.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum)));
+ Log5((" Checksum.IPv4Transmit.IpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Receive.Encapsulation =", pOffloadConfig->Checksum.IPv4Receive.Encapsulation);
+ Log5((" Checksum.IPv4Receive.IpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpChecksum)));
+ Log5((" Checksum.IPv4Receive.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.UdpChecksum)));
+ Log5((" Checksum.IPv4Receive.IpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv6Transmit.Encapsulation);
+ Log5((" Checksum.IPv6Transmit.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv6Transmit.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Receive.Encapsulation =", pOffloadConfig->Checksum.IPv6Receive.Encapsulation);
+ Log5((" Checksum.IPv6Receive.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Receive.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpChecksum)));
+ Log5((" Checksum.IPv6Receive.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV1.IPv4.Encapsulation =", pOffloadConfig->LsoV1.IPv4.Encapsulation);
+ Log5((" LsoV1.IPv4.TcpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.TcpOptions)));
+ Log5((" LsoV1.IPv4.IpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.IpOptions)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv4.Encapsulation =", pOffloadConfig->LsoV2.IPv4.Encapsulation);
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv6.Encapsulation =", pOffloadConfig->LsoV2.IPv6.Encapsulation);
+ Log5((" LsoV2.IPv6.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported)));
+ Log5((" LsoV2.IPv6.TcpOptionsSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported)));
+}
+
+static const char *vboxNetLwfWinStateToText(uint32_t enmState)
+{
+ switch (enmState)
+ {
+ case LwfState_Detached: return "Detached";
+ case LwfState_Attaching: return "Attaching";
+ case LwfState_Paused: return "Paused";
+ case LwfState_Restarting: return "Restarting";
+ case LwfState_Running: return "Running";
+ case LwfState_Pausing: return "Pausing";
+ }
+ return "invalid";
+}
+
+static void vboxNetLwfWinDumpPackets(const char *pszMsg, PNET_BUFFER_LIST pBufLists)
+{
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
+ {
+ Log6(("%s packet: src=%p cb=%d offset=%d", pszMsg, pList->SourceHandle, NET_BUFFER_DATA_LENGTH(pBuf), NET_BUFFER_DATA_OFFSET(pBuf)));
+ for (PMDL pMdl = NET_BUFFER_FIRST_MDL(pBuf);
+ pMdl != NULL;
+ pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ Log6((" MDL: cb=%d", MmGetMdlByteCount(pMdl)));
+ }
+ Log6(("\n"));
+ }
+ }
+}
+
+DECLINLINE(const char *) vboxNetLwfWinEthTypeStr(uint16_t uType)
+{
+ switch (uType)
+ {
+ case RTNET_ETHERTYPE_IPV4: return "IP";
+ case RTNET_ETHERTYPE_IPV6: return "IPv6";
+ case RTNET_ETHERTYPE_ARP: return "ARP";
+ }
+ return "unknown";
+}
+
+#define VBOXNETLWF_PKTDMPSIZE 0x50
+
+/**
+ * Dump a packet to debug log.
+ *
+ * @param cpPacket The packet.
+ * @param cb The size of the packet.
+ * @param cszText A string denoting direction of packet transfer.
+ */
+DECLINLINE(void) vboxNetLwfWinDumpPacket(PCINTNETSG pSG, const char *cszText)
+{
+ uint8_t bPacket[VBOXNETLWF_PKTDMPSIZE];
+
+ uint32_t cb = pSG->cbTotal < VBOXNETLWF_PKTDMPSIZE ? pSG->cbTotal : VBOXNETLWF_PKTDMPSIZE;
+ IntNetSgReadEx(pSG, 0, cb, bPacket);
+
+ AssertReturnVoid(cb >= 14);
+
+ uint8_t *pHdr = bPacket;
+ uint8_t *pEnd = bPacket + cb;
+ AssertReturnVoid(pEnd - pHdr >= 14);
+ uint16_t uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+12));
+ Log2(("NetLWF: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n",
+ cszText, pSG->cbTotal, pHdr+6, pHdr, vboxNetLwfWinEthTypeStr(uEthType), uEthType));
+ pHdr += sizeof(RTNETETHERHDR);
+ if (uEthType == RTNET_ETHERTYPE_VLAN)
+ {
+ AssertReturnVoid(pEnd - pHdr >= 4);
+ uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+2));
+ Log2((" + VLAN: id=%d EthType=%s(0x%x)\n", RT_N2H_U16(*(uint16_t*)(pHdr)) & 0xFFF,
+ vboxNetLwfWinEthTypeStr(uEthType), uEthType));
+ pHdr += 2 * sizeof(uint16_t);
+ }
+ uint8_t uProto = 0xFF;
+ switch (uEthType)
+ {
+ case RTNET_ETHERTYPE_IPV6:
+ AssertReturnVoid(pEnd - pHdr >= 40);
+ uProto = pHdr[6];
+ Log2((" + IPv6: %RTnaipv6 => %RTnaipv6\n", pHdr+8, pHdr+24));
+ pHdr += 40;
+ break;
+ case RTNET_ETHERTYPE_IPV4:
+ AssertReturnVoid(pEnd - pHdr >= 20);
+ uProto = pHdr[9];
+ Log2((" + IP: %RTnaipv4 => %RTnaipv4\n", *(uint32_t*)(pHdr+12), *(uint32_t*)(pHdr+16)));
+ pHdr += (pHdr[0] & 0xF) * 4;
+ break;
+ case RTNET_ETHERTYPE_ARP:
+ AssertReturnVoid(pEnd - pHdr >= 28);
+ AssertReturnVoid(RT_N2H_U16(*(uint16_t*)(pHdr+2)) == RTNET_ETHERTYPE_IPV4);
+ switch (RT_N2H_U16(*(uint16_t*)(pHdr+6)))
+ {
+ case 1: /* ARP request */
+ Log2((" + ARP-REQ: who-has %RTnaipv4 tell %RTnaipv4\n",
+ *(uint32_t*)(pHdr+24), *(uint32_t*)(pHdr+14)));
+ break;
+ case 2: /* ARP reply */
+ Log2((" + ARP-RPL: %RTnaipv4 is-at %RTmac\n",
+ *(uint32_t*)(pHdr+14), pHdr+8));
+ break;
+ default:
+ Log2((" + ARP: unknown op %d\n", RT_N2H_U16(*(uint16_t*)(pHdr+6))));
+ break;
+ }
+ break;
+ /* There is no default case as uProto is initialized with 0xFF */
+ }
+ while (uProto != 0xFF)
+ {
+ switch (uProto)
+ {
+ case 0: /* IPv6 Hop-by-Hop option*/
+ case 60: /* IPv6 Destination option*/
+ case 43: /* IPv6 Routing option */
+ case 44: /* IPv6 Fragment option */
+ Log2((" + IPv6 option (%d): <not implemented>\n", uProto));
+ uProto = pHdr[0];
+ pHdr += pHdr[1] * 8 + 8; /* Skip to the next extension/protocol */
+ break;
+ case 51: /* IPv6 IPsec AH */
+ Log2((" + IPv6 IPsec AH: <not implemented>\n"));
+ uProto = pHdr[0];
+ pHdr += (pHdr[1] + 2) * 4; /* Skip to the next extension/protocol */
+ break;
+ case 50: /* IPv6 IPsec ESP */
+ /* Cannot decode IPsec, fall through */
+ Log2((" + IPv6 IPsec ESP: <not implemented>\n"));
+ uProto = 0xFF;
+ break;
+ case 59: /* No Next Header */
+ Log2((" + IPv6 No Next Header\n"));
+ uProto = 0xFF;
+ break;
+ case 58: /* IPv6-ICMP */
+ switch (pHdr[0])
+ {
+ case 1: Log2((" + IPv6-ICMP: destination unreachable, code %d\n", pHdr[1])); break;
+ case 128: Log2((" + IPv6-ICMP: echo request\n")); break;
+ case 129: Log2((" + IPv6-ICMP: echo reply\n")); break;
+ default: Log2((" + IPv6-ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
+ }
+ uProto = 0xFF;
+ break;
+ case 1: /* ICMP */
+ switch (pHdr[0])
+ {
+ case 0: Log2((" + ICMP: echo reply\n")); break;
+ case 8: Log2((" + ICMP: echo request\n")); break;
+ case 3: Log2((" + ICMP: destination unreachable, code %d\n", pHdr[1])); break;
+ default: Log2((" + ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
+ }
+ uProto = 0xFF;
+ break;
+ case 6: /* TCP */
+ Log2((" + TCP: src=%d dst=%d seq=%x ack=%x\n",
+ RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)),
+ RT_N2H_U32(*(uint32_t*)(pHdr+4)), RT_N2H_U32(*(uint32_t*)(pHdr+8))));
+ uProto = 0xFF;
+ break;
+ case 17: /* UDP */
+ Log2((" + UDP: src=%d dst=%d\n",
+ RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2))));
+ uProto = 0xFF;
+ break;
+ default:
+ Log2((" + Unknown: proto=0x%x\n", uProto));
+ uProto = 0xFF;
+ break;
+ }
+ }
+ Log3(("%.*Rhxd\n", cb, bPacket));
+}
+
+#else /* !DEBUG */
+# define vboxNetLwfWinDumpFilterTypes(uFlags) do { } while (0)
+# define vboxNetLwfWinDumpOffloadSettings(p) do { } while (0)
+# define vboxNetLwfWinDumpSetOffloadSettings(p) do { } while (0)
+# define vboxNetLwfWinDumpPackets(m,l) do { } while (0)
+# define vboxNetLwfWinDumpPacket(p,t) do { } while (0)
+#endif /* !DEBUG */
+
+DECLINLINE(bool) vboxNetLwfWinChangeState(PVBOXNETLWF_MODULE pModuleCtx, uint32_t enmNew, uint32_t enmOld = LwfState_32BitHack)
+{
+ AssertReturn(pModuleCtx, false);
+
+ bool fSuccess = true;
+ if (enmOld != LwfState_32BitHack)
+ {
+ fSuccess = ASMAtomicCmpXchgU32(&pModuleCtx->enmState, enmNew, enmOld);
+ if (fSuccess)
+ Log(("vboxNetLwfWinChangeState: state change %s -> %s\n",
+ vboxNetLwfWinStateToText(enmOld),
+ vboxNetLwfWinStateToText(enmNew)));
+ else
+ Log(("ERROR! vboxNetLwfWinChangeState: failed state change %s (actual=%s) -> %s\n",
+ vboxNetLwfWinStateToText(enmOld),
+ vboxNetLwfWinStateToText(ASMAtomicReadU32(&pModuleCtx->enmState)),
+ vboxNetLwfWinStateToText(enmNew)));
+ Assert(fSuccess);
+ }
+ else
+ {
+ uint32_t enmPrevState = ASMAtomicXchgU32(&pModuleCtx->enmState, enmNew);
+ Log(("vboxNetLwfWinChangeState: state change %s -> %s\n",
+ vboxNetLwfWinStateToText(enmPrevState),
+ vboxNetLwfWinStateToText(enmNew)));
+ NOREF(enmPrevState);
+ }
+ return fSuccess;
+}
+
+DECLINLINE(void) vboxNetLwfWinInitOidRequest(PVBOXNETLWF_OIDREQ pRequest)
+{
+ NdisZeroMemory(pRequest, sizeof(VBOXNETLWF_OIDREQ));
+
+ NdisInitializeEvent(&pRequest->Event);
+
+ pRequest->Request.Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ pRequest->Request.Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ pRequest->Request.Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1;
+
+ pRequest->Request.RequestId = (PVOID)VBOXNETLWF_REQ_ID;
+}
+
+static NDIS_STATUS vboxNetLwfWinSyncOidRequest(PVBOXNETLWF_MODULE pModuleCtx, PVBOXNETLWF_OIDREQ pRequest)
+{
+ NDIS_STATUS Status = NdisFOidRequest(pModuleCtx->hFilter, &pRequest->Request);
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pRequest->Event, 0);
+ Status = pRequest->Status;
+ }
+ return Status;
+}
+
+DECLINLINE(void) vboxNetLwfWinCopyOidRequestResults(PNDIS_OID_REQUEST pFrom, PNDIS_OID_REQUEST pTo)
+{
+ switch (pFrom->RequestType)
+ {
+ case NdisRequestSetInformation:
+ pTo->DATA.SET_INFORMATION.BytesRead = pFrom->DATA.SET_INFORMATION.BytesRead;
+ pTo->DATA.SET_INFORMATION.BytesNeeded = pFrom->DATA.SET_INFORMATION.BytesNeeded;
+ break;
+ case NdisRequestMethod:
+ pTo->DATA.METHOD_INFORMATION.OutputBufferLength = pFrom->DATA.METHOD_INFORMATION.OutputBufferLength;
+ pTo->DATA.METHOD_INFORMATION.BytesWritten = pFrom->DATA.METHOD_INFORMATION.BytesWritten;
+ pTo->DATA.METHOD_INFORMATION.BytesRead = pFrom->DATA.METHOD_INFORMATION.BytesRead;
+ pTo->DATA.METHOD_INFORMATION.BytesNeeded = pFrom->DATA.METHOD_INFORMATION.BytesNeeded;
+ break;
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ default:
+ pTo->DATA.QUERY_INFORMATION.BytesWritten = pFrom->DATA.QUERY_INFORMATION.BytesWritten;
+ pTo->DATA.QUERY_INFORMATION.BytesNeeded = pFrom->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+}
+
+void inline vboxNetLwfWinOverridePacketFiltersUp(PVBOXNETLWF_MODULE pModuleCtx, ULONG *pFilters)
+{
+ if (ASMAtomicReadBool(&pModuleCtx->fActive) && !ASMAtomicReadBool(&pModuleCtx->fHostPromisc))
+ *pFilters &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
+}
+
+NDIS_STATUS vboxNetLwfWinOidRequest(IN NDIS_HANDLE hModuleCtx,
+ IN PNDIS_OID_REQUEST pOidRequest)
+{
+ LogFlow(("==>vboxNetLwfWinOidRequest: module=%p\n", hModuleCtx));
+ vboxNetCmnWinDumpOidRequest(__FUNCTION__, pOidRequest);
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNDIS_OID_REQUEST pClone = NULL;
+ NDIS_STATUS Status = NdisAllocateCloneOidRequest(pModuleCtx->hFilter,
+ pOidRequest,
+ VBOXNETLWF_MEM_TAG,
+ &pClone);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ /* Save the pointer to the original */
+ *((PNDIS_OID_REQUEST*)(pClone->SourceReserved)) = pOidRequest;
+
+ pClone->RequestId = pOidRequest->RequestId;
+ /* We are not supposed to get another request until we are through with the one we "postponed" */
+ PNDIS_OID_REQUEST pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, pClone, PNDIS_OID_REQUEST);
+ Assert(pPrev == NULL);
+ pModuleCtx->pPendingRequest = pClone;
+ if (pOidRequest->RequestType == NdisRequestSetInformation
+ && pOidRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
+ {
+ ASMAtomicWriteBool(&pModuleCtx->fHostPromisc, !!(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer & NDIS_PACKET_TYPE_PROMISCUOUS));
+ Log(("vboxNetLwfWinOidRequest: host wanted to set packet filter value to:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
+ /* Keep adapter in promisc mode as long as we are active. */
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ *(ULONG*)pClone->DATA.SET_INFORMATION.InformationBuffer |= NDIS_PACKET_TYPE_PROMISCUOUS;
+ Log5(("vboxNetLwfWinOidRequest: pass the following packet filters to miniport:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
+ }
+ if (pOidRequest->RequestType == NdisRequestSetInformation
+ && pOidRequest->DATA.SET_INFORMATION.Oid == OID_TCP_OFFLOAD_CURRENT_CONFIG)
+ {
+ Log5(("vboxNetLwfWinOidRequest: offloading set to:\n"));
+ vboxNetLwfWinDumpSetOffloadSettings((PNDIS_OFFLOAD)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
+ }
+
+ /* Forward the clone to underlying filters/miniport */
+ Status = NdisFOidRequest(pModuleCtx->hFilter, pClone);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ /* Synchronous completion */
+ pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, NULL, PNDIS_OID_REQUEST);
+ Assert(pPrev == pClone);
+ Log5(("vboxNetLwfWinOidRequest: got the following packet filters from miniport:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ /*
+ * The host does not expect the adapter to be in promisc mode,
+ * unless it enabled the mode. Let's not disillusion it.
+ */
+ if ( pOidRequest->RequestType == NdisRequestQueryInformation
+ && pOidRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
+ vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ Log5(("vboxNetLwfWinOidRequest: reporting to the host the following packet filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ vboxNetLwfWinCopyOidRequestResults(pClone, pOidRequest);
+ NdisFreeCloneOidRequest(pModuleCtx->hFilter, pClone);
+ }
+ /* In case of async completion we do the rest in vboxNetLwfWinOidRequestComplete() */
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinOidRequest: NdisAllocateCloneOidRequest failed with 0x%x\n", Status));
+ }
+ LogFlow(("<==vboxNetLwfWinOidRequest: Status=0x%x\n", Status));
+ return Status;
+}
+
+VOID vboxNetLwfWinOidRequestComplete(IN NDIS_HANDLE hModuleCtx,
+ IN PNDIS_OID_REQUEST pRequest,
+ IN NDIS_STATUS Status)
+{
+ LogFlow(("==>vboxNetLwfWinOidRequestComplete: module=%p req=%p status=0x%x\n", hModuleCtx, pRequest, Status));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNDIS_OID_REQUEST pOriginal = *((PNDIS_OID_REQUEST*)(pRequest->SourceReserved));
+ if (pOriginal)
+ {
+ /* NDIS is supposed to serialize requests */
+ PNDIS_OID_REQUEST pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, NULL, PNDIS_OID_REQUEST);
+ Assert(pPrev == pRequest); NOREF(pPrev);
+
+ Log5(("vboxNetLwfWinOidRequestComplete: completed rq type=%d oid=%x\n", pRequest->RequestType, pRequest->DATA.QUERY_INFORMATION.Oid));
+ vboxNetLwfWinCopyOidRequestResults(pRequest, pOriginal);
+ if ( pRequest->RequestType == NdisRequestQueryInformation
+ && pRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
+ {
+ Log5(("vboxNetLwfWinOidRequestComplete: underlying miniport reports its packet filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ Log5(("vboxNetLwfWinOidRequestComplete: reporting the following packet filters to upper protocol:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ }
+ NdisFreeCloneOidRequest(pModuleCtx->hFilter, pRequest);
+ NdisFOidRequestComplete(pModuleCtx->hFilter, pOriginal, Status);
+ }
+ else
+ {
+ /* This is not a clone, we originated it */
+ Log(("vboxNetLwfWinOidRequestComplete: locally originated request (%p) completed, status=0x%x\n", pRequest, Status));
+ PVBOXNETLWF_OIDREQ pRqWrapper = RT_FROM_MEMBER(pRequest, VBOXNETLWF_OIDREQ, Request);
+ pRqWrapper->Status = Status;
+ NdisSetEvent(&pRqWrapper->Event);
+ }
+ LogFlow(("<==vboxNetLwfWinOidRequestComplete\n"));
+}
+
+
+static bool vboxNetLwfWinIsPromiscuous(PVBOXNETLWF_MODULE pModuleCtx)
+{
+ return ASMAtomicReadBool(&pModuleCtx->fHostPromisc);
+}
+
+#if 0
+static NDIS_STATUS vboxNetLwfWinGetPacketFilter(PVBOXNETLWF_MODULE pModuleCtx)
+{
+ LogFlow(("==>vboxNetLwfWinGetPacketFilter: module=%p\n", pModuleCtx));
+ VBOXNETLWF_OIDREQ Rq;
+ vboxNetLwfWinInitOidRequest(&Rq);
+ Rq.Request.RequestType = NdisRequestQueryInformation;
+ Rq.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBuffer = &pModuleCtx->uPacketFilter;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(pModuleCtx->uPacketFilter);
+ NDIS_STATUS Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinGetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed with 0x%x\n", Status));
+ return FALSE;
+ }
+ if (Rq.Request.DATA.QUERY_INFORMATION.BytesWritten != sizeof(pModuleCtx->uPacketFilter))
+ {
+ LogError(("vboxNetLwfWinGetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed to write neccessary amount (%d bytes), actually written %d bytes\n", sizeof(pModuleCtx->uPacketFilter), Rq.Request.DATA.QUERY_INFORMATION.BytesWritten));
+ }
+
+ Log5(("vboxNetLwfWinGetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER query returned the following filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(pModuleCtx->uPacketFilter);
+
+ LogFlow(("<==vboxNetLwfWinGetPacketFilter: status=0x%x\n", Status));
+ return Status;
+}
+#endif
+
+static NDIS_STATUS vboxNetLwfWinSetPacketFilter(PVBOXNETLWF_MODULE pModuleCtx, bool fPromisc)
+{
+ LogFlow(("==>vboxNetLwfWinSetPacketFilter: module=%p %s\n", pModuleCtx, fPromisc ? "promiscuous" : "normal"));
+ ULONG uFilter = 0;
+ VBOXNETLWF_OIDREQ Rq;
+ vboxNetLwfWinInitOidRequest(&Rq);
+ Rq.Request.RequestType = NdisRequestQueryInformation;
+ Rq.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBuffer = &uFilter;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(uFilter);
+ NDIS_STATUS Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed with 0x%x\n", Status));
+ return Status;
+ }
+ if (Rq.Request.DATA.QUERY_INFORMATION.BytesWritten != sizeof(uFilter))
+ {
+ LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed to write neccessary amount (%d bytes), actually written %d bytes\n", sizeof(uFilter), Rq.Request.DATA.QUERY_INFORMATION.BytesWritten));
+ return NDIS_STATUS_FAILURE;
+ }
+
+ Log5(("vboxNetLwfWinSetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER query returned the following filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(uFilter);
+
+ if (fPromisc)
+ {
+ /* If we about to go promiscuous, save the state before we change it. */
+ ASMAtomicWriteBool(&pModuleCtx->fHostPromisc, !!(uFilter & NDIS_PACKET_TYPE_PROMISCUOUS));
+ uFilter |= NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+ else
+ {
+ /* Reset promisc only if it was not enabled before we had changed it. */
+ if (!ASMAtomicReadBool(&pModuleCtx->fHostPromisc))
+ uFilter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ Log5(("vboxNetLwfWinSetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER about to set the following filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(uFilter);
+
+ NdisResetEvent(&Rq.Event); /* need to reset as it has been set by query op */
+ Rq.Request.RequestType = NdisRequestSetInformation;
+ Rq.Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ Rq.Request.DATA.SET_INFORMATION.InformationBuffer = &uFilter;
+ Rq.Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(uFilter);
+ Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(set, OID_GEN_CURRENT_PACKET_FILTER, vvv below vvv) failed with 0x%x\n", Status));
+ vboxNetLwfWinDumpFilterTypes(uFilter);
+ }
+ LogFlow(("<==vboxNetLwfWinSetPacketFilter: status=0x%x\n", Status));
+ return Status;
+}
+
+
+static NTSTATUS vboxNetLwfWinDevDispatch(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;
+}
+
+/** @todo So far we had no use for device, should we even bother to create it? */
+static NDIS_STATUS vboxNetLwfWinDevCreate(PVBOXNETLWFGLOBALS pGlobals)
+{
+ NDIS_STRING DevName, LinkName;
+ PDRIVER_DISPATCH aMajorFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
+ NdisInitUnicodeString(&DevName, VBOXNETLWF_NAME_DEVICE);
+ NdisInitUnicodeString(&LinkName, VBOXNETLWF_NAME_LINK);
+
+ Assert(!pGlobals->hDevice);
+ Assert(!pGlobals->pDevObj);
+ NdisZeroMemory(aMajorFunctions, sizeof (aMajorFunctions));
+ aMajorFunctions[IRP_MJ_CREATE] = vboxNetLwfWinDevDispatch;
+ aMajorFunctions[IRP_MJ_CLEANUP] = vboxNetLwfWinDevDispatch;
+ aMajorFunctions[IRP_MJ_CLOSE] = vboxNetLwfWinDevDispatch;
+ aMajorFunctions[IRP_MJ_DEVICE_CONTROL] = vboxNetLwfWinDevDispatch;
+
+ NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceAttributes;
+ NdisZeroMemory(&DeviceAttributes, sizeof(DeviceAttributes));
+ DeviceAttributes.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
+ DeviceAttributes.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
+ DeviceAttributes.Header.Size = sizeof(DeviceAttributes);
+ DeviceAttributes.DeviceName = &DevName;
+ DeviceAttributes.SymbolicName = &LinkName;
+ DeviceAttributes.MajorFunctions = aMajorFunctions;
+ //DeviceAttributes.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
+
+ NDIS_STATUS Status = NdisRegisterDeviceEx(pGlobals->hFilterDriver,
+ &DeviceAttributes,
+ &pGlobals->pDevObj,
+ &pGlobals->hDevice);
+ Log(("vboxNetLwfWinDevCreate: NdisRegisterDeviceEx returned 0x%x\n", Status));
+ Assert(Status == NDIS_STATUS_SUCCESS);
+#if 0
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PFILTER_DEVICE_EXTENSION pExtension;
+ pExtension = NdisGetDeviceReservedExtension(pGlobals->pDevObj);
+ pExtension->Signature = VBOXNETLWF_MEM_TAG;
+ pExtension->Handle = pGlobals->hFilterDriver;
+ }
+#endif
+ return Status;
+}
+
+static void vboxNetLwfWinDevDestroy(PVBOXNETLWFGLOBALS pGlobals)
+{
+ Assert(pGlobals->hDevice);
+ Assert(pGlobals->pDevObj);
+ NdisDeregisterDeviceEx(pGlobals->hDevice);
+ pGlobals->hDevice = NULL;
+ pGlobals->pDevObj = NULL;
+}
+
+static void vboxNetLwfWinDisableOffloading(PNDIS_OFFLOAD pOffloadConfig)
+{
+ pOffloadConfig->Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv6.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+}
+
+static void vboxNetLwfWinUpdateSavedOffloadConfig(PVBOXNETLWF_MODULE pModuleCtx, PNDIS_OFFLOAD pOffload)
+{
+ if (pModuleCtx->cbOffloadConfig < pOffload->Header.Size)
+ {
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 10);
+ return;
+ }
+
+ NdisMoveMemory(pModuleCtx->pSavedOffloadConfig, pOffload, pOffload->Header.Size);
+ NdisMoveMemory(pModuleCtx->pDisabledOffloadConfig, pOffload, pOffload->Header.Size);
+ vboxNetLwfWinDisableOffloading(pModuleCtx->pDisabledOffloadConfig);
+ pModuleCtx->fOffloadConfigValid = true;
+}
+
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+static void vboxNetLwfWinFreePools(PVBOXNETLWF_MODULE pModuleCtx, int cPools)
+{
+ for (int i = 0; i < cPools; ++i)
+ {
+ if (pModuleCtx->hPool[i])
+ {
+ NdisFreeNetBufferListPool(pModuleCtx->hPool[i]);
+ Log4(("vboxNetLwfWinFreePools: freed NBL+NB pool 0x%p\n", pModuleCtx->hPool[i]));
+ }
+ }
+}
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+
+
+static void vboxNetLwfWinFreeModuleResources(PVBOXNETLWF_MODULE pModuleCtx)
+{
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+ vboxNetLwfWinFreePools(pModuleCtx, RT_ELEMENTS(g_cbPool));
+#else /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ if (pModuleCtx->hPool)
+ {
+ NdisFreeNetBufferListPool(pModuleCtx->hPool);
+ Log4(("vboxNetLwfWinFreeModuleResources: freed NBL+NB pool 0x%p\n", pModuleCtx->hPool));
+ }
+#endif /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ if (pModuleCtx->pDisabledOffloadConfig)
+ NdisFreeMemory(pModuleCtx->pDisabledOffloadConfig, 0, 0);
+ if (pModuleCtx->pSavedOffloadConfig)
+ NdisFreeMemory(pModuleCtx->pSavedOffloadConfig, 0, 0);
+ if (pModuleCtx->hWorkItem)
+ NdisFreeIoWorkItem(pModuleCtx->hWorkItem);
+ NdisFreeMemory(pModuleCtx, 0, 0);
+}
+
+
+DECLARE_GLOBAL_CONST_UNICODE_STRING(g_strHostOnlyMiniportName, L"VirtualBox Host-Only");
+
+static NDIS_STATUS vboxNetLwfWinAttach(IN NDIS_HANDLE hFilter, IN NDIS_HANDLE hDriverCtx,
+ IN PNDIS_FILTER_ATTACH_PARAMETERS pParameters)
+{
+ LogFlow(("==>vboxNetLwfWinAttach: filter=%p\n", hFilter));
+
+ PVBOXNETLWFGLOBALS pGlobals = (PVBOXNETLWFGLOBALS)hDriverCtx;
+ if (!pGlobals)
+ {
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 1);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /*
+ * We need a copy of NDIS_STRING structure as we are going to modify length
+ * of the base miniport instance name since RTL does not support comparing
+ * first n characters of two strings. We check if miniport names start with
+ * "Virtual Host-Only" to detect host-only adapters. It is a waste of resources
+ * to bind our filter to host-only adapters since they now operate independently.
+ */
+ NDIS_STRING strTruncatedInstanceName = *pParameters->BaseMiniportInstanceName; /* Do not copy data, only the structure itself */
+ strTruncatedInstanceName.Length = g_strHostOnlyMiniportName.Length; /* Truncate instance name */
+ if (RtlEqualUnicodeString(&strTruncatedInstanceName, &g_strHostOnlyMiniportName, TRUE /* Case insensitive */))
+ {
+ DbgPrint("vboxNetLwfWinAttach: won't attach to %wZ\n", pParameters->BaseMiniportInstanceName);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ ANSI_STRING strMiniportName;
+ /* We use the miniport name to associate this filter module with the netflt instance */
+ NTSTATUS rc = RtlUnicodeStringToAnsiString(&strMiniportName,
+ pParameters->BaseMiniportName,
+ TRUE);
+ if (rc != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinAttach: RtlUnicodeStringToAnsiString(%ls) failed with 0x%x\n",
+ pParameters->BaseMiniportName, rc));
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 2);
+ return NDIS_STATUS_FAILURE;
+ }
+ DbgPrint("vboxNetLwfWinAttach: friendly name=%wZ\n", pParameters->BaseMiniportInstanceName);
+ DbgPrint("vboxNetLwfWinAttach: name=%Z\n", &strMiniportName);
+
+ UINT cbModuleWithNameExtra = sizeof(VBOXNETLWF_MODULE) + strMiniportName.Length;
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)NdisAllocateMemoryWithTagPriority(hFilter,
+ cbModuleWithNameExtra,
+ VBOXNETLWF_MEM_TAG,
+ LowPoolPriority);
+ if (!pModuleCtx)
+ {
+ LogError(("vboxNetLwfWinAttach: Failed to allocate module context for %ls\n", pParameters->BaseMiniportName));
+ RtlFreeAnsiString(&strMiniportName);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 3);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetLwfWinAttach: allocated module context 0x%p\n", pModuleCtx));
+
+ NdisZeroMemory(pModuleCtx, cbModuleWithNameExtra);
+ NdisMoveMemory(pModuleCtx->szMiniportName, strMiniportName.Buffer, strMiniportName.Length);
+ RtlFreeAnsiString(&strMiniportName);
+
+ pModuleCtx->hWorkItem = NdisAllocateIoWorkItem(g_VBoxNetLwfGlobals.hFilterDriver);
+ if (!pModuleCtx->hWorkItem)
+ {
+ LogError(("vboxNetLwfWinAttach: Failed to allocate work item for %ls\n",
+ pParameters->BaseMiniportName));
+ NdisFreeMemory(pModuleCtx, 0, 0);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 4);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ Assert(pParameters->MacAddressLength == sizeof(RTMAC));
+ NdisMoveMemory(&pModuleCtx->MacAddr, pParameters->CurrentMacAddress, RT_MIN(sizeof(RTMAC), pParameters->MacAddressLength));
+
+ pModuleCtx->cbOffloadConfig = sizeof(NDIS_OFFLOAD) * 2; /* Best guess to accomodate future expansion. */
+ /* Get the exact size, if possible. */
+ if (pParameters->DefaultOffloadConfiguration)
+ pModuleCtx->cbOffloadConfig = pParameters->DefaultOffloadConfiguration->Header.Size;
+ else
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 8);
+
+ pModuleCtx->pSavedOffloadConfig =
+ (PNDIS_OFFLOAD)NdisAllocateMemoryWithTagPriority(hFilter, pModuleCtx->cbOffloadConfig,
+ VBOXNETLWF_MEM_TAG, LowPoolPriority);
+ pModuleCtx->pDisabledOffloadConfig =
+ (PNDIS_OFFLOAD)NdisAllocateMemoryWithTagPriority(hFilter, pModuleCtx->cbOffloadConfig,
+ VBOXNETLWF_MEM_TAG, LowPoolPriority);
+ if (!pModuleCtx->pSavedOffloadConfig || !pModuleCtx->pDisabledOffloadConfig)
+ {
+ LogError(("vboxNetLwfWinAttach: Failed to allocate offload config buffers for %ls\n",
+ pParameters->BaseMiniportName));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 9);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ if (pParameters->DefaultOffloadConfiguration)
+ vboxNetLwfWinUpdateSavedOffloadConfig(pModuleCtx, pParameters->DefaultOffloadConfiguration);
+ else
+ {
+ NdisZeroMemory(pModuleCtx->pDisabledOffloadConfig, pModuleCtx->cbOffloadConfig);
+ pModuleCtx->pDisabledOffloadConfig->Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
+ pModuleCtx->pDisabledOffloadConfig->Header.Revision = NDIS_OFFLOAD_REVISION_1;
+ pModuleCtx->pDisabledOffloadConfig->Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1;
+ }
+
+ pModuleCtx->pGlobals = pGlobals;
+ pModuleCtx->hFilter = hFilter;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Attaching);
+ /* Initialize transmission mutex and events */
+ NDIS_INIT_MUTEX(&pModuleCtx->InTransmit);
+#ifdef VBOXNETLWF_SYNC_SEND
+ KeInitializeEvent(&pModuleCtx->EventWire, SynchronizationEvent, FALSE);
+ KeInitializeEvent(&pModuleCtx->EventHost, SynchronizationEvent, FALSE);
+#else /* !VBOXNETLWF_SYNC_SEND */
+ NdisInitializeEvent(&pModuleCtx->EventSendComplete);
+ pModuleCtx->cPendingBuffers = 0;
+#endif /* !VBOXNETLWF_SYNC_SEND */
+
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+ for (int i = 0; i < RT_ELEMENTS(g_cbPool); ++i)
+ {
+ /* Allocate buffer pools */
+ NET_BUFFER_LIST_POOL_PARAMETERS PoolParams;
+ NdisZeroMemory(&PoolParams, sizeof(PoolParams));
+ PoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ PoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ PoolParams.Header.Size = sizeof(PoolParams);
+ PoolParams.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
+ PoolParams.fAllocateNetBuffer = TRUE;
+ PoolParams.ContextSize = 0; /** @todo Do we need to consider underlying drivers? I think not. */
+ PoolParams.PoolTag = VBOXNETLWF_MEM_TAG;
+ PoolParams.DataSize = g_cbPool[i];
+ pModuleCtx->hPool[i] = NdisAllocateNetBufferListPool(hFilter, &PoolParams);
+ if (!pModuleCtx->hPool[i])
+ {
+ LogError(("vboxNetLwfWinAttach: NdisAllocateNetBufferListPool failed\n"));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 7);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetLwfWinAttach: allocated NBL+NB pool (data size=%u) 0x%p\n",
+ PoolParams.DataSize, pModuleCtx->hPool[i]));
+ }
+#else /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ /* Allocate buffer pools */
+ NET_BUFFER_LIST_POOL_PARAMETERS PoolParams;
+ NdisZeroMemory(&PoolParams, sizeof(PoolParams));
+ PoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ PoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ PoolParams.Header.Size = sizeof(PoolParams);
+ PoolParams.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
+ PoolParams.fAllocateNetBuffer = TRUE;
+ PoolParams.ContextSize = 0; /** @todo Do we need to consider underlying drivers? I think not. */
+ PoolParams.PoolTag = VBOXNETLWF_MEM_TAG;
+ pModuleCtx->hPool = NdisAllocateNetBufferListPool(hFilter, &PoolParams);
+ if (!pModuleCtx->hPool)
+ {
+ LogError(("vboxNetLwfWinAttach: NdisAllocateNetBufferListPool failed\n"));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 7);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetLwfWinAttach: allocated NBL+NB pool 0x%p\n", pModuleCtx->hPool));
+#endif /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+
+ NDIS_FILTER_ATTRIBUTES Attributes;
+ NdisZeroMemory(&Attributes, sizeof(Attributes));
+ Attributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
+ Attributes.Header.Size = sizeof(Attributes);
+ Attributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
+ Attributes.Flags = 0;
+ NDIS_STATUS Status = NdisFSetAttributes(hFilter, pModuleCtx, &Attributes);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinAttach: NdisFSetAttributes failed with 0x%x\n", Status));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_RESOURCES, 5);
+ return NDIS_STATUS_RESOURCES;
+ }
+ /* Insert into module chain */
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ RTListPrepend(&pGlobals->listModules, &pModuleCtx->node);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Paused);
+
+ /// @todo Somehow the packet filter is 0 at this point: Status = vboxNetLwfWinGetPacketFilter(pModuleCtx);
+ /// @todo We actually update it later in status handler, perhaps we should not do anything here.
+
+ LogFlow(("<==vboxNetLwfWinAttach: Status = 0x%x\n", Status));
+ return Status;
+}
+
+static VOID vboxNetLwfWinDetach(IN NDIS_HANDLE hModuleCtx)
+{
+ LogFlow(("==>vboxNetLwfWinDetach: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Detached, LwfState_Paused);
+
+ /* Remove from module chain */
+ NdisAcquireSpinLock(&pModuleCtx->pGlobals->Lock);
+ RTListNodeRemove(&pModuleCtx->node);
+ NdisReleaseSpinLock(&pModuleCtx->pGlobals->Lock);
+
+ PVBOXNETFLTINS pNetFltIns = pModuleCtx->pNetFlt; /// @todo Atomic?
+ if (pNetFltIns && vboxNetFltTryRetainBusyNotDisconnected(pNetFltIns))
+ {
+ /*
+ * Set hModuleCtx to null now in order to prevent filter restart,
+ * OID requests and other stuff associated with NetFlt deactivation.
+ */
+ pNetFltIns->u.s.WinIf.hModuleCtx = NULL;
+ /* Notify NetFlt that we are going down */
+ pNetFltIns->pSwitchPort->pfnDisconnect(pNetFltIns->pSwitchPort, &pNetFltIns->MyPort, vboxNetFltPortReleaseBusy);
+ /* We do not 'release' netflt instance since it has been done by pfnDisconnect */
+ }
+ pModuleCtx->pNetFlt = NULL;
+
+ /*
+ * We have to make sure that all NET_BUFFER_LIST structures have been freed by now, but
+ * it does not require us to do anything here since it has already been taken care of
+ * by vboxNetLwfWinPause().
+ */
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ Log4(("vboxNetLwfWinDetach: freed module context 0x%p\n", pModuleCtx));
+ LogFlow(("<==vboxNetLwfWinDetach\n"));
+}
+
+
+static NDIS_STATUS vboxNetLwfWinPause(IN NDIS_HANDLE hModuleCtx, IN PNDIS_FILTER_PAUSE_PARAMETERS pParameters)
+{
+ RT_NOREF1(pParameters);
+ LogFlow(("==>vboxNetLwfWinPause: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Pausing, LwfState_Running);
+ /* Wait for pending send/indication operations to complete. */
+ NDIS_WAIT_FOR_MUTEX(&pModuleCtx->InTransmit);
+#ifndef VBOXNETLWF_SYNC_SEND
+ NdisWaitEvent(&pModuleCtx->EventSendComplete, 1000 /* ms */);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Paused, LwfState_Pausing);
+ NDIS_RELEASE_MUTEX(&pModuleCtx->InTransmit);
+ LogFlow(("<==vboxNetLwfWinPause\n"));
+ return NDIS_STATUS_SUCCESS; /* Failure is not an option */
+}
+
+
+static void vboxNetLwfWinIndicateOffload(PVBOXNETLWF_MODULE pModuleCtx, PNDIS_OFFLOAD pOffload)
+{
+ Log5(("vboxNetLwfWinIndicateOffload: offload config changed to:\n"));
+ vboxNetLwfWinDumpOffloadSettings(pOffload);
+ NDIS_STATUS_INDICATION OffloadingIndication;
+ NdisZeroMemory(&OffloadingIndication, sizeof(OffloadingIndication));
+ OffloadingIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ OffloadingIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ OffloadingIndication.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
+ OffloadingIndication.SourceHandle = pModuleCtx->hFilter;
+ OffloadingIndication.StatusCode = NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG;
+ OffloadingIndication.StatusBuffer = pOffload;
+ OffloadingIndication.StatusBufferSize = pOffload->Header.Size;
+ NdisFIndicateStatus(pModuleCtx->hFilter, &OffloadingIndication);
+}
+
+
+static NDIS_STATUS vboxNetLwfWinRestart(IN NDIS_HANDLE hModuleCtx, IN PNDIS_FILTER_RESTART_PARAMETERS pParameters)
+{
+ RT_NOREF1(pParameters);
+ LogFlow(("==>vboxNetLwfWinRestart: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Restarting, LwfState_Paused);
+
+ /* By default the packets that go between VMs and wire are invisible to the host. */
+ pModuleCtx->fPassVmTrafficToHost = false;
+
+ NDIS_HANDLE hConfig;
+ NDIS_CONFIGURATION_OBJECT cfgObj;
+ cfgObj.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ cfgObj.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+ cfgObj.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
+ cfgObj.NdisHandle = g_VBoxNetLwfGlobals.hFilterDriver;
+
+ NDIS_STATUS Status = NdisOpenConfigurationEx(&cfgObj, &hConfig);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NDIS_STRING strCfgParam = NDIS_STRING_CONST("PassVmTrafficToHost");
+ PNDIS_CONFIGURATION_PARAMETER pParam = NULL;
+ NdisReadConfiguration(&Status, &pParam, hConfig, &strCfgParam, NdisParameterInteger);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetLwfWinRestart: Failed to read 'PassVmTrafficToHost' from the registry.\n"));
+ }
+ else if (pParam->ParameterData.IntegerData != 0)
+ {
+ Log(("vboxNetLwfWinRestart: Allowing the host to see VM traffic in promisc mode by user request.\n"));
+ pModuleCtx->fPassVmTrafficToHost = true;
+ }
+ NdisCloseConfiguration(hConfig);
+ }
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Running, LwfState_Restarting);
+ LogFlow(("<==vboxNetLwfWinRestart: Status = 0x%x, returning NDIS_STATUS_SUCCESS nontheless.\n", Status));
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+static void vboxNetLwfWinDestroySG(PINTNETSG pSG)
+{
+ NdisFreeMemory(pSG, 0, 0);
+ Log4(("vboxNetLwfWinDestroySG: freed SG 0x%p\n", pSG));
+}
+
+/**
+ * Worker for vboxNetLwfWinNBtoSG() that gets the max segment count needed.
+ * @note vboxNetLwfWinNBtoSG may use fewer depending on cbPacket and offset!
+ * @note vboxNetAdpWinCalcSegments() is a copy of this code.
+ */
+DECLINLINE(ULONG) vboxNetLwfWinCalcSegments(PNET_BUFFER pNetBuf)
+{
+ ULONG cSegs = 0;
+ for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf); pMdl; pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ /* Skip empty MDLs (see @bugref{9233}) */
+ if (MmGetMdlByteCount(pMdl))
+ cSegs++;
+ }
+ return cSegs;
+}
+
+DECLINLINE(void) vboxNetLwfWinFreeMdlChain(PMDL pMdl)
+{
+#ifndef VBOXNETLWF_FIXED_SIZE_POOLS
+ PMDL pMdlNext;
+ while (pMdl)
+ {
+ pMdlNext = pMdl->Next;
+# ifndef VBOXNETLWF_SYNC_SEND
+ PUCHAR pDataBuf;
+ ULONG cb = 0;
+ NdisQueryMdl(pMdl, &pDataBuf, &cb, NormalPagePriority);
+# endif /* !VBOXNETLWF_SYNC_SEND */
+ NdisFreeMdl(pMdl);
+ Log4(("vboxNetLwfWinFreeMdlChain: freed MDL 0x%p\n", pMdl));
+# ifndef VBOXNETLWF_SYNC_SEND
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetLwfWinFreeMdlChain: freed data buffer 0x%p\n", pDataBuf));
+# endif /* !VBOXNETLWF_SYNC_SEND */
+ pMdl = pMdlNext;
+ }
+#else /* VBOXNETLWF_FIXED_SIZE_POOLS */
+ RT_NOREF1(pMdl);
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+}
+
+/** @todo
+ * 1) Copy data from SG to MDL (if we decide to complete asynchronously).
+ * 2) Provide context/backfill space. Nobody does it, should we?
+ * 3) We always get a single segment from intnet. Simplify?
+ */
+static PNET_BUFFER_LIST vboxNetLwfWinSGtoNB(PVBOXNETLWF_MODULE pModule, PINTNETSG pSG)
+{
+ AssertReturn(pSG->cSegsUsed >= 1, NULL);
+ LogFlow(("==>vboxNetLwfWinSGtoNB: segments=%d hPool=%p cb=%u\n", pSG->cSegsUsed,
+ pModule->hPool, pSG->cbTotal));
+ AssertReturn(pModule->hPool, NULL);
+
+#ifdef VBOXNETLWF_SYNC_SEND
+ PINTNETSEG pSeg = pSG->aSegs;
+ PMDL pMdl = NdisAllocateMdl(pModule->hFilter, pSeg->pv, pSeg->cb);
+ if (!pMdl)
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL\n"));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ Log4(("vboxNetLwfWinSGtoNB: allocated Mdl 0x%p\n", pMdl));
+ PMDL pMdlCurr = pMdl;
+ for (int i = 1; i < pSG->cSegsUsed; i++)
+ {
+ pSeg = &pSG->aSegs[i];
+ pMdlCurr->Next = NdisAllocateMdl(pModule->hFilter, pSeg->pv, pSeg->cb);
+ if (!pMdlCurr->Next)
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL\n"));
+ /* Tear down all MDL we chained so far */
+ vboxNetLwfWinFreeMdlChain(pMdl);
+ return NULL;
+ }
+ pMdlCurr = pMdlCurr->Next;
+ Log4(("vboxNetLwfWinSGtoNB: allocated Mdl 0x%p\n", pMdlCurr));
+ }
+ PNET_BUFFER_LIST pBufList = NdisAllocateNetBufferAndNetBufferList(pModule->hPool,
+ 0 /* ContextSize */,
+ 0 /* ContextBackFill */,
+ pMdl,
+ 0 /* DataOffset */,
+ pSG->cbTotal);
+ if (pBufList)
+ {
+ Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pModule->hFilter;
+ /** @todo Do we need to initialize anything else? */
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an NBL+NB\n"));
+ vboxNetLwfWinFreeMdlChain(pMdl);
+ }
+#else /* !VBOXNETLWF_SYNC_SEND */
+
+# ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+ int iPool = 0;
+ ULONG cbFrame = VBOXNETLWF_MAX_FRAME_SIZE(pSG->cbTotal);
+ /* Let's find the appropriate pool first */
+ for (iPool = 0; iPool < RT_ELEMENTS(g_cbPool); ++iPool)
+ if (cbFrame <= g_cbPool[iPool])
+ break;
+ if (iPool >= RT_ELEMENTS(g_cbPool))
+ {
+ LogError(("vboxNetLwfWinSGtoNB: frame is too big (%u > %u), drop it.\n", cbFrame, g_cbPool[RT_ELEMENTS(g_cbPool)-1]));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ PNET_BUFFER_LIST pBufList = NdisAllocateNetBufferList(pModule->hPool[iPool],
+ 0 /** @todo ContextSize */,
+ 0 /** @todo ContextBackFill */);
+ if (!pBufList)
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate netbuffer (cb=%u) from pool %d\n", cbFrame, iPool));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ const ULONG cbAlignmentMask = sizeof(USHORT) - 1; /* Microsoft LB/FO provider expects packets to be aligned at word boundary. */
+ ULONG cbAlignedFrame = (pSG->cbTotal + cbAlignmentMask) & ~cbAlignmentMask;
+ Assert(cbAlignedFrame >= pSG->cbTotal);
+ Assert(cbFrame >= cbAlignedFrame);
+ NET_BUFFER *pBuffer = NET_BUFFER_LIST_FIRST_NB(pBufList);
+ NDIS_STATUS Status = NdisRetreatNetBufferDataStart(pBuffer, cbAlignedFrame, 0 /** @todo DataBackfill */, NULL);
+ if (cbAlignedFrame - pSG->cbTotal > 0)
+ {
+ /* Make sure padding zeros do not get to the wire. */
+ if (NET_BUFFER_DATA_LENGTH(pBuffer) != cbAlignedFrame)
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 11);
+ else
+ NET_BUFFER_DATA_LENGTH(pBuffer) = pSG->cbTotal;
+ }
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ uint8_t *pDst = (uint8_t*)NdisGetDataBuffer(pBuffer, pSG->cbTotal, NULL, 1, 0);
+ if (pDst)
+ {
+ for (int i = 0; i < pSG->cSegsUsed; i++)
+ {
+ NdisMoveMemory(pDst, pSG->aSegs[i].pv, pSG->aSegs[i].cb);
+ pDst += pSG->aSegs[i].cb;
+ }
+ Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pModule->hFilter;
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to obtain the buffer pointer (size=%u)\n", pSG->cbTotal));
+ NdisAdvanceNetBufferDataStart(pBuffer, cbAlignedFrame, false, NULL); /** @todo why bother? */
+ NdisFreeNetBufferList(pBufList);
+ pBufList = NULL;
+ }
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: NdisRetreatNetBufferDataStart failed with 0x%x (size=%u)\n", Status, pSG->cbTotal));
+ NdisFreeNetBufferList(pBufList);
+ pBufList = NULL;
+ }
+# else /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ PNET_BUFFER_LIST pBufList = NULL;
+ ULONG cbMdl = VBOXNETLWF_MAX_FRAME_SIZE(pSG->cbTotal);
+ ULONG uDataOffset = cbMdl - pSG->cbTotal;
+ PUCHAR pDataBuf = (PUCHAR)NdisAllocateMemoryWithTagPriority(pModule->hFilter, cbMdl,
+ VBOXNETLWF_MEM_TAG, NormalPoolPriority);
+ if (pDataBuf)
+ {
+ Log4(("vboxNetLwfWinSGtoNB: allocated data buffer (cb=%u) 0x%p\n", cbMdl, pDataBuf));
+ PMDL pMdl = NdisAllocateMdl(pModule->hFilter, pDataBuf, cbMdl);
+ if (!pMdl)
+ {
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetLwfWinSGtoNB: freed data buffer 0x%p\n", pDataBuf));
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL (cb=%u)\n", cbMdl));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ PUCHAR pDst = pDataBuf + uDataOffset;
+ for (int i = 0; i < pSG->cSegsUsed; i++)
+ {
+ NdisMoveMemory(pDst, pSG->aSegs[i].pv, pSG->aSegs[i].cb);
+ pDst += pSG->aSegs[i].cb;
+ }
+ pBufList = NdisAllocateNetBufferAndNetBufferList(pModule->hPool,
+ 0 /* ContextSize */,
+ 0 /* ContextBackFill */,
+ pMdl,
+ uDataOffset,
+ pSG->cbTotal);
+ if (pBufList)
+ {
+ Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pModule->hFilter;
+ /** @todo Do we need to initialize anything else? */
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an NBL+NB\n"));
+ vboxNetLwfWinFreeMdlChain(pMdl);
+ }
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate data buffer (size=%u)\n", cbMdl));
+ }
+# endif /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return %p\n", pBufList));
+ return pBufList;
+}
+
+/**
+ * @note vboxNetAdpWinNBtoSG() is a copy of this code.
+ */
+static PINTNETSG vboxNetLwfWinNBtoSG(PVBOXNETLWF_MODULE pModule, PNET_BUFFER pNetBuf)
+{
+ ULONG cbPacket = NET_BUFFER_DATA_LENGTH(pNetBuf);
+ ULONG cSegs = vboxNetLwfWinCalcSegments(pNetBuf);
+ /* Allocate and initialize SG */
+ PINTNETSG pSG = (PINTNETSG)NdisAllocateMemoryWithTagPriority(pModule->hFilter,
+ RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]),
+ VBOXNETLWF_MEM_TAG,
+ NormalPoolPriority);
+ AssertReturn(pSG, pSG);
+ Log4(("vboxNetLwfWinNBtoSG: allocated SG 0x%p\n", pSG));
+ IntNetSgInitTempSegs(pSG, cbPacket /*cbTotal*/, cSegs, cSegs /*cSegsUsed*/);
+
+ ULONG uOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pNetBuf);
+ cSegs = 0;
+ for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf);
+ pMdl != NULL && cbPacket > 0;
+ pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ ULONG cbSrc = MmGetMdlByteCount(pMdl);
+ if (cbSrc == 0)
+ continue; /* Skip empty MDLs (see @bugref{9233}) */
+
+ PUCHAR pSrc = (PUCHAR)MmGetSystemAddressForMdlSafe(pMdl, LowPagePriority);
+ if (!pSrc)
+ {
+ vboxNetLwfWinDestroySG(pSG);
+ return NULL;
+ }
+
+ /* Handle the offset in the current (which is the first for us) MDL */
+ if (uOffset)
+ {
+ if (uOffset < cbSrc)
+ {
+ pSrc += uOffset;
+ cbSrc -= uOffset;
+ uOffset = 0;
+ }
+ else
+ {
+ /* This is an invalid MDL chain */
+ vboxNetLwfWinDestroySG(pSG);
+ return NULL;
+ }
+ }
+
+ /* Do not read the last MDL beyond packet's end */
+ if (cbSrc > cbPacket)
+ cbSrc = cbPacket;
+
+ Assert(cSegs < pSG->cSegsAlloc);
+ pSG->aSegs[cSegs].pv = pSrc;
+ pSG->aSegs[cSegs].cb = cbSrc;
+ pSG->aSegs[cSegs].Phys = NIL_RTHCPHYS;
+ cSegs++;
+ cbPacket -= cbSrc;
+ }
+
+ Assert(cbPacket == 0);
+ Assert(cSegs <= pSG->cSegsUsed);
+
+ /* Update actual segment count in case we used fewer than anticipated. */
+ pSG->cSegsUsed = (uint16_t)cSegs;
+
+ return pSG;
+}
+
+VOID vboxNetLwfWinStatus(IN NDIS_HANDLE hModuleCtx, IN PNDIS_STATUS_INDICATION pIndication)
+{
+ LogFlow(("==>vboxNetLwfWinStatus: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ Log(("vboxNetLwfWinStatus: Got status indication: %s\n", vboxNetLwfWinStatusToText(pIndication->StatusCode)));
+ switch (pIndication->StatusCode)
+ {
+ case NDIS_STATUS_PACKET_FILTER:
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pIndication->StatusBuffer);
+ vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pIndication->StatusBuffer);
+ Log(("vboxNetLwfWinStatus: Reporting status: %s\n", vboxNetLwfWinStatusToText(pIndication->StatusCode)));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pIndication->StatusBuffer);
+ break;
+ case NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
+ Log5(("vboxNetLwfWinStatus: offloading currently set to:\n"));
+ vboxNetLwfWinDumpOffloadSettings((PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ vboxNetLwfWinUpdateSavedOffloadConfig(pModuleCtx, (PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ vboxNetLwfWinDisableOffloading((PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ Log5(("vboxNetLwfWinStatus: reporting offloading up as:\n"));
+ vboxNetLwfWinDumpOffloadSettings((PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ break;
+ }
+ NdisFIndicateStatus(pModuleCtx->hFilter, pIndication);
+ LogFlow(("<==vboxNetLwfWinStatus\n"));
+}
+
+static bool vboxNetLwfWinForwardToIntNet(PVBOXNETLWF_MODULE pModuleCtx, PNET_BUFFER_LIST pBufLists, uint32_t fSrc)
+{
+ /* We must not forward anything to the trunk unless it is ready to receive. */
+ if (!ASMAtomicReadBool(&pModuleCtx->fActive))
+ {
+ Log(("vboxNetLwfWinForwardToIntNet: trunk is inactive, won't forward\n"));
+ return false;
+ }
+ /* Some NPF protocols make NDIS to loop back packets at miniport level, we must ignore those. */
+ if (NdisTestNblFlag(pBufLists, NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET))
+ {
+ if (pBufLists->SourceHandle == pModuleCtx->hFilter && !pModuleCtx->fPassVmTrafficToHost)
+ {
+ /* Drop the packets we've injected. */
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinForwardToIntNet: dropping loopback", pBufLists);
+ return true;
+ }
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinForwardToIntNet: passing through loopback", pBufLists);
+ return false;
+ }
+
+ AssertReturn(pModuleCtx->pNetFlt, false);
+ AssertReturn(pModuleCtx->pNetFlt->pSwitchPort, false);
+ AssertReturn(pModuleCtx->pNetFlt->pSwitchPort->pfnRecv, false);
+ LogFlow(("==>vboxNetLwfWinForwardToIntNet: module=%p\n", pModuleCtx));
+ Assert(pBufLists); /* The chain must contain at least one list */
+ Assert(NET_BUFFER_LIST_NEXT_NBL(pBufLists) == NULL); /* The caller is supposed to unlink the list from the chain */
+ /*
+ * Even if NBL contains more than one buffer we are prepared to deal with it.
+ * When any of buffers should not be dropped we keep the whole list. It is
+ * better to leak some "unexpected" packets to the wire/host than to loose any.
+ */
+ bool fDropIt = false;
+ bool fDontDrop = false;
+ int nLists = 0;
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ int nBuffers = 0;
+ nLists++;
+ for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
+ {
+ nBuffers++;
+ PINTNETSG pSG = vboxNetLwfWinNBtoSG(pModuleCtx, pBuf);
+ if (pSG)
+ {
+ vboxNetLwfWinDumpPacket(pSG, (fSrc & INTNETTRUNKDIR_WIRE)?"intnet <-- wire":"intnet <-- host");
+ /* A bit paranoid, but we do not use any locks, so... */
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ if (pModuleCtx->pNetFlt->pSwitchPort->pfnRecv(pModuleCtx->pNetFlt->pSwitchPort, NULL, pSG, fSrc))
+ fDropIt = true;
+ else
+ fDontDrop = true;
+ vboxNetLwfWinDestroySG(pSG);
+ }
+ }
+ Log(("vboxNetLwfWinForwardToIntNet: list=%d buffers=%d\n", nLists, nBuffers));
+ }
+ Log(("vboxNetLwfWinForwardToIntNet: lists=%d drop=%s don't=%s\n", nLists, fDropIt ? "true":"false", fDontDrop ? "true":"false"));
+
+ /* If the host (and the user) wants to see all packets we must not drop any. */
+ if (pModuleCtx->fPassVmTrafficToHost && vboxNetLwfWinIsPromiscuous(pModuleCtx))
+ fDropIt = false;
+
+ LogFlow(("<==vboxNetLwfWinForwardToIntNet: return '%s'\n",
+ fDropIt ? (fDontDrop ? "do not drop (some)" : "drop it") : "do not drop (any)"));
+ return fDropIt && !fDontDrop; /* Drop the list if ALL its buffers are being dropped! */
+}
+
+DECLINLINE(bool) vboxNetLwfWinIsRunning(PVBOXNETLWF_MODULE pModule)
+{
+ Log(("vboxNetLwfWinIsRunning: state=%d\n", ASMAtomicReadU32(&pModule->enmState)));
+ return ASMAtomicReadU32(&pModule->enmState) == LwfState_Running;
+}
+
+VOID vboxNetLwfWinSendNetBufferLists(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN NDIS_PORT_NUMBER nPort, IN ULONG fFlags)
+{
+ LogFlow(("==>vboxNetLwfWinSendNetBufferLists: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: got", pBufLists);
+
+ if (!ASMAtomicReadBool(&pModule->fActive))
+ {
+ /*
+ * The trunk is inactive, jusp pass along all packets to the next
+ * underlying driver.
+ */
+ NdisFSendNetBufferLists(pModule->hFilter, pBufLists, nPort, fFlags);
+ return;
+ }
+
+ if (vboxNetLwfWinIsRunning(pModule))
+ {
+ PNET_BUFFER_LIST pNext = NULL;
+ PNET_BUFFER_LIST pDropHead = NULL;
+ PNET_BUFFER_LIST pDropTail = NULL;
+ PNET_BUFFER_LIST pPassHead = NULL;
+ PNET_BUFFER_LIST pPassTail = NULL;
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = pNext)
+ {
+ pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
+ NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink */
+ if (vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_HOST))
+ {
+ NET_BUFFER_LIST_STATUS(pList) = NDIS_STATUS_SUCCESS;
+ if (pDropHead)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pDropTail) = pList;
+ pDropTail = pList;
+ }
+ else
+ pDropHead = pDropTail = pList;
+ }
+ else
+ {
+ if (pPassHead)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pPassTail) = pList;
+ pPassTail = pList;
+ }
+ else
+ pPassHead = pPassTail = pList;
+ }
+ }
+ Assert((pBufLists == pPassHead) || (pBufLists == pDropHead));
+ if (pPassHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: passing down", pPassHead);
+ NdisFSendNetBufferLists(pModule->hFilter, pBufLists, nPort, fFlags);
+ }
+ if (pDropHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: consumed", pDropHead);
+ NdisFSendNetBufferListsComplete(pModule->hFilter, pDropHead,
+ fFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+ }
+ }
+ else
+ {
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ NET_BUFFER_LIST_STATUS(pList) = NDIS_STATUS_PAUSED;
+ }
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: consumed", pBufLists);
+ NdisFSendNetBufferListsComplete(pModule->hFilter, pBufLists,
+ fFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+
+ }
+ LogFlow(("<==vboxNetLwfWinSendNetBufferLists\n"));
+}
+
+VOID vboxNetLwfWinSendNetBufferListsComplete(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN ULONG fFlags)
+{
+ LogFlow(("==>vboxNetLwfWinSendNetBufferListsComplete: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNET_BUFFER_LIST pList = pBufLists;
+ PNET_BUFFER_LIST pNextList;
+ PNET_BUFFER_LIST pPrevList = NULL;
+ while (pList)
+ {
+ pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
+ if (pList->SourceHandle == pModule->hFilter)
+ {
+ /* We allocated this NET_BUFFER_LIST, let's free it up */
+ Assert(NET_BUFFER_LIST_FIRST_NB(pList));
+ Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /*
+ * All our NBLs hold a single NB each, no need to iterate over a list.
+ * There is no need to free an associated NB explicitly either, as it was
+ * preallocated with NBL structure.
+ */
+ Assert(!NET_BUFFER_NEXT_NB(NET_BUFFER_LIST_FIRST_NB(pList)));
+ vboxNetLwfWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /* Unlink this list from the chain */
+ if (pPrevList)
+ NET_BUFFER_LIST_NEXT_NBL(pPrevList) = pNextList;
+ else
+ pBufLists = pNextList;
+ Log(("vboxNetLwfWinSendNetBufferListsComplete: our list %p, next=%p, previous=%p, head=%p\n", pList, pNextList, pPrevList, pBufLists));
+ NdisFreeNetBufferList(pList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ Log4(("vboxNetLwfWinSendNetBufferListsComplete: freed NBL+NB 0x%p\n", pList));
+ KeSetEvent(&pModule->EventWire, 0, FALSE);
+#else /* !VBOXNETLWF_SYNC_SEND */
+ Log4(("vboxNetLwfWinSendNetBufferListsComplete: freed NBL+NB+MDL+Data 0x%p\n", pList));
+ Assert(ASMAtomicReadS32(&pModule->cPendingBuffers) > 0);
+ if (ASMAtomicDecS32(&pModule->cPendingBuffers) == 0)
+ NdisSetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ }
+ else
+ {
+ pPrevList = pList;
+ Log(("vboxNetLwfWinSendNetBufferListsComplete: passing list %p, next=%p, previous=%p, head=%p\n", pList, pNextList, pPrevList, pBufLists));
+ }
+ pList = pNextList;
+ }
+ if (pBufLists)
+ {
+ /* There are still lists remaining in the chain, pass'em up */
+ NdisFSendNetBufferListsComplete(pModule->hFilter, pBufLists, fFlags);
+ }
+ LogFlow(("<==vboxNetLwfWinSendNetBufferListsComplete\n"));
+}
+
+VOID vboxNetLwfWinReceiveNetBufferLists(IN NDIS_HANDLE hModuleCtx,
+ IN PNET_BUFFER_LIST pBufLists,
+ IN NDIS_PORT_NUMBER nPort,
+ IN ULONG nBufLists,
+ IN ULONG fFlags)
+{
+ /// @todo Do we need loopback handling?
+ LogFlow(("==>vboxNetLwfWinReceiveNetBufferLists: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: got", pBufLists);
+
+ if (!ASMAtomicReadBool(&pModule->fActive))
+ {
+ /*
+ * The trunk is inactive, just pass along all packets to the next
+ * overlying driver.
+ */
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pBufLists, nPort, nBufLists, fFlags);
+ LogFlow(("<==vboxNetLwfWinReceiveNetBufferLists: inactive trunk\n"));
+ return;
+ }
+
+ if (vboxNetLwfWinIsRunning(pModule))
+ {
+ if (NDIS_TEST_RECEIVE_CANNOT_PEND(fFlags))
+ {
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ PNET_BUFFER_LIST pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
+ NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink temporarily */
+ if (!vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_WIRE))
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: passing up", pList);
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pList, nPort, nBufLists, fFlags);
+ }
+ NET_BUFFER_LIST_NEXT_NBL(pList) = pNext; /* Restore the link */
+ }
+ }
+ else
+ {
+ /* We collect dropped NBLs in a separate list in order to "return" them. */
+ PNET_BUFFER_LIST pNext = NULL;
+ PNET_BUFFER_LIST pDropHead = NULL;
+ PNET_BUFFER_LIST pDropTail = NULL;
+ PNET_BUFFER_LIST pPassHead = NULL;
+ PNET_BUFFER_LIST pPassTail = NULL;
+ ULONG nDrop = 0, nPass = 0;
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = pNext)
+ {
+ pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
+ NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink */
+ if (vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_WIRE))
+ {
+ if (nDrop++)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pDropTail) = pList;
+ pDropTail = pList;
+ }
+ else
+ pDropHead = pDropTail = pList;
+ }
+ else
+ {
+ if (nPass++)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pPassTail) = pList;
+ pPassTail = pList;
+ }
+ else
+ pPassHead = pPassTail = pList;
+ }
+ }
+ Assert((pBufLists == pPassHead) || (pBufLists == pDropHead));
+ Assert(nDrop + nPass == nBufLists);
+ if (pPassHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: passing up", pPassHead);
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pPassHead, nPort, nPass, fFlags);
+ }
+ if (pDropHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: consumed", pDropHead);
+ NdisFReturnNetBufferLists(pModule->hFilter, pDropHead,
+ fFlags & NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0);
+ }
+ }
+
+ }
+ else
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: consumed", pBufLists);
+ if ((fFlags & NDIS_RECEIVE_FLAGS_RESOURCES) == 0)
+ NdisFReturnNetBufferLists(pModule->hFilter, pBufLists,
+ fFlags & NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0);
+ }
+ LogFlow(("<==vboxNetLwfWinReceiveNetBufferLists\n"));
+}
+
+VOID vboxNetLwfWinReturnNetBufferLists(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN ULONG fFlags)
+{
+ LogFlow(("==>vboxNetLwfWinReturnNetBufferLists: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNET_BUFFER_LIST pList = pBufLists;
+ PNET_BUFFER_LIST pNextList;
+ PNET_BUFFER_LIST pPrevList = NULL;
+ /** @todo Move common part into a separate function to be used by vboxNetLwfWinSendNetBufferListsComplete() as well */
+ while (pList)
+ {
+ pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
+ if (pList->SourceHandle == pModule->hFilter)
+ {
+ /* We allocated this NET_BUFFER_LIST, let's free it up */
+ Assert(NET_BUFFER_LIST_FIRST_NB(pList));
+ Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /*
+ * All our NBLs hold a single NB each, no need to iterate over a list.
+ * There is no need to free an associated NB explicitly either, as it was
+ * preallocated with NBL structure.
+ */
+ vboxNetLwfWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /* Unlink this list from the chain */
+ if (pPrevList)
+ NET_BUFFER_LIST_NEXT_NBL(pPrevList) = pNextList;
+ else
+ pBufLists = pNextList;
+ NdisFreeNetBufferList(pList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB 0x%p\n", pList));
+ KeSetEvent(&pModule->EventHost, 0, FALSE);
+#else /* !VBOXNETLWF_SYNC_SEND */
+ Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB+MDL+Data 0x%p\n", pList));
+ Assert(ASMAtomicReadS32(&pModule->cPendingBuffers) > 0);
+ if (ASMAtomicDecS32(&pModule->cPendingBuffers) == 0)
+ NdisSetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ }
+ else
+ pPrevList = pList;
+ pList = pNextList;
+ }
+ if (pBufLists)
+ {
+ /* There are still lists remaining in the chain, pass'em up */
+ NdisFReturnNetBufferLists(pModule->hFilter, pBufLists, fFlags);
+ }
+ LogFlow(("<==vboxNetLwfWinReturnNetBufferLists\n"));
+}
+
+/**
+ * register the filter driver
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetLwfWinRegister(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
+{
+ RT_NOREF1(pRegistryPathStr);
+ NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
+ NDIS_STRING FriendlyName;
+ NDIS_STRING UniqueName;
+ NDIS_STRING ServiceName;
+
+ NdisInitUnicodeString(&FriendlyName, VBOXNETLWF_NAME_FRIENDLY);
+ NdisInitUnicodeString(&UniqueName, VBOXNETLWF_NAME_UNIQUE);
+ NdisInitUnicodeString(&ServiceName, VBOXNETLWF_NAME_SERVICE);
+
+ NdisZeroMemory(&FChars, sizeof (FChars));
+
+ FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
+ FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
+ FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
+
+ FChars.MajorNdisVersion = VBOXNETLWF_VERSION_NDIS_MAJOR;
+ FChars.MinorNdisVersion = VBOXNETLWF_VERSION_NDIS_MINOR;
+
+ FChars.FriendlyName = FriendlyName;
+ FChars.UniqueName = UniqueName;
+ FChars.ServiceName = ServiceName;
+
+ /* Mandatory functions */
+ FChars.AttachHandler = vboxNetLwfWinAttach;
+ FChars.DetachHandler = vboxNetLwfWinDetach;
+ FChars.RestartHandler = vboxNetLwfWinRestart;
+ FChars.PauseHandler = vboxNetLwfWinPause;
+
+ /* Optional functions, non changeble at run-time */
+ FChars.OidRequestHandler = vboxNetLwfWinOidRequest;
+ FChars.OidRequestCompleteHandler = vboxNetLwfWinOidRequestComplete;
+ //FChars.CancelOidRequestHandler = vboxNetLwfWinCancelOidRequest;
+ FChars.StatusHandler = vboxNetLwfWinStatus;
+ //FChars.NetPnPEventHandler = vboxNetLwfWinPnPEvent;
+
+ /* Datapath functions */
+ FChars.SendNetBufferListsHandler = vboxNetLwfWinSendNetBufferLists;
+ FChars.SendNetBufferListsCompleteHandler = vboxNetLwfWinSendNetBufferListsComplete;
+ FChars.ReceiveNetBufferListsHandler = vboxNetLwfWinReceiveNetBufferLists;
+ FChars.ReturnNetBufferListsHandler = vboxNetLwfWinReturnNetBufferLists;
+
+ pDriverObject->DriverUnload = vboxNetLwfWinUnloadDriver;
+
+ NDIS_STATUS Status;
+ g_VBoxNetLwfGlobals.hFilterDriver = NULL;
+ Log(("vboxNetLwfWinRegister: registering filter driver...\n"));
+ Status = NdisFRegisterFilterDriver(pDriverObject,
+ (NDIS_HANDLE)&g_VBoxNetLwfGlobals,
+ &FChars,
+ &g_VBoxNetLwfGlobals.hFilterDriver);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Log(("vboxNetLwfWinRegister: successfully registered filter driver; registering device...\n"));
+ Status = vboxNetLwfWinDevCreate(&g_VBoxNetLwfGlobals);
+ Assert(Status == STATUS_SUCCESS);
+ Log(("vboxNetLwfWinRegister: vboxNetLwfWinDevCreate() returned 0x%x\n", Status));
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinRegister: failed to register filter driver, status=0x%x", Status));
+ }
+ return Status;
+}
+
+static int vboxNetLwfWinStartInitIdcThread()
+{
+ int rc = VERR_INVALID_STATE;
+
+ if (ASMAtomicCmpXchgU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Connecting, LwfIdcState_Disconnected))
+ {
+ Log(("vboxNetLwfWinStartInitIdcThread: IDC state change Diconnected -> Connecting\n"));
+
+ NTSTATUS Status = PsCreateSystemThread(&g_VBoxNetLwfGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ vboxNetLwfWinInitIdcWorker,
+ &g_VBoxNetLwfGlobals);
+ Log(("vboxNetLwfWinStartInitIdcThread: create IDC initialization thread, status=0x%x\n", Status));
+ if (Status != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinStartInitIdcThread: IDC initialization failed (system thread creation, status=0x%x)\n", Status));
+ /*
+ * We failed to init IDC and there will be no second chance.
+ */
+ Log(("vboxNetLwfWinStartInitIdcThread: IDC state change Connecting -> Diconnected\n"));
+ ASMAtomicWriteU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Disconnected);
+ }
+ rc = RTErrConvertFromNtStatus(Status);
+ }
+ return rc;
+}
+
+static void vboxNetLwfWinStopInitIdcThread()
+{
+}
+
+
+RT_C_DECLS_BEGIN
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath);
+
+RT_C_DECLS_END
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
+{
+ 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 = vboxNetLwfWinInitBase();
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ NdisZeroMemory(&g_VBoxNetLwfGlobals, sizeof (g_VBoxNetLwfGlobals));
+ RTListInit(&g_VBoxNetLwfGlobals.listModules);
+ NdisAllocateSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ /*
+ * We choose to ignore IDC initialization errors here because if we fail to load
+ * our filter the upper protocols won't bind to the associated adapter, causing
+ * network failure at the host. Better to have non-working filter than broken
+ * networking on the host.
+ */
+ rc = vboxNetLwfWinStartInitIdcThread();
+ AssertRC(rc);
+
+ Status = vboxNetLwfWinRegister(pDriverObject, pRegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Log(("NETLWF: started successfully\n"));
+ return STATUS_SUCCESS;
+ }
+ NdisFreeSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ vboxNetLwfWinFini();
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+
+
+static VOID vboxNetLwfWinUnloadDriver(IN PDRIVER_OBJECT pDriver)
+{
+ RT_NOREF1(pDriver);
+ LogFlow(("==>vboxNetLwfWinUnloadDriver: driver=%p\n", pDriver));
+ vboxNetLwfWinDevDestroy(&g_VBoxNetLwfGlobals);
+ NdisFDeregisterFilterDriver(g_VBoxNetLwfGlobals.hFilterDriver);
+ NdisFreeSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ LogFlow(("<==vboxNetLwfWinUnloadDriver\n"));
+ vboxNetLwfWinFini();
+}
+
+static const char *vboxNetLwfWinIdcStateToText(uint32_t enmState)
+{
+ switch (enmState)
+ {
+ case LwfIdcState_Disconnected: return "Disconnected";
+ case LwfIdcState_Connecting: return "Connecting";
+ case LwfIdcState_Connected: return "Connected";
+ case LwfIdcState_Stopping: return "Stopping";
+ }
+ return "Unknown";
+}
+
+static VOID vboxNetLwfWinInitIdcWorker(PVOID pvContext)
+{
+ int rc;
+ PVBOXNETLWFGLOBALS pGlobals = (PVBOXNETLWFGLOBALS)pvContext;
+
+ while (ASMAtomicReadU32(&pGlobals->enmIdcState) == LwfIdcState_Connecting)
+ {
+ rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ if (!ASMAtomicCmpXchgU32(&pGlobals->enmIdcState, LwfIdcState_Connected, LwfIdcState_Connecting))
+ {
+ /* The state has been changed (the only valid transition is to "Stopping"), undo init */
+ rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
+ Log(("vboxNetLwfWinInitIdcWorker: state change (Connecting -> %s) while initializing IDC, deleted IDC, rc=0x%x\n",
+ vboxNetLwfWinIdcStateToText(ASMAtomicReadU32(&pGlobals->enmIdcState)), rc));
+ }
+ else
+ {
+ Log(("vboxNetLwfWinInitIdcWorker: IDC state change Connecting -> Connected\n"));
+ }
+ }
+ else
+ {
+ LARGE_INTEGER WaitIn100nsUnits;
+ WaitIn100nsUnits.QuadPart = -(LONGLONG)10000000; /* 1 sec */
+ KeDelayExecutionThread(KernelMode, FALSE /* non-alertable */, &WaitIn100nsUnits);
+ }
+ }
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+static int vboxNetLwfWinTryFiniIdc()
+{
+ int rc = VINF_SUCCESS;
+ NTSTATUS Status;
+ PKTHREAD pThread = NULL;
+ uint32_t enmPrevState = ASMAtomicXchgU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Stopping);
+
+ Log(("vboxNetLwfWinTryFiniIdc: IDC state change %s -> Stopping\n", vboxNetLwfWinIdcStateToText(enmPrevState)));
+
+ switch (enmPrevState)
+ {
+ case LwfIdcState_Disconnected:
+ /* Have not even attempted to connect -- nothing to do. */
+ break;
+ case LwfIdcState_Stopping:
+ /* Impossible, but another thread is alreading doing FiniIdc, bail out */
+ LogError(("vboxNetLwfWinTryFiniIdc: called in 'Stopping' state\n"));
+ rc = VERR_INVALID_STATE;
+ break;
+ case LwfIdcState_Connecting:
+ /* the worker thread is running, let's wait for it to stop */
+ Status = ObReferenceObjectByHandle(g_VBoxNetLwfGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS, NULL, KernelMode,
+ (PVOID*)&pThread, NULL);
+ if (Status == STATUS_SUCCESS)
+ {
+ KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
+ ObDereferenceObject(pThread);
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinTryFiniIdc: ObReferenceObjectByHandle(%p) failed with 0x%x\n",
+ g_VBoxNetLwfGlobals.hInitIdcThread, Status));
+ }
+ rc = RTErrConvertFromNtStatus(Status);
+ break;
+ case LwfIdcState_Connected:
+ /* the worker succeeded in IDC init and terminated */
+ rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
+ Log(("vboxNetLwfWinTryFiniIdc: deleted IDC, rc=0x%x\n", rc));
+ break;
+ }
+ return rc;
+}
+
+static void vboxNetLwfWinFiniBase()
+{
+ 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();
+}
+
+static int vboxNetLwfWinInitBase()
+{
+ int rc = RTR0Init(0);
+ if (!RT_SUCCESS(rc))
+ return rc;
+
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
+ if (!RT_SUCCESS(rc))
+ RTR0Term();
+
+ return rc;
+}
+
+static int vboxNetLwfWinFini()
+{
+ int rc = vboxNetLwfWinTryFiniIdc();
+ if (RT_SUCCESS(rc))
+ {
+ vboxNetLwfWinFiniBase();
+ }
+ return rc;
+}
+
+
+/*
+ *
+ * The OS specific interface definition
+ *
+ */
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltOsMaybeRediscovered: instance=%p\n", pThis));
+ LogFlow(("<==vboxNetFltOsMaybeRediscovered: return %RTbool\n", !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)));
+ /* 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;
+
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
+ LogFlow(("==>vboxNetFltPortOsXmit: instance=%p module=%p\n", pThis, pModule));
+ if (!pModule)
+ {
+ LogFlow(("<==vboxNetFltPortOsXmit: pModule is null, return %d\n", VERR_INTERNAL_ERROR));
+ return VERR_INTERNAL_ERROR;
+ }
+ /* Prevent going into "paused" state until all transmissions have been completed. */
+ NDIS_WAIT_FOR_MUTEX(&pModule->InTransmit);
+ /* Ignore all sends if the stack is paused or being paused, etc... */
+ if (!vboxNetLwfWinIsRunning(pModule))
+ {
+ NDIS_RELEASE_MUTEX(&pModule->InTransmit);
+ return VINF_SUCCESS;
+ }
+
+ vboxNetLwfWinDumpPacket(pSG, !(fDst & INTNETTRUNKDIR_WIRE) ? "intnet --> host"
+ : !(fDst & INTNETTRUNKDIR_HOST) ? "intnet --> wire" : "intnet --> all");
+
+ /*
+ * There are two possible strategies to deal with incoming SGs:
+ * 1) make a copy of data and complete asynchronously;
+ * 2) complete synchronously using the original data buffers.
+ * Before we consider implementing (1) it is quite interesting to see
+ * how well (2) performs. So we block until our requests are complete.
+ * Actually there is third possibility -- to use SG retain/release
+ * callbacks, but those seem not be fully implemented yet.
+ * Note that ansynchronous completion will require different implementation
+ * of vboxNetLwfWinPause(), not relying on InTransmit mutex.
+ */
+#ifdef VBOXNETLWF_SYNC_SEND
+ PVOID aEvents[2]; /* To wire and to host */
+ ULONG nEvents = 0;
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = -(LONGLONG)10000000; /* 1 sec */
+#endif /* VBOXNETLWF_SYNC_SEND */
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ {
+ PNET_BUFFER_LIST pBufList = vboxNetLwfWinSGtoNB(pModule, pSG);
+ if (pBufList)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetFltPortOsXmit: sending down", pBufList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ aEvents[nEvents++] = &pModule->EventWire;
+#else /* !VBOXNETLWF_SYNC_SEND */
+ if (ASMAtomicIncS32(&pModule->cPendingBuffers) == 1)
+ NdisResetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ NdisFSendNetBufferLists(pModule->hFilter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 0); /** @todo sendFlags! */
+ }
+ }
+ if (fDst & INTNETTRUNKDIR_HOST)
+ {
+ PNET_BUFFER_LIST pBufList = vboxNetLwfWinSGtoNB(pModule, pSG);
+ if (pBufList)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetFltPortOsXmit: sending up", pBufList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ aEvents[nEvents++] = &pModule->EventHost;
+#else /* !VBOXNETLWF_SYNC_SEND */
+ if (ASMAtomicIncS32(&pModule->cPendingBuffers) == 1)
+ NdisResetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 1, 0);
+ }
+ }
+#ifdef VBOXNETLWF_SYNC_SEND
+ if (nEvents)
+ {
+ NTSTATUS Status = KeWaitForMultipleObjects(nEvents, aEvents, WaitAll, Executive, KernelMode, FALSE, &timeout, NULL);
+ if (Status != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetFltPortOsXmit: KeWaitForMultipleObjects() failed with 0x%x\n", Status));
+ if (Status == STATUS_TIMEOUT)
+ rc = VERR_TIMEOUT;
+ else
+ rc = RTErrConvertFromNtStatus(Status);
+ }
+ }
+#endif /* VBOXNETLWF_SYNC_SEND */
+ NDIS_RELEASE_MUTEX(&pModule->InTransmit);
+
+ LogFlow(("<==vboxNetFltPortOsXmit: return %d\n", rc));
+ return rc;
+}
+
+
+NDIS_IO_WORKITEM_FUNCTION vboxNetLwfWinToggleOffloading;
+
+VOID vboxNetLwfWinToggleOffloading(PVOID WorkItemContext, NDIS_HANDLE NdisIoWorkItemHandle)
+{
+ /* WARNING! Call this with IRQL=Passive! */
+ RT_NOREF1(NdisIoWorkItemHandle);
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)WorkItemContext;
+
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ {
+ /* Disable offloading temporarily by indicating offload config change. */
+ /** @todo Be sure to revise this when implementing offloading support! */
+ vboxNetLwfWinIndicateOffload(pModuleCtx, pModuleCtx->pDisabledOffloadConfig);
+ Log(("vboxNetLwfWinToggleOffloading: set offloading off\n"));
+ }
+ else
+ {
+ /* The filter is inactive -- restore offloading configuration. */
+ if (pModuleCtx->fOffloadConfigValid)
+ {
+ vboxNetLwfWinIndicateOffload(pModuleCtx, pModuleCtx->pSavedOffloadConfig);
+ Log(("vboxNetLwfWinToggleOffloading: restored offloading config\n"));
+ }
+ else
+ DbgPrint("VBoxNetLwf: no saved offload config to restore for %s\n", pModuleCtx->szMiniportName);
+ }
+}
+
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
+ LogFlow(("==>vboxNetFltPortOsSetActive: instance=%p module=%p fActive=%RTbool\n", pThis, pModuleCtx, fActive));
+ if (!pModuleCtx)
+ {
+ LogFlow(("<==vboxNetFltPortOsSetActive: pModuleCtx is null\n"));
+ return;
+ }
+
+ NDIS_STATUS Status = STATUS_SUCCESS;
+ bool fOldActive = ASMAtomicXchgBool(&pModuleCtx->fActive, fActive);
+ if (fOldActive != fActive)
+ {
+ NdisQueueIoWorkItem(pModuleCtx->hWorkItem, vboxNetLwfWinToggleOffloading, pModuleCtx);
+ Status = vboxNetLwfWinSetPacketFilter(pModuleCtx, fActive);
+ LogFlow(("<==vboxNetFltPortOsSetActive: vboxNetLwfWinSetPacketFilter() returned 0x%x\n", Status));
+ }
+ else
+ LogFlow(("<==vboxNetFltPortOsSetActive: no change, remain %sactive\n", fActive ? "":"in"));
+}
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ RT_NOREF1(pThis);
+ LogFlow(("==>vboxNetFltOsDisconnectIt: instance=%p\n", pThis));
+ LogFlow(("<==vboxNetFltOsDisconnectIt: return 0\n"));
+ return VINF_SUCCESS;
+}
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ RT_NOREF1(pThis);
+ LogFlow(("==>vboxNetFltOsConnectIt: instance=%p\n", pThis));
+ LogFlow(("<==vboxNetFltOsConnectIt: return 0\n"));
+ return VINF_SUCCESS;
+}
+
+/*
+ * Uncommenting the following line produces debug log messages on IP address changes,
+ * including wired interfaces. No actual calls to a switch port are made. This is for
+ * debug purposes only!
+ * #define VBOXNETLWFWIN_DEBUGIPADDRNOTIF 1
+ */
+static void __stdcall vboxNetLwfWinIpAddrChangeCallback(IN PVOID pvCtx,
+ IN PMIB_UNICASTIPADDRESS_ROW pRow,
+ IN MIB_NOTIFICATION_TYPE enmNotifType)
+{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvCtx;
+
+ /* We are only interested in add or remove notifications. */
+ bool fAdded;
+ if (enmNotifType == MibAddInstance)
+ fAdded = true;
+ else if (enmNotifType == MibDeleteInstance)
+ fAdded = false;
+ else
+ return;
+
+ if ( pRow
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ && pThis->pSwitchPort->pfnNotifyHostAddress
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ )
+ {
+ switch (pRow->Address.si_family)
+ {
+ case AF_INET:
+ if ( IN4_IS_ADDR_LINKLOCAL(&pRow->Address.Ipv4.sin_addr)
+ || pRow->Address.Ipv4.sin_addr.s_addr == IN4ADDR_LOOPBACK)
+ {
+ Log(("vboxNetLwfWinIpAddrChangeCallback: ignoring %s address (%RTnaipv4)\n",
+ pRow->Address.Ipv4.sin_addr.s_addr == IN4ADDR_LOOPBACK ? "loopback" : "link-local",
+ pRow->Address.Ipv4.sin_addr));
+ break;
+ }
+ Log(("vboxNetLwfWinIpAddrChangeCallback: %s IPv4 addr=%RTnaipv4 on luid=(%u,%u)\n",
+ fAdded ? "add" : "remove", pRow->Address.Ipv4.sin_addr,
+ pRow->InterfaceLuid.Info.IfType, pRow->InterfaceLuid.Info.NetLuidIndex));
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, fAdded, kIntNetAddrType_IPv4,
+ &pRow->Address.Ipv4.sin_addr);
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ break;
+ case AF_INET6:
+ if (Ipv6AddressScope(pRow->Address.Ipv6.sin6_addr.u.Byte) <= ScopeLevelLink)
+ {
+ Log(("vboxNetLwfWinIpAddrChangeCallback: ignoring link-local address (%RTnaipv6)\n",
+ &pRow->Address.Ipv6.sin6_addr));
+ break;
+ }
+ Log(("vboxNetLwfWinIpAddrChangeCallback: %s IPv6 addr=%RTnaipv6 scope=%d luid=(%u,%u)\n",
+ fAdded ? "add" : "remove", &pRow->Address.Ipv6.sin6_addr,
+ Ipv6AddressScope(pRow->Address.Ipv6.sin6_addr.u.Byte),
+ pRow->InterfaceLuid.Info.IfType, pRow->InterfaceLuid.Info.NetLuidIndex));
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, fAdded, kIntNetAddrType_IPv6,
+ &pRow->Address.Ipv6.sin6_addr);
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ break;
+ }
+ }
+ else
+ Log(("vboxNetLwfWinIpAddrChangeCallback: pRow=%p pfnNotifyHostAddress=%p\n",
+ pRow, pThis->pSwitchPort->pfnNotifyHostAddress));
+}
+
+void vboxNetLwfWinRegisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetLwfWinRegisterIpAddrNotifier: instance=%p\n", pThis));
+ if ( pThis->pSwitchPort
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ && pThis->pSwitchPort->pfnNotifyHostAddress
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ )
+ {
+ NETIO_STATUS Status;
+ /* First we need to go over all host IP addresses and add them via pfnNotifyHostAddress. */
+ PMIB_UNICASTIPADDRESS_TABLE HostIpAddresses = NULL;
+ Status = GetUnicastIpAddressTable(AF_UNSPEC, &HostIpAddresses);
+ if (NETIO_SUCCESS(Status))
+ {
+ for (unsigned i = 0; i < HostIpAddresses->NumEntries; i++)
+ vboxNetLwfWinIpAddrChangeCallback(pThis, &HostIpAddresses->Table[i], MibAddInstance);
+ }
+ else
+ LogError(("vboxNetLwfWinRegisterIpAddrNotifier: GetUnicastIpAddressTable failed with %x\n", Status));
+ /* Now we can register a callback function to keep track of address changes. */
+ Status = NotifyUnicastIpAddressChange(AF_UNSPEC, vboxNetLwfWinIpAddrChangeCallback,
+ pThis, false, &pThis->u.s.WinIf.hNotifier);
+ if (NETIO_SUCCESS(Status))
+ Log(("vboxNetLwfWinRegisterIpAddrNotifier: notifier=%p\n", pThis->u.s.WinIf.hNotifier));
+ else
+ LogError(("vboxNetLwfWinRegisterIpAddrNotifier: NotifyUnicastIpAddressChange failed with %x\n", Status));
+ }
+ else
+ pThis->u.s.WinIf.hNotifier = NULL;
+ LogFlow(("<==vboxNetLwfWinRegisterIpAddrNotifier\n"));
+}
+
+void vboxNetLwfWinUnregisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ Log(("vboxNetLwfWinUnregisterIpAddrNotifier: notifier=%p\n", pThis->u.s.WinIf.hNotifier));
+ if (pThis->u.s.WinIf.hNotifier)
+ CancelMibChangeNotify2(pThis->u.s.WinIf.hNotifier);
+}
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
+ LogFlow(("==>vboxNetFltOsDeleteInstance: instance=%p module=%p\n", pThis, pModuleCtx));
+ /* Cancel IP address change notifications */
+ vboxNetLwfWinUnregisterIpAddrNotifier(pThis);
+ /* Technically it is possible that the module has already been gone by now. */
+ if (pModuleCtx)
+ {
+ Assert(!pModuleCtx->fActive); /* Deactivation ensures bypass mode */
+ pModuleCtx->pNetFlt = NULL;
+ pThis->u.s.WinIf.hModuleCtx = NULL;
+ }
+ LogFlow(("<==vboxNetFltOsDeleteInstance\n"));
+}
+
+static void vboxNetLwfWinReportCapabilities(PVBOXNETFLTINS pThis, PVBOXNETLWF_MODULE pModuleCtx)
+{
+ if (pThis->pSwitchPort
+ && vboxNetFltTryRetainBusyNotDisconnected(pThis))
+ {
+ pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pModuleCtx->MacAddr);
+ pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort,
+ vboxNetLwfWinIsPromiscuous(pModuleCtx));
+ pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
+ INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
+ pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
+ vboxNetFltRelease(pThis, true /*fBusy*/);
+ }
+}
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
+{
+ RT_NOREF1(pvContext);
+ LogFlow(("==>vboxNetFltOsInitInstance: instance=%p context=%p\n", pThis, pvContext));
+ AssertReturn(pThis, VERR_INVALID_PARAMETER);
+ Log(("vboxNetFltOsInitInstance: trunk name=%s\n", pThis->szName));
+ NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ PVBOXNETLWF_MODULE pModuleCtx;
+ RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
+ {
+ DbgPrint("vboxNetFltOsInitInstance: evaluating module, name=%s\n", pModuleCtx->szMiniportName);
+ if (!RTStrICmp(pThis->szName, pModuleCtx->szMiniportName))
+ {
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ Log(("vboxNetFltOsInitInstance: found matching module, name=%s\n", pThis->szName));
+ pThis->u.s.WinIf.hModuleCtx = pModuleCtx;
+ pModuleCtx->pNetFlt = pThis;
+ vboxNetLwfWinReportCapabilities(pThis, pModuleCtx);
+ vboxNetLwfWinRegisterIpAddrNotifier(pThis);
+ LogFlow(("<==vboxNetFltOsInitInstance: return 0\n"));
+ return VINF_SUCCESS;
+ }
+ }
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ // Internal network code will try to reconnect periodically, we should not spam in event log
+ //vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 6);
+ LogFlow(("<==vboxNetFltOsInitInstance: return VERR_INTNET_FLT_IF_NOT_FOUND\n"));
+ return VERR_INTNET_FLT_IF_NOT_FOUND;
+}
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltOsPreInitInstance: instance=%p\n", pThis));
+ pThis->u.s.WinIf.hModuleCtx = 0;
+ pThis->u.s.WinIf.hNotifier = NULL;
+ LogFlow(("<==vboxNetFltOsPreInitInstance: return 0\n"));
+ return VINF_SUCCESS;
+}
+
+void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
+{
+ RT_NOREF3(pThis, pvIfData, pMac);
+ LogFlow(("==>vboxNetFltPortOsNotifyMacAddress: instance=%p data=%p mac=%RTmac\n", pThis, pvIfData, pMac));
+ LogFlow(("<==vboxNetFltPortOsNotifyMacAddress\n"));
+}
+
+int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
+{
+ RT_NOREF3(pThis, pvIf, ppvIfData);
+ LogFlow(("==>vboxNetFltPortOsConnectInterface: instance=%p if=%p data=%p\n", pThis, pvIf, ppvIfData));
+ LogFlow(("<==vboxNetFltPortOsConnectInterface: return 0\n"));
+ /* Nothing to do */
+ return VINF_SUCCESS;
+}
+
+int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
+{
+ RT_NOREF2(pThis, pvIfData);
+ LogFlow(("==>vboxNetFltPortOsDisconnectInterface: instance=%p data=%p\n", pThis, pvIfData));
+ LogFlow(("<==vboxNetFltPortOsDisconnectInterface: return 0\n"));
+ /* Nothing to do */
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h
new file mode 100644
index 00000000..1a0a9e7e
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h
@@ -0,0 +1,55 @@
+/* $Id: VBoxNetLwf-win.h $ */
+/** @file
+ * VBoxNetLwf-win.h - Bridged Networking Driver, Windows-specific code.
+ */
+/*
+ * Copyright (C) 2014-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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetLwf_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetLwf_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define VBOXNETLWF_VERSION_NDIS_MAJOR 6
+#define VBOXNETLWF_VERSION_NDIS_MINOR 0
+
+#define VBOXNETLWF_NAME_FRIENDLY L"VirtualBox NDIS Light-Weight Filter"
+#define VBOXNETLWF_NAME_UNIQUE L"{7af6b074-048d-4444-bfce-1ecc8bc5cb76}"
+#define VBOXNETLWF_NAME_SERVICE L"VBoxNetLwf"
+
+#define VBOXNETLWF_NAME_LINK L"\\DosDevices\\Global\\VBoxNetLwf"
+#define VBOXNETLWF_NAME_DEVICE L"\\Device\\VBoxNetLwf"
+
+#define VBOXNETLWF_MEM_TAG 'FLBV'
+#define VBOXNETLWF_REQ_ID 'fLBV'
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetLwf_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf
new file mode 100644
index 00000000..f5d9cdca
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf
@@ -0,0 +1,120 @@
+; $Id: VBoxNetLwf.inf $
+; @file
+; VBoxNetLwf.inf - VirtualBox Bridged Networking Driver inf file
+;
+
+;
+; Copyright (C) 2014-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
+;
+
+[Version]
+Signature = "$Windows NT$"
+;cat CatalogFile = VBoxNetLwf.cat
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+Provider = %ORACLE%
+;edit-DriverVer=10/23/2014,1.0.1.0
+
+
+[Manufacturer]
+%ORACLE% = VBoxNetLwf@COMMA-NT-ARCH@
+
+[ControlFlags]
+
+[VBoxNetLwf@DOT-NT-ARCH@]
+%VBoxNetLwf_Desc% = VBoxNetLwf.ndi, oracle_VBoxNetLwf
+
+[VBoxNetLwf.ndi]
+AddReg = VBoxNetLwf.ndi.AddReg, VBoxNetLwf.AddReg
+Characteristics = 0x40000 ; NCF_LW_FILTER
+CopyFiles = VBoxNetLwf.Files.Sys
+NetCfgInstanceId = "{7af6b074-048d-4444-bfce-1ecc8bc5cb76}"
+
+[VBoxNetLwf.ndi.Remove.Services]
+DelService = VBoxNetLwf,0x200 ; Stop the service before uninstalling
+
+[VBoxNetLwf.ndi.Services]
+AddService = VBoxNetLwf,, VBoxNetLwf.AddService, VBoxNetLwf.AddEventLog
+
+[VBoxNetLwf.AddService]
+DisplayName = %VBoxNetLwfService_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 1 ;SERVICE_SYSTEM_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetLwf.sys
+LoadOrderGroup = NDIS
+AddReg = VBoxNetLwf.AddService.AddReg
+
+[VBoxNetLwf.AddService.AddReg]
+
+[VBoxNetLwf.AddEventLog]
+AddReg = VBoxNetLwf.AddEventLog.AddReg
+
+[VBoxNetLwf.AddEventLog.AddReg]
+HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll"
+HKR,,TypesSupported,0x00010001,7
+
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetLwf.sys=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetLwf.Files.Sys = 12 ; %windir%\System32\drivers
+
+[VBoxNetLwf.Files.Sys]
+VBoxNetLwf.sys,,,2
+
+
+[VBoxNetLwf.ndi.AddReg]
+HKR, Ndi, HelpText, , %VBoxNetLwf_HELP%
+;HKR, Ndi, ClsID, 0, {f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}
+;HKR, Ndi, ComponentDll, , VBoxNetLwfNobj.dll
+HKR, Ndi, FilterClass, , compression
+HKR, Ndi, FilterType, 0x10001, 0x2
+HKR, Ndi, FilterRunType,0x10001, 2 ; OPTIONAL, to prevent unbinding of protocol drivers
+HKR, Ndi, Service, , VBoxNetLwf
+HKR, Ndi, CoServices, 0x10000, VBoxNetLwf
+HKR, Ndi\Interfaces, UpperRange, , noupper
+HKR, Ndi\Interfaces, LowerRange, , nolower
+HKR, Ndi\Interfaces, FilterMediaTypes, , ethernet
+
+[VBoxNetLwf.AddReg]
+;HKR, Parameters, Param1, 0, 4
+
+[Strings]
+ORACLE = "Oracle Corporation"
+DiskDescription = "VirtualBox NDIS6 Bridged Networking Driver"
+VBoxNetLwf_Desc = "VirtualBox NDIS6 Bridged Networking Driver"
+VBoxNetLwf_HELP = "VirtualBox NDIS6 Bridged Networking Driver"
+VBoxNetLwfService_Desc = "VirtualBox NDIS6 Bridged Networking Service"
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
new file mode 100644
index 00000000..a5cf004c
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.cpp
@@ -0,0 +1,747 @@
+/* $Id: VBoxNetFltNobj.cpp $ */
+/** @file
+ * VBoxNetFltNobj.cpp - Notify Object for Bridged Networking Driver.
+ *
+ * Used to filter Bridged Networking Driver bindings
+ */
+
+/*
+ * 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 "VBoxNetFltNobj.h"
+#include <iprt/win/ntddndis.h>
+#include <iprt/win/windows.h>
+#include <winreg.h>
+#include <Olectl.h>
+
+#include <VBoxNetFltNobjT_i.c>
+
+#include <iprt/assert.h>
+#include <iprt/utf16.h>
+#include <iprt/string.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+//# define VBOXNETFLTNOTIFY_DEBUG_BIND
+
+#ifdef DEBUG
+# define NonStandardAssert(a) Assert(a)
+# define NonStandardAssertBreakpoint() AssertFailed()
+#else
+# define NonStandardAssert(a) do{}while (0)
+# define NonStandardAssertBreakpoint() do{}while (0)
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static HMODULE g_hModSelf = (HMODULE)~(uintptr_t)0;
+
+
+VBoxNetFltNobj::VBoxNetFltNobj()
+ : mpNetCfg(NULL)
+ , mpNetCfgComponent(NULL)
+ , mbInstalling(FALSE)
+{
+}
+
+VBoxNetFltNobj::~VBoxNetFltNobj()
+{
+ cleanup();
+}
+
+void VBoxNetFltNobj::cleanup()
+{
+ if (mpNetCfg)
+ {
+ mpNetCfg->Release();
+ mpNetCfg = NULL;
+ }
+
+ if (mpNetCfgComponent)
+ {
+ mpNetCfgComponent->Release();
+ mpNetCfgComponent = NULL;
+ }
+}
+
+void VBoxNetFltNobj::init(IN INetCfgComponent *pNetCfgComponent, IN INetCfg *pNetCfg, IN BOOL bInstalling)
+{
+ cleanup();
+
+ NonStandardAssert(pNetCfg);
+ NonStandardAssert(pNetCfgComponent);
+ if (pNetCfg)
+ {
+ pNetCfg->AddRef();
+ mpNetCfg = pNetCfg;
+ }
+
+ if (pNetCfgComponent)
+ {
+ pNetCfgComponent->AddRef();
+ mpNetCfgComponent = pNetCfgComponent;
+ }
+
+ mbInstalling = bInstalling;
+}
+
+/* INetCfgComponentControl methods */
+STDMETHODIMP VBoxNetFltNobj::Initialize(IN INetCfgComponent *pNetCfgComponent, IN INetCfg *pNetCfg, IN BOOL bInstalling)
+{
+ init(pNetCfgComponent, pNetCfg, bInstalling);
+ return S_OK;
+}
+
+STDMETHODIMP VBoxNetFltNobj::ApplyRegistryChanges()
+{
+ return S_OK;
+}
+
+STDMETHODIMP VBoxNetFltNobj::ApplyPnpChanges(IN INetCfgPnpReconfigCallback *pCallback)
+{
+ RT_NOREF1(pCallback);
+ return S_OK;
+}
+
+STDMETHODIMP VBoxNetFltNobj::CancelChanges()
+{
+ return S_OK;
+}
+
+static HRESULT vboxNetFltWinQueryInstanceKey(IN INetCfgComponent *pComponent, OUT PHKEY phKey)
+{
+ LPWSTR pwszPnpId;
+ HRESULT hrc = pComponent->GetPnpDevNodeId(&pwszPnpId);
+ if (hrc == S_OK)
+ {
+ WCHAR wszKeyName[MAX_PATH];
+ RTUtf16Copy(wszKeyName, MAX_PATH, L"SYSTEM\\CurrentControlSet\\Enum\\");
+ int rc = RTUtf16Cat(wszKeyName, MAX_PATH, pwszPnpId);
+ if (RT_SUCCESS(rc))
+ {
+ LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszKeyName, 0 /*ulOptions*/, KEY_READ, phKey);
+ if (lrc != ERROR_SUCCESS)
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+ }
+ else
+ AssertRCStmt(rc, hrc = ERROR_BUFFER_OVERFLOW);
+
+ CoTaskMemFree(pwszPnpId);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinQueryDriverKey(IN HKEY InstanceKey, OUT PHKEY phKey)
+{
+ HRESULT hrc = S_OK;
+
+ WCHAR wszValue[MAX_PATH];
+ DWORD cbValue = sizeof(wszValue) - sizeof(WCHAR);
+ DWORD dwType = REG_SZ;
+ LSTATUS lrc = RegQueryValueExW(InstanceKey, L"Driver", NULL /*lpReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
+ if (lrc == ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ wszValue[RT_ELEMENTS(wszValue) - 1] = '\0'; /* registry strings does not need to be zero terminated. */
+
+ WCHAR wszKeyName[MAX_PATH];
+ RTUtf16Copy(wszKeyName, MAX_PATH, L"SYSTEM\\CurrentControlSet\\Control\\Class\\");
+ int rc = RTUtf16Cat(wszKeyName, MAX_PATH, wszValue);
+ if (RT_SUCCESS(rc))
+ {
+ lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszKeyName, 0 /*ulOptions*/, KEY_READ, phKey);
+ if (lrc != ERROR_SUCCESS)
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+ }
+ else
+ AssertRCStmt(rc, hrc = ERROR_BUFFER_OVERFLOW);
+ }
+ else
+ {
+ hrc = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+ NonStandardAssertBreakpoint();
+ }
+ }
+ else
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinQueryDriverKey(IN INetCfgComponent *pComponent, OUT PHKEY phKey)
+{
+ HKEY hKeyInstance = NULL;
+ HRESULT hrc = vboxNetFltWinQueryInstanceKey(pComponent, &hKeyInstance);
+ if (hrc == S_OK)
+ {
+ hrc = vboxNetFltWinQueryDriverKey(hKeyInstance, phKey);
+ if (hrc != S_OK)
+ NonStandardAssertBreakpoint();
+ RegCloseKey(hKeyInstance);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckNetAdp(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ LPWSTR pwszDevId = NULL;
+ HRESULT hrc = pComponent->GetId(&pwszDevId);
+ if (hrc == S_OK)
+ {
+ /** @todo r=bird: This was _wcsnicmp(pwszDevId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2))
+ * which includes the terminator, so it translates to a full compare. Goes way back. */
+ if (RTUtf16ICmpAscii(pwszDevId, "sun_VBoxNetAdp") == 0)
+ *pfShouldBind = false;
+ else
+ hrc = S_FALSE;
+ CoTaskMemFree(pwszDevId);
+ }
+ else
+ NonStandardAssertBreakpoint();
+
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckMsLoop(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ LPWSTR pwszDevId = NULL;
+ HRESULT hrc = pComponent->GetId(&pwszDevId);
+ if (hrc == S_OK)
+ {
+ /** @todo r=bird: This was _wcsnicmp(pwszDevId, L"*msloop", sizeof(L"*msloop")/2)
+ * which includes the terminator, making it a full compare. Goes way back. */
+ if (RTUtf16ICmpAscii(pwszDevId, "*msloop") == 0)
+ {
+ /* we need to detect the medium the adapter is presenting
+ * to do that we could examine in the registry the *msloop params */
+ HKEY hKeyDriver;
+ hrc = vboxNetFltWinQueryDriverKey(pComponent, &hKeyDriver);
+ if (hrc == S_OK)
+ {
+ WCHAR wszValue[64]; /* 2 should be enough actually, paranoid check for extra spaces */
+ DWORD cbValue = sizeof(wszValue) - sizeof(WCHAR);
+ DWORD dwType = REG_SZ;
+ LSTATUS lrc = RegQueryValueExW(hKeyDriver, L"Medium", NULL /*lpReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
+ if (lrc == ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ wszValue[RT_ELEMENTS(wszValue) - 1] = '\0';
+
+ char szUtf8[256];
+ char *pszUtf8 = szUtf8;
+ RTUtf16ToUtf8Ex(wszValue, RTSTR_MAX, &pszUtf8, sizeof(szUtf8), NULL);
+ pszUtf8 = RTStrStrip(pszUtf8);
+
+ uint64_t uValue = 0;
+ int rc = RTStrToUInt64Ex(pszUtf8, NULL, 0, &uValue);
+ if (RT_SUCCESS(rc))
+ {
+ if (uValue == 0) /* 0 is Ethernet */
+ *pfShouldBind = true;
+ else
+ *pfShouldBind = false;
+ }
+ else
+ {
+ NonStandardAssertBreakpoint();
+ *pfShouldBind = true;
+ }
+ }
+ else
+ NonStandardAssertBreakpoint();
+ }
+ else
+ {
+ /** @todo we should check the default medium in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\<driver_id>\Ndi\Params\Medium, REG_SZ "Default" value */
+ NonStandardAssertBreakpoint();
+ *pfShouldBind = true;
+ }
+
+ RegCloseKey(hKeyDriver);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ }
+ else
+ hrc = S_FALSE;
+ CoTaskMemFree(pwszDevId);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckLowerRange(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ HKEY hKeyDriver = NULL;
+ HRESULT hrc = vboxNetFltWinQueryDriverKey(pComponent, &hKeyDriver);
+ if (hrc == S_OK)
+ {
+ HKEY hKeyInterfaces = NULL;
+ LSTATUS lrc = RegOpenKeyExW(hKeyDriver, L"Ndi\\Interfaces", 0 /*ulOptions*/, KEY_READ, &hKeyInterfaces);
+ if (lrc == ERROR_SUCCESS)
+ {
+ WCHAR wszValue[MAX_PATH];
+ DWORD cbValue = sizeof(wszValue) - sizeof(WCHAR);
+ DWORD dwType = REG_SZ;
+ lrc = RegQueryValueExW(hKeyInterfaces, L"LowerRange", NULL /*lpReserved*/, &dwType, (LPBYTE)wszValue, &cbValue);
+ if (lrc == ERROR_SUCCESS)
+ {
+ if (dwType == REG_SZ)
+ {
+ if (RTUtf16FindAscii(wszValue, "ethernet") >= 0 || RTUtf16FindAscii(wszValue, "wan") >= 0)
+ *pfShouldBind = true;
+ else
+ *pfShouldBind = false;
+ }
+ }
+ else
+ {
+ /* do not set err status to it */
+ *pfShouldBind = false;
+ NonStandardAssertBreakpoint();
+ }
+
+ RegCloseKey(hKeyInterfaces);
+ }
+ else
+ {
+ hrc = HRESULT_FROM_WIN32(lrc);
+ NonStandardAssertBreakpoint();
+ }
+
+ RegCloseKey(hKeyDriver);
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgComponent *pComponent, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ /* filter out only physical adapters */
+ DWORD fCharacteristics = 0;
+ HRESULT hrc = pComponent->GetCharacteristics(&fCharacteristics);
+ if (hrc != S_OK)
+ {
+ NonStandardAssertBreakpoint();
+ return hrc;
+ }
+
+ /* we are not binding to hidden adapters */
+ if (fCharacteristics & NCF_HIDDEN)
+ return S_OK;
+
+ hrc = vboxNetFltWinNotifyCheckMsLoop(pComponent, pfShouldBind);
+ if ( hrc == S_OK /* this is a loopback adapter, the pfShouldBind already contains the result */
+ || hrc != S_FALSE /* error occurred */)
+ return hrc;
+
+ hrc = vboxNetFltWinNotifyCheckNetAdp(pComponent, pfShouldBind);
+ if ( hrc == S_OK /* this is a VBoxNetAdp adapter, the pfShouldBind already contains the result */
+ || hrc != S_FALSE /* error occurred */)
+ return hrc;
+
+ //if (!(fCharacteristics & NCF_PHYSICAL))
+ //{
+ // *pfShouldBind = false; /* we are binding to physical adapters only */
+ // return S_OK;
+ //}
+
+ return vboxNetFltWinNotifyCheckLowerRange(pComponent, pfShouldBind);
+}
+
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgBindingInterface *pIf, OUT bool *pfShouldBind)
+{
+ INetCfgComponent *pAdapterComponent = NULL;
+ HRESULT hrc = pIf->GetLowerComponent(&pAdapterComponent);
+ if (hrc == S_OK)
+ {
+ hrc = vboxNetFltWinNotifyShouldBind(pAdapterComponent, pfShouldBind);
+
+ pAdapterComponent->Release();
+ }
+ else
+ {
+ NonStandardAssertBreakpoint();
+ *pfShouldBind = false;
+ }
+ return hrc;
+}
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgBindingPath *pPath, OUT bool *pfShouldBind)
+{
+ *pfShouldBind = false;
+
+ IEnumNetCfgBindingInterface *pIEnumBinding = NULL;
+ HRESULT hrc = pPath->EnumBindingInterfaces(&pIEnumBinding);
+ if (hrc == S_OK)
+ {
+ hrc = pIEnumBinding->Reset();
+ if (hrc == S_OK)
+ {
+ for (;;)
+ {
+ ULONG uCount = 0;
+ INetCfgBindingInterface *pIBinding = NULL;
+ hrc = pIEnumBinding->Next(1, &pIBinding, &uCount);
+ if (hrc == S_OK)
+ {
+ hrc = vboxNetFltWinNotifyShouldBind(pIBinding, pfShouldBind);
+ pIBinding->Release();
+
+ if (hrc != S_OK)
+ break; /* break on failure. */
+ if (!*pfShouldBind)
+ break;
+ }
+ else if (hrc == S_FALSE)
+ {
+ /* no more elements */
+ hrc = S_OK;
+ break;
+ }
+ else
+ {
+ NonStandardAssertBreakpoint();
+ /* break on falure */
+ break;
+ }
+ }
+ }
+ else
+ NonStandardAssertBreakpoint();
+
+ pIEnumBinding->Release();
+ }
+ else
+ NonStandardAssertBreakpoint();
+ return hrc;
+}
+
+static bool vboxNetFltWinNotifyShouldBind(IN INetCfgBindingPath *pPath)
+{
+#ifdef VBOXNETFLTNOTIFY_DEBUG_BIND
+ return VBOXNETFLTNOTIFY_DEBUG_BIND;
+#else
+ bool fShouldBind;
+ HRESULT hrc = vboxNetFltWinNotifyShouldBind(pPath, &fShouldBind);
+ if (hrc != S_OK)
+ fShouldBind = VBOXNETFLTNOTIFY_ONFAIL_BINDDEFAULT;
+
+ return fShouldBind;
+#endif
+}
+
+
+/* INetCfgComponentNotifyBinding methods */
+STDMETHODIMP VBoxNetFltNobj::NotifyBindingPath(IN DWORD dwChangeFlag, IN INetCfgBindingPath *pNetCfgBP)
+{
+ if (!(dwChangeFlag & NCN_ENABLE) || (dwChangeFlag & NCN_REMOVE) || vboxNetFltWinNotifyShouldBind(pNetCfgBP))
+ return S_OK;
+ return NETCFG_S_DISABLE_QUERY;
+}
+
+STDMETHODIMP VBoxNetFltNobj::QueryBindingPath(IN DWORD dwChangeFlag, IN INetCfgBindingPath *pNetCfgBP)
+{
+ RT_NOREF1(dwChangeFlag);
+ if (vboxNetFltWinNotifyShouldBind(pNetCfgBP))
+ return S_OK;
+ return NETCFG_S_DISABLE_QUERY;
+}
+
+
+static ATL::CComModule _Module;
+
+BEGIN_OBJECT_MAP(ObjectMap)
+ OBJECT_ENTRY(CLSID_VBoxNetFltNobj, VBoxNetFltNobj)
+END_OBJECT_MAP()
+
+
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hModSelf = (HMODULE)hInstance;
+
+ _Module.Init(ObjectMap, hInstance);
+ DisableThreadLibraryCalls(hInstance);
+ }
+ else if (dwReason == DLL_PROCESS_DETACH)
+ {
+ _Module.Term();
+ }
+ return TRUE;
+}
+
+STDAPI DllCanUnloadNow(void)
+{
+ return _Module.GetLockCount() == 0 ? S_OK : S_FALSE;
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ return _Module.GetClassObject(rclsid, riid, ppv);
+}
+
+
+/*
+ * ATL::CComModule does not suport server registration/unregistration methods,
+ * so we need to do it manually. Since this is the only place we do registraton
+ * manually, we do it the quick-and-dirty way.
+ */
+
+#ifdef RT_EXCEPTIONS_ENABLED
+/* Someday we may want to log errors. */
+class AdHocRegError
+{
+public:
+ AdHocRegError(LSTATUS rc) { RT_NOREF1(rc); };
+};
+#endif
+
+/**
+ * A simple wrapper on Windows registry functions.
+ */
+class AdHocRegKey
+{
+public:
+ AdHocRegKey(HKEY hKey) : m_hKey(hKey) {};
+ AdHocRegKey(LPCWSTR pcwszName, HKEY hParent = HKEY_CLASSES_ROOT);
+ ~AdHocRegKey() { RegCloseKey(m_hKey); };
+
+ AdHocRegKey *create(LPCWSTR pcwszSubkey);
+ LSTATUS setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue);
+ HKEY getKey(void) { return m_hKey; };
+private:
+ HKEY m_hKey;
+};
+
+AdHocRegKey::AdHocRegKey(LPCWSTR pcwszName, HKEY hParent) : m_hKey(NULL)
+{
+ LSTATUS rc = RegOpenKeyExW(hParent, pcwszName, 0, KEY_ALL_ACCESS, &m_hKey);
+ if (rc != ERROR_SUCCESS)
+#ifdef RT_EXCEPTIONS_ENABLED
+ throw AdHocRegError(rc);
+#else
+ m_hKey = NULL;
+#endif
+}
+
+AdHocRegKey *AdHocRegKey::create(LPCWSTR pcwszSubkey)
+{
+ HKEY hSubkey;
+ LSTATUS rc = RegCreateKeyExW(m_hKey, pcwszSubkey,
+ 0 /*Reserved*/, NULL /*pszClass*/, 0 /*fOptions*/,
+ KEY_ALL_ACCESS, NULL /*pSecAttr*/, &hSubkey, NULL /*pdwDisposition*/);
+ if (rc != ERROR_SUCCESS)
+#ifdef RT_EXCEPTIONS_ENABLED
+ throw AdHocRegError(rc);
+#else
+ return NULL;
+#endif
+ AdHocRegKey *pSubkey = new AdHocRegKey(hSubkey);
+ if (!pSubkey)
+ RegCloseKey(hSubkey);
+ return pSubkey;
+}
+
+LSTATUS AdHocRegKey::setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue)
+{
+ LSTATUS rc = RegSetValueExW(m_hKey, pcwszName, 0, REG_SZ, (const BYTE *)pcwszValue,
+ (DWORD)((RTUtf16Len(pcwszValue) + 1) * sizeof(WCHAR)));
+#ifdef RT_EXCEPTIONS_ENABLED
+ if (rc != ERROR_SUCCESS)
+ throw AdHocRegError(rc);
+#endif
+ return rc;
+}
+
+/**
+ * Auxiliary class that facilitates automatic destruction of AdHocRegKey objects
+ * allocated in heap. No reference counting here!
+ */
+class AdHocRegKeyPtr
+{
+public:
+ AdHocRegKeyPtr(AdHocRegKey *pKey) : m_pKey(pKey) {};
+ ~AdHocRegKeyPtr()
+ {
+ if (m_pKey)
+ {
+ delete m_pKey;
+ m_pKey = NULL;
+ }
+ }
+
+ AdHocRegKey *create(LPCWSTR pcwszSubkey)
+ { return m_pKey ? m_pKey->create(pcwszSubkey) : NULL; };
+
+ LSTATUS setValue(LPCWSTR pcwszName, LPCWSTR pcwszValue)
+ { return m_pKey ? m_pKey->setValue(pcwszName, pcwszValue) : ERROR_INVALID_STATE; };
+
+private:
+ AdHocRegKey *m_pKey;
+ /* Prevent copying, since we do not support reference counting */
+ AdHocRegKeyPtr(const AdHocRegKeyPtr&);
+ AdHocRegKeyPtr& operator=(const AdHocRegKeyPtr&);
+};
+
+
+STDAPI DllRegisterServer(void)
+{
+ /* Get the path to the DLL we're running inside. */
+ WCHAR wszModule[MAX_PATH + 1];
+ UINT cwcModule = GetModuleFileNameW(g_hModSelf, wszModule, MAX_PATH);
+ if (cwcModule == 0 || cwcModule > MAX_PATH)
+ return SELFREG_E_CLASS;
+ wszModule[MAX_PATH] = '\0';
+
+ /*
+ * Create registry keys and values. When exceptions are disabled, we depend
+ * on setValue() to propagate fail key creation failures.
+ */
+#ifdef RT_EXCEPTIONS_ENABLED
+ try
+#endif
+ {
+ AdHocRegKey keyCLSID(L"CLSID");
+ AdHocRegKeyPtr pkeyNobjClass(keyCLSID.create(L"{f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}"));
+ LSTATUS lrc = pkeyNobjClass.setValue(NULL, L"VirtualBox Bridged Networking Driver Notify Object v1.1");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_CLASS;
+
+ AdHocRegKeyPtr pkeyNobjSrv(pkeyNobjClass.create(L"InProcServer32"));
+ lrc = pkeyNobjSrv.setValue(NULL, wszModule);
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_CLASS;
+ lrc = pkeyNobjSrv.setValue(L"ThreadingModel", L"Both");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_CLASS;
+ }
+#ifdef RT_EXCEPTIONS_ENABLED
+ catch (AdHocRegError) { return SELFREG_E_CLASS; }
+#endif
+
+#ifdef RT_EXCEPTIONS_ENABLED
+ try
+#endif
+ {
+ AdHocRegKey keyTypeLib(L"TypeLib");
+ AdHocRegKeyPtr pkeyNobjLib(keyTypeLib.create(L"{2A0C94D1-40E1-439C-8FE8-24107CAB0840}\\1.1"));
+ LSTATUS lrc = pkeyNobjLib.setValue(NULL, L"VirtualBox Bridged Networking Driver Notify Object v1.1 Type Library");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+
+ AdHocRegKeyPtr pkeyNobjLib0(pkeyNobjLib.create(L"0\\win64"));
+ lrc = pkeyNobjLib0.setValue(NULL, wszModule);
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+ AdHocRegKeyPtr pkeyNobjLibFlags(pkeyNobjLib.create(L"FLAGS"));
+ lrc = pkeyNobjLibFlags.setValue(NULL, L"0");
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+
+ if (GetSystemDirectoryW(wszModule, MAX_PATH) == 0)
+ return SELFREG_E_TYPELIB;
+ AdHocRegKeyPtr pkeyNobjLibHelpDir(pkeyNobjLib.create(L"HELPDIR"));
+ lrc = pkeyNobjLibHelpDir.setValue(NULL, wszModule);
+ if (lrc != ERROR_SUCCESS)
+ return SELFREG_E_TYPELIB;
+ }
+#ifdef RT_EXCEPTIONS_ENABLED
+ catch (AdHocRegError) { return SELFREG_E_TYPELIB; }
+#endif
+
+ return S_OK;
+}
+
+
+STDAPI DllUnregisterServer(void)
+{
+ static struct { HKEY hKeyRoot; wchar_t const *pwszParentKey; wchar_t const *pwszKeyToDelete; HRESULT hrcFail; }
+ s_aKeys[] =
+ {
+ { HKEY_CLASSES_ROOT, L"TypeLib", L"{2A0C94D1-40E1-439C-8FE8-24107CAB0840}", SELFREG_E_TYPELIB },
+ { HKEY_CLASSES_ROOT, L"CLSID", L"{f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}", SELFREG_E_CLASS },
+ };
+
+ HRESULT hrc = S_OK;
+ for (size_t i = 0; i < RT_ELEMENTS(s_aKeys); i++)
+ {
+ HKEY hKey = NULL;
+ LSTATUS lrc = RegOpenKeyExW(s_aKeys[i].hKeyRoot, s_aKeys[i].pwszParentKey, 0, KEY_ALL_ACCESS, &hKey);
+ if (lrc == ERROR_SUCCESS)
+ {
+ lrc = RegDeleteTreeW(hKey, s_aKeys[i].pwszKeyToDelete); /* Vista and later */
+ RegCloseKey(hKey);
+ }
+
+ if (lrc != ERROR_SUCCESS && lrc != ERROR_FILE_NOT_FOUND && hrc == S_OK)
+ hrc = s_aKeys[i].hrcFail;
+ }
+
+ return S_OK;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.def b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.def
new file mode 100644
index 00000000..abfe3834
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.def
@@ -0,0 +1,42 @@
+; $Id: VBoxNetFltNobj.def $
+; @file
+; VBoxNetFltNobj.def - Notify Object for Bridged Networking Driver.
+; Library def file
+;
+
+;
+; 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
+;
+LIBRARY VBoxNetFltNobj
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.h b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.h
new file mode 100644
index 00000000..87eed992
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.h
@@ -0,0 +1,96 @@
+/* $Id: VBoxNetFltNobj.h $ */
+/** @file
+ * VBoxNetFltNobj.h - Notify Object for Bridged Networking Driver.
+ * Used to filter Bridged Networking Driver bindings
+ */
+/*
+ * 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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_nobj_VBoxNetFltNobj_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_nobj_VBoxNetFltNobj_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/win/windows.h>
+
+#include "VBox/com/defs.h"
+#include "VBoxNetFltNobjT.h"
+#include "VBoxNetFltNobjRc.h"
+
+#define VBOXNETFLTNOTIFY_ONFAIL_BINDDEFAULT false
+
+/*
+ * VirtualBox Bridging driver notify object.
+ * Needed to make our driver bind to "real" host adapters only
+ */
+class ATL_NO_VTABLE VBoxNetFltNobj
+ : public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>
+ , public ATL::CComCoClass<VBoxNetFltNobj, &CLSID_VBoxNetFltNobj>
+ , public INetCfgComponentControl
+ , public INetCfgComponentNotifyBinding
+{
+public:
+ VBoxNetFltNobj();
+ virtual ~VBoxNetFltNobj();
+
+ BEGIN_COM_MAP(VBoxNetFltNobj)
+ COM_INTERFACE_ENTRY(INetCfgComponentControl)
+ COM_INTERFACE_ENTRY(INetCfgComponentNotifyBinding)
+ END_COM_MAP()
+
+ // this is a "just in case" conditional, which is not defined
+#ifdef VBOX_FORCE_REGISTER_SERVER
+ DECLARE_REGISTRY_RESOURCEID(IDR_VBOXNETFLT_NOBJ)
+#endif
+
+ /* INetCfgComponentControl methods */
+ STDMETHOD(Initialize)(IN INetCfgComponent *pNetCfgComponent, IN INetCfg *pNetCfg, IN BOOL bInstalling);
+ STDMETHOD(ApplyRegistryChanges)();
+ STDMETHOD(ApplyPnpChanges)(IN INetCfgPnpReconfigCallback *pCallback);
+ STDMETHOD(CancelChanges)();
+
+ /* INetCfgComponentNotifyBinding methods */
+ STDMETHOD(NotifyBindingPath)(IN DWORD dwChangeFlag, IN INetCfgBindingPath *pNetCfgBP);
+ STDMETHOD(QueryBindingPath)(IN DWORD dwChangeFlag, IN INetCfgBindingPath *pNetCfgBP);
+private:
+
+ void init(IN INetCfgComponent *pNetCfgComponent, IN INetCfg *pNetCfg, IN BOOL bInstalling);
+ void cleanup();
+
+ /* these two used to maintain the component info passed to
+ * INetCfgComponentControl::Initialize */
+ INetCfg *mpNetCfg;
+ INetCfgComponent *mpNetCfgComponent;
+ BOOL mbInstalling;
+};
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_nobj_VBoxNetFltNobj_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rc b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rc
new file mode 100644
index 00000000..4a1398c6
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rc
@@ -0,0 +1,78 @@
+/* $Id: VBoxNetFltNobj.rc $ */
+/** @file
+ * VBoxNetFltNobj - Resource file containing version info and icon.
+ */
+/*
+ * 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 <windows.h>
+#include <VBox/version.h>
+
+#include "VBoxNetFltNobjRc.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
+ BEGIN
+ VALUE "FileDescription", "VirtualBox Bridged Networking Driver Notify Object v1.1\0"
+ VALUE "InternalName", "VBoxNetFltNobj\0"
+ VALUE "OriginalFilename", "VBoxNetFltNobj.dll\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// REGISTRY
+//
+
+IDR_VBOXNETFLT_NOBJ REGISTRY "VBoxNetFltNobj.rgs"
+
+1 TYPELIB "VBoxNetFltNobjT.tlb"
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rgs b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rgs
new file mode 100644
index 00000000..d6f9bae3
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobj.rgs
@@ -0,0 +1,13 @@
+HKCR
+{
+ NoRemove CLSID
+ {
+ ForceRemove {f374d1a0-bf08-4bdc-9cb2-c15ddaeef955} = s 'VirtualBox Bridged Networking Driver Notify Object v1.1'
+ {
+ InProcServer32 = s '%MODULE%'
+ {
+ val ThreadingModel = s 'Both'
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjRc.h b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjRc.h
new file mode 100644
index 00000000..187af500
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjRc.h
@@ -0,0 +1,46 @@
+/* $Id: VBoxNetFltNobjRc.h $ */
+/** @file
+ * VBoxNetFltNobjRc.h - Notify Object for Bridged Networking Driver.
+ * Resource definitions
+ */
+/*
+ * 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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_nobj_VBoxNetFltNobjRc_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_nobj_VBoxNetFltNobjRc_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+/* registry script rc ID */
+#define IDR_VBOXNETFLT_NOBJ 101
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_nobj_VBoxNetFltNobjRc_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjT.idl b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjT.idl
new file mode 100644
index 00000000..9bf8b6f9
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/nobj/VBoxNetFltNobjT.idl
@@ -0,0 +1,55 @@
+/* $Id: VBoxNetFltNobjT.idl $ */
+/** @file
+ * VBoxNetFltNobjT.idl - Notify Object for Bridged Networking Driver, typelib definition.
+ */
+
+/*
+ * 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 <netcfgn.idl>
+
+[
+ uuid(2a0c94d1-40e1-439c-8fe8-24107cab0840),
+ version(1.1),
+ helpstring("VirtualBox Bridged Networking Driver Notify Object v1.1 Type Library")
+]
+library VBoxNetFltNobjLib
+{
+ [
+ uuid(f374d1a0-bf08-4bdc-9cb2-c15ddaeef955),
+ helpstring("VirtualBox Bridged Networking Driver Notify Object Class")
+ ]
+ coclass VBoxNetFltNobj
+ {
+ [restricted] interface INetCfgComponentControl;
+ [restricted] interface INetCfgComponentNotifyBinding;
+ };
+};
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/tools/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpInstall.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpInstall.cpp
new file mode 100644
index 00000000..40a79b1a
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpInstall.cpp
@@ -0,0 +1,341 @@
+/* $Id: VBoxNetAdpInstall.cpp $ */
+/** @file
+ * NetAdpInstall - VBoxNetAdp installer command line tool.
+ */
+
+/*
+ * Copyright (C) 2009-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 <VBox/VBoxNetCfg-win.h>
+#include <VBox/VBoxDrvCfg-win.h>
+#include <devguid.h>
+
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/process.h>
+#include <iprt/stream.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define VBOX_NETADP_APP_NAME L"NetAdpInstall"
+
+#define VBOX_NETADP_HWID L"sun_VBoxNetAdp"
+#ifdef NDIS60
+# define VBOX_NETADP_INF L"VBoxNetAdp6.inf"
+#else
+# define VBOX_NETADP_INF L"VBoxNetAdp.inf"
+#endif
+
+
+static DECLCALLBACK(void) winNetCfgLogger(const char *pszString)
+{
+ RTMsgInfo("%s", pszString);
+}
+
+
+/** Wrapper around GetfullPathNameW that will try an alternative INF location.
+ *
+ * The default location is the current directory. If not found there, the
+ * alternative location is the executable directory. If not found there either,
+ * the first alternative is present to the caller.
+ */
+static DWORD MyGetfullPathNameW(LPCWSTR pwszName, size_t cchFull, LPWSTR pwszFull)
+{
+ LPWSTR pwszFilePart;
+ DWORD dwSize = GetFullPathNameW(pwszName, (DWORD)cchFull, pwszFull, &pwszFilePart);
+ if (dwSize <= 0)
+ return dwSize;
+
+ /* if it doesn't exist, see if the file exists in the same directory as the executable. */
+ if (GetFileAttributesW(pwszFull) == INVALID_FILE_ATTRIBUTES)
+ {
+ WCHAR wsz[512];
+ DWORD cch = GetModuleFileNameW(GetModuleHandle(NULL), &wsz[0], RT_ELEMENTS(wsz));
+ if (cch > 0)
+ {
+ while (cch > 0 && wsz[cch - 1] != '/' && wsz[cch - 1] != '\\' && wsz[cch - 1] != ':')
+ cch--;
+ unsigned i = 0;
+ while (cch < sizeof(wsz) / sizeof(wsz[0]))
+ {
+ wsz[cch] = pwszFilePart[i++];
+ if (!wsz[cch])
+ {
+ dwSize = GetFullPathNameW(wsz, (DWORD)cchFull, pwszFull, NULL);
+ if (dwSize > 0 && GetFileAttributesW(pwszFull) != INVALID_FILE_ATTRIBUTES)
+ return dwSize;
+ break;
+ }
+ cch++;
+ }
+ }
+ }
+
+ /* fallback */
+ return GetFullPathNameW(pwszName, (DWORD)cchFull, pwszFull, NULL);
+}
+
+
+static int VBoxNetAdpInstall(void)
+{
+ RTMsgInfo("Adding host-only interface...");
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (SUCCEEDED(hr))
+ {
+ WCHAR wszInfFile[MAX_PATH];
+ DWORD cwcInfFile = MyGetfullPathNameW(VBOX_NETADP_INF, RT_ELEMENTS(wszInfFile), wszInfFile);
+ if (cwcInfFile > 0)
+ {
+ INetCfg *pnc;
+ LPWSTR lpszLockedBy = NULL;
+ hr = VBoxNetCfgWinQueryINetCfg(&pnc, TRUE, VBOX_NETADP_APP_NAME, 10000, &lpszLockedBy);
+ if (hr == S_OK)
+ {
+
+ hr = VBoxNetCfgWinNetAdpInstall(pnc, wszInfFile);
+
+ if (hr == S_OK)
+ RTMsgInfo("Installed successfully!");
+ else
+ RTMsgError("failed to install VBoxNetAdp: %Rhrc", hr);
+
+ VBoxNetCfgWinReleaseINetCfg(pnc, TRUE);
+ }
+ else
+ RTMsgError("VBoxNetCfgWinQueryINetCfg failed: %Rhrc", hr);
+ /*
+ hr = VBoxDrvCfgInfInstall(MpInf);
+ if (FAILED(hr))
+ printf("VBoxDrvCfgInfInstall failed %#x\n", hr);
+
+ GUID guid;
+ BSTR name, errMsg;
+
+ hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface (MpInf, true, &guid, &name, &errMsg);
+ if (SUCCEEDED(hr))
+ {
+ ULONG ip, mask;
+ hr = VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(&ip, &mask);
+ if (SUCCEEDED(hr))
+ {
+ // ip returned by VBoxNetCfgWinGenHostOnlyNetworkNetworkIp is a network ip,
+ // i.e. 192.168.xxx.0, assign 192.168.xxx.1 for the hostonly adapter
+ ip = ip | (1 << 24);
+ hr = VBoxNetCfgWinEnableStaticIpConfig(&guid, ip, mask);
+ if (SUCCEEDED(hr))
+ printf("installation successful\n");
+ else
+ printf("VBoxNetCfgWinEnableStaticIpConfig failed: hr=%#lx\n", hr);
+ }
+ else
+ printf("VBoxNetCfgWinGenHostOnlyNetworkNetworkIp failed: hr=%#lx\n", hr);
+ }
+ else
+ printf("VBoxNetCfgWinCreateHostOnlyNetworkInterface failed: hr=%#lx\n", hr);
+ */
+ }
+ else
+ {
+ DWORD dwErr = GetLastError();
+ RTMsgError("MyGetfullPathNameW failed: %Rwc", dwErr);
+ hr = HRESULT_FROM_WIN32(dwErr);
+ }
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return SUCCEEDED(hr) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static int VBoxNetAdpUninstall(void)
+{
+ RTMsgInfo("Uninstalling all host-only interfaces...");
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (SUCCEEDED(hr))
+ {
+ hr = VBoxNetCfgWinRemoveAllNetDevicesOfId(VBOX_NETADP_HWID);
+ if (SUCCEEDED(hr))
+ {
+ hr = VBoxDrvCfgInfUninstallAllSetupDi(&GUID_DEVCLASS_NET, L"Net", VBOX_NETADP_HWID, 0/* could be SUOI_FORCEDELETE */);
+ if (SUCCEEDED(hr))
+ RTMsgInfo("Uninstallation successful!");
+ else
+ RTMsgWarning("uninstalled successfully, but failed to remove infs (%Rhrc)\n", hr);
+ }
+ else
+ RTMsgError("uninstall failed: %Rhrc", hr);
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return SUCCEEDED(hr) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static int VBoxNetAdpUpdate(void)
+{
+ RTMsgInfo("Uninstalling all host-only interfaces...");
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (SUCCEEDED(hr))
+ {
+ BOOL fRebootRequired = FALSE;
+ /*
+ * Before we can update the driver for existing adapters we need to remove
+ * all old driver packages from the driver cache. Otherwise we may end up
+ * with both NDIS5 and NDIS6 versions of VBoxNetAdp in the cache which
+ * will cause all sorts of trouble.
+ */
+ VBoxDrvCfgInfUninstallAllF(L"Net", VBOX_NETADP_HWID, SUOI_FORCEDELETE);
+ hr = VBoxNetCfgWinUpdateHostOnlyNetworkInterface(VBOX_NETADP_INF, &fRebootRequired, VBOX_NETADP_HWID);
+ if (SUCCEEDED(hr))
+ {
+ if (fRebootRequired)
+ RTMsgWarning("!!REBOOT REQUIRED!!");
+ RTMsgInfo("Updated successfully!");
+ }
+ else
+ RTMsgError("update failed: %Rhrc", hr);
+
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return SUCCEEDED(hr) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static int VBoxNetAdpDisable(void)
+{
+ RTMsgInfo("Disabling all host-only interfaces...");
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (SUCCEEDED(hr))
+ {
+ hr = VBoxNetCfgWinPropChangeAllNetDevicesOfId(VBOX_NETADP_HWID, VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE);
+ if (SUCCEEDED(hr))
+ RTMsgInfo("Disabling successful");
+ else
+ RTMsgError("disable failed: %Rhrc", hr);
+
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return SUCCEEDED(hr) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static int VBoxNetAdpEnable(void)
+{
+ RTMsgInfo("Enabling all host-only interfaces...");
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (SUCCEEDED(hr))
+ {
+ hr = VBoxNetCfgWinPropChangeAllNetDevicesOfId(VBOX_NETADP_HWID, VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE);
+ if (SUCCEEDED(hr))
+ RTMsgInfo("Enabling successful!");
+ else
+ RTMsgError("enabling failed: %hrc", hr);
+
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return SUCCEEDED(hr) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static void printUsage(void)
+{
+ RTPrintf("host-only network adapter configuration tool\n"
+ " Usage: %s [cmd]\n"
+ " cmd can be one of the following values:\n"
+ " i - install a new host-only interface (default command)\n"
+ " u - uninstall all host-only interfaces\n"
+ " a - update the host-only driver\n"
+ " d - disable all host-only interfaces\n"
+ " e - enable all host-only interfaces\n"
+ " h - print this message\n",
+ RTProcShortName());
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ RTR3InitExe(argc, &argv, 0);
+
+ if (argc < 2)
+ return VBoxNetAdpInstall();
+ if (argc > 2)
+ {
+ printUsage();
+ return RTEXITCODE_SYNTAX;
+ }
+
+ if (!strcmp(argv[1], "i"))
+ return VBoxNetAdpInstall();
+ if (!strcmp(argv[1], "u"))
+ return VBoxNetAdpUninstall();
+ if (!strcmp(argv[1], "a"))
+ return VBoxNetAdpUpdate();
+ if (!strcmp(argv[1], "d"))
+ return VBoxNetAdpDisable();
+ if (!strcmp(argv[1], "e"))
+ return VBoxNetAdpEnable();
+
+ printUsage();
+ return !strcmp(argv[1], "h") ? RTEXITCODE_SUCCESS : RTEXITCODE_SYNTAX;
+}
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpUninstall.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpUninstall.cpp
new file mode 100644
index 00000000..03508669
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetAdpUninstall.cpp
@@ -0,0 +1,107 @@
+/* $Id: VBoxNetAdpUninstall.cpp $ */
+/** @file
+ * NetAdpUninstall - VBoxNetAdp uninstaller command line tool
+ */
+
+/*
+ * Copyright (C) 2009-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 <VBox/VBoxNetCfg-win.h>
+#include <VBox/VBoxDrvCfg-win.h>
+
+#include <devguid.h>
+
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#ifdef NDIS60
+# define VBOX_NETADP_HWID L"sun_VBoxNetAdp6"
+#else
+# define VBOX_NETADP_HWID L"sun_VBoxNetAdp"
+#endif
+
+
+static DECLCALLBACK(void) winNetCfgLogger(const char *pszString)
+{
+ RTMsgInfo("%s", pszString);
+}
+
+static int VBoxNetAdpUninstall(void)
+{
+ RTMsgInfo("Uninstalling all Host-Only interfaces ...");
+
+ int rcExit = RTEXITCODE_FAILURE;
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (hr == S_OK)
+ {
+ hr = VBoxNetCfgWinRemoveAllNetDevicesOfId(VBOX_NETADP_HWID);
+ if (hr == S_OK)
+ {
+ hr = VBoxDrvCfgInfUninstallAllSetupDi(&GUID_DEVCLASS_NET, L"Net", VBOX_NETADP_HWID, 0/* could be SUOI_FORCEDELETE */);
+ if (hr == S_OK)
+ RTMsgInfo("Uninstalled successfully!");
+ else
+ RTMsgError("uninstalled successfully, but failed to remove infs (%Rhrc)\n", hr);
+ rcExit = RTEXITCODE_SUCCESS;
+ }
+ else
+ RTMsgError("uninstall failed: %Rhrc", hr);
+
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return rcExit;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ RTR3InitExeNoArguments(0);
+ if (argc != 1)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "This utility takes no arguments\n");
+ NOREF(argv);
+
+ return VBoxNetAdpUninstall();
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltInstall.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltInstall.cpp
new file mode 100644
index 00000000..e6c4f2de
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltInstall.cpp
@@ -0,0 +1,201 @@
+/* $Id: VBoxNetFltInstall.cpp $ */
+/** @file
+ * NetFltInstall - VBoxNetFlt installer command line tool
+ */
+
+/*
+ * Copyright (C) 2008-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 <VBox/VBoxNetCfg-win.h>
+#include <devguid.h>
+#include <stdio.h>
+
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define NETFLT_ID L"sun_VBoxNetFlt"
+#define VBOX_NETCFG_APP_NAME L"NetFltInstall"
+#define VBOX_NETFLT_PT_INF L".\\VBoxNetFlt.inf"
+#define VBOX_NETFLT_MP_INF L".\\VBoxNetFltM.inf"
+#define VBOX_NETFLT_RETRIES 10
+
+
+static DECLCALLBACK(void) winNetCfgLogger(const char *pszString)
+{
+ printf("%s", pszString);
+}
+
+/** Wrapper around GetfullPathNameW that will try an alternative INF location.
+ *
+ * The default location is the current directory. If not found there, the
+ * alternative location is the executable directory. If not found there either,
+ * the first alternative is present to the caller.
+ */
+static DWORD MyGetfullPathNameW(LPCWSTR pwszName, size_t cchFull, LPWSTR pwszFull)
+{
+ LPWSTR pwszFilePart;
+ DWORD dwSize = GetFullPathNameW(pwszName, (DWORD)cchFull, pwszFull, &pwszFilePart);
+ if (dwSize <= 0)
+ return dwSize;
+
+ /* if it doesn't exist, see if the file exists in the same directory as the executable. */
+ if (GetFileAttributesW(pwszFull) == INVALID_FILE_ATTRIBUTES)
+ {
+ WCHAR wsz[512];
+ DWORD cch = GetModuleFileNameW(GetModuleHandle(NULL), &wsz[0], RT_ELEMENTS(wsz));
+ if (cch > 0)
+ {
+ while (cch > 0 && wsz[cch - 1] != '/' && wsz[cch - 1] != '\\' && wsz[cch - 1] != ':')
+ cch--;
+ unsigned i = 0;
+ while (cch < RT_ELEMENTS(wsz))
+ {
+ wsz[cch] = pwszFilePart[i++];
+ if (!wsz[cch])
+ {
+ dwSize = GetFullPathNameW(wsz, (DWORD)cchFull, pwszFull, NULL);
+ if (dwSize > 0 && GetFileAttributesW(pwszFull) != INVALID_FILE_ATTRIBUTES)
+ return dwSize;
+ break;
+ }
+ cch++;
+ }
+ }
+ }
+
+ /* fallback */
+ return GetFullPathNameW(pwszName, (DWORD)cchFull, pwszFull, NULL);
+}
+
+static int VBoxNetFltInstall()
+{
+ WCHAR wszPtInf[MAX_PATH];
+ WCHAR wszMpInf[MAX_PATH];
+ INetCfg *pnc;
+ int rcExit = RTEXITCODE_FAILURE;
+
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (hr == S_OK)
+ {
+ for (int i = 0;; i++)
+ {
+ LPWSTR pwszLockedBy = NULL;
+ hr = VBoxNetCfgWinQueryINetCfg(&pnc, TRUE, VBOX_NETCFG_APP_NAME, 10000, &pwszLockedBy);
+ if (hr == S_OK)
+ {
+ DWORD dwSize;
+ dwSize = MyGetfullPathNameW(VBOX_NETFLT_PT_INF, RT_ELEMENTS(wszPtInf), wszPtInf);
+ if (dwSize > 0)
+ {
+ /** @todo add size check for (RT_ELEMENTS(wszPtInf) == dwSize (string length in WCHARs) */
+
+ dwSize = MyGetfullPathNameW(VBOX_NETFLT_MP_INF, RT_ELEMENTS(wszMpInf), wszMpInf);
+ if (dwSize > 0)
+ {
+ /** @todo add size check for (RT_ELEMENTS(wszMpInf) == dwSize (string length in WHCARs) */
+
+ LPCWSTR apwszInfs[] = { wszPtInf, wszMpInf };
+ hr = VBoxNetCfgWinNetFltInstall(pnc, apwszInfs, 2);
+ if (hr == S_OK)
+ {
+ wprintf(L"installed successfully\n");
+ rcExit = RTEXITCODE_SUCCESS;
+ }
+ else
+ wprintf(L"error installing VBoxNetFlt (%#lx)\n", hr);
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ wprintf(L"error getting full inf path for VBoxNetFltM.inf (%#lx)\n", hr);
+ }
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ wprintf(L"error getting full inf path for VBoxNetFlt.inf (%#lx)\n", hr);
+ }
+
+ VBoxNetCfgWinReleaseINetCfg(pnc, TRUE);
+ break;
+ }
+
+ if (hr == NETCFG_E_NO_WRITE_LOCK && pwszLockedBy)
+ {
+ if (i < VBOX_NETFLT_RETRIES && !wcscmp(pwszLockedBy, L"6to4svc.dll"))
+ {
+ wprintf(L"6to4svc.dll is holding the lock, retrying %d out of %d\n", i + 1, VBOX_NETFLT_RETRIES);
+ CoTaskMemFree(pwszLockedBy);
+ }
+ else
+ {
+ wprintf(L"Error: write lock is owned by another application (%s), close the application and retry installing\n", pwszLockedBy);
+ CoTaskMemFree(pwszLockedBy);
+ break;
+ }
+ }
+ else
+ {
+ wprintf(L"Error getting the INetCfg interface (%#lx)\n", hr);
+ break;
+ }
+ }
+
+ CoUninitialize();
+ }
+ else
+ wprintf(L"Error initializing COM (%#lx)\n", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return rcExit;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ RTR3InitExeNoArguments(0);
+ if (argc != 1)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "This utility takes no arguments\n");
+ NOREF(argv);
+
+ return VBoxNetFltInstall();
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltUninstall.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltUninstall.cpp
new file mode 100644
index 00000000..c62d7726
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetFltUninstall.cpp
@@ -0,0 +1,133 @@
+/* $Id: VBoxNetFltUninstall.cpp $ */
+/** @file
+ * NetFltUninstall - VBoxNetFlt uninstaller command line tool
+ */
+
+/*
+ * Copyright (C) 2008-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 <VBox/VBoxNetCfg-win.h>
+#include <stdio.h>
+
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define NETFLT_ID L"sun_VBoxNetFlt"
+#define VBOX_NETCFG_APP_NAME L"NetFltUninstall"
+#define VBOX_NETFLT_PT_INF L".\\VBoxNetFlt.inf"
+#define VBOX_NETFLT_MP_INF L".\\VBoxNetFltM.inf"
+#define VBOX_NETFLT_RETRIES 10
+
+
+static DECLCALLBACK(void) winNetCfgLogger(const char *pszString)
+{
+ printf("%s", pszString);
+}
+
+static int VBoxNetFltUninstall()
+{
+ INetCfg *pnc;
+ int rcExit = RTEXITCODE_FAILURE;
+
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (hr == S_OK)
+ {
+ for (int i = 0;; i++)
+ {
+ LPWSTR pwszLockedBy = NULL;
+ hr = VBoxNetCfgWinQueryINetCfg(&pnc, TRUE, VBOX_NETCFG_APP_NAME, 10000, &pwszLockedBy);
+ if (hr == S_OK)
+ {
+ hr = VBoxNetCfgWinNetFltUninstall(pnc);
+ if (hr != S_OK && hr != S_FALSE)
+ wprintf(L"error uninstalling VBoxNetFlt (%#lx)\n", hr);
+ else
+ {
+ wprintf(L"uninstalled successfully\n");
+ rcExit = RTEXITCODE_SUCCESS;
+ }
+
+ VBoxNetCfgWinReleaseINetCfg(pnc, TRUE);
+ break;
+ }
+
+ if (hr == NETCFG_E_NO_WRITE_LOCK && pwszLockedBy)
+ {
+ if (i < VBOX_NETFLT_RETRIES && !wcscmp(pwszLockedBy, L"6to4svc.dll"))
+ {
+ wprintf(L"6to4svc.dll is holding the lock, retrying %d out of %d\n", i + 1, VBOX_NETFLT_RETRIES);
+ CoTaskMemFree(pwszLockedBy);
+ }
+ else
+ {
+ wprintf(L"Error: write lock is owned by another application (%s), close the application and retry uninstalling\n",
+ pwszLockedBy);
+ CoTaskMemFree(pwszLockedBy);
+ break;
+ }
+ }
+ else
+ {
+ wprintf(L"Error getting the INetCfg interface (%#lx)\n", hr);
+ break;
+ }
+ }
+
+ CoUninitialize();
+ }
+ else
+ wprintf(L"Error initializing COM (%#lx)\n", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return rcExit;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ RTR3InitExeNoArguments(0);
+ if (argc != 1)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "This utility takes no arguments\n");
+ NOREF(argv);
+
+ return VBoxNetFltUninstall();
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfInstall.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfInstall.cpp
new file mode 100644
index 00000000..1b8cf693
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfInstall.cpp
@@ -0,0 +1,186 @@
+/* $Id: VBoxNetLwfInstall.cpp $ */
+/** @file
+ * NetLwfInstall - VBoxNetLwf installer command line tool
+ */
+
+/*
+ * Copyright (C) 2014-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 <VBox/VBoxNetCfg-win.h>
+#include <devguid.h>
+
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/utf16.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define VBOX_NETCFG_APP_NAME L"NetLwfInstall"
+#define VBOX_NETLWF_INF L".\\VBoxNetLwf.inf"
+#define VBOX_NETLWF_RETRIES 10
+
+
+static DECLCALLBACK(void) winNetCfgLogger(const char *pszString)
+{
+ RTMsgInfo("%s", pszString);
+}
+
+/** Wrapper around GetfullPathNameW that will try an alternative INF location.
+ *
+ * The default location is the current directory. If not found there, the
+ * alternative location is the executable directory. If not found there either,
+ * the first alternative is present to the caller.
+ */
+static DWORD MyGetfullPathNameW(LPCWSTR pwszName, size_t cchFull, LPWSTR pwszFull)
+{
+ LPWSTR pwszFilePart;
+ DWORD dwSize = GetFullPathNameW(pwszName, (DWORD)cchFull, pwszFull, &pwszFilePart);
+ if (dwSize <= 0)
+ return dwSize;
+
+ /* if it doesn't exist, see if the file exists in the same directory as the executable. */
+ if (GetFileAttributesW(pwszFull) == INVALID_FILE_ATTRIBUTES)
+ {
+ WCHAR wsz[512];
+ DWORD cch = GetModuleFileNameW(GetModuleHandle(NULL), &wsz[0], RT_ELEMENTS(wsz));
+ if (cch > 0)
+ {
+ while (cch > 0 && wsz[cch - 1] != '/' && wsz[cch - 1] != '\\' && wsz[cch - 1] != ':')
+ cch--;
+ unsigned i = 0;
+ while (cch < RT_ELEMENTS(wsz))
+ {
+ wsz[cch] = pwszFilePart[i++];
+ if (!wsz[cch])
+ {
+ dwSize = GetFullPathNameW(wsz, (DWORD)cchFull, pwszFull, NULL);
+ if (dwSize > 0 && GetFileAttributesW(pwszFull) != INVALID_FILE_ATTRIBUTES)
+ return dwSize;
+ break;
+ }
+ cch++;
+ }
+ }
+ }
+
+ /* fallback */
+ return GetFullPathNameW(pwszName, (DWORD)cchFull, pwszFull, NULL);
+}
+
+static int VBoxNetLwfInstall()
+{
+ WCHAR wszInf[MAX_PATH];
+ INetCfg *pnc;
+ int rcExit = RTEXITCODE_FAILURE;
+
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (hr == S_OK)
+ {
+ for (int i = 0;; i++)
+ {
+ LPWSTR pwszLockedBy = NULL;
+ hr = VBoxNetCfgWinQueryINetCfg(&pnc, TRUE, VBOX_NETCFG_APP_NAME, 10000, &pwszLockedBy);
+ if (hr == S_OK)
+ {
+ DWORD dwSize;
+ dwSize = MyGetfullPathNameW(VBOX_NETLWF_INF, RT_ELEMENTS(wszInf), wszInf);
+ if (dwSize > 0)
+ {
+ /** @todo add size check for (RT_ELEMENTS(wszInf) == dwSize (string length in WCHARs) */
+ hr = VBoxNetCfgWinNetLwfInstall(pnc, wszInf);
+ if (hr == S_OK)
+ {
+ RTMsgInfo("Installed successfully!");
+ rcExit = RTEXITCODE_SUCCESS;
+ }
+ else
+ RTMsgError("Failed installing VBoxNetLwf: %Rhrc", hr);
+ }
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ RTMsgError("Failed getting full inf path for VBoxNetLwf.inf: %Rhrc", hr);
+ }
+
+ VBoxNetCfgWinReleaseINetCfg(pnc, TRUE);
+ break;
+ }
+
+ if (hr == NETCFG_E_NO_WRITE_LOCK && pwszLockedBy)
+ {
+ if (i < VBOX_NETLWF_RETRIES && RTUtf16ICmpAscii(pwszLockedBy, "6to4svc.dll") == 0)
+ {
+ RTMsgInfo("6to4svc.dll is holding the lock - retrying %d out of %d\n", i + 1, VBOX_NETLWF_RETRIES);
+ CoTaskMemFree(pwszLockedBy);
+ }
+ else
+ {
+ RTMsgError("write lock is owned by another application (%ls), close the application and retry installing",
+ pwszLockedBy);
+ CoTaskMemFree(pwszLockedBy);
+ break;
+ }
+ }
+ else
+ {
+ RTMsgError("Failed getting the INetCfg interface: %Rhrc", hr);
+ break;
+ }
+ }
+
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return rcExit;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ RTR3InitExeNoArguments(0);
+ if (argc != 1)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "This utility takes no arguments\n");
+ NOREF(argv);
+
+ return VBoxNetLwfInstall();
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfUninstall.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfUninstall.cpp
new file mode 100644
index 00000000..0648a127
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/tools/VBoxNetLwfUninstall.cpp
@@ -0,0 +1,130 @@
+/* $Id: VBoxNetLwfUninstall.cpp $ */
+/** @file
+ * NetLwfUninstall - VBoxNetLwf uninstaller command line tool
+ */
+
+/*
+ * Copyright (C) 2014-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 <VBox/VBoxNetCfg-win.h>
+
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/utf16.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define VBOX_NETCFG_APP_NAME L"NetLwfUninstall"
+#define VBOX_NETLWF_RETRIES 10
+
+
+static DECLCALLBACK(void) winNetCfgLogger(const char *pszString)
+{
+ RTMsgInfo("%s", pszString);
+}
+
+static int VBoxNetLwfUninstall()
+{
+ int rcExit = RTEXITCODE_FAILURE;
+
+ VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+ HRESULT hr = CoInitialize(NULL);
+ if (hr == S_OK)
+ {
+ for (int i = 0;; i++)
+ {
+ LPWSTR pwszLockedBy = NULL;
+ INetCfg *pnc = NULL;
+ hr = VBoxNetCfgWinQueryINetCfg(&pnc, TRUE, VBOX_NETCFG_APP_NAME, 10000, &pwszLockedBy);
+ if (hr == S_OK)
+ {
+ hr = VBoxNetCfgWinNetLwfUninstall(pnc);
+ if (hr == S_OK)
+ {
+ RTMsgInfo("uninstalled successfully!");
+ rcExit = RTEXITCODE_SUCCESS;
+ }
+ else
+ RTMsgError("error uninstalling VBoxNetLwf: %Rhrc");
+
+ VBoxNetCfgWinReleaseINetCfg(pnc, TRUE);
+ break;
+ }
+
+ if (hr == NETCFG_E_NO_WRITE_LOCK && pwszLockedBy)
+ {
+ if (i < VBOX_NETLWF_RETRIES && RTUtf16ICmpAscii(pwszLockedBy, "6to4svc.dll") == 0)
+ {
+ RTMsgInfo("6to4svc.dll is holding the lock - retry %d out of %d ...", i + 1, VBOX_NETLWF_RETRIES);
+ CoTaskMemFree(pwszLockedBy);
+ }
+ else
+ {
+ RTMsgError("Write lock is owned by another application (%ls), close the application and retry uninstalling",
+ pwszLockedBy);
+ CoTaskMemFree(pwszLockedBy);
+ break;
+ }
+ }
+ else
+ {
+ RTMsgError("Failed getting the INetCfg interface: %Rhrc", hr);
+ break;
+ }
+ }
+
+ CoUninitialize();
+ }
+ else
+ RTMsgError("Failed initializing COM: %Rhrc", hr);
+
+ VBoxNetCfgWinSetLogging(NULL);
+
+ return rcExit;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ RTR3InitExeNoArguments(0);
+ if (argc != 1)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "This utility takes no arguments\n");
+ NOREF(argv);
+
+ return VBoxNetLwfUninstall();
+}
+