summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp3677
1 files changed, 3677 insertions, 0 deletions
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..7a3a2373
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp
@@ -0,0 +1,3677 @@
+/* $Id: VBoxNetCfg.cpp $ */
+/** @file
+ * VBoxNetCfg.cpp - Network Configuration API.
+ */
+/*
+ * Copyright (C) 2011-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE 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.
+ */
+#include "VBox/VBoxNetCfg-win.h"
+#include "VBox/VBoxDrvCfg-win.h"
+
+#define _WIN32_DCOM
+
+#include <devguid.h>
+#include <stdio.h>
+#include <regstr.h>
+#include <iprt/win/shlobj.h>
+#include <cfgmgr32.h>
+#include <tchar.h>
+#include <iprt/win/objbase.h>
+
+#include <crtdbg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Wbemidl.h>
+#include <comdef.h>
+
+#include <iprt/win/winsock2.h>
+#include <iprt/win/ws2tcpip.h>
+#include <ws2ipdef.h>
+#include <iprt/win/netioapi.h>
+#include <iprt/win/iphlpapi.h>
+
+
+#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
+static LOG_ROUTINE g_Logger = NULL;
+
+static VOID DoLogging(LPCSTR szString, ...);
+#define NonStandardLog DoLogging
+#define NonStandardLogFlow(x) DoLogging x
+
+#define DbgLog /** @todo r=bird: What does this do? */
+
+#define VBOX_NETCFG_LOCK_TIME_OUT 5000 /** @todo r=bird: What does this do? */
+
+#define VBOXNETCFGWIN_NETADP_ID L"sun_VBoxNetAdp"
+
+/*
+* 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;
+
+static PFNINITIALIZEIPINTERFACEENTRY g_pfnInitializeIpInterfaceEntry = NULL;
+static PFNGETIPINTERFACEENTRY g_pfnGetIpInterfaceEntry = NULL;
+static PFNSETIPINTERFACEENTRY g_pfnSetIpInterfaceEntry = NULL;
+
+
+/*
+* Forward declaration for using vboxNetCfgWinSetupMetric()
+*/
+HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid);
+HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID);
+
+
+/*
+ * For some weird reason we do not want to use IPRT here, hence the following
+ * function provides a replacement for BstrFmt.
+ */
+static bstr_t bstr_printf(const char *cszFmt, ...)
+{
+ char szBuffer[4096];
+ szBuffer[sizeof(szBuffer) - 1] = 0; /* Make sure the string will be null-terminated */
+ va_list va;
+ va_start(va, cszFmt);
+ _vsnprintf(szBuffer, sizeof(szBuffer) - 1, cszFmt, va);
+ va_end(va);
+ return bstr_t(szBuffer);
+}
+
+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, hr (0x%x)\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, hr (0x%x)\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, hr (0x%x)\n", hr));
+ return hr;
+ }
+
+ hr = pLock->ReleaseWriteLock();
+ if (FAILED(hr))
+ NonStandardLogFlow(("ReleaseWriteLock failed, hr (0x%x)\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;
+ HRESULT hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (PVOID*)&pNetCfg);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\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;
+ }
+ else
+ NonStandardLogFlow(("Initialize failed, hr (0x%x)\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, hr (0x%x)\n", hr));
+ /* Try to release the write lock below. */
+ }
+
+ if (fHasWriteLock)
+ {
+ HRESULT hr2 = vboxNetCfgWinINetCfgUnlock(pNetCfg);
+ if (FAILED(hr2))
+ NonStandardLogFlow(("vboxNetCfgWinINetCfgUnlock failed, hr (0x%x)\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, hr (0x%x)\n", hr));
+ return hr;
+ }
+
+ INetCfgComponent *pNcc;
+ while ((hr = pEnumNcc->Next(1, &pNcc, NULL)) == S_OK)
+ {
+ ULONG uComponentStatus;
+ 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, hr (0x%x)\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;
+ 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, hr (0x%x)\n", hr));
+ }
+ pEnumNcc->Release();
+ }
+ else
+ NonStandardLogFlow(("EnumComponents failed, hr (0x%x)\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, hr (0x%x)\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, hr (0x%x)\n", hr));
+ return hr;
+ }
+
+ OBO_TOKEN Token;
+ ZeroMemory(&Token, sizeof (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)
+ {
+ HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
+ HRESULT res;
+
+ /*
+ * Set default metric value of interface to fix multicast issue
+ * See @bugref{6379} for details.
+ */
+ res = pTempComponent->OpenParamKey(&hkey);
+
+ /* Set default metric value for host-only interface only */
+ if ( SUCCEEDED(res)
+ && hkey != INVALID_HANDLE_VALUE
+ && wcsnicmp(pszwComponentId, VBOXNETCFGWIN_NETADP_ID, 256) == 0)
+ {
+ NET_LUID luid;
+ res = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
+
+ /* Close the key as soon as possible. See @bugref{7973}. */
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+
+ if (FAILED(res))
+ {
+ /*
+ * 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, hr (0x%x)\n", res));
+ }
+ else
+ {
+ res = vboxNetCfgWinSetupMetric(&luid);
+ if (FAILED(res))
+ {
+ /*
+ * 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, hr (0x%x)\n", res));
+ }
+ }
+ }
+ if (hkey != INVALID_HANDLE_VALUE)
+ {
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+ }
+ if (ppComponent != NULL)
+ *ppComponent = pTempComponent;
+ else
+ pTempComponent->Release();
+ }
+
+ /* ignore the apply failure */
+ HRESULT tmpHr = pNetCfg->Apply();
+ Assert(tmpHr == S_OK);
+ if (tmpHr != S_OK)
+ NonStandardLogFlow(("Apply failed, hr (0x%x)\n", tmpHr));
+ }
+ else
+ NonStandardLogFlow(("Install failed, hr (0x%x)\n", hr));
+
+ pSetup->Release();
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinInstallInfAndComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
+ IN LPCWSTR const *apInfPaths, IN UINT cInfPaths,
+ OUT INetCfgComponent **ppComponent)
+{
+ HRESULT hr = S_OK;
+ UINT cFilesProcessed = 0;
+
+ NonStandardLogFlow(("Installing %u INF files ...\n", cInfPaths));
+
+ for (; cFilesProcessed < cInfPaths; cFilesProcessed++)
+ {
+ NonStandardLogFlow(("Installing INF file \"%ws\" ...\n", apInfPaths[cFilesProcessed]));
+ hr = VBoxDrvCfgInfInstall(apInfPaths[cFilesProcessed]);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("VBoxNetCfgWinInfInstall failed, hr (0x%x)\n", hr));
+ break;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = VBoxNetCfgWinInstallComponent(pNetCfg, pszwComponentId, pguidClass, ppComponent);
+ if (FAILED(hr))
+ NonStandardLogFlow(("VBoxNetCfgWinInstallComponent failed, hr (0x%x)\n", hr));
+ }
+
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("Installation failed, rolling back installation set ...\n"));
+
+ do
+ {
+ HRESULT hr2 = VBoxDrvCfgInfUninstall(apInfPaths[cFilesProcessed], 0);
+ if (FAILED(hr2))
+ NonStandardLogFlow(("VBoxDrvCfgInfUninstall failed, hr (0x%x)\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, hr (0x%x)\n", hr));
+ return hr;
+ }
+
+ INetCfgClassSetup *pSetup = NULL;
+ hr = vboxNetCfgWinQueryInstaller(pNetCfg, &GuidClass, &pSetup);
+ if (FAILED(hr))
+ {
+ NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed, hr (0x%x)\n", hr));
+ return hr;
+ }
+
+ OBO_TOKEN Token;
+ ZeroMemory(&Token, sizeof(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, hr (0x%x)\n", hr));
+ }
+ else
+ NonStandardLogFlow(("DeInstall failed, hr (0x%x)\n", hr));
+
+ if (pSetup)
+ pSetup->Release();
+ return hr;
+}
+
+typedef BOOL (*VBOXNETCFGWIN_NETCFGENUM_CALLBACK) (IN INetCfg *pNetCfg, IN INetCfgComponent *pNetCfgComponent, PVOID pContext);
+
+static HRESULT vboxNetCfgWinEnumNetCfgComponents(IN INetCfg *pNetCfg,
+ IN const GUID *pguidClass,
+ VBOXNETCFGWIN_NETCFGENUM_CALLBACK callback,
+ PVOID pContext)
+{
+ IEnumNetCfgComponent *pEnumComponent;
+ HRESULT hr = pNetCfg->EnumComponents(pguidClass, &pEnumComponent);
+ if (SUCCEEDED(hr))
+ {
+ INetCfgComponent *pNetCfgComponent;
+ hr = pEnumComponent->Reset();
+ do
+ {
+ hr = pEnumComponent->Next(1, &pNetCfgComponent, NULL);
+ if (hr == S_OK)
+ {
+// ULONG uComponentStatus;
+// hr = pNcc->GetDeviceStatus(&uComponentStatus);
+// if (SUCCEEDED(hr))
+ BOOL fResult = FALSE;
+ if (pNetCfgComponent)
+ {
+ if (pContext)
+ fResult = callback(pNetCfg, pNetCfgComponent, pContext);
+ pNetCfgComponent->Release();
+ }
+
+ if (!fResult)
+ break;
+ }
+ else
+ {
+ if (hr == S_FALSE)
+ {
+ hr = S_OK;
+ }
+ else
+ NonStandardLogFlow(("Next failed, hr (0x%x)\n", hr));
+ break;
+ }
+ } while (true);
+ pEnumComponent->Release();
+ }
+ return hr;
+}
+
+/*
+ * Forward declarations of functions used in vboxNetCfgWinRemoveAllNetDevicesOfIdCallback.
+ */
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(LPWSTR pGuid, PCWSTR NewName);
+
+static BOOL vboxNetCfgWinRemoveAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pvContext)
+{
+ RT_NOREF1(pvContext);
+ SP_REMOVEDEVICE_PARAMS rmdParams;
+ memset(&rmdParams, 0, sizeof(SP_REMOVEDEVICE_PARAMS));
+ 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 %ld\n",
+ GetLastError()));
+ }
+ else
+ {
+ WCHAR wszCfgGuidString[50] = { L'' };
+ DWORD cbSize = sizeof(wszCfgGuidString);
+ DWORD dwValueType;
+ DWORD ret = RegQueryValueExW(hKey, L"NetCfgInstanceId", NULL,
+ &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
+ if (ret == ERROR_SUCCESS)
+ {
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Processing device ID \"%S\"\n",
+ wszCfgGuidString));
+
+ /* Figure out device name. */
+ WCHAR wszDevName[256], wszTempName[256];
+ ULONG cbName = sizeof(wszTempName);
+
+ if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev,
+ SPDRP_FRIENDLYNAME, /* IN DWORD Property,*/
+ NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL*/
+ (PBYTE)wszDevName, /* OUT PBYTE PropertyBuffer,*/
+ sizeof(wszDevName), /* IN DWORD PropertyBufferSize,*/
+ NULL /* OUT PDWORD RequiredSize OPTIONAL*/))
+ {
+ /*
+ * 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}).
+ */
+ HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszTempName, &cbName);
+ wcscat_s(wszTempName, sizeof(wszTempName), L" removed");
+ if (SUCCEEDED(hr))
+ hr = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszTempName);
+ //NonStandardLogFlow(("VBoxNetCfgWinRenameConnection(%S,%S) => 0x%x\n", pWCfgGuidString, TempName, hr_tmp));
+ }
+ else
+ {
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Failed to get friendly name for device \"%S\"\n",
+ wszCfgGuidString));
+ }
+ }
+ else
+ {
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Querying instance ID failed with %d\n",
+ ret));
+ }
+
+ RegCloseKey(hKey);
+ }
+#endif /* VBOXNETCFG_DELAYEDRENAME */
+
+ if (SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, pDev))
+ {
+ SP_DEVINSTALL_PARAMS devParams;
+ memset(&devParams, 0, sizeof(SP_DEVINSTALL_PARAMS));
+ devParams.cbSize = 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 %ld\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetSelectedDevice failed with %ld\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetClassInstallParams failed with %ld\n",
+ GetLastError()));
+
+ /* Continue enumeration. */
+ return TRUE;
+}
+
+typedef struct VBOXNECTFGWINPROPCHANGE
+{
+ VBOXNECTFGWINPROPCHANGE_TYPE enmPcType;
+ HRESULT hr;
+} VBOXNECTFGWINPROPCHANGE ,*PVBOXNECTFGWINPROPCHANGE;
+
+static BOOL vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
+{
+ PVBOXNECTFGWINPROPCHANGE pPc = (PVBOXNECTFGWINPROPCHANGE)pContext;
+
+ SP_PROPCHANGE_PARAMS PcParams;
+ memset (&PcParams, 0, sizeof (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 (SetupDiSetClassInstallParams(hDevInfo, pDev, &PcParams.ClassInstallHeader, sizeof(PcParams)))
+ {
+ if (SetupDiSetSelectedDevice(hDevInfo, pDev))
+ {
+ if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, pDev))
+ {
+ SP_DEVINSTALL_PARAMS devParams;
+ devParams.cbSize = sizeof(devParams);
+ if (SetupDiGetDeviceInstallParams(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 %ld\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
+ GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("SetupDiSetSelectedDevice failed with %ld\n", GetLastError()));
+ }
+ else
+ NonStandardLogFlow(("SetupDiSetClassInstallParams failed with %ld\n", GetLastError()));
+
+ /* Continue enumeration. */
+ return TRUE;
+}
+
+typedef BOOL (*PFNVBOXNETCFGWINNETENUMCALLBACK)(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnumNetDevices(LPCWSTR pwszPnPId,
+ PFNVBOXNETCFGWINNETENUMCALLBACK pfnCallback, PVOID pvContext)
+{
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Searching for: %S\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)
+ {
+ DWORD winEr = NO_ERROR;
+
+ DWORD dwDevId = 0;
+ size_t cPnPId = wcslen(pwszPnPId);
+
+ PBYTE pBuffer = 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 = ERROR_SUCCESS;
+ break;
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Enumerating device %ld ... \n", dwDevId));
+ dwDevId++;
+
+ if (pBuffer)
+ free(pBuffer);
+ pBuffer = NULL;
+ DWORD cbBuffer = 0;
+ DWORD cbRequired = 0;
+
+ if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
+ SPDRP_HARDWAREID, /* IN DWORD Property */
+ NULL, /* OUT PDWORD PropertyRegDataType OPTIONAL */
+ pBuffer, /* OUT PBYTE PropertyBuffer */
+ cbBuffer, /* IN DWORD PropertyBufferSize */
+ &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
+ {
+ winEr = GetLastError();
+ if (winEr != ERROR_INSUFFICIENT_BUFFER)
+ {
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with %ld\n", winEr));
+ break;
+ }
+
+ pBuffer = (PBYTE)malloc(cbRequired);
+ if (!pBuffer)
+ {
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Out of memory allocating %ld bytes\n",
+ cbRequired));
+ winEr = ERROR_OUTOFMEMORY;
+ break;
+ }
+
+ cbBuffer = cbRequired;
+
+ if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo,&Dev,
+ SPDRP_HARDWAREID, /* IN DWORD Property */
+ NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL */
+ pBuffer, /* OUT PBYTE PropertyBuffer */
+ cbBuffer, /* IN DWORD PropertyBufferSize */
+ &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
+ {
+ winEr = GetLastError();
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (2) failed with %ld\n",
+ winEr));
+ break;
+ }
+ }
+
+ PWSTR pCurId = (PWSTR)pBuffer;
+ size_t cCurId = wcslen(pCurId);
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Device %ld: %S\n", dwDevId, pCurId));
+
+ if (cCurId >= cPnPId)
+ {
+ NonStandardLogFlow(("!wcsnicmp(pCurId = (%S), pwszPnPId = (%S), cPnPId = (%d))\n", pCurId, pwszPnPId, cPnPId));
+
+ pCurId += cCurId - cPnPId;
+ if (!wcsnicmp(pCurId, pwszPnPId, cPnPId))
+ {
+ if (!pfnCallback(hDevInfo, &Dev, pvContext))
+ break;
+ }
+ }
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Found %ld devices total\n", dwDevId));
+
+ if (pBuffer)
+ free(pBuffer);
+
+ hr = HRESULT_FROM_WIN32(winEr);
+
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ }
+ else
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetClassDevsExW failed with %ld\n", winEr));
+ hr = HRESULT_FROM_WIN32(winEr);
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Ended with hr (0x%x)\n", hr));
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR lpszPnPId)
+{
+ return VBoxNetCfgWinEnumNetDevices(lpszPnPId, vboxNetCfgWinRemoveAllNetDevicesOfIdCallback, NULL);
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR lpszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE enmPcType)
+{
+ VBOXNECTFGWINPROPCHANGE Pc;
+ Pc.enmPcType = enmPcType;
+ Pc.hr = S_OK;
+ NonStandardLogFlow(("Calling VBoxNetCfgWinEnumNetDevices with lpszPnPId =(%S) and vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback\n", lpszPnPId));
+
+ HRESULT hr = VBoxNetCfgWinEnumNetDevices(lpszPnPId, 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(LPCSTR szString, ...)
+{
+ LOG_ROUTINE pfnRoutine = (LOG_ROUTINE)(*((void * volatile *)&g_Logger));
+ if (pfnRoutine)
+ {
+ char szBuffer[4096] = {0};
+ va_list va;
+ va_start(va, szString);
+ _vsnprintf(szBuffer, RT_ELEMENTS(szBuffer), szString, va);
+ va_end(va);
+
+ pfnRoutine(szBuffer);
+ }
+}
+
+VBOXNETCFGWIN_DECL(VOID) VBoxNetCfgWinSetLogging(IN LOG_ROUTINE pfnLog)
+{
+ *((void * volatile *)&g_Logger) = pfnLog;
+}
+
+/*
+ * IP configuration API
+ */
+/* network settings config */
+/**
+ * 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
+ {
+ private:
+#if !defined (VBOX_WITH_XPCOM)
+ STDMETHOD_(ULONG, AddRef)() = 0;
+ STDMETHOD_(ULONG, Release)() = 0;
+#else /* !defined (VBOX_WITH_XPCOM) */
+ NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
+ NS_IMETHOD_(nsrefcnt) Release(void) = 0;
+#endif /* !defined (VBOX_WITH_XPCOM) */
+ };
+
+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);
+ }
+ else
+ {
+ *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);
+ }
+};
+
+static HRESULT netIfWinFindAdapterClassById(IWbemServices * pSvc, const GUID * pGuid, IWbemClassObject **pAdapterConfig)
+{
+ HRESULT hr;
+ WCHAR wszQuery[256];
+ WCHAR wszGuid[50];
+
+ int length = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
+ if (length)
+ {
+ swprintf(wszQuery, L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"%s\"", wszGuid);
+ IEnumWbemClassObject* pEnumerator = NULL;
+ hr = pSvc->ExecQuery(bstr_t("WQL"), bstr_t(wszQuery), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (SUCCEEDED(hr))
+ {
+ if (pEnumerator)
+ {
+ IWbemClassObject *pclsObj;
+ 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 * pbIsHostOnly)
+{
+ VARIANT vtServiceName;
+ VariantInit(&vtServiceName);
+
+ HRESULT hr = pAdapterConfig->Get(L"ServiceName", 0 /*lFlags*/, &vtServiceName, NULL /*pvtType*/, NULL /*plFlavor*/);
+ if (SUCCEEDED(hr))
+ {
+ *pbIsHostOnly = bstr_t(vtServiceName.bstrVal) == bstr_t("VBoxNetAdp");
+
+ VariantClear(&vtServiceName);
+ }
+
+ return hr;
+}
+
+static HRESULT netIfWinGetIpSettings(IWbemClassObject * pAdapterConfig, ULONG *pIpv4, ULONG *pMaskv4)
+{
+ VARIANT vtIp;
+ HRESULT hr;
+ VariantInit(&vtIp);
+
+ *pIpv4 = 0;
+ *pMaskv4 = 0;
+
+ 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 pCurIp;
+ BSTR pCurMask;
+ for (LONG i = 0;
+ SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
+ && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
+ i++)
+ {
+ bstr_t ip(pCurIp);
+
+ ULONG Ipv4 = inet_addr((char*)(ip));
+ if (Ipv4 != INADDR_NONE)
+ {
+ *pIpv4 = Ipv4;
+ bstr_t mask(pCurMask);
+ *pMaskv4 = inet_addr((char*)(mask));
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ *pIpv4 = 0;
+ *pMaskv4 = 0;
+ }
+
+ VariantClear(&vtMask);
+ }
+ }
+ else
+ {
+ *pIpv4 = 0;
+ *pMaskv4 = 0;
+ }
+
+ 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(bstr_t(L"ROOT\\CIMV2"), /* [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;
+ }
+ else
+ NonStandardLogFlow(("CoSetProxyBlanket failed, hr (0x%x)\n", hr));
+
+ pSvc->Release();
+ }
+ else
+ NonStandardLogFlow(("ConnectServer failed, hr (0x%x)\n", hr));
+ pLoc->Release();
+ }
+ else
+ NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\n", hr));
+ return hr;
+}
+
+static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, BSTR * pStr)
+{
+ VARIANT index;
+ HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
+ if (SUCCEEDED(hr))
+ {
+ WCHAR strIndex[8];
+ swprintf(strIndex, L"%u", index.uintVal);
+ *pStr = (bstr_t(L"Win32_NetworkAdapterConfiguration.Index='") + strIndex + "'").copy();
+ }
+ else
+ NonStandardLogFlow(("Get failed, hr (0x%x)\n", hr));
+ return hr;
+}
+
+static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, BSTR ObjPath,
+ BSTR MethodName, LPWSTR *pArgNames, LPVARIANT *pArgs, UINT cArgs,
+ IWbemClassObject** ppOutParams
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IWbemClassObject> pInParamsDefinition;
+ ComPtr<IWbemClassObject> pClassInstance;
+
+ if (cArgs)
+ {
+ hr = pClass->GetMethod(MethodName, 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(pArgNames[i], 0,
+ pArgs[i], 0);
+ if (FAILED(hr))
+ break;
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ IWbemClassObject* pOutParams = NULL;
+ hr = pSvc->ExecMethod(ObjPath, MethodName, 0, NULL, pClassInstance, &pOutParams, NULL);
+ if (SUCCEEDED(hr))
+ {
+ *ppOutParams = pOutParams;
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr* aIp, UINT cIp)
+{
+ HRESULT hr = S_OK; /* MSC maybe used uninitialized */
+ SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIp);
+ if (pIpArray)
+ {
+ for (UINT i = 0; i < cIp; i++)
+ {
+ char* addr = inet_ntoa(aIp[i]);
+ BSTR val = bstr_t(addr).copy();
+ long aIndex[1];
+ aIndex[0] = i;
+ hr = SafeArrayPutElement(pIpArray, aIndex, val);
+ if (FAILED(hr))
+ {
+ SysFreeString(val);
+ SafeArrayDestroy(pIpArray);
+ break;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *ppArray = 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 = bstr_t(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* aIp, UINT cIp)
+{
+ HRESULT hr;
+ VariantInit(pIpAddresses);
+ pIpAddresses->vt = VT_ARRAY | VT_BSTR;
+ SAFEARRAY *pIpArray;
+ hr = netIfWinCreateIpArray(&pIpArray, aIp, cIp);
+ 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, BSTR ObjPath, VARIANT *pIp, VARIANT *pMask)
+{
+ 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"IPAddress", L"SubnetMask"};
+ LPVARIANT args[] = {pIp, pMask};
+ ComPtr<IWbemClassObject> pOutParams;
+
+ hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableStatic"), argNames, args, 2, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ hr = pOutParams->Get(bstr_t(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;
+// bool bFound;
+// HRESULT tmpHr = netIfWinWaitIpSettings(pSvc, pGuid, pIp->parray, pMask->parray, 180, &bFound);
+ NOREF(pGuid);
+ break;
+ }
+ default:
+ hr = HRESULT_FROM_WIN32( winEr );
+ break;
+ }
+ }
+ }
+ }
+ SysFreeString(ClassName);
+ }
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
+
+ return hr;
+}
+
+
+static HRESULT netIfWinEnableStaticV4(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, in_addr* aIp, in_addr * aMask, UINT cIp)
+{
+ VARIANT ipAddresses;
+ HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, aIp, cIp);
+ if (SUCCEEDED(hr))
+ {
+ VARIANT ipMasks;
+ hr = netIfWinCreateIpArrayVariantV4(&ipMasks, aMask, cIp);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &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, bstr_t(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ hr = pOutParams->Get(bstr_t(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, BSTR ObjPath)
+{
+ 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))
+ {
+ ComPtr<IWbemClassObject> pOutParams;
+
+ hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableDHCP"), NULL, NULL, 0, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ hr = pOutParams->Get(bstr_t(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;
+}
+
+static HRESULT netIfWinDhcpRediscover(IWbemServices * pSvc, BSTR ObjPath)
+{
+ 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))
+ {
+ ComPtr<IWbemClassObject> pOutParams;
+
+ hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"ReleaseDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ hr = pOutParams->Get(bstr_t(L"ReturnValue"), 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, ObjPath, bstr_t(L"RenewDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ VARIANT varReturnValue;
+ hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
+ Assert(SUCCEEDED(hr));
+ if (SUCCEEDED(hr))
+ {
+ // Assert(varReturnValue.vt == VT_UINT);
+ int winEr = varReturnValue.uintVal;
+ if (winEr == 0)
+ hr = S_OK;
+ else
+ hr = HRESULT_FROM_WIN32( winEr );
+ }
+ }
+ }
+ else
+ hr = HRESULT_FROM_WIN32( winEr );
+ }
+ }
+ }
+ SysFreeString(ClassName);
+ }
+ else
+ hr = HRESULT_FROM_WIN32(GetLastError());
+
+ return hr;
+}
+
+static HRESULT vboxNetCfgWinIsDhcpEnabled(IWbemClassObject * pAdapterConfig, BOOL *pEnabled)
+{
+ VARIANT vtEnabled;
+ HRESULT hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
+ if (SUCCEEDED(hr))
+ *pEnabled = vtEnabled.boolVal;
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(IN const GUID * pGuid, OUT PADAPTER_SETTINGS pSettings)
+{
+ HRESULT hr;
+ ComPtr <IWbemServices> pSvc;
+ 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)
+{
+ HRESULT hr;
+ ComPtr <IWbemServices> pSvc;
+ 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 bIsHostOnly;
+ hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
+ if (SUCCEEDED(hr))
+ {
+ if (bIsHostOnly)
+ {
+ in_addr aIp[1];
+ in_addr aMask[1];
+ aIp[0].S_un.S_addr = ip;
+ aMask[0].S_un.S_addr = mask;
+
+ BSTR ObjPath;
+ hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableStaticV4(pSvc, pGuid, ObjPath, 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, ObjPath, aGw, 1);
+ if (SUCCEEDED(hr))
+#endif
+ {
+ }
+ }
+ SysFreeString(ObjPath);
+ }
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ }
+ }
+ }
+
+ NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: returns 0x%x\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)
+{
+ HRESULT hr;
+ ComPtr <IWbemServices> pSvc;
+ hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ BOOL bIsHostOnly;
+ hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
+ if (SUCCEEDED(hr))
+ {
+ if (bIsHostOnly)
+ {
+ BSTR ObjPath;
+ hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinEnableDHCP(pSvc, ObjPath);
+ if (SUCCEEDED(hr))
+ {
+// hr = netIfWinUpdateConfig(pIf);
+ }
+ SysFreeString(ObjPath);
+ }
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ }
+ }
+ }
+
+
+ return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(IN const GUID *pGuid)
+{
+ HRESULT hr;
+ ComPtr <IWbemServices> pSvc;
+ hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IWbemClassObject> pAdapterConfig;
+ hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+ if (SUCCEEDED(hr))
+ {
+ BOOL bIsHostOnly;
+ hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
+ if (SUCCEEDED(hr))
+ {
+ if (bIsHostOnly)
+ {
+ BSTR ObjPath;
+ hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = netIfWinDhcpRediscover(pSvc, ObjPath);
+ if (SUCCEEDED(hr))
+ {
+ //hr = netIfWinUpdateConfig(pIf);
+ }
+ SysFreeString(ObjPath);
+ }
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ }
+ }
+ }
+
+
+ return hr;
+}
+
+static const char *vboxNetCfgWinAddrToStr(char *pszBuf, LPSOCKADDR pAddr)
+{
+ switch (pAddr->sa_family)
+ {
+ case AF_INET:
+ sprintf(pszBuf, "%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:
+ sprintf(pszBuf, "%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:
+ strcpy(pszBuf, "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)
+ {
+ char szBuf[80];
+
+ NonStandardLogFlow(("+- Enumerating adapter '%ls' %s\n", pAdapter->FriendlyName, pAdapter->AdapterName));
+ for (PIP_ADAPTER_PREFIX pPrefix = pAdapter->FirstPrefix; pPrefix; pPrefix = pPrefix->Next)
+ {
+ const char *pcszAddress = vboxNetCfgWinAddrToStr(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;
+ }
+ else
+ NonStandardLogFlow(("| +- %s %d: no conflict, moving on\n", pcszAddress, pPrefix->PrefixLength));
+ }
+ }
+}
+
+typedef struct _IPPROBE_CONTEXT
+{
+ ULONG Prefix;
+ bool bConflict;
+}IPPROBE_CONTEXT, *PIPPROBE_CONTEXT;
+
+#define IPPROBE_INIT(_pContext, _addr) \
+ ((_pContext)->bConflict = false, \
+ (_pContext)->Prefix = _addr)
+
+#define IPPROBE_INIT_STR(_pContext, _straddr) \
+ IPROBE_INIT(_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->bConflict = true;
+ return false;
+ }
+
+ return true;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(OUT PULONG pNetIp, OUT PULONG pNetMask)
+{
+ DWORD dwRc;
+ HRESULT hr = S_OK;
+ /*
+ * MSDN recommends to pre-allocate a 15KB buffer.
+ */
+ ULONG uBufLen = 15 * 1024;
+ PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
+ if (!pAddresses)
+ return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+ dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
+ if (dwRc == ERROR_BUFFER_OVERFLOW)
+ {
+ /* Impressive! More than 10 adapters! Get more memory and try again. */
+ free(pAddresses);
+ pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
+ if (!pAddresses)
+ return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+ dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
+ }
+ if (dwRc == NO_ERROR)
+ {
+ IPPROBE_CONTEXT Context;
+ const ULONG ip192168 = inet_addr("192.168.0.0");
+ srand(GetTickCount());
+
+ *pNetIp = 0;
+ *pNetMask = 0;
+
+ for (int i = 0; i < 255; i++)
+ {
+ ULONG ipProbe = rand()*255/RAND_MAX;
+ ipProbe = ip192168 | (ipProbe << 16);
+ unsigned char *a = (unsigned char *)&ipProbe;
+ NonStandardLogFlow(("probing %d.%d.%d.%d\n", a[0], a[1], a[2], a[3]));
+ IPPROBE_INIT(&Context, ipProbe);
+ vboxNetCfgWinEnumIpConfig(pAddresses, vboxNetCfgWinIpProbeCallback, &Context);
+ if (!Context.bConflict)
+ {
+ NonStandardLogFlow(("found unused net %d.%d.%d.%d\n", a[0], a[1], a[2], a[3]));
+ *pNetIp = ipProbe;
+ *pNetMask = inet_addr("255.255.255.0");
+ break;
+ }
+ }
+ if (*pNetIp == 0)
+ dwRc = ERROR_DHCP_ADDRESS_CONFLICT;
+ }
+ else
+ NonStandardLogFlow(("GetAdaptersAddresses err (%d)\n", dwRc));
+
+ if (pAddresses)
+ free(pAddresses);
+
+ 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 (0x%x)\n", hr));
+
+ pNcc->Release();
+ }
+ else if (hr == S_FALSE)
+ {
+ NonStandardLog("NetFlt is not installed currently\n");
+ }
+ else
+ {
+ NonStandardLogFlow(("FindComponent failed, hr (0x%x)\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 *apInfFullPaths, 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,
+ apInfFullPaths,
+ 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 pInfFullPath)
+{
+ NonStandardLog("NetAdp will be installed ...\n");
+ HRESULT hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETADP_ID,
+ &GUID_DEVCLASS_NET,
+ &pInfFullPath,
+ 1,
+ NULL);
+ return hr;
+}
+
+#define VBOXNETCFGWIN_NETLWF_ID L"oracle_VBoxNetLwf"
+
+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, hr (0x%x)\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}.
+ */
+ HKEY hNetKey;
+ DWORD dwMaxNumFilters = 0;
+ DWORD cbMaxNumFilters = sizeof(dwMaxNumFilters);
+ LONG hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ _T("SYSTEM\\CurrentControlSet\\Control\\Network"),
+ 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hNetKey);
+ if (SUCCEEDED(hr))
+ {
+ hr = RegQueryValueEx(hNetKey, _T("MaxNumFilters"), NULL, NULL,
+ (LPBYTE)&dwMaxNumFilters, &cbMaxNumFilters);
+ if (SUCCEEDED(hr) && cbMaxNumFilters == sizeof(dwMaxNumFilters) && dwMaxNumFilters == 8)
+ {
+ dwMaxNumFilters = 14;
+ hr = RegSetValueEx(hNetKey, _T("MaxNumFilters"), 0, REG_DWORD,
+ (LPBYTE)&dwMaxNumFilters, sizeof(dwMaxNumFilters));
+ if (SUCCEEDED(hr))
+ NonStandardLog("Adjusted the installed filter limit to 14...\n");
+ else
+ NonStandardLog("Failed to set MaxNumFilters, error code 0x%x\n", hr);
+ }
+ RegCloseKey(hNetKey);
+ }
+ else
+ {
+ NonStandardLog("Failed to open network key, error code 0x%x\n", hr);
+ }
+
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc,
+ IN LPCWSTR const pInfFullPath)
+{
+ 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,
+ &pInfFullPath,
+ 1,
+ NULL);
+ }
+ return hr;
+}
+
+#define VBOX_CONNECTION_NAME L"VirtualBox Host-Only Network"
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf)
+{
+ const WCHAR * pSuffix = wcsrchr( DevName, L'#' );
+ ULONG cbSize = sizeof(VBOX_CONNECTION_NAME);
+
+ if (pSuffix)
+ {
+ cbSize += (ULONG)wcslen(pSuffix) * 2;
+ cbSize += 2; /* for space */
+ }
+
+ if (*pcbBuf < cbSize)
+ {
+ *pcbBuf = cbSize;
+ return E_FAIL;
+ }
+
+ wcscpy(pBuf, VBOX_CONNECTION_NAME);
+ if (pSuffix)
+ {
+ wcscat(pBuf, L" ");
+ wcscat(pBuf, pSuffix);
+ }
+
+ return S_OK;
+}
+
+static BOOL vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
+{
+ RT_NOREF1(pNc);
+ INetCfgComponentBindings *pNetCfgBindings;
+ GUID *pGuid = (GUID*)pContext;
+
+ /* Get component's binding. */
+ HRESULT hr = pNcc->QueryInterface(IID_INetCfgComponentBindings, (PVOID*)&pNetCfgBindings);
+ if (SUCCEEDED(hr))
+ {
+ /* Get binding path enumerator reference. */
+ IEnumNetCfgBindingPath *pEnumNetCfgBindPath;
+ hr = pNetCfgBindings->EnumBindingPaths(EBP_BELOW, &pEnumNetCfgBindPath);
+ if (SUCCEEDED(hr))
+ {
+ bool bFoundIface = false;
+ hr = pEnumNetCfgBindPath->Reset();
+ do
+ {
+ INetCfgBindingPath *pNetCfgBindPath;
+ 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, hr (0x%x)\n", hr));
+ bFoundIface = 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, hr (0x%x)\n", hr2));
+ else if (_wcsnicmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID,
+ sizeof(VBOXNETCFGWIN_NETLWF_ID)/2))
+ NonStandardLogFlow(("Ignoring component %ls\n", pwszHwId));
+ else if ((hr2 = pNetCfgBindPath->IsEnabled()) != S_FALSE)
+ NonStandardLogFlow(("Already enabled binding path, hr (0x%x)\n", hr2));
+ else if ((hr2 = pNetCfgBindPath->Enable(TRUE)) != S_OK)
+ NonStandardLogFlow(("Failed to enable binding path, hr (0x%x)\n", hr2));
+ else
+ NonStandardLogFlow(("Enabled binding path\n"));
+ if (pwszHwId)
+ CoTaskMemFree(pwszHwId);
+ }
+ }
+ pNetCfgCompo->Release();
+ }
+ else
+ NonStandardLogFlow(("GetLowerComponent failed, hr (0x%x)\n", hr));
+ pNetCfgBindIfce->Release();
+ }
+ else
+ {
+ if (hr == S_FALSE) /* No more binding interfaces? */
+ hr = S_OK;
+ else
+ NonStandardLogFlow(("Next binding interface failed, hr (0x%x)\n", hr));
+ break;
+ }
+ } while (!bFoundIface);
+ pEnumNetCfgBindIface->Release();
+ }
+ else
+ NonStandardLogFlow(("EnumBindingInterfaces failed, hr (0x%x)\n", hr));
+ pNetCfgBindPath->Release();
+ }
+ else
+ {
+ if (hr == S_FALSE) /* No more binding paths? */
+ hr = S_OK;
+ else
+ NonStandardLogFlow(("Next bind path failed, hr (0x%x)\n", hr));
+ break;
+ }
+ } while (!bFoundIface);
+ pEnumNetCfgBindPath->Release();
+ }
+ else
+ NonStandardLogFlow(("EnumBindingPaths failed, hr (0x%x)\n", hr));
+ pNetCfgBindings->Release();
+ }
+ else
+ NonStandardLogFlow(("QueryInterface for IID_INetCfgComponentBindings failed, hr (0x%x)\n", hr));
+ return TRUE;
+}
+
+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 SetupDefaultQueueCallback(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 wGuid, PCWSTR wNewName)
+{
+ /* This is the GUID for the network connections folder. It is constant.
+ * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
+ const GUID CLSID_NetworkConnections = {
+ 0x7007ACC7, 0x3202, 0x11D1, {
+ 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
+ }
+ };
+
+ LPITEMIDLIST pidl = NULL;
+ IShellFolder *pShellFolder = NULL;
+ HRESULT hr;
+
+ /* Build the display name in the form "::{GUID}". */
+ if (wcslen(wGuid) >= MAX_PATH)
+ return E_INVALIDARG;
+ WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
+ swprintf(szAdapterGuid, L"::%ls", wGuid);
+
+ /* Create an instance of the network connections folder. */
+ hr = CoCreateInstance(CLSID_NetworkConnections, NULL,
+ CLSCTX_INPROC_SERVER, IID_IShellFolder,
+ reinterpret_cast<LPVOID *>(&pShellFolder));
+ /* Parse the display name. */
+ if (SUCCEEDED (hr))
+ {
+ hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
+ &pidl, NULL);
+ }
+ if (SUCCEEDED (hr))
+ {
+ hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
+ &pidl);
+ }
+
+ CoTaskMemFree (pidl);
+
+ if (pShellFolder)
+ pShellFolder->Release();
+
+ return hr;
+}
+
+/**
+ * Loads a system DLL.
+ *
+ * @returns Module handle or NULL
+ * @param pszName The DLL name.
+ */
+static HMODULE loadSystemDll(const char *pszName)
+{
+ char szPath[MAX_PATH];
+ UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
+ size_t cbName = strlen(pszName) + 1;
+ if (cchPath + 1 + cbName > sizeof(szPath))
+ return NULL;
+ szPath[cchPath] = '\\';
+ memcpy(&szPath[cchPath + 1], pszName, cbName);
+ return LoadLibraryA(szPath);
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection (LPWSTR pGuid, PCWSTR NewName)
+{
+ typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
+ lpHrRenameConnection RenameConnectionFunc = NULL;
+ HRESULT status;
+
+ /* First try the IShellFolder interface, which was unimplemented
+ * for the network connections folder before XP. */
+ status = rename_shellfolder (pGuid, NewName);
+ if (status == 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;
+ HINSTANCE hNetShell;
+ status = CLSIDFromString ((LPOLESTR) pGuid, &clsid);
+ if (FAILED(status))
+ return E_FAIL;
+ hNetShell = loadSystemDll("netshell.dll");
+ if (hNetShell == NULL)
+ return E_FAIL;
+ RenameConnectionFunc =
+ (lpHrRenameConnection) GetProcAddress (hNetShell,
+ "HrRenameConnection");
+ if (RenameConnectionFunc == NULL)
+ {
+ FreeLibrary (hNetShell);
+ return E_FAIL;
+ }
+ status = RenameConnectionFunc (&clsid, NewName);
+ FreeLibrary (hNetShell);
+ }
+ if (FAILED (status))
+ return status;
+
+ return S_OK;
+}
+
+#define DRIVERHWID _T("sun_VBoxNetAdp")
+
+#define SetErrBreak(strAndArgs) \
+ if (1) { \
+ hrc = E_FAIL; \
+ NonStandardLog strAndArgs; \
+ bstrError = bstr_printf strAndArgs; \
+ break; \
+ } else do {} while (0)
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pErrMsg)
+{
+ HRESULT hrc = S_OK;
+ bstr_t bstrError;
+
+ do
+ {
+ TCHAR lszPnPInstanceId [512] = {0};
+
+ /* We have to find the device instance ID through a registry search */
+
+ HKEY hkeyNetwork = 0;
+ HKEY hkeyConnection = 0;
+
+ do
+ {
+ WCHAR strRegLocation [256];
+ WCHAR wszGuid[50];
+
+ int length = StringFromGUID2(*pGUID, wszGuid, RT_ELEMENTS(wszGuid));
+ if (!length)
+ SetErrBreak(("Failed to create a Guid string"));
+
+ swprintf (strRegLocation,
+ L"SYSTEM\\CurrentControlSet\\Control\\Network\\"
+ L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+ wszGuid);
+
+ LONG status;
+ status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, strRegLocation, 0,
+ KEY_READ, &hkeyNetwork);
+ if ((status != ERROR_SUCCESS) || !hkeyNetwork)
+ SetErrBreak (("Host interface network is not found in registry (%S) [1]",
+ strRegLocation));
+
+ status = RegOpenKeyExW (hkeyNetwork, L"Connection", 0,
+ KEY_READ, &hkeyConnection);
+ if ((status != ERROR_SUCCESS) || !hkeyConnection)
+ SetErrBreak (("Host interface network is not found in registry (%S) [2]",
+ strRegLocation));
+
+ DWORD len = sizeof (lszPnPInstanceId);
+ DWORD dwKeyType;
+ status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
+ &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
+ if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
+ SetErrBreak (("Host interface network is not found in registry (%S) [3]",
+ strRegLocation));
+ }
+ 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
+ {
+ BOOL ok;
+ GUID netGuid;
+ SP_DEVINFO_DATA DeviceInfoData;
+ DWORD index = 0;
+ BOOL found = FALSE;
+ DWORD size = 0;
+
+ /* initialize the structure size */
+ DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
+
+ /* copy the net class GUID */
+ 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 */
+ while (TRUE)
+ {
+ TCHAR *deviceHwid;
+
+ ok = SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData);
+
+ if (!ok)
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ else
+ {
+ index++;
+ continue;
+ }
+ }
+
+ /* try to get the hardware ID registry property */
+ ok = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
+ &DeviceInfoData,
+ SPDRP_HARDWAREID,
+ NULL,
+ NULL,
+ 0,
+ &size);
+ if (!ok)
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ index++;
+ continue;
+ }
+
+ deviceHwid = (TCHAR *) malloc(size);
+ ok = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
+ &DeviceInfoData,
+ SPDRP_HARDWAREID,
+ NULL,
+ (PBYTE)deviceHwid,
+ size,
+ NULL);
+ if (!ok)
+ {
+ free(deviceHwid);
+ deviceHwid = NULL;
+ index++;
+ continue;
+ }
+ }
+ else
+ {
+ /* something is wrong. This shouldn't have worked with a NULL buffer */
+ index++;
+ continue;
+ }
+
+ for (TCHAR *t = deviceHwid;
+ t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
+ t += _tcslen(t) + 1)
+ {
+ if (!_tcsicmp(DRIVERHWID, t))
+ {
+ /* get the device instance ID */
+ TCHAR devId[MAX_DEVICE_ID_LEN];
+ if (CM_Get_Device_ID(DeviceInfoData.DevInst,
+ devId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
+ {
+ /* compare to what we determined before */
+ if (wcscmp(devId, lszPnPInstanceId) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (deviceHwid)
+ {
+ free (deviceHwid);
+ deviceHwid = NULL;
+ }
+
+ if (found)
+ break;
+
+ index++;
+ }
+
+ if (found == FALSE)
+ 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);
+
+ if (FAILED (hrc))
+ break;
+ }
+ while (0);
+
+ if (pErrMsg && bstrError.length())
+ *pErrMsg = bstrError.Detach();
+
+ return hrc;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pbRebootRequired, LPCWSTR pcsxwId)
+{
+ return VBoxDrvCfgDrvUpdate(pcsxwId, pcsxwInf, pbRebootRequired);
+}
+
+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;
+}
+
+static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile,
+ OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
+{
+ HRESULT hrc = S_OK;
+
+ HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
+ SP_DEVINFO_DATA DeviceInfoData;
+ PVOID pQueueCallbackContext = NULL;
+ DWORD ret = 0;
+ BOOL registered = FALSE;
+ BOOL destroyList = FALSE;
+ WCHAR pWCfgGuidString [50];
+ WCHAR DevName[256];
+ HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
+ bstr_t bstrError;
+
+ do
+ {
+ BOOL found = FALSE;
+ GUID netGuid;
+ SP_DRVINFO_DATA DriverInfoData;
+ SP_DEVINSTALL_PARAMS DeviceInstallParams;
+ TCHAR className [MAX_PATH];
+ DWORD index = 0;
+ PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
+ /* for our purposes, 2k buffer is more
+ * than enough to obtain the hardware ID
+ * of the VBoxNetAdp driver. */
+ DWORD detailBuf [2048];
+
+ DWORD cbSize;
+ DWORD dwValueType;
+
+ /* initialize the structure size */
+ DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
+ DriverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
+
+ /* copy the net class GUID */
+ 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 (0x%08X)",
+ GetLastError()));
+
+ /* get the class name from GUID */
+ BOOL fResult = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
+ if (!fResult)
+ SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
+ GetLastError()));
+
+ /* create a device info element and add the new device instance
+ * key to registry */
+ fResult = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
+ DICD_GENERATE_ID, &DeviceInfoData);
+ if (!fResult)
+ SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
+ GetLastError()));
+
+ /* select the newly created device info to be the currently
+ selected member */
+ fResult = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
+ if (!fResult)
+ SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
+ GetLastError()));
+
+ if (pInfPath)
+ {
+ /* get the device install parameters and disable filecopy */
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+ &DeviceInstallParams);
+ if (fResult)
+ {
+ memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
+ size_t pathLenght = wcslen(pInfPath) + 1/* null terminator */;
+ if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
+ {
+ memcpy(DeviceInstallParams.DriverPath, pInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
+
+ if (bIsInfPathFile)
+ {
+ DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
+ }
+
+ fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
+ &DeviceInstallParams);
+ if (!fResult)
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
+ break;
+ }
+ }
+ else
+ {
+ NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
+ break;
+ }
+ }
+ else
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
+ }
+ }
+
+ /* build a list of class drivers */
+ fResult = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
+ SPDIT_CLASSDRIVER);
+ if (!fResult)
+ SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
+ GetLastError()));
+
+ destroyList = TRUE;
+
+ /* enumerate the driver info list */
+ while (TRUE)
+ {
+ BOOL ret;
+
+ ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
+ SPDIT_CLASSDRIVER, index, &DriverInfoData);
+
+ /* if the function failed and GetLastError() returned
+ * ERROR_NO_MORE_ITEMS, then we have reached the end of the
+ * list. Otherwise there was something wrong with this
+ * particular driver. */
+ if (!ret)
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ else
+ {
+ index++;
+ continue;
+ }
+ }
+
+ pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
+ pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+
+ /* if we successfully find the hardware ID and it turns out to
+ * be the one for the loopback driver, then we are done. */
+ if (SetupDiGetDriverInfoDetail (hDeviceInfo,
+ &DeviceInfoData,
+ &DriverInfoData,
+ pDriverInfoDetail,
+ sizeof (detailBuf),
+ NULL))
+ {
+ TCHAR * t;
+
+ /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
+ * whole list and see if there is a match somewhere. */
+ t = pDriverInfoDetail->HardwareID;
+ while (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
+ {
+ if (!_tcsicmp(t, DRIVERHWID))
+ break;
+
+ t += _tcslen(t) + 1;
+ }
+
+ if (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ index ++;
+ }
+
+ if (!found)
+ SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
+
+ /* set the loopback driver to be the currently selected */
+ fResult = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
+ &DriverInfoData);
+ if (!fResult)
+ SetErrBreak(("SetupDiSetSelectedDriver failed (0x%08X)",
+ GetLastError()));
+
+ /* register the phantom device to prepare for install */
+ fResult = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
+ &DeviceInfoData);
+ if (!fResult)
+ {
+ DWORD err = GetLastError();
+ SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
+ err));
+ }
+
+ /* registered, but remove if errors occur in the following code */
+ registered = TRUE;
+
+ /* ask the installer if we can install the device */
+ fResult = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
+ &DeviceInfoData);
+ if (!fResult)
+ {
+ if (GetLastError() != ERROR_DI_DO_DEFAULT)
+ SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
+ GetLastError()));
+ /* that's fine */
+ }
+
+ /* get the device install parameters and disable filecopy */
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+ &DeviceInstallParams);
+ if (fResult)
+ {
+ pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
+ if (pQueueCallbackContext)
+ {
+ DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
+ DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
+ fResult = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+ &DeviceInstallParams);
+ if (!fResult)
+ {
+ DWORD winEr = GetLastError();
+ NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
+ }
+ Assert(fResult);
+ }
+ 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 */
+ fResult = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
+ &DeviceInfoData);
+ if (!fResult)
+ SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
+ GetLastError()));
+ /* get the device install parameters and disable filecopy */
+ DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+ fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+ &DeviceInstallParams);
+ if (fResult)
+ {
+ DeviceInstallParams.Flags |= DI_NOFILECOPY;
+ fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
+ &DeviceInstallParams);
+ if (!fResult)
+ SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
+ GetLastError()));
+ }
+
+ /*
+ * Register any device-specific co-installers for this device,
+ */
+ fResult = SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
+ hDeviceInfo,
+ &DeviceInfoData);
+ if (!fResult)
+ SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
+ GetLastError()));
+
+ /*
+ * install any installer-specified interfaces.
+ * and then do the real install
+ */
+ fResult = SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
+ hDeviceInfo,
+ &DeviceInfoData);
+ if (!fResult)
+ SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
+ GetLastError()));
+
+ fResult = SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
+ hDeviceInfo,
+ &DeviceInfoData);
+ if (!fResult)
+ SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
+ 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;
+
+ cbSize = sizeof(pWCfgGuidString);
+ ret = RegQueryValueExW (hkey, L"NetCfgInstanceId", NULL,
+ &dwValueType, (LPBYTE) pWCfgGuidString, &cbSize);
+ /* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
+ if (ret != ERROR_FILE_NOT_FOUND)
+ break;
+
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+ }
+
+ if (ret == ERROR_FILE_NOT_FOUND)
+ {
+ hrc = E_ABORT;
+ break;
+ }
+
+ /*
+ * We need to check 'hkey' after we check 'ret' to distinguish the case
+ * of failed SetupDiOpenDevRegKey from the case when we timed out.
+ */
+ if (hkey == INVALID_HANDLE_VALUE)
+ SetErrBreak(("SetupDiOpenDevRegKey failed (0x%08X)", GetLastError()));
+
+ if (ret != ERROR_SUCCESS)
+ SetErrBreak(("Querying NetCfgInstanceId failed (0x%08X)", ret));
+
+ NET_LUID luid;
+ HRESULT hSMRes = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
+
+ /* Close the key as soon as possible. See @bugref{7973}. */
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+
+ if (FAILED(hSMRes))
+ {
+ /*
+ * 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, hr (0x%x)\n", hSMRes));
+ }
+ else
+ {
+ /*
+ * Set default metric value of interface to fix multicast issue
+ * See @bugref{6379} for details.
+ */
+ hSMRes = vboxNetCfgWinSetupMetric(&luid);
+ if (FAILED(hSMRes))
+ {
+ /*
+ * 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, hr (0x%x)\n", hSMRes));
+ }
+ }
+
+
+#ifndef VBOXNETCFG_DELAYEDRENAME
+ /*
+ * 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)DevName, /*OUT PBYTE PropertyBuffer,*/
+ sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
+ NULL /*OUT PDWORD RequiredSize OPTIONAL*/))
+ {
+ int err = GetLastError();
+ if (err != ERROR_INVALID_DATA)
+ {
+ SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
+ err));
+ }
+
+ if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
+ SPDRP_DEVICEDESC, /* IN DWORD Property,*/
+ NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
+ (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
+ sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
+ NULL /*OUT PDWORD RequiredSize OPTIONAL*/
+ ))
+ {
+ err = GetLastError();
+ SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
+ err));
+ }
+ }
+#else /* !VBOXNETCFG_DELAYEDRENAME */
+ /* Re-use DevName for device instance id retrieval. */
+ if (!SetupDiGetDeviceInstanceId(hDeviceInfo, &DeviceInfoData, DevName, RT_ELEMENTS(DevName), &cbSize))
+ SetErrBreak (("SetupDiGetDeviceInstanceId failed (0x%08X)",
+ 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 (ret != 0 && registered)
+ SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
+
+ SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
+
+ /* destroy the driver info list */
+ if (destroyList)
+ SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData,
+ SPDIT_CLASSDRIVER);
+ /* clean up the device info set */
+ SetupDiDestroyDeviceInfoList (hDeviceInfo);
+ }
+
+ /* return the network connection GUID on success */
+ if (SUCCEEDED(hrc))
+ {
+ HRESULT hr;
+ INetCfg *pNetCfg = NULL;
+ LPWSTR lpszApp = NULL;
+#ifndef VBOXNETCFG_DELAYEDRENAME
+ WCHAR ConnectionName[128];
+ ULONG cbName = sizeof(ConnectionName);
+
+ hr = VBoxNetCfgWinGenHostonlyConnectionName(DevName, ConnectionName, &cbName);
+ if (SUCCEEDED(hr))
+ hr = VBoxNetCfgWinRenameConnection(pWCfgGuidString, ConnectionName);
+#endif
+ if (lppszName)
+ {
+ *lppszName = SysAllocString((const OLECHAR *) DevName);
+ if (!*lppszName)
+ {
+ NonStandardLogFlow(("SysAllocString failed\n"));
+ hrc = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ }
+
+ if (pGuid)
+ {
+ hrc = CLSIDFromString(pWCfgGuidString, (LPCLSID)pGuid);
+ if (FAILED(hrc))
+ NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
+ }
+
+ hr = 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 */
+ &lpszApp);
+ if (hr == S_OK)
+ {
+ hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
+ &GUID_DEVCLASS_NETSERVICE,
+ vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
+ pGuid);
+ if (SUCCEEDED(hr))
+ {
+ hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
+ &GUID_DEVCLASS_NETTRANS,
+ vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
+ pGuid);
+ if (SUCCEEDED(hr))
+ hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
+ &GUID_DEVCLASS_NETCLIENT,
+ vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
+ pGuid);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pNetCfg->Apply();
+ }
+ else
+ NonStandardLogFlow(("Enumeration failed, hr 0x%x\n", hr));
+ VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
+ }
+ else if (hr == NETCFG_E_NO_WRITE_LOCK && lpszApp)
+ {
+ NonStandardLogFlow(("Application %ws is holding the lock, failed\n", lpszApp));
+ CoTaskMemFree(lpszApp);
+ }
+ else
+ NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hr 0x%x\n", hr));
+ }
+
+ if (pErrMsg && bstrError.length())
+ *pErrMsg = bstrError.Detach();
+
+ return hrc;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile,
+ OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
+{
+ HRESULT hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pGuid, lppszName, pErrMsg);
+ 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(pInfPath, bIsInfPathFile, pGuid, lppszName, pErrMsg);
+ 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 = NULL;
+ SC_HANDLE hService = NULL;
+
+ hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
+ if (hSCM)
+ {
+ hService = OpenService(hSCM, _T("NetSetupSvc"), GENERIC_READ);
+ if (hService)
+ {
+ for (int retries = 0; retries < 60 && !vboxNetCfgWinIsNetSetupStopped(hService); ++retries)
+ Sleep(1000);
+ CloseServiceHandle(hService);
+ hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pGuid, lppszName, pErrMsg);
+ }
+ else
+ NonStandardLogFlow(("OpenService failed (0x%x)\n", GetLastError()));
+ CloseServiceHandle(hSCM);
+ }
+ else
+ NonStandardLogFlow(("OpenSCManager failed (0x%x)", GetLastError()));
+ /* Give up and report the error. */
+ if (hrc == E_ABORT)
+ {
+ if (pErrMsg)
+ {
+ bstr_t bstrError = bstr_printf("Querying NetCfgInstanceId failed (0x%08X)", ERROR_FILE_NOT_FOUND);
+ *pErrMsg = bstrError.Detach();
+ }
+ hrc = E_FAIL;
+ }
+ }
+ }
+ return hrc;
+}
+
+
+HRESULT vboxLoadIpHelpFunctions(HINSTANCE& pIpHlpInstance)
+{
+ Assert(pIpHlpInstance != NULL);
+
+ pIpHlpInstance = loadSystemDll("Iphlpapi.dll");
+ if (pIpHlpInstance == NULL)
+ return E_FAIL;
+
+ g_pfnInitializeIpInterfaceEntry =
+ (PFNINITIALIZEIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "InitializeIpInterfaceEntry");
+ Assert(g_pfnInitializeIpInterfaceEntry);
+
+ if (g_pfnInitializeIpInterfaceEntry)
+ {
+ g_pfnGetIpInterfaceEntry =
+ (PFNGETIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "GetIpInterfaceEntry");
+ Assert(g_pfnGetIpInterfaceEntry);
+ }
+
+ if (g_pfnGetIpInterfaceEntry)
+ {
+ g_pfnSetIpInterfaceEntry =
+ (PFNSETIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "SetIpInterfaceEntry");
+ Assert(g_pfnSetIpInterfaceEntry);
+ }
+
+ if (g_pfnInitializeIpInterfaceEntry == NULL)
+ {
+ FreeLibrary(pIpHlpInstance);
+ pIpHlpInstance = NULL;
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+
+HRESULT vboxNetCfgWinGetLoopbackMetric(OUT int* Metric)
+{
+ HRESULT rc = S_OK;
+ MIB_IPINTERFACE_ROW row;
+
+ Assert(g_pfnInitializeIpInterfaceEntry != NULL);
+ Assert(g_pfnGetIpInterfaceEntry != NULL);
+
+ g_pfnInitializeIpInterfaceEntry(&row);
+ row.Family = AF_INET;
+ row.InterfaceLuid.Info.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
+
+ rc = g_pfnGetIpInterfaceEntry(&row);
+ if (rc != NO_ERROR)
+ return HRESULT_FROM_WIN32(rc);
+
+ *Metric = row.Metric;
+
+ return rc;
+}
+
+
+HRESULT vboxNetCfgWinSetInterfaceMetric(
+ IN NET_LUID* pInterfaceLuid,
+ IN DWORD metric)
+{
+ MIB_IPINTERFACE_ROW newRow;
+
+ Assert(g_pfnInitializeIpInterfaceEntry != NULL);
+ Assert(g_pfnSetIpInterfaceEntry != NULL);
+
+ 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
+ return HRESULT_FROM_WIN32(g_pfnSetIpInterfaceEntry(&newRow));
+}
+
+
+HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID)
+{
+ HRESULT res = S_OK;
+ DWORD luidIndex = 0;
+ DWORD ifType = 0;
+ DWORD cbSize = sizeof(luidIndex);
+ DWORD dwValueType = REG_DWORD;
+
+ if (pLUID == NULL)
+ return E_INVALIDARG;
+
+ res = RegQueryValueExW(hKey, L"NetLuidIndex", NULL,
+ &dwValueType, (LPBYTE)&luidIndex, &cbSize);
+ if (res != 0)
+ return HRESULT_FROM_WIN32(res);
+
+ cbSize = sizeof(ifType);
+ dwValueType = REG_DWORD;
+ res = RegQueryValueExW(hKey, L"*IfType", NULL,
+ &dwValueType, (LPBYTE)&ifType, &cbSize);
+ if (res != 0)
+ return HRESULT_FROM_WIN32(res);
+
+ ZeroMemory(pLUID, sizeof(NET_LUID));
+ pLUID->Info.IfType = ifType;
+ pLUID->Info.NetLuidIndex = luidIndex;
+
+ return res;
+}
+
+
+HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid)
+{
+ HINSTANCE hModule = NULL;
+ HRESULT rc = vboxLoadIpHelpFunctions(hModule);
+ if (SUCCEEDED(rc))
+ {
+ int loopbackMetric;
+ rc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
+ if (SUCCEEDED(rc))
+ rc = vboxNetCfgWinSetInterfaceMetric(pLuid, loopbackMetric - 1);
+ }
+
+ g_pfnInitializeIpInterfaceEntry = NULL;
+ g_pfnSetIpInterfaceEntry = NULL;
+ g_pfnGetIpInterfaceEntry = NULL;
+
+ FreeLibrary(hModule);
+ return rc;
+}
+#ifdef VBOXNETCFG_DELAYEDRENAME
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pwszId, OUT BSTR *pDevName)
+{
+ HRESULT hr = S_OK;
+ WCHAR wszDevName[256];
+ WCHAR wszConnectionNewName[128];
+ ULONG cbName = sizeof(wszConnectionNewName);
+
+ HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
+ if (hDevInfo != INVALID_HANDLE_VALUE)
+ {
+ SP_DEVINFO_DATA DevInfoData;
+
+ DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+ if (SetupDiOpenDeviceInfo(hDevInfo, pwszId, NULL, 0, &DevInfoData))
+ {
+ DWORD err = ERROR_SUCCESS;
+ if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData,
+ SPDRP_FRIENDLYNAME, NULL,
+ (PBYTE)wszDevName, RT_ELEMENTS(wszDevName), NULL))
+ {
+ err = GetLastError();
+ if (err == ERROR_INVALID_DATA)
+ {
+ err = SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData,
+ SPDRP_DEVICEDESC, NULL,
+ (PBYTE)wszDevName, RT_ELEMENTS(wszDevName), NULL)
+ ? ERROR_SUCCESS
+ : GetLastError();
+ }
+ }
+ if (err == ERROR_SUCCESS)
+ {
+ hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionNewName, &cbName);
+ 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
+