VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp@ 104760

Last change on this file since 104760 was 99828, checked in by vboxsync, 20 months ago

*: A bunch of adjustments that allows using /permissive- with Visual C++ (qt 6.x necessity).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 144.1 KB
Line 
1/* $Id: VBoxNetCfg.cpp 99828 2023-05-17 13:48:57Z vboxsync $ */
2/** @file
3 * VBoxNetCfg.cpp - Network Configuration API.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define _WIN32_DCOM
42
43#include "VBox/VBoxNetCfg-win.h"
44#include "VBox/VBoxDrvCfg-win.h"
45
46#include <devguid.h>
47#include <regstr.h>
48#include <iprt/win/shlobj.h>
49#include <cfgmgr32.h>
50#include <iprt/win/objbase.h>
51
52#include <Wbemidl.h>
53
54#include <iprt/win/winsock2.h>
55#include <iprt/win/ws2tcpip.h>
56#include <ws2ipdef.h>
57#include <iprt/win/netioapi.h>
58#include <iprt/win/iphlpapi.h>
59
60#include <iprt/asm.h>
61#include <iprt/assertcompile.h>
62#include <iprt/mem.h>
63#include <iprt/list.h>
64#include <iprt/rand.h>
65#include <iprt/string.h>
66#include <iprt/utf16.h>
67#include <VBox/com/string.h>
68
69
70/*********************************************************************************************************************************
71* Defined Constants And Macros *
72*********************************************************************************************************************************/
73#ifndef Assert /** @todo r=bird: where would this be defined? */
74//# ifdef DEBUG
75//# define Assert(_expr) assert(_expr)
76//# else
77//# define Assert(_expr) do{ }while (0)
78//# endif
79# define Assert _ASSERT
80# define AssertMsg(expr, msg) do{}while (0)
81#endif
82
83#define NonStandardLog DoLogging
84#define NonStandardLogFlow(x) DoLogging x
85
86#define SetErrBreak(strAndArgs) \
87 if (1) { \
88 hrc = E_FAIL; \
89 NonStandardLog strAndArgs; \
90 bstrError.printfNoThrow strAndArgs; \
91 break; \
92 } else do {} while (0)
93
94
95#define VBOXNETCFGWIN_NETADP_ID_SZ "sun_VBoxNetAdp"
96#define VBOXNETCFGWIN_NETADP_ID_WSZ RT_CONCAT(L,VBOXNETCFGWIN_NETADP_ID_SZ)
97#define DRIVERHWID VBOXNETCFGWIN_NETADP_ID_WSZ
98
99/* We assume the following name matches the device description in vboxnetadp6.inf */
100#define HOSTONLY_ADAPTER_NAME_SZ "VirtualBox Host-Only Ethernet Adapter"
101#define HOSTONLY_ADAPTER_NAME_WSZ RT_CONCAT(L,HOSTONLY_ADAPTER_NAME_SZ)
102
103#define VBOX_CONNECTION_NAME_SZ "VirtualBox Host-Only Network"
104#define VBOX_CONNECTION_NAME_WSZ RT_CONCAT(L,VBOX_CONNECTION_NAME_SZ)
105
106#define VBOXNETCFGWIN_NETLWF_ID L"oracle_VBoxNetLwf"
107
108
109
110/*********************************************************************************************************************************
111* Global Variables *
112*********************************************************************************************************************************/
113static PFNVBOXNETCFGLOGGER volatile g_pfnLogger = NULL;
114
115/*
116 * Wrappers for HelpAPI functions
117 */
118typedef void FNINITIALIZEIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
119typedef FNINITIALIZEIPINTERFACEENTRY *PFNINITIALIZEIPINTERFACEENTRY;
120
121typedef NETIOAPI_API FNGETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
122typedef FNGETIPINTERFACEENTRY *PFNGETIPINTERFACEENTRY;
123
124typedef NETIOAPI_API FNSETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
125typedef FNSETIPINTERFACEENTRY *PFNSETIPINTERFACEENTRY;
126
127
128/*********************************************************************************************************************************
129* Internal Functions *
130*********************************************************************************************************************************/
131static PFNINITIALIZEIPINTERFACEENTRY g_pfnInitializeIpInterfaceEntry = NULL;
132static PFNGETIPINTERFACEENTRY g_pfnGetIpInterfaceEntry = NULL;
133static PFNSETIPINTERFACEENTRY g_pfnSetIpInterfaceEntry = NULL;
134
135static void DoLogging(const char *pszString, ...);
136
137/*
138 * Forward declaration for using vboxNetCfgWinSetupMetric()
139 */
140static HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID *pLuid);
141static HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID *pLUID);
142
143
144
145static HRESULT vboxNetCfgWinINetCfgLock(IN INetCfg *pNetCfg,
146 IN LPCWSTR pszwClientDescription,
147 IN DWORD cmsTimeout,
148 OUT LPWSTR *ppszwClientDescription)
149{
150 INetCfgLock *pLock;
151 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID *)&pLock);
152 if (FAILED(hr))
153 {
154 NonStandardLogFlow(("QueryInterface failed: %Rhrc\n", hr));
155 return hr;
156 }
157
158 hr = pLock->AcquireWriteLock(cmsTimeout, pszwClientDescription, ppszwClientDescription);
159 if (hr == S_FALSE)
160 NonStandardLogFlow(("Write lock busy\n"));
161 else if (FAILED(hr))
162 NonStandardLogFlow(("AcquireWriteLock failed: %Rhrc\n", hr));
163
164 pLock->Release();
165 return hr;
166}
167
168static HRESULT vboxNetCfgWinINetCfgUnlock(IN INetCfg *pNetCfg)
169{
170 INetCfgLock *pLock;
171 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID *)&pLock);
172 if (FAILED(hr))
173 {
174 NonStandardLogFlow(("QueryInterface failed: %Rhrc\n", hr));
175 return hr;
176 }
177
178 hr = pLock->ReleaseWriteLock();
179 if (FAILED(hr))
180 NonStandardLogFlow(("ReleaseWriteLock failed: %Rhrc\n", hr));
181
182 pLock->Release();
183 return hr;
184}
185
186VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(OUT INetCfg **ppNetCfg,
187 IN BOOL fGetWriteLock,
188 IN LPCWSTR pszwClientDescription,
189 IN DWORD cmsTimeout,
190 OUT LPWSTR *ppszwClientDescription)
191{
192 INetCfg *pNetCfg = NULL;
193 HRESULT hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (PVOID *)&pNetCfg);
194 if (FAILED(hr))
195 {
196 NonStandardLogFlow(("CoCreateInstance failed: %Rhrc\n", hr));
197 return hr;
198 }
199
200 if (fGetWriteLock)
201 {
202 hr = vboxNetCfgWinINetCfgLock(pNetCfg, pszwClientDescription, cmsTimeout, ppszwClientDescription);
203 if (hr == S_FALSE)
204 {
205 NonStandardLogFlow(("Write lock is busy\n", hr));
206 hr = NETCFG_E_NO_WRITE_LOCK;
207 }
208 }
209
210 if (SUCCEEDED(hr))
211 {
212 hr = pNetCfg->Initialize(NULL);
213 if (SUCCEEDED(hr))
214 {
215 *ppNetCfg = pNetCfg;
216 return S_OK;
217 }
218 NonStandardLogFlow(("Initialize failed: %Rhrc\n", hr));
219 }
220
221 pNetCfg->Release();
222 return hr;
223}
224
225VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pNetCfg, IN BOOL fHasWriteLock)
226{
227 if (!pNetCfg) /* If network config has been released already, just bail out. */
228 {
229 NonStandardLogFlow(("Warning: No network config given but write lock is set to TRUE\n"));
230 return S_OK;
231 }
232
233 HRESULT hr = pNetCfg->Uninitialize();
234 if (FAILED(hr))
235 {
236 NonStandardLogFlow(("Uninitialize failed: %Rhrc\n", hr));
237 /* Try to release the write lock below. */
238 }
239
240 if (fHasWriteLock)
241 {
242 HRESULT hr2 = vboxNetCfgWinINetCfgUnlock(pNetCfg);
243 if (FAILED(hr2))
244 NonStandardLogFlow(("vboxNetCfgWinINetCfgUnlock failed: %Rhrc\n", hr2));
245 if (SUCCEEDED(hr))
246 hr = hr2;
247 }
248
249 pNetCfg->Release();
250 return hr;
251}
252
253static HRESULT vboxNetCfgWinGetComponentByGuidEnum(IEnumNetCfgComponent *pEnumNcc,
254 IN const GUID *pGuid,
255 OUT INetCfgComponent **ppNcc)
256{
257 HRESULT hr = pEnumNcc->Reset();
258 if (FAILED(hr))
259 {
260 NonStandardLogFlow(("Reset failed: %Rhrc\n", hr));
261 return hr;
262 }
263
264 INetCfgComponent *pNcc = NULL;
265 while ((hr = pEnumNcc->Next(1, &pNcc, NULL)) == S_OK)
266 {
267 ULONG uComponentStatus = 0;
268 hr = pNcc->GetDeviceStatus(&uComponentStatus);
269 if (SUCCEEDED(hr))
270 {
271 if (uComponentStatus == 0)
272 {
273 GUID NccGuid;
274 hr = pNcc->GetInstanceGuid(&NccGuid);
275
276 if (SUCCEEDED(hr))
277 {
278 if (NccGuid == *pGuid)
279 {
280 /* found the needed device */
281 *ppNcc = pNcc;
282 break;
283 }
284 }
285 else
286 NonStandardLogFlow(("GetInstanceGuid failed: %Rhrc\n", hr));
287 }
288 }
289
290 pNcc->Release();
291 }
292 return hr;
293}
294
295VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc,
296 IN const GUID *pguidClass,
297 IN const GUID * pComponentGuid,
298 OUT INetCfgComponent **ppncc)
299{
300 IEnumNetCfgComponent *pEnumNcc = NULL;
301 HRESULT hr = pNc->EnumComponents(pguidClass, &pEnumNcc);
302 if (SUCCEEDED(hr))
303 {
304 hr = vboxNetCfgWinGetComponentByGuidEnum(pEnumNcc, pComponentGuid, ppncc);
305 if (hr == S_FALSE)
306 NonStandardLogFlow(("Component not found\n"));
307 else if (FAILED(hr))
308 NonStandardLogFlow(("vboxNetCfgWinGetComponentByGuidEnum failed: %Rhrc\n", hr));
309 pEnumNcc->Release();
310 }
311 else
312 NonStandardLogFlow(("EnumComponents failed: %Rhrc\n", hr));
313 return hr;
314}
315
316static HRESULT vboxNetCfgWinQueryInstaller(IN INetCfg *pNetCfg, IN const GUID *pguidClass, INetCfgClassSetup **ppSetup)
317{
318 HRESULT hr = pNetCfg->QueryNetCfgClass(pguidClass, IID_INetCfgClassSetup, (void **)ppSetup);
319 if (FAILED(hr))
320 NonStandardLogFlow(("QueryNetCfgClass failed: %Rhrc\n", hr));
321 return hr;
322}
323
324VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId,
325 IN const GUID *pguidClass, OUT INetCfgComponent **ppComponent)
326{
327 INetCfgClassSetup *pSetup;
328 HRESULT hr = vboxNetCfgWinQueryInstaller(pNetCfg, pguidClass, &pSetup);
329 if (FAILED(hr))
330 {
331 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed: %Rhrc\n", hr));
332 return hr;
333 }
334
335 OBO_TOKEN Token;
336 RT_ZERO(Token);
337 Token.Type = OBO_USER;
338
339 INetCfgComponent *pTempComponent = NULL;
340 hr = pSetup->Install(pszwComponentId, &Token,
341 0, /* IN DWORD dwSetupFlags */
342 0, /* IN DWORD dwUpgradeFromBuildNo */
343 NULL, /* IN LPCWSTR pszwAnswerFile */
344 NULL, /* IN LPCWSTR pszwAnswerSections */
345 &pTempComponent);
346 if (SUCCEEDED(hr))
347 {
348 if (pTempComponent != NULL)
349 {
350 /*
351 * Set default metric value of interface to fix multicast issue
352 * See @bugref{6379} for details.
353 */
354 HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
355 HRESULT hrc2 = pTempComponent->OpenParamKey(&hKey);
356
357 /* Set default metric value for host-only interface only */
358 if ( SUCCEEDED(hrc2)
359 && hKey != (HKEY)INVALID_HANDLE_VALUE
360 /* Original was weird: && wcsnicmp(pszwComponentId, VBOXNETCFGWIN_NETADP_ID_WSZ, 256) == 0) */
361 && RTUtf16ICmpAscii(pszwComponentId, VBOXNETCFGWIN_NETADP_ID_SZ) == 0)
362 {
363 NET_LUID luid;
364 hrc2 = vboxNetCfgWinGetInterfaceLUID(hKey, &luid);
365
366 /* Close the key as soon as possible. See @bugref{7973}. */
367 RegCloseKey(hKey);
368 hKey = (HKEY)INVALID_HANDLE_VALUE;
369
370 if (FAILED(hrc2))
371 {
372 /*
373 * The setting of Metric is not very important functionality,
374 * So we will not break installation process due to this error.
375 */
376 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! vboxNetCfgWinGetInterfaceLUID failed, default metric for new interface will not be set: %Rhrc\n", hrc2));
377 }
378 else
379 {
380 hrc2 = vboxNetCfgWinSetupMetric(&luid);
381 if (FAILED(hrc2))
382 {
383 /*
384 * The setting of Metric is not very important functionality,
385 * So we will not break installation process due to this error.
386 */
387 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! vboxNetCfgWinSetupMetric failed, default metric for new interface will not be set: %Rhrc\n", hrc2));
388 }
389 }
390 }
391 if (hKey != (HKEY)INVALID_HANDLE_VALUE)
392 RegCloseKey(hKey);
393 if (ppComponent != NULL)
394 *ppComponent = pTempComponent;
395 else
396 pTempComponent->Release();
397 }
398
399 /* ignore the apply failure */
400 HRESULT hrc3 = pNetCfg->Apply();
401 Assert(hrc3 == S_OK);
402 if (hrc3 != S_OK)
403 NonStandardLogFlow(("Apply failed: %Rhrc\n", hrc3));
404 }
405 else
406 NonStandardLogFlow(("Install failed: %Rhrc\n", hr));
407
408 pSetup->Release();
409 return hr;
410}
411
412static HRESULT vboxNetCfgWinInstallInfAndComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
413 IN LPCWSTR const *apwszInfPaths, IN UINT cInfPaths,
414 OUT INetCfgComponent **ppComponent)
415{
416 NonStandardLogFlow(("Installing %u INF files ...\n", cInfPaths));
417
418 HRESULT hr = S_OK;
419 UINT cFilesProcessed = 0;
420 for (; cFilesProcessed < cInfPaths; cFilesProcessed++)
421 {
422 NonStandardLogFlow(("Installing INF file \"%ls\" ...\n", apwszInfPaths[cFilesProcessed]));
423 hr = VBoxDrvCfgInfInstall(apwszInfPaths[cFilesProcessed]);
424 if (FAILED(hr))
425 {
426 NonStandardLogFlow(("VBoxNetCfgWinInfInstall failed: %Rhrc\n", hr));
427 break;
428 }
429 }
430
431 if (SUCCEEDED(hr))
432 {
433 hr = VBoxNetCfgWinInstallComponent(pNetCfg, pszwComponentId, pguidClass, ppComponent);
434 if (FAILED(hr))
435 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent failed: %Rhrc\n", hr));
436 }
437
438 if (FAILED(hr))
439 {
440 NonStandardLogFlow(("Installation failed, rolling back installation set ...\n"));
441
442 do
443 {
444 HRESULT hr2 = VBoxDrvCfgInfUninstall(apwszInfPaths[cFilesProcessed], 0);
445 if (FAILED(hr2))
446 NonStandardLogFlow(("VBoxDrvCfgInfUninstall failed: %Rhrc\n", hr2));
447 /* Keep going. */
448 if (!cFilesProcessed)
449 break;
450 } while (cFilesProcessed--);
451
452 NonStandardLogFlow(("Rollback complete\n"));
453 }
454
455 return hr;
456}
457
458VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUninstallComponent(IN INetCfg *pNetCfg, IN INetCfgComponent *pComponent)
459{
460 GUID GuidClass;
461 HRESULT hr = pComponent->GetClassGuid(&GuidClass);
462 if (FAILED(hr))
463 {
464 NonStandardLogFlow(("GetClassGuid failed: %Rhrc\n", hr));
465 return hr;
466 }
467
468 INetCfgClassSetup *pSetup = NULL;
469 hr = vboxNetCfgWinQueryInstaller(pNetCfg, &GuidClass, &pSetup);
470 if (FAILED(hr))
471 {
472 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed: %Rhrc\n", hr));
473 return hr;
474 }
475
476 OBO_TOKEN Token;
477 RT_ZERO(Token);
478 Token.Type = OBO_USER;
479
480 hr = pSetup->DeInstall(pComponent, &Token, NULL /* OUT LPWSTR *pmszwRefs */);
481 if (SUCCEEDED(hr))
482 {
483 hr = pNetCfg->Apply();
484 if (FAILED(hr))
485 NonStandardLogFlow(("Apply failed: %Rhrc\n", hr));
486 }
487 else
488 NonStandardLogFlow(("DeInstall failed: %Rhrc\n", hr));
489
490 if (pSetup)
491 pSetup->Release();
492 return hr;
493}
494
495typedef BOOL (*PFN_VBOXNETCFGWIN_NETCFGENUM_CALLBACK_T)(IN INetCfg *pNetCfg, IN INetCfgComponent *pNetCfgComponent,
496 PVOID pvContext);
497
498static HRESULT vboxNetCfgWinEnumNetCfgComponents(IN INetCfg *pNetCfg,
499 IN const GUID *pguidClass,
500 PFN_VBOXNETCFGWIN_NETCFGENUM_CALLBACK_T pfnCallback,
501 PVOID pContext)
502{
503 IEnumNetCfgComponent *pEnumComponent = NULL;
504 HRESULT hr = pNetCfg->EnumComponents(pguidClass, &pEnumComponent);
505 if (SUCCEEDED(hr))
506 {
507 INetCfgComponent *pNetCfgComponent;
508 hr = pEnumComponent->Reset();
509 for (;;)
510 {
511 hr = pEnumComponent->Next(1, &pNetCfgComponent, NULL);
512 if (hr == S_OK)
513 {
514// ULONG uComponentStatus;
515// hr = pNcc->GetDeviceStatus(&uComponentStatus);
516// if (SUCCEEDED(hr))
517 BOOL fResult = FALSE;
518 if (pNetCfgComponent)
519 {
520 fResult = pfnCallback(pNetCfg, pNetCfgComponent, pContext);
521 pNetCfgComponent->Release();
522 }
523
524 if (!fResult)
525 break;
526 }
527 else
528 {
529 if (hr == S_FALSE)
530 hr = S_OK; /* no more components */
531 else
532 NonStandardLogFlow(("Next failed: %Rhrc\n", hr));
533 break;
534 }
535 }
536 pEnumComponent->Release();
537 }
538 return hr;
539}
540
541/** PFNVBOXNETCFGWINNETENUMCALLBACK */
542static BOOL vboxNetCfgWinRemoveAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pvContext)
543{
544 RT_NOREF1(pvContext);
545
546 SP_REMOVEDEVICE_PARAMS rmdParams;
547 RT_ZERO(rmdParams);
548 rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
549 rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
550 rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
551
552 if (SetupDiSetClassInstallParams(hDevInfo,pDev,
553 &rmdParams.ClassInstallHeader, sizeof(rmdParams)))
554 {
555 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
556 {
557#ifndef VBOXNETCFG_DELAYEDRENAME
558 /* Figure out NetCfgInstanceId. */
559 HKEY hKey = SetupDiOpenDevRegKey(hDevInfo,
560 pDev,
561 DICS_FLAG_GLOBAL,
562 0,
563 DIREG_DRV,
564 KEY_READ);
565 if (hKey == INVALID_HANDLE_VALUE)
566 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiOpenDevRegKey failed with error %u\n",
567 GetLastError()));
568 else
569 {
570 WCHAR wszCfgGuidString[50] = { L'' };
571 DWORD cbSize = sizeof(wszCfgGuidString) - sizeof(WCHAR); /* make sure we get a terminated string back */
572 DWORD dwValueType = 0;
573 LSTATUS lrc = RegQueryValueExW(hKey, L"NetCfgInstanceId", NULL, &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
574 if (lrc == ERROR_SUCCESS)
575 {
576 /** @todo r=bird: original didn't check the type here, just assumed it was a
577 * valid zero terminated string. (zero term handled by -sizeof(WHCAR) above now). */
578 if (dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ || dwValueType == REG_EXPAND_SZ)
579 {
580 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Processing device ID \"%ls\"\n",
581 wszCfgGuidString));
582
583 /* Figure out device name. */
584 WCHAR wszDevName[256 + 1] = {0};
585 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev, SPDRP_FRIENDLYNAME, NULL, (PBYTE)wszDevName,
586 sizeof(wszDevName) - sizeof(WCHAR) /* yes, in bytes */, NULL))
587 {
588 /*
589 * Rename the connection before removing the device. This will
590 * hopefully prevent an error when we will be attempting
591 * to rename a newly created connection (see @bugref{6740}).
592 */
593 WCHAR wszNewName[RT_ELEMENTS(wszDevName) + 128 /* ensure sufficient buffer */];
594 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszNewName,
595 RT_ELEMENTS(wszNewName) - 10 /*removed++*/,
596 NULL);
597 RTUtf16CatAscii(wszNewName, sizeof(wszNewName), " removed");
598 if (SUCCEEDED(hr))
599 hr = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszNewName);
600 //NonStandardLogFlow(("VBoxNetCfgWinRenameConnection(%S,%S) => 0x%x\n", wszCfgGuidString, TempName, hr_tmp));
601 }
602 else
603 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Failed to get friendly name for device \"%ls\"\n",
604 wszCfgGuidString));
605 }
606 else
607 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Friendly name for \"%S\" isn't a string: %d\n",
608 wszCfgGuidString, dwValueType
609 }
610 else
611 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Querying instance ID failed with %u (%#x)\n",
612 lrc, lrc));
613
614 RegCloseKey(hKey);
615 }
616#endif /* VBOXNETCFG_DELAYEDRENAME */
617
618 if (SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, pDev))
619 {
620 SP_DEVINSTALL_PARAMS_W DevParams = { sizeof(DevParams) };
621 if (SetupDiGetDeviceInstallParams(hDevInfo, pDev, &DevParams))
622 {
623 if ( (DevParams.Flags & DI_NEEDRESTART)
624 || (DevParams.Flags & DI_NEEDREBOOT))
625 NonStandardLog(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: A reboot is required\n"));
626 }
627 else
628 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %u\n",
629 GetLastError()));
630 }
631 else
632 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %u\n",
633 GetLastError()));
634 }
635 else
636 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetSelectedDevice failed with %u\n",
637 GetLastError()));
638 }
639 else
640 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetClassInstallParams failed with %u\n",
641 GetLastError()));
642
643 /* Continue enumeration. */
644 return TRUE;
645}
646
647typedef struct VBOXNECTFGWINPROPCHANGE
648{
649 VBOXNECTFGWINPROPCHANGE_TYPE_T enmPcType;
650 HRESULT hr;
651} VBOXNECTFGWINPROPCHANGE, *PVBOXNECTFGWINPROPCHANGE;
652
653static BOOL vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
654{
655 PVBOXNECTFGWINPROPCHANGE pPc = (PVBOXNECTFGWINPROPCHANGE)pContext;
656
657 SP_PROPCHANGE_PARAMS PcParams;
658 RT_ZERO(PcParams);
659 PcParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
660 PcParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
661 PcParams.Scope = DICS_FLAG_GLOBAL;
662
663 switch (pPc->enmPcType)
664 {
665 case VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE:
666 PcParams.StateChange = DICS_DISABLE;
667 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_DISABLE): %d\n", pPc->enmPcType));
668 break;
669 case VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE:
670 PcParams.StateChange = DICS_ENABLE;
671 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_ENABLE): %d\n", pPc->enmPcType));
672 break;
673 default:
674 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Unexpected prop change type: %d\n", pPc->enmPcType));
675 pPc->hr = E_INVALIDARG;
676 return FALSE;
677 }
678
679 if (SetupDiSetClassInstallParamsW(hDevInfo, pDev, &PcParams.ClassInstallHeader, sizeof(PcParams)))
680 {
681 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
682 {
683 if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, pDev))
684 {
685 SP_DEVINSTALL_PARAMS_W DevParams = { sizeof(DevParams) };
686 if (SetupDiGetDeviceInstallParamsW(hDevInfo, pDev, &DevParams))
687 {
688 if ( (DevParams.Flags & DI_NEEDRESTART)
689 || (DevParams.Flags & DI_NEEDREBOOT))
690 NonStandardLog(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: A reboot is required\n"));
691 }
692 else
693 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %u\n",
694 GetLastError()));
695 }
696 else
697 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %u\n",
698 GetLastError()));
699 }
700 else
701 NonStandardLogFlow(("SetupDiSetSelectedDevice failed with %u\n", GetLastError()));
702 }
703 else
704 NonStandardLogFlow(("SetupDiSetClassInstallParams failed with %u\n", GetLastError()));
705
706 /* Continue enumeration. */
707 return TRUE;
708}
709
710typedef BOOL (*PFNVBOXNETCFGWINNETENUMCALLBACK)(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext);
711
712static HRESULT vboxNetCfgWinEnumNetDevices(LPCWSTR pwszPnPId, PFNVBOXNETCFGWINNETENUMCALLBACK pfnCallback, PVOID pvContext)
713{
714 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Searching for: %ls\n", pwszPnPId));
715
716 HRESULT hr;
717 HDEVINFO hDevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET,
718 NULL, /* IN PCTSTR Enumerator, OPTIONAL */
719 NULL, /* IN HWND hwndParent, OPTIONAL */
720 DIGCF_PRESENT, /* IN DWORD Flags,*/
721 NULL, /* IN HDEVINFO DeviceInfoSet, OPTIONAL */
722 NULL, /* IN PCTSTR MachineName, OPTIONAL */
723 NULL /* IN PVOID Reserved */);
724 if (hDevInfo != INVALID_HANDLE_VALUE)
725 {
726 size_t const cwcPnPId = RTUtf16Len(pwszPnPId);
727 DWORD winEr = NO_ERROR;
728 DWORD dwDevId = 0;
729 DWORD cbBuffer = 0;
730 PBYTE pbBuffer = NULL;
731 for (;;)
732 {
733 SP_DEVINFO_DATA Dev;
734 memset(&Dev, 0, sizeof(SP_DEVINFO_DATA));
735 Dev.cbSize = sizeof(SP_DEVINFO_DATA);
736
737 if (!SetupDiEnumDeviceInfo(hDevInfo, dwDevId, &Dev))
738 {
739 winEr = GetLastError();
740 if (winEr == ERROR_NO_MORE_ITEMS)
741 winEr = NO_ERROR;
742 break;
743 }
744
745 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Enumerating device %u ... \n", dwDevId));
746 dwDevId++;
747
748 DWORD cbRequired = 0;
749 SetLastError(0);
750 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
751 SPDRP_HARDWAREID, /* IN DWORD Property */
752 NULL, /* OUT PDWORD PropertyRegDataType OPTIONAL */
753 pbBuffer, /* OUT PBYTE PropertyBuffer */
754 cbBuffer, /* IN DWORD PropertyBufferSize */
755 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
756 {
757 winEr = GetLastError();
758 if (winEr != ERROR_INSUFFICIENT_BUFFER)
759 {
760 if (winEr == ERROR_INVALID_DATA)
761 {
762 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with ERROR_INVALID_DATA - ignoring, skipping to next device\n"));
763 continue;
764 }
765 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with %u\n", winEr));
766 break;
767 }
768 winEr = NO_ERROR;
769
770 cbBuffer = RT_ALIGN_32(cbRequired, 64);
771 void *pvNew = RTMemRealloc(pbBuffer, cbBuffer);
772 if (pvNew)
773 pbBuffer = (PBYTE)pvNew;
774 else
775 {
776 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Out of memory allocating %u bytes\n", cbBuffer));
777 winEr = ERROR_OUTOFMEMORY;
778 break;
779 }
780
781 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
782 SPDRP_HARDWAREID, /* IN DWORD Property */
783 NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL */
784 pbBuffer, /* OUT PBYTE PropertyBuffer */
785 cbBuffer, /* IN DWORD PropertyBufferSize */
786 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
787 {
788 winEr = GetLastError();
789 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (2) failed with %u\n",
790 winEr));
791 break;
792 }
793 }
794
795 PWSTR pwszCurId = (PWSTR)pbBuffer;
796 size_t cwcCurId = RTUtf16Len(pwszCurId);
797
798 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Device %u: %ls\n", dwDevId, pwszCurId));
799
800 if (cwcCurId >= cwcPnPId)
801 {
802 NonStandardLogFlow(("!RTUtf16NICmp(pwszCurId = (%ls), pwszPnPId = (%ls), cwcPnPId = (%d))\n", pwszCurId, pwszPnPId, cwcPnPId));
803
804 pwszCurId += cwcCurId - cwcPnPId;
805 if (!RTUtf16NICmp(pwszCurId, pwszPnPId, cwcPnPId))
806 {
807 if (!pfnCallback(hDevInfo, &Dev, pvContext))
808 break;
809 }
810 }
811 }
812
813 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Found %u devices total\n", dwDevId));
814
815 if (pbBuffer)
816 RTMemFree(pbBuffer);
817
818 hr = HRESULT_FROM_WIN32(winEr);
819
820 SetupDiDestroyDeviceInfoList(hDevInfo);
821 }
822 else
823 {
824 DWORD winEr = GetLastError();
825 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetClassDevsExW failed with %u\n", winEr));
826 hr = HRESULT_FROM_WIN32(winEr);
827 }
828
829 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Ended with hr (0x%x)\n", hr));
830 return hr;
831}
832
833VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR pwszPnPId)
834{
835 return vboxNetCfgWinEnumNetDevices(pwszPnPId, vboxNetCfgWinRemoveAllNetDevicesOfIdCallback, NULL);
836}
837
838VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR pwszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE_T enmPcType)
839{
840 VBOXNECTFGWINPROPCHANGE Pc;
841 Pc.enmPcType = enmPcType;
842 Pc.hr = S_OK;
843 NonStandardLogFlow(("Calling VBoxNetCfgWinEnumNetDevices with pwszPnPId (= %ls) and vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback\n", pwszPnPId));
844
845 HRESULT hr = vboxNetCfgWinEnumNetDevices(pwszPnPId, vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback, &Pc);
846 if (!SUCCEEDED(hr))
847 {
848 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices failed 0x%x\n", hr));
849 return hr;
850 }
851
852 if (!SUCCEEDED(Pc.hr))
853 {
854 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback failed 0x%x\n", Pc.hr));
855 return Pc.hr;
856 }
857
858 return S_OK;
859}
860
861
862
863/*********************************************************************************************************************************
864* Logging *
865*********************************************************************************************************************************/
866
867static void DoLogging(const char *pszString, ...)
868{
869 PFNVBOXNETCFGLOGGER pfnLogger = g_pfnLogger;
870 if (pfnLogger)
871 {
872 char szBuffer[4096];
873 va_list va;
874 va_start(va, pszString);
875 RTStrPrintfV(szBuffer, RT_ELEMENTS(szBuffer), pszString, va);
876 va_end(va);
877
878 pfnLogger(szBuffer);
879 }
880}
881
882VBOXNETCFGWIN_DECL(void) VBoxNetCfgWinSetLogging(IN PFNVBOXNETCFGLOGGER pfnLogger)
883{
884 g_pfnLogger = pfnLogger;
885}
886
887
888
889/*********************************************************************************************************************************
890* IP configuration API *
891*********************************************************************************************************************************/
892/* network settings config */
893#if 1 /** @todo r=bird: Can't we replace this with VBox/com/ptr.h? */
894/**
895 * Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
896 */
897template<class C>
898class ComStrongRef
899{
900protected:
901
902 static void addref(C *p) { p->AddRef(); }
903 static void release(C *p) { p->Release(); }
904};
905
906
907/**
908 * Base template for smart COM pointers. Not intended to be used directly.
909 */
910template<class C, template<class> class RefOps = ComStrongRef>
911class ComPtrBase : protected RefOps<C>
912{
913public:
914
915 /* special template to disable AddRef()/Release() */
916 template<class I>
917 class NoAddRefRelease : public I
918 {
919 public:
920 virtual ~NoAddRefRelease() { /* Make VC++ 19.2 happy. */ }
921 private:
922#ifndef VBOX_WITH_XPCOM
923 STDMETHOD_(ULONG, AddRef)() = 0;
924 STDMETHOD_(ULONG, Release)() = 0;
925#else
926 NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
927 NS_IMETHOD_(nsrefcnt) Release(void) = 0;
928#endif
929 };
930
931protected:
932
933 ComPtrBase() : p(NULL) {}
934 ComPtrBase(const ComPtrBase &that) : p(that.p) { addref(); }
935 ComPtrBase(C *that_p) : p(that_p) { addref(); }
936
937 ~ComPtrBase() { release(); }
938
939 ComPtrBase &operator=(const ComPtrBase &that)
940 {
941 safe_assign(that.p);
942 return *this;
943 }
944
945 ComPtrBase &operator=(C *that_p)
946 {
947 safe_assign(that_p);
948 return *this;
949 }
950
951public:
952
953 void setNull()
954 {
955 release();
956 p = NULL;
957 }
958
959 bool isNull() const
960 {
961 return (p == NULL);
962 }
963
964 bool operator!() const { return isNull(); }
965
966 bool operator<(C* that_p) const { return p < that_p; }
967 bool operator==(C* that_p) const { return p == that_p; }
968
969 template<class I>
970 bool equalsTo(I *aThat) const
971 {
972 return ComPtrEquals(p, aThat);
973 }
974
975 template<class OC>
976 bool equalsTo(const ComPtrBase<OC> &oc) const
977 {
978 return equalsTo((OC *) oc);
979 }
980
981 /** Intended to pass instances as in parameters to interface methods */
982 operator C *() const { return p; }
983
984 /**
985 * Dereferences the instance (redirects the -> operator to the managed
986 * pointer).
987 */
988 NoAddRefRelease<C> *operator->() const
989 {
990 AssertMsg (p, ("Managed pointer must not be null\n"));
991 return (NoAddRefRelease <C> *) p;
992 }
993
994 template<class I>
995 HRESULT queryInterfaceTo(I **pp) const
996 {
997 if (pp)
998 {
999 if (p)
1000 return p->QueryInterface(COM_IIDOF(I), (void **)pp);
1001 *pp = NULL;
1002 return S_OK;
1003 }
1004 return E_INVALIDARG;
1005 }
1006
1007 /** Intended to pass instances as out parameters to interface methods */
1008 C **asOutParam()
1009 {
1010 setNull();
1011 return &p;
1012 }
1013
1014private:
1015
1016 void addref()
1017 {
1018 if (p)
1019 RefOps<C>::addref(p);
1020 }
1021
1022 void release()
1023 {
1024 if (p)
1025 RefOps<C>::release(p);
1026 }
1027
1028 void safe_assign(C *that_p)
1029 {
1030 /* be aware of self-assignment */
1031 if (that_p)
1032 RefOps<C>::addref(that_p);
1033 release();
1034 p = that_p;
1035 }
1036
1037 C *p;
1038};
1039
1040/**
1041 * Smart COM pointer wrapper that automatically manages refcounting of
1042 * interface pointers.
1043 *
1044 * @param I COM interface class
1045 */
1046template<class I, template<class> class RefOps = ComStrongRef>
1047class ComPtr : public ComPtrBase<I, RefOps>
1048{
1049 typedef ComPtrBase<I, RefOps> Base;
1050
1051public:
1052
1053 ComPtr() : Base() {}
1054 ComPtr(const ComPtr &that) : Base(that) {}
1055 ComPtr&operator= (const ComPtr &that)
1056 {
1057 Base::operator=(that);
1058 return *this;
1059 }
1060
1061 template<class OI>
1062 ComPtr(OI *that_p) : Base () { operator=(that_p); }
1063
1064 /* specialization for I */
1065 ComPtr(I *that_p) : Base (that_p) {}
1066
1067 template <class OC>
1068 ComPtr(const ComPtr<OC, RefOps> &oc) : Base() { operator=((OC *) oc); }
1069
1070 template<class OI>
1071 ComPtr &operator=(OI *that_p)
1072 {
1073 if (that_p)
1074 that_p->QueryInterface(COM_IIDOF(I), (void **)Base::asOutParam());
1075 else
1076 Base::setNull();
1077 return *this;
1078 }
1079
1080 /* specialization for I */
1081 ComPtr &operator=(I *that_p)
1082 {
1083 Base::operator=(that_p);
1084 return *this;
1085 }
1086
1087 template<class OC>
1088 ComPtr &operator=(const ComPtr<OC, RefOps> &oc)
1089 {
1090 return operator=((OC *) oc);
1091 }
1092};
1093#endif
1094
1095static HRESULT netIfWinFindAdapterClassById(IWbemServices *pSvc, const GUID *pGuid, IWbemClassObject **pAdapterConfig)
1096{
1097 HRESULT hr;
1098
1099 WCHAR wszGuid[50];
1100 int cwcGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
1101 if (cwcGuid)
1102 {
1103 com::BstrFmt bstrQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"%ls\"", wszGuid);
1104 IEnumWbemClassObject* pEnumerator = NULL;
1105 hr = pSvc->ExecQuery(com::Bstr("WQL").raw(), bstrQuery.raw(), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
1106 NULL, &pEnumerator);
1107 if (SUCCEEDED(hr))
1108 {
1109 if (pEnumerator)
1110 {
1111 IWbemClassObject *pclsObj = NULL;
1112 ULONG uReturn = 0;
1113 hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
1114 NonStandardLogFlow(("netIfWinFindAdapterClassById: IEnumWbemClassObject::Next -> hr=0x%x pclsObj=%p uReturn=%u 42=%u\n",
1115 hr, (void *)pclsObj, uReturn, 42));
1116 if (SUCCEEDED(hr))
1117 {
1118 if (uReturn && pclsObj != NULL)
1119 {
1120 *pAdapterConfig = pclsObj;
1121 pEnumerator->Release();
1122 NonStandardLogFlow(("netIfWinFindAdapterClassById: S_OK and %p\n", *pAdapterConfig));
1123 return S_OK;
1124 }
1125 hr = E_FAIL;
1126 }
1127 pEnumerator->Release();
1128 }
1129 else
1130 {
1131 NonStandardLogFlow(("ExecQuery returned no enumerator\n"));
1132 hr = E_FAIL;
1133 }
1134 }
1135 else
1136 NonStandardLogFlow(("ExecQuery failed (0x%x)\n", hr));
1137 }
1138 else
1139 {
1140 DWORD winEr = GetLastError();
1141 hr = HRESULT_FROM_WIN32(winEr);
1142 if (SUCCEEDED(hr))
1143 hr = E_FAIL;
1144 NonStandardLogFlow(("StringFromGUID2 failed winEr=%u, hr=0x%x\n", winEr, hr));
1145 }
1146
1147 NonStandardLogFlow(("netIfWinFindAdapterClassById: 0x%x and %p\n", hr, *pAdapterConfig));
1148 return hr;
1149}
1150
1151static HRESULT netIfWinIsHostOnly(IWbemClassObject *pAdapterConfig, BOOL *pfIsHostOnly)
1152{
1153 VARIANT vtServiceName;
1154 VariantInit(&vtServiceName);
1155
1156 HRESULT hr = pAdapterConfig->Get(L"ServiceName", 0 /*lFlags*/, &vtServiceName, NULL /*pvtType*/, NULL /*plFlavor*/);
1157 if (SUCCEEDED(hr))
1158 {
1159 *pfIsHostOnly = RTUtf16CmpAscii(vtServiceName.bstrVal, "VBoxNetAdp") == 0;
1160
1161 VariantClear(&vtServiceName);
1162 }
1163
1164 return hr;
1165}
1166
1167static HRESULT netIfWinGetIpSettings(IWbemClassObject * pAdapterConfig, ULONG *pIpv4, ULONG *pMaskv4)
1168{
1169 *pIpv4 = 0;
1170 *pMaskv4 = 0;
1171
1172 VARIANT vtIp;
1173 VariantInit(&vtIp);
1174 HRESULT hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1175 if (SUCCEEDED(hr))
1176 {
1177 if (vtIp.vt == (VT_ARRAY | VT_BSTR))
1178 {
1179 VARIANT vtMask;
1180 VariantInit(&vtMask);
1181 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1182 if (SUCCEEDED(hr))
1183 {
1184 if (vtMask.vt == (VT_ARRAY | VT_BSTR))
1185 {
1186 SAFEARRAY *pIpArray = vtIp.parray;
1187 SAFEARRAY *pMaskArray = vtMask.parray;
1188 if (pIpArray && pMaskArray)
1189 {
1190 BSTR pBstrCurIp;
1191 BSTR pBstrCurMask;
1192 for (LONG i = 0;
1193 SafeArrayGetElement(pIpArray, &i, (PVOID)&pBstrCurIp) == S_OK
1194 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pBstrCurMask) == S_OK;
1195 i++)
1196 {
1197 com::Utf8Str strIp(pBstrCurIp);
1198 ULONG Ipv4 = inet_addr(strIp.c_str());
1199 if (Ipv4 != INADDR_NONE)
1200 {
1201 *pIpv4 = Ipv4;
1202
1203 com::Utf8Str strMask(pBstrCurMask);
1204 *pMaskv4 = inet_addr(strMask.c_str());
1205 break;
1206 }
1207 }
1208 }
1209 }
1210 VariantClear(&vtMask);
1211 }
1212 }
1213 VariantClear(&vtIp);
1214 }
1215
1216 return hr;
1217}
1218
1219#if 0 /* unused */
1220
1221static HRESULT netIfWinHasIpSettings(IWbemClassObject * pAdapterConfig, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, bool *pFound)
1222{
1223 VARIANT vtIp;
1224 HRESULT hr;
1225 VariantInit(&vtIp);
1226
1227 *pFound = false;
1228
1229 hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1230 if (SUCCEEDED(hr))
1231 {
1232 VARIANT vtMask;
1233 VariantInit(&vtMask);
1234 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1235 if (SUCCEEDED(hr))
1236 {
1237 SAFEARRAY * pIpArray = vtIp.parray;
1238 SAFEARRAY * pMaskArray = vtMask.parray;
1239 if (pIpArray && pMaskArray)
1240 {
1241 BSTR pIp, pMask;
1242 for (LONG k = 0;
1243 SafeArrayGetElement(pCheckIp, &k, (PVOID)&pIp) == S_OK
1244 && SafeArrayGetElement(pCheckMask, &k, (PVOID)&pMask) == S_OK;
1245 k++)
1246 {
1247 BSTR pCurIp;
1248 BSTR pCurMask;
1249 for (LONG i = 0;
1250 SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
1251 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
1252 i++)
1253 {
1254 if (!wcsicmp(pCurIp, pIp))
1255 {
1256 if (!wcsicmp(pCurMask, pMask))
1257 *pFound = true;
1258 break;
1259 }
1260 }
1261 }
1262 }
1263
1264
1265 VariantClear(&vtMask);
1266 }
1267
1268 VariantClear(&vtIp);
1269 }
1270
1271 return hr;
1272}
1273
1274static HRESULT netIfWinWaitIpSettings(IWbemServices *pSvc, const GUID * pGuid, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, ULONG sec2Wait, bool *pFound)
1275{
1276 /* on Vista we need to wait for the address to get applied */
1277 /* wait for the address to appear in the list */
1278 HRESULT hr = S_OK;
1279 ULONG i;
1280 *pFound = false;
1281 ComPtr<IWbemClassObject> pAdapterConfig;
1282 for (i = 0;
1283 (hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam())) == S_OK
1284 && (hr = netIfWinHasIpSettings(pAdapterConfig, pCheckIp, pCheckMask, pFound)) == S_OK
1285 && !(*pFound)
1286 && i < sec2Wait/6;
1287 i++)
1288 {
1289 Sleep(6000);
1290 }
1291
1292 return hr;
1293}
1294
1295#endif /* unused */
1296
1297static HRESULT netIfWinCreateIWbemServices(IWbemServices **ppSvc)
1298{
1299 IWbemLocator *pLoc = NULL;
1300 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&pLoc);
1301 if (SUCCEEDED(hr))
1302 {
1303 IWbemServices *pSvc = NULL;
1304 hr = pLoc->ConnectServer(com::Bstr(L"ROOT\\CIMV2").raw(), /* [in] const BSTR strNetworkResource */
1305 NULL, /* [in] const BSTR strUser */
1306 NULL, /* [in] const BSTR strPassword */
1307 0, /* [in] const BSTR strLocale */
1308 NULL, /* [in] LONG lSecurityFlags */
1309 0, /* [in] const BSTR strAuthority */
1310 0, /* [in] IWbemContext* pCtx */
1311 &pSvc /* [out] IWbemServices** ppNamespace */);
1312 if (SUCCEEDED(hr))
1313 {
1314 hr = CoSetProxyBlanket(pSvc, /* IUnknown * pProxy */
1315 RPC_C_AUTHN_WINNT, /* DWORD dwAuthnSvc */
1316 RPC_C_AUTHZ_NONE, /* DWORD dwAuthzSvc */
1317 NULL, /* WCHAR * pServerPrincName */
1318 RPC_C_AUTHN_LEVEL_CALL, /* DWORD dwAuthnLevel */
1319 RPC_C_IMP_LEVEL_IMPERSONATE, /* DWORD dwImpLevel */
1320 NULL, /* RPC_AUTH_IDENTITY_HANDLE pAuthInfo */
1321 EOAC_NONE /* DWORD dwCapabilities */
1322 );
1323 if (SUCCEEDED(hr))
1324 {
1325 *ppSvc = pSvc;
1326 /* do not need it any more */
1327 pLoc->Release();
1328 return hr;
1329 }
1330
1331 NonStandardLogFlow(("CoSetProxyBlanket failed: %Rhrc\n", hr));
1332 pSvc->Release();
1333 }
1334 else
1335 NonStandardLogFlow(("ConnectServer failed: %Rhrc\n", hr));
1336 pLoc->Release();
1337 }
1338 else
1339 NonStandardLogFlow(("CoCreateInstance failed: %Rhrc\n", hr));
1340 return hr;
1341}
1342
1343static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, com::Bstr *pRet)
1344{
1345 VARIANT index;
1346 VariantInit(&index);
1347 HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
1348 if (SUCCEEDED(hr))
1349 hr = pRet->printfNoThrow("Win32_NetworkAdapterConfiguration.Index='%u'", index.uintVal);
1350 else
1351 {
1352 pRet->setNull();
1353 NonStandardLogFlow(("Get failed: %Rhrc\n", hr));
1354 }
1355 return hr;
1356}
1357
1358static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, com::Bstr const &rObjPath,
1359 const char *pszMethodName, LPCWSTR *papwszArgNames, LPVARIANT *pArgs, UINT cArgs,
1360 IWbemClassObject **ppOutParams)
1361{
1362 *ppOutParams = NULL;
1363 com::Bstr bstrMethodName;
1364 HRESULT hr = bstrMethodName.assignEx(pszMethodName);
1365 if (SUCCEEDED(hr))
1366 {
1367 ComPtr<IWbemClassObject> pInParamsDefinition;
1368 ComPtr<IWbemClassObject> pClassInstance;
1369 if (cArgs)
1370 {
1371 hr = pClass->GetMethod(bstrMethodName.raw(), 0, pInParamsDefinition.asOutParam(), NULL);
1372 if (SUCCEEDED(hr))
1373 {
1374 hr = pInParamsDefinition->SpawnInstance(0, pClassInstance.asOutParam());
1375 if (SUCCEEDED(hr))
1376 {
1377 for (UINT i = 0; i < cArgs; i++)
1378 {
1379 hr = pClassInstance->Put(papwszArgNames[i], 0, pArgs[i], 0);
1380 if (FAILED(hr))
1381 break;
1382 }
1383 }
1384 }
1385 }
1386
1387 if (SUCCEEDED(hr))
1388 {
1389 IWbemClassObject *pOutParams = NULL;
1390 hr = pSvc->ExecMethod(rObjPath.raw(), bstrMethodName.raw(), 0, NULL, pClassInstance, &pOutParams, NULL);
1391 if (SUCCEEDED(hr))
1392 *ppOutParams = pOutParams;
1393 }
1394 }
1395
1396 return hr;
1397}
1398
1399static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr const *paIps, UINT cIps)
1400{
1401 HRESULT hr = S_OK;
1402 SAFEARRAY *pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIps);
1403 if (pIpArray)
1404 {
1405 for (UINT i = 0; i < cIps; i++)
1406 {
1407 com::Bstr bstrVal;
1408 hr = bstrVal.printfNoThrow("%RTnaipv4", paIps[i].s_addr);
1409 if (SUCCEEDED(hr))
1410 {
1411 Assert(bstrVal.equals(inet_ntoa(paIps[i])));
1412
1413 BSTR pRawVal;
1414 hr = bstrVal.detachToEx(&pRawVal);
1415 if (SUCCEEDED(hr))
1416 {
1417 LONG aIndex[1] = { (LONG)i };
1418 hr = SafeArrayPutElement(pIpArray, aIndex, pRawVal);
1419 if (SUCCEEDED(hr))
1420 continue;
1421 SysFreeString(pRawVal);
1422 }
1423 }
1424 break;
1425 }
1426
1427 if (SUCCEEDED(hr))
1428 *ppArray = pIpArray;
1429 else
1430 SafeArrayDestroy(pIpArray);
1431 }
1432 else
1433 hr = HRESULT_FROM_WIN32(GetLastError());
1434 return hr;
1435}
1436
1437#if 0 /* unused */
1438static HRESULT netIfWinCreateIpArrayV4V6(SAFEARRAY **ppArray, BSTR Ip)
1439{
1440 HRESULT hr;
1441 SAFEARRAY *pIpArray = SafeArrayCreateVector(VT_BSTR, 0, 1);
1442 if (pIpArray)
1443 {
1444 BSTR val = com::Bstr(Ip, false).copy();
1445 long aIndex[1];
1446 aIndex[0] = 0;
1447 hr = SafeArrayPutElement(pIpArray, aIndex, val);
1448 if (FAILED(hr))
1449 {
1450 SysFreeString(val);
1451 SafeArrayDestroy(pIpArray);
1452 }
1453
1454 if (SUCCEEDED(hr))
1455 {
1456 *ppArray = pIpArray;
1457 }
1458 }
1459 else
1460 hr = HRESULT_FROM_WIN32(GetLastError());
1461
1462 return hr;
1463}
1464#endif
1465
1466
1467static HRESULT netIfWinCreateIpArrayVariantV4(VARIANT *pIpAddresses, in_addr const *paIps, UINT cIps)
1468{
1469 VariantInit(pIpAddresses);
1470 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1471
1472 SAFEARRAY *pIpArray;
1473 HRESULT hr = netIfWinCreateIpArray(&pIpArray, paIps, cIps);
1474 if (SUCCEEDED(hr))
1475 pIpAddresses->parray = pIpArray;
1476 return hr;
1477}
1478
1479#if 0 /* unused */
1480static HRESULT netIfWinCreateIpArrayVariantV4V6(VARIANT * pIpAddresses, BSTR Ip)
1481{
1482 HRESULT hr;
1483 VariantInit(pIpAddresses);
1484 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1485 SAFEARRAY *pIpArray;
1486 hr = netIfWinCreateIpArrayV4V6(&pIpArray, Ip);
1487 if (SUCCEEDED(hr))
1488 {
1489 pIpAddresses->parray = pIpArray;
1490 }
1491 return hr;
1492}
1493#endif
1494
1495static HRESULT netIfWinEnableStatic(IWbemServices *pSvc, const GUID *pGuid, com::Bstr &rObjPath, VARIANT *pIp, VARIANT *pMask)
1496{
1497 com::Bstr bstrClassName;
1498 HRESULT hr = bstrClassName.assignEx("Win32_NetworkAdapterConfiguration");
1499 if (SUCCEEDED(hr))
1500 {
1501 ComPtr<IWbemClassObject> pClass;
1502 hr = pSvc->GetObject(bstrClassName.raw(), 0, NULL, pClass.asOutParam(), NULL);
1503 if (SUCCEEDED(hr))
1504 {
1505 LPCWSTR argNames[] = {L"IPAddress", L"SubnetMask"};
1506 LPVARIANT args[] = { pIp, pMask };
1507
1508 ComPtr<IWbemClassObject> pOutParams;
1509 hr = netIfExecMethod(pSvc, pClass, rObjPath.raw(), "EnableStatic", argNames, args,
1510 2, pOutParams.asOutParam());
1511 if (SUCCEEDED(hr))
1512 {
1513 com::Bstr bstrReturnValue;
1514 hr = bstrReturnValue.assignEx("ReturnValue");
1515 if (SUCCEEDED(hr))
1516 {
1517 VARIANT varReturnValue;
1518 VariantInit(&varReturnValue);
1519 hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
1520 Assert(SUCCEEDED(hr));
1521 if (SUCCEEDED(hr))
1522 {
1523 //Assert(varReturnValue.vt == VT_UINT);
1524 int winEr = varReturnValue.uintVal;
1525 switch (winEr)
1526 {
1527 case 0:
1528 {
1529 hr = S_OK;
1530 //bool bFound;
1531 //HRESULT tmpHr = netIfWinWaitIpSettings(pSvc, pGuid, pIp->parray, pMask->parray, 180, &bFound);
1532 NOREF(pGuid);
1533 break;
1534 }
1535 default:
1536 hr = HRESULT_FROM_WIN32( winEr );
1537 break;
1538 }
1539 }
1540 }
1541 }
1542 }
1543 }
1544 return hr;
1545}
1546
1547
1548static HRESULT netIfWinEnableStaticV4(IWbemServices *pSvc, const GUID *pGuid, com::Bstr &rObjPath,
1549 in_addr const *paIps, in_addr const *paMasks, UINT cIpAndMasks)
1550{
1551 VARIANT ipAddresses;
1552 HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, paIps, cIpAndMasks);
1553 if (SUCCEEDED(hr))
1554 {
1555 VARIANT ipMasks;
1556 hr = netIfWinCreateIpArrayVariantV4(&ipMasks, paMasks, cIpAndMasks);
1557 if (SUCCEEDED(hr))
1558 {
1559 hr = netIfWinEnableStatic(pSvc, pGuid, rObjPath, &ipAddresses, &ipMasks);
1560 VariantClear(&ipMasks);
1561 }
1562 VariantClear(&ipAddresses);
1563 }
1564 return hr;
1565}
1566
1567#if 0 /* unused */
1568
1569static HRESULT netIfWinEnableStaticV4V6(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, BSTR Ip, BSTR Mask)
1570{
1571 VARIANT ipAddresses;
1572 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&ipAddresses, Ip);
1573 if (SUCCEEDED(hr))
1574 {
1575 VARIANT ipMasks;
1576 hr = netIfWinCreateIpArrayVariantV4V6(&ipMasks, Mask);
1577 if (SUCCEEDED(hr))
1578 {
1579 hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
1580 VariantClear(&ipMasks);
1581 }
1582 VariantClear(&ipAddresses);
1583 }
1584 return hr;
1585}
1586
1587/* win API allows to set gw metrics as well, we are not setting them */
1588static HRESULT netIfWinSetGateways(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pGw)
1589{
1590 ComPtr<IWbemClassObject> pClass;
1591 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1592 HRESULT hr;
1593 if (ClassName)
1594 {
1595 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1596 if (SUCCEEDED(hr))
1597 {
1598 LPCWSTR argNames[] = {L"DefaultIPGateway"};
1599 LPVARIANT args[] = {pGw};
1600 ComPtr<IWbemClassObject> pOutParams;
1601
1602 hr = netIfExecMethod(pSvc, pClass, ObjPath, com::Bstr(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
1603 if (SUCCEEDED(hr))
1604 {
1605 VARIANT varReturnValue;
1606 hr = pOutParams->Get(com::Bstr(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1607 Assert(SUCCEEDED(hr));
1608 if (SUCCEEDED(hr))
1609 {
1610// Assert(varReturnValue.vt == VT_UINT);
1611 int winEr = varReturnValue.uintVal;
1612 switch (winEr)
1613 {
1614 case 0:
1615 hr = S_OK;
1616 break;
1617 default:
1618 hr = HRESULT_FROM_WIN32( winEr );
1619 break;
1620 }
1621 }
1622 }
1623 }
1624 SysFreeString(ClassName);
1625 }
1626 else
1627 hr = HRESULT_FROM_WIN32(GetLastError());
1628
1629 return hr;
1630}
1631
1632/* win API allows to set gw metrics as well, we are not setting them */
1633static HRESULT netIfWinSetGatewaysV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aGw, UINT cGw)
1634{
1635 VARIANT gwais;
1636 HRESULT hr = netIfWinCreateIpArrayVariantV4(&gwais, aGw, cGw);
1637 if (SUCCEEDED(hr))
1638 {
1639 netIfWinSetGateways(pSvc, ObjPath, &gwais);
1640 VariantClear(&gwais);
1641 }
1642 return hr;
1643}
1644
1645/* win API allows to set gw metrics as well, we are not setting them */
1646static HRESULT netIfWinSetGatewaysV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Gw)
1647{
1648 VARIANT vGw;
1649 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&vGw, Gw);
1650 if (SUCCEEDED(hr))
1651 {
1652 netIfWinSetGateways(pSvc, ObjPath, &vGw);
1653 VariantClear(&vGw);
1654 }
1655 return hr;
1656}
1657
1658#endif /* unused */
1659
1660static HRESULT netIfWinEnableDHCP(IWbemServices * pSvc, const com::Bstr &rObjPath)
1661{
1662 com::Bstr bstrClassName;
1663 HRESULT hr = bstrClassName.assignEx("Win32_NetworkAdapterConfiguration");
1664 if (SUCCEEDED(hr))
1665 {
1666 ComPtr<IWbemClassObject> pClass;
1667 hr = pSvc->GetObject(bstrClassName.raw(), 0, NULL, pClass.asOutParam(), NULL);
1668 if (SUCCEEDED(hr))
1669 {
1670 ComPtr<IWbemClassObject> pOutParams;
1671 hr = netIfExecMethod(pSvc, pClass, rObjPath, "EnableDHCP", NULL, NULL, 0, pOutParams.asOutParam());
1672 if (SUCCEEDED(hr))
1673 {
1674 com::Bstr bstrReturnValue;
1675 hr = bstrReturnValue.assignEx("ReturnValue");
1676 if (SUCCEEDED(hr))
1677 {
1678 VARIANT varReturnValue;
1679 VariantInit(&varReturnValue);
1680 hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
1681 Assert(SUCCEEDED(hr));
1682 if (SUCCEEDED(hr))
1683 {
1684 //Assert(varReturnValue.vt == VT_UINT);
1685 int winEr = varReturnValue.uintVal;
1686 switch (winEr)
1687 {
1688 case 0:
1689 hr = S_OK;
1690 break;
1691 default:
1692 hr = HRESULT_FROM_WIN32( winEr );
1693 break;
1694 }
1695 }
1696 }
1697 }
1698 }
1699 }
1700 return hr;
1701}
1702
1703static HRESULT netIfWinDhcpRediscover(IWbemServices * pSvc, const com::Bstr &rObjPath)
1704{
1705 com::Bstr bstrClassName;
1706 HRESULT hr = bstrClassName.assignEx("Win32_NetworkAdapterConfiguration");
1707 if (SUCCEEDED(hr))
1708 {
1709 ComPtr<IWbemClassObject> pClass;
1710 hr = pSvc->GetObject(bstrClassName.raw(), 0, NULL, pClass.asOutParam(), NULL);
1711 if (SUCCEEDED(hr))
1712 {
1713 ComPtr<IWbemClassObject> pOutParams;
1714 hr = netIfExecMethod(pSvc, pClass, rObjPath, "ReleaseDHCPLease", NULL, NULL, 0, pOutParams.asOutParam());
1715 if (SUCCEEDED(hr))
1716 {
1717 com::Bstr bstrReturnValue;
1718 hr = bstrReturnValue.assignEx("ReturnValue");
1719 if (SUCCEEDED(hr))
1720 {
1721 VARIANT varReturnValue;
1722 VariantInit(&varReturnValue);
1723 hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
1724 Assert(SUCCEEDED(hr));
1725 if (SUCCEEDED(hr))
1726 {
1727 //Assert(varReturnValue.vt == VT_UINT);
1728 int winEr = varReturnValue.uintVal;
1729 if (winEr == 0)
1730 {
1731 hr = netIfExecMethod(pSvc, pClass, rObjPath, "RenewDHCPLease", NULL, NULL, 0, pOutParams.asOutParam());
1732 if (SUCCEEDED(hr))
1733 {
1734 hr = pOutParams->Get(bstrReturnValue.raw(), 0, &varReturnValue, NULL, 0);
1735 Assert(SUCCEEDED(hr));
1736 if (SUCCEEDED(hr))
1737 {
1738 //Assert(varReturnValue.vt == VT_UINT);
1739 winEr = varReturnValue.uintVal;
1740 if (winEr == 0)
1741 hr = S_OK;
1742 else
1743 hr = HRESULT_FROM_WIN32( winEr );
1744 }
1745 }
1746 }
1747 else
1748 hr = HRESULT_FROM_WIN32( winEr );
1749 }
1750 }
1751 }
1752 }
1753 }
1754
1755 return hr;
1756}
1757
1758static HRESULT vboxNetCfgWinIsDhcpEnabled(IWbemClassObject *pAdapterConfig, BOOL *pfEnabled)
1759{
1760 VARIANT vtEnabled;
1761 VariantInit(&vtEnabled);
1762 HRESULT hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
1763 if (SUCCEEDED(hr))
1764 *pfEnabled = vtEnabled.boolVal;
1765 else
1766 *pfEnabled = FALSE;
1767 return hr;
1768}
1769
1770VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(IN const GUID *pGuid, OUT PADAPTER_SETTINGS pSettings)
1771{
1772 ComPtr<IWbemServices> pSvc;
1773 HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1774 if (SUCCEEDED(hr))
1775 {
1776 ComPtr<IWbemClassObject> pAdapterConfig;
1777 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1778 if (SUCCEEDED(hr))
1779 {
1780 hr = vboxNetCfgWinIsDhcpEnabled(pAdapterConfig, &pSettings->bDhcp);
1781 if (SUCCEEDED(hr))
1782 hr = netIfWinGetIpSettings(pAdapterConfig, &pSettings->ip, &pSettings->mask);
1783 }
1784 }
1785
1786 return hr;
1787}
1788
1789VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinIsDhcpEnabled(const GUID * pGuid, BOOL *pEnabled)
1790{
1791 ComPtr<IWbemServices> pSvc;
1792 HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1793 if (SUCCEEDED(hr))
1794 {
1795 ComPtr<IWbemClassObject> pAdapterConfig;
1796 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1797 if (SUCCEEDED(hr))
1798 {
1799 VARIANT vtEnabled;
1800 hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
1801 if (SUCCEEDED(hr))
1802 *pEnabled = vtEnabled.boolVal;
1803 }
1804 }
1805
1806 return hr;
1807}
1808
1809VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(IN const GUID *pGuid, IN ULONG ip, IN ULONG mask)
1810{
1811 NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: ip=0x%x mask=0x%x\n", ip, mask));
1812 ComPtr<IWbemServices> pSvc;
1813 HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1814 if (SUCCEEDED(hr))
1815 {
1816 ComPtr<IWbemClassObject> pAdapterConfig;
1817 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1818 if (SUCCEEDED(hr))
1819 {
1820 BOOL fIsHostOnly;
1821 hr = netIfWinIsHostOnly(pAdapterConfig, &fIsHostOnly);
1822 if (SUCCEEDED(hr))
1823 {
1824 if (fIsHostOnly)
1825 {
1826 in_addr aIp[1];
1827 in_addr aMask[1];
1828 aIp[0].S_un.S_addr = ip;
1829 aMask[0].S_un.S_addr = mask;
1830
1831 com::Bstr bstrObjPath;
1832 hr = netIfWinAdapterConfigPath(pAdapterConfig, &bstrObjPath);
1833 if (SUCCEEDED(hr))
1834 {
1835 hr = netIfWinEnableStaticV4(pSvc, pGuid, bstrObjPath, aIp, aMask, ip != 0 ? 1 : 0);
1836 if (SUCCEEDED(hr))
1837 {
1838#if 0
1839 in_addr aGw[1];
1840 aGw[0].S_un.S_addr = gw;
1841 hr = netIfWinSetGatewaysV4(pSvc, bstrObjPath, aGw, 1);
1842 if (SUCCEEDED(hr))
1843#endif
1844 {
1845 }
1846 }
1847 }
1848 }
1849 else
1850 {
1851 hr = E_FAIL;
1852 }
1853 }
1854 }
1855 }
1856
1857 NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: returns %Rhrc\n", hr));
1858 return hr;
1859}
1860
1861#if 0
1862static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, IN_BSTR aIPV6Mask, IN_BSTR aIPV6DefaultGateway)
1863{
1864 HRESULT hr;
1865 ComPtr<IWbemServices> pSvc;
1866 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1867 if (SUCCEEDED(hr))
1868 {
1869 ComPtr<IWbemClassObject> pAdapterConfig;
1870 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1871 if (SUCCEEDED(hr))
1872 {
1873 BSTR ObjPath;
1874 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1875 if (SUCCEEDED(hr))
1876 {
1877 hr = netIfWinEnableStaticV4V6(pSvc, pAdapterConfig, ObjPath, aIPV6Address, aIPV6Mask);
1878 if (SUCCEEDED(hr))
1879 {
1880 if (aIPV6DefaultGateway)
1881 {
1882 hr = netIfWinSetGatewaysV4V6(pSvc, ObjPath, aIPV6DefaultGateway);
1883 }
1884 if (SUCCEEDED(hr))
1885 {
1886// hr = netIfWinUpdateConfig(pIf);
1887 }
1888 }
1889 SysFreeString(ObjPath);
1890 }
1891 }
1892 }
1893
1894 return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
1895}
1896
1897static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
1898{
1899 RTNETADDRIPV6 Mask;
1900 int rc = RTNetPrefixToMaskIPv6(aIPV6MaskPrefixLength, &Mask);
1901 if (RT_SUCCESS(rc))
1902 {
1903 Bstr maskStr = composeIPv6Address(&Mask);
1904 rc = netIfEnableStaticIpConfigV6(pGuid, aIPV6Address, maskStr, NULL);
1905 }
1906 return rc;
1907}
1908#endif
1909
1910VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(IN const GUID *pGuid)
1911{
1912 ComPtr<IWbemServices> pSvc;
1913 HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1914 if (SUCCEEDED(hr))
1915 {
1916 ComPtr<IWbemClassObject> pAdapterConfig;
1917 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1918 if (SUCCEEDED(hr))
1919 {
1920 BOOL fIsHostOnly;
1921 hr = netIfWinIsHostOnly(pAdapterConfig, &fIsHostOnly);
1922 if (SUCCEEDED(hr))
1923 {
1924 if (fIsHostOnly)
1925 {
1926 com::Bstr bstrObjPath;
1927 hr = netIfWinAdapterConfigPath(pAdapterConfig, &bstrObjPath);
1928 if (SUCCEEDED(hr))
1929 {
1930 hr = netIfWinEnableDHCP(pSvc, bstrObjPath);
1931 if (SUCCEEDED(hr))
1932 {
1933 //hr = netIfWinUpdateConfig(pIf);
1934 }
1935 }
1936 }
1937 else
1938 hr = E_FAIL;
1939 }
1940 }
1941 }
1942 return hr;
1943}
1944
1945VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(IN const GUID *pGuid)
1946{
1947 ComPtr<IWbemServices> pSvc;
1948 HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1949 if (SUCCEEDED(hr))
1950 {
1951 ComPtr<IWbemClassObject> pAdapterConfig;
1952 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1953 if (SUCCEEDED(hr))
1954 {
1955 BOOL fIsHostOnly;
1956 hr = netIfWinIsHostOnly(pAdapterConfig, &fIsHostOnly);
1957 if (SUCCEEDED(hr))
1958 {
1959 if (fIsHostOnly)
1960 {
1961 com::Bstr bstrObjPath;
1962 hr = netIfWinAdapterConfigPath(pAdapterConfig, &bstrObjPath);
1963 if (SUCCEEDED(hr))
1964 {
1965 hr = netIfWinDhcpRediscover(pSvc, bstrObjPath);
1966 if (SUCCEEDED(hr))
1967 {
1968 //hr = netIfWinUpdateConfig(pIf);
1969 }
1970 }
1971 }
1972 else
1973 hr = E_FAIL;
1974 }
1975 }
1976 }
1977
1978
1979 return hr;
1980}
1981
1982static const char *vboxNetCfgWinAddrToStr(char *pszBuf, size_t cbBuf, LPSOCKADDR pAddr)
1983{
1984 switch (pAddr->sa_family)
1985 {
1986 case AF_INET:
1987 RTStrPrintf(pszBuf, cbBuf, "%d.%d.%d.%d",
1988 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b1,
1989 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b2,
1990 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b3,
1991 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b4);
1992 break;
1993 case AF_INET6:
1994 RTStrPrintf(pszBuf, cbBuf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
1995 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[0], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[1],
1996 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[2], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[3],
1997 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[4], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[5],
1998 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[6], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[7],
1999 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[8], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[9],
2000 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[10], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[11],
2001 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[12], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[13],
2002 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[14], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[15]);
2003 break;
2004 default:
2005 RTStrCopy(pszBuf, cbBuf, "unknown");
2006 break;
2007 }
2008 return pszBuf;
2009}
2010
2011typedef bool (*PFNVBOXNETCFG_IPSETTINGS_CALLBACK) (ULONG ip, ULONG mask, PVOID pContext);
2012
2013static void vboxNetCfgWinEnumIpConfig(PIP_ADAPTER_ADDRESSES pAddresses, PFNVBOXNETCFG_IPSETTINGS_CALLBACK pfnCallback, PVOID pContext)
2014{
2015 PIP_ADAPTER_ADDRESSES pAdapter;
2016 for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next)
2017 {
2018 NonStandardLogFlow(("+- Enumerating adapter '%ls' %s\n", pAdapter->FriendlyName, pAdapter->AdapterName));
2019 for (PIP_ADAPTER_PREFIX pPrefix = pAdapter->FirstPrefix; pPrefix; pPrefix = pPrefix->Next)
2020 {
2021 char szBuf[80];
2022 const char *pcszAddress = vboxNetCfgWinAddrToStr(szBuf, sizeof(szBuf), pPrefix->Address.lpSockaddr);
2023
2024 /* We are concerned with IPv4 only, ignore the rest. */
2025 if (pPrefix->Address.lpSockaddr->sa_family != AF_INET)
2026 {
2027 NonStandardLogFlow(("| +- %s %d: not IPv4, ignoring\n", pcszAddress, pPrefix->PrefixLength));
2028 continue;
2029 }
2030
2031 /* Ignore invalid prefixes as well as host addresses. */
2032 if (pPrefix->PrefixLength < 1 || pPrefix->PrefixLength > 31)
2033 {
2034 NonStandardLogFlow(("| +- %s %d: host or broadcast, ignoring\n", pcszAddress, pPrefix->PrefixLength));
2035 continue;
2036 }
2037
2038 /* Ignore multicast and beyond. */
2039 ULONG ip = ((struct sockaddr_in *)pPrefix->Address.lpSockaddr)->sin_addr.s_addr;
2040 if ((ip & 0xF0) > 224)
2041 {
2042 NonStandardLogFlow(("| +- %s %d: multicast, ignoring\n", pcszAddress, pPrefix->PrefixLength));
2043 continue;
2044 }
2045
2046 ULONG mask = htonl((~(((ULONG)~0) >> pPrefix->PrefixLength)));
2047 bool fContinue = pfnCallback(ip, mask, pContext);
2048 if (!fContinue)
2049 {
2050 NonStandardLogFlow(("| +- %s %d: CONFLICT!\n", pcszAddress, pPrefix->PrefixLength));
2051 return;
2052 }
2053
2054 NonStandardLogFlow(("| +- %s %d: no conflict, moving on\n", pcszAddress, pPrefix->PrefixLength));
2055 }
2056 }
2057}
2058
2059typedef struct _IPPROBE_CONTEXT
2060{
2061 ULONG Prefix;
2062 bool fConflict;
2063}IPPROBE_CONTEXT, *PIPPROBE_CONTEXT;
2064
2065#define IPPROBE_INIT(a_pContext, a_addr) \
2066 do { (a_pContext)->fConflict = false; (a_pContext)->Prefix = (a_addr); } while (0)
2067
2068#define IPPROBE_INIT_STR(a_pContext, a_straddr) \
2069 IPROBE_INIT(a_pContext, inet_addr(_straddr))
2070
2071static bool vboxNetCfgWinIpProbeCallback (ULONG ip, ULONG mask, PVOID pContext)
2072{
2073 PIPPROBE_CONTEXT pProbe = (PIPPROBE_CONTEXT)pContext;
2074
2075 if ((ip & mask) == (pProbe->Prefix & mask))
2076 {
2077 pProbe->fConflict = true;
2078 return false;
2079 }
2080
2081 return true;
2082}
2083
2084VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(OUT PULONG pNetIp, OUT PULONG pNetMask)
2085{
2086 HRESULT hr = S_OK;
2087
2088 *pNetIp = 0;
2089 *pNetMask = 0;
2090
2091 /*
2092 * MSDN recommends to pre-allocate a 15KB buffer.
2093 */
2094 ULONG cbBuf = 15 * _1K;
2095 PIP_ADAPTER_ADDRESSES paAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAllocZ(cbBuf);
2096 if (!paAddresses)
2097 return E_OUTOFMEMORY;
2098 DWORD dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, paAddresses, &cbBuf);
2099 if (dwRc == ERROR_BUFFER_OVERFLOW)
2100 {
2101 /* Impressive! More than 10 adapters! Get more memory and try again. */
2102 RTMemFree(paAddresses);
2103 paAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAllocZ(cbBuf);
2104 if (!paAddresses)
2105 return E_OUTOFMEMORY;
2106 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, paAddresses, &cbBuf);
2107 }
2108 if (dwRc == NO_ERROR)
2109 {
2110 const ULONG ip192168 = inet_addr("192.168.0.0");
2111 for (int i = 0; i < 384; i++)
2112 {
2113#if 0
2114 ULONG ipProbe = rand()*255 / RAND_MAX;
2115#else
2116 uint32_t ipProbe = RTRandU32Ex(0, 255);
2117#endif
2118 ipProbe = ip192168 | (ipProbe << 16);
2119 NonStandardLogFlow(("probing %RTnaipv4\n", ipProbe));
2120
2121 IPPROBE_CONTEXT Context;
2122 IPPROBE_INIT(&Context, ipProbe);
2123 vboxNetCfgWinEnumIpConfig(paAddresses, vboxNetCfgWinIpProbeCallback, &Context);
2124 if (!Context.fConflict)
2125 {
2126 NonStandardLogFlow(("found unused net %RTnaipv4\n", ipProbe));
2127 *pNetIp = ipProbe;
2128 *pNetMask = inet_addr("255.255.255.0");
2129 break;
2130 }
2131 }
2132 if (*pNetIp == 0)
2133 dwRc = ERROR_DHCP_ADDRESS_CONFLICT;
2134 }
2135 else
2136 NonStandardLogFlow(("GetAdaptersAddresses err (%u)\n", dwRc));
2137
2138 RTMemFree(paAddresses);
2139
2140 if (dwRc != NO_ERROR)
2141 hr = HRESULT_FROM_WIN32(dwRc);
2142 return hr;
2143}
2144
2145/*
2146 * convenience functions to perform netflt/adp manipulations
2147 */
2148#define VBOXNETCFGWIN_NETFLT_ID L"sun_VBoxNetFlt"
2149#define VBOXNETCFGWIN_NETFLT_MP_ID L"sun_VBoxNetFltmp"
2150
2151static HRESULT vboxNetCfgWinNetFltUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
2152{
2153 INetCfgComponent *pNcc = NULL;
2154 HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETFLT_ID, &pNcc);
2155 if (hr == S_OK)
2156 {
2157 NonStandardLog("NetFlt is installed currently, uninstalling ...\n");
2158
2159 hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
2160 NonStandardLogFlow(("NetFlt component uninstallation ended with hr (%Rhrc)\n", hr));
2161
2162 pNcc->Release();
2163 }
2164 else if (hr == S_FALSE)
2165 NonStandardLog("NetFlt is not installed currently\n");
2166 else
2167 NonStandardLogFlow(("FindComponent failed: %Rhrc\n", hr));
2168
2169 VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETFLT_ID, InfRmFlags);
2170 VBoxDrvCfgInfUninstallAllF(L"Net", VBOXNETCFGWIN_NETFLT_MP_ID, InfRmFlags);
2171
2172 return hr;
2173}
2174
2175VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc)
2176{
2177 return vboxNetCfgWinNetFltUninstall(pNc, 0);
2178}
2179
2180VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc, IN LPCWSTR const *pwszInfFullPath, IN UINT cInfFullPaths)
2181{
2182 HRESULT hr = vboxNetCfgWinNetFltUninstall(pNc, SUOI_FORCEDELETE);
2183 if (SUCCEEDED(hr))
2184 {
2185 NonStandardLog("NetFlt will be installed ...\n");
2186 hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETFLT_ID,
2187 &GUID_DEVCLASS_NETSERVICE,
2188 pwszInfFullPath,
2189 cInfFullPaths,
2190 NULL);
2191 }
2192 return hr;
2193}
2194
2195static HRESULT vboxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, LPCWSTR pwszId, DWORD InfRmFlags)
2196{
2197 NOREF(pNc);
2198 NonStandardLog("Finding NetAdp driver package and trying to uninstall it ...\n");
2199
2200 VBoxDrvCfgInfUninstallAllF(L"Net", pwszId, InfRmFlags);
2201 NonStandardLog("NetAdp is not installed currently\n");
2202 return S_OK;
2203}
2204
2205VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, IN LPCWSTR pwszId)
2206{
2207 return vboxNetCfgWinNetAdpUninstall(pNc, pwszId, SUOI_FORCEDELETE);
2208}
2209
2210VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpInstall(IN INetCfg *pNc,
2211 IN LPCWSTR const pwszInfFullPath)
2212{
2213 NonStandardLog("NetAdp will be installed ...\n");
2214 HRESULT hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETADP_ID_WSZ,
2215 &GUID_DEVCLASS_NET,
2216 &pwszInfFullPath,
2217 1,
2218 NULL);
2219 return hr;
2220}
2221
2222
2223static HRESULT vboxNetCfgWinNetLwfUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
2224{
2225 INetCfgComponent * pNcc = NULL;
2226 HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETLWF_ID, &pNcc);
2227 if (hr == S_OK)
2228 {
2229 NonStandardLog("NetLwf is installed currently, uninstalling ...\n");
2230
2231 hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
2232
2233 pNcc->Release();
2234 }
2235 else if (hr == S_FALSE)
2236 {
2237 NonStandardLog("NetLwf is not installed currently\n");
2238 hr = S_OK;
2239 }
2240 else
2241 {
2242 NonStandardLogFlow(("FindComponent failed: %Rhrc\n", hr));
2243 hr = S_OK;
2244 }
2245
2246 VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETLWF_ID, InfRmFlags);
2247
2248 return hr;
2249}
2250
2251VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfUninstall(IN INetCfg *pNc)
2252{
2253 return vboxNetCfgWinNetLwfUninstall(pNc, 0);
2254}
2255
2256static void VBoxNetCfgWinFilterLimitWorkaround(void)
2257{
2258 /*
2259 * Need to check if the system has a limit of installed filter drivers. If it
2260 * has, bump the limit to 14, which the maximum value supported by Windows 7.
2261 * Note that we only touch the limit if it is set to the default value (8).
2262 * See @bugref{7899}.
2263 */
2264 /** @todo r=bird: This code was mixing HRESULT and LSTATUS, checking the return
2265 * codes using SUCCEEDED(lrc) instead of lrc == ERROR_SUCCESS. So, it might
2266 * have misbehaved on bogus registry content, but worked fine on sane values. */
2267 HKEY hKeyNet = NULL;
2268 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Network", 0,
2269 KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyNet);
2270 if (lrc == ERROR_SUCCESS)
2271 {
2272 DWORD dwMaxNumFilters = 0;
2273 DWORD cbMaxNumFilters = sizeof(dwMaxNumFilters);
2274 lrc = RegQueryValueExW(hKeyNet, L"MaxNumFilters", NULL, NULL, (LPBYTE)&dwMaxNumFilters, &cbMaxNumFilters);
2275 if (lrc == ERROR_SUCCESS && cbMaxNumFilters == sizeof(dwMaxNumFilters) && dwMaxNumFilters == 8)
2276 {
2277 dwMaxNumFilters = 14;
2278 lrc = RegSetValueExW(hKeyNet, L"MaxNumFilters", 0, REG_DWORD, (LPBYTE)&dwMaxNumFilters, sizeof(dwMaxNumFilters));
2279 if (lrc == ERROR_SUCCESS)
2280 NonStandardLog("Adjusted the installed filter limit to 14...\n");
2281 else
2282 NonStandardLog("Failed to set MaxNumFilters, error code %d\n", lrc);
2283 }
2284 RegCloseKey(hKeyNet);
2285 }
2286 else
2287 NonStandardLog("Failed to open network key, error code %d\n", lrc);
2288
2289}
2290
2291VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc, IN LPCWSTR const pwszInfFullPath)
2292{
2293 HRESULT hr = vboxNetCfgWinNetLwfUninstall(pNc, SUOI_FORCEDELETE);
2294 if (SUCCEEDED(hr))
2295 {
2296 VBoxNetCfgWinFilterLimitWorkaround();
2297 NonStandardLog("NetLwf will be installed ...\n");
2298 hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETLWF_ID,
2299 &GUID_DEVCLASS_NETSERVICE,
2300 &pwszInfFullPath,
2301 1,
2302 NULL);
2303 }
2304 return hr;
2305}
2306
2307VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(IN PCWSTR pwszDevName, OUT WCHAR *pwszBuf,
2308 IN ULONG cwcBuf, OUT PULONG pcwcNeeded)
2309{
2310 /* Look for a suffix that we need to preserve. */
2311 size_t const cwcDevName = RTUtf16Len(pwszDevName);
2312 size_t offSuffix = cwcDevName;
2313 while (offSuffix > 0 && pwszDevName[offSuffix - 1] != '#')
2314 offSuffix--;
2315 size_t const cwcSuffix = pwszDevName[offSuffix] != '#' ? 0 : cwcDevName - offSuffix;
2316
2317 /* Calculate required buffer size: */
2318 size_t cwcNeeded = sizeof(VBOX_CONNECTION_NAME_WSZ) / sizeof(wchar_t) /* includes terminator */
2319 + !!cwcSuffix /*space*/ + cwcSuffix;
2320 if (pcwcNeeded)
2321 *pcwcNeeded = (ULONG)cwcNeeded;
2322
2323 if (cwcNeeded <= cwcBuf)
2324 {
2325 memcpy(pwszBuf, VBOX_CONNECTION_NAME_WSZ, sizeof(VBOX_CONNECTION_NAME_WSZ));
2326 if (cwcSuffix > 0)
2327 {
2328 size_t offDst = sizeof(VBOX_CONNECTION_NAME_WSZ) / sizeof(wchar_t) - 1;
2329 pwszBuf[offDst++] = ' ';
2330 memcpy(&pwszBuf[offDst], &pwszDevName[offSuffix], cwcSuffix * sizeof(wchar_t));
2331 pwszBuf[offDst + cwcSuffix] = '\0';
2332 }
2333 return S_OK;
2334 }
2335 return E_FAIL;
2336}
2337
2338static BOOL vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
2339{
2340 GUID * const pGuid = (GUID*)pContext;
2341 RT_NOREF1(pNc);
2342
2343 /* Get component's binding. */
2344 INetCfgComponentBindings *pNetCfgBindings = NULL;
2345 HRESULT hr = pNcc->QueryInterface(IID_INetCfgComponentBindings, (PVOID *)&pNetCfgBindings);
2346 if (SUCCEEDED(hr))
2347 {
2348 /* Get binding path enumerator reference. */
2349 IEnumNetCfgBindingPath *pEnumNetCfgBindPath = NULL;
2350 hr = pNetCfgBindings->EnumBindingPaths(EBP_BELOW, &pEnumNetCfgBindPath);
2351 if (SUCCEEDED(hr))
2352 {
2353 bool fFoundIface = false;
2354 hr = pEnumNetCfgBindPath->Reset();
2355 do
2356 {
2357 INetCfgBindingPath *pNetCfgBindPath = NULL;
2358 hr = pEnumNetCfgBindPath->Next(1, &pNetCfgBindPath, NULL);
2359 if (hr == S_OK)
2360 {
2361 IEnumNetCfgBindingInterface *pEnumNetCfgBindIface;
2362 hr = pNetCfgBindPath->EnumBindingInterfaces(&pEnumNetCfgBindIface);
2363 if (hr == S_OK)
2364 {
2365 pEnumNetCfgBindIface->Reset();
2366 do
2367 {
2368 INetCfgBindingInterface *pNetCfgBindIfce;
2369 hr = pEnumNetCfgBindIface->Next(1, &pNetCfgBindIfce, NULL);
2370 if (hr == S_OK)
2371 {
2372 INetCfgComponent *pNetCfgCompo;
2373 hr = pNetCfgBindIfce->GetLowerComponent(&pNetCfgCompo);
2374 if (hr == S_OK)
2375 {
2376 ULONG uComponentStatus;
2377 hr = pNetCfgCompo->GetDeviceStatus(&uComponentStatus);
2378 if (hr == S_OK)
2379 {
2380 GUID guid;
2381 hr = pNetCfgCompo->GetInstanceGuid(&guid);
2382 if ( hr == S_OK
2383 && guid == *pGuid)
2384 {
2385 hr = pNetCfgBindings->MoveAfter(pNetCfgBindPath, NULL);
2386 if (FAILED(hr))
2387 NonStandardLogFlow(("Unable to move interface: %Rhrc\n", hr));
2388 fFoundIface = true;
2389
2390 /*
2391 * Enable binding paths for host-only adapters bound to bridged filter
2392 * (see @bugref{8140}).
2393 */
2394 HRESULT hr2;
2395 LPWSTR pwszHwId = NULL;
2396 if ((hr2 = pNcc->GetId(&pwszHwId)) != S_OK)
2397 NonStandardLogFlow(("Failed to get HW ID: %Rhrc\n", hr2));
2398 else
2399 {
2400 /** @todo r=bird: Original was:
2401 * _wcsnicmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID, sizeof(VBOXNETCFGWIN_NETLWF_ID)/2)
2402 * which is the same as _wcsicmp. Not sure if this was accidental, but it's not the
2403 * only one in this code area (VBoxNetFltNobj.cpp had some too IIRC). */
2404 if (RTUtf16ICmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID) != 0)
2405 NonStandardLogFlow(("Ignoring component %ls\n", pwszHwId));
2406 else if ((hr2 = pNetCfgBindPath->IsEnabled()) != S_FALSE)
2407 NonStandardLogFlow(("Already enabled binding path: %Rhrc\n", hr2));
2408 else if ((hr2 = pNetCfgBindPath->Enable(TRUE)) != S_OK)
2409 NonStandardLogFlow(("Failed to enable binding path: %Rhrc\n", hr2));
2410 else
2411 NonStandardLogFlow(("Enabled binding path\n"));
2412 CoTaskMemFree(pwszHwId);
2413 }
2414 }
2415 }
2416 pNetCfgCompo->Release();
2417 }
2418 else
2419 NonStandardLogFlow(("GetLowerComponent failed: %Rhrc\n", hr));
2420 pNetCfgBindIfce->Release();
2421 }
2422 else
2423 {
2424 if (hr == S_FALSE) /* No more binding interfaces? */
2425 hr = S_OK;
2426 else
2427 NonStandardLogFlow(("Next binding interface failed: %Rhrc\n", hr));
2428 break;
2429 }
2430 } while (!fFoundIface);
2431 pEnumNetCfgBindIface->Release();
2432 }
2433 else
2434 NonStandardLogFlow(("EnumBindingInterfaces failed: %Rhrc\n", hr));
2435 pNetCfgBindPath->Release();
2436 }
2437 else
2438 {
2439 if (hr == S_FALSE) /* No more binding paths? */
2440 hr = S_OK;
2441 else
2442 NonStandardLogFlow(("Next bind path failed: %Rhrc\n", hr));
2443 break;
2444 }
2445 } while (!fFoundIface);
2446 pEnumNetCfgBindPath->Release();
2447 }
2448 else
2449 NonStandardLogFlow(("EnumBindingPaths failed: %Rhrc\n", hr));
2450 pNetCfgBindings->Release();
2451 }
2452 else
2453 NonStandardLogFlow(("QueryInterface for IID_INetCfgComponentBindings failed: %Rhrc\n", hr));
2454 return TRUE;
2455}
2456
2457/** Callback for SetupDiSetDeviceInstallParams used by
2458 * vboxNetCfgWinCreateHostOnlyNetworkInterface */
2459static UINT WINAPI vboxNetCfgWinPspFileCallback(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
2460{
2461 switch (Notification)
2462 {
2463 case SPFILENOTIFY_TARGETNEWER:
2464 case SPFILENOTIFY_TARGETEXISTS:
2465 return TRUE;
2466 }
2467 return SetupDefaultQueueCallbackW(Context, Notification, Param1, Param2);
2468}
2469
2470
2471
2472
2473/* The original source of the VBoxNetAdp adapter creation/destruction code has the following copyright: */
2474/*
2475 Copyright 2004 by the Massachusetts Institute of Technology
2476
2477 All rights reserved.
2478
2479 Permission to use, copy, modify, and distribute this software and its
2480 documentation for any purpose and without fee is hereby granted,
2481 provided that the above copyright notice appear in all copies and that
2482 both that copyright notice and this permission notice appear in
2483 supporting documentation, and that the name of the Massachusetts
2484 Institute of Technology (M.I.T.) not be used in advertising or publicity
2485 pertaining to distribution of the software without specific, written
2486 prior permission.
2487
2488 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2489 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2490 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2491 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2492 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2493 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2494 SOFTWARE.
2495*/
2496
2497
2498/**
2499 * Use the IShellFolder API to rename the connection.
2500 */
2501static HRESULT rename_shellfolder(PCWSTR pwszGuid, PCWSTR pwszNewName)
2502{
2503 /* Build the display name in the form "::{GUID}". Do this first in case it overflows. */
2504 WCHAR wszAdapterGuid[MAX_PATH + 2] = {0};
2505 ssize_t cwc = RTUtf16Printf(wszAdapterGuid, RT_ELEMENTS(wszAdapterGuid), "::%ls", pwszGuid);
2506 if (cwc < 0)
2507 return E_INVALIDARG;
2508
2509 /* This is the GUID for the network connections folder. It is constant.
2510 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2511 const GUID MY_CLSID_NetworkConnections = {
2512 0x7007ACC7, 0x3202, 0x11D1, {
2513 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2514 }
2515 };
2516
2517 /* Create an instance of the network connections folder. */
2518 IShellFolder *pShellFolder = NULL;
2519 HRESULT hr = CoCreateInstance(MY_CLSID_NetworkConnections, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder,
2520 reinterpret_cast<LPVOID *>(&pShellFolder));
2521 if (SUCCEEDED(hr))
2522 {
2523 /* Parse the display name. */
2524 LPITEMIDLIST pidl = NULL;
2525 hr = pShellFolder->ParseDisplayName(NULL, NULL, wszAdapterGuid, NULL, &pidl, NULL);
2526 if (SUCCEEDED(hr))
2527 hr = pShellFolder->SetNameOf(NULL, pidl, pwszNewName, SHGDN_NORMAL, &pidl);
2528 CoTaskMemFree(pidl);
2529 pShellFolder->Release();
2530 }
2531 return hr;
2532}
2533
2534/**
2535 * Loads a system DLL.
2536 *
2537 * @returns Module handle or NULL
2538 * @param pwszName The DLL name.
2539 */
2540static HMODULE loadSystemDll(const wchar_t *pwszName)
2541{
2542 WCHAR wszPath[MAX_PATH];
2543 UINT cwcPath = GetSystemDirectoryW(wszPath, RT_ELEMENTS(wszPath));
2544 size_t cwcName = RTUtf16Len(pwszName) + 1;
2545 if (cwcPath + 1 + cwcName > RT_ELEMENTS(wszPath))
2546 return NULL;
2547
2548 wszPath[cwcPath++] = '\\';
2549 memcpy(&wszPath[cwcPath], pwszName, cwcName * sizeof(wszPath[0]));
2550 return LoadLibraryW(wszPath);
2551}
2552
2553static bool vboxNetCfgWinDetectStaleConnection(PCWSTR pwszName)
2554{
2555 HKEY hKeyAdapters = NULL;
2556 LSTATUS lrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2557 L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
2558 0 /*ulOptions*/, KEY_ALL_ACCESS, &hKeyAdapters);
2559 if (lrc != ERROR_SUCCESS)
2560 return false;
2561
2562 bool fFailureImminent = false;
2563 for (DWORD i = 0; !fFailureImminent; ++i)
2564 {
2565 WCHAR wszAdapterSubKeyName[MAX_PATH];
2566 DWORD cwcAdapterSubKeyName = MAX_PATH;
2567 lrc = RegEnumKeyEx(hKeyAdapters, i, wszAdapterSubKeyName, &cwcAdapterSubKeyName, NULL, NULL, NULL, NULL);
2568 if (lrc != ERROR_SUCCESS)
2569 break;
2570
2571 HKEY hKeyAdapter = NULL;
2572 lrc = RegOpenKeyEx(hKeyAdapters, wszAdapterSubKeyName, 0, KEY_ALL_ACCESS, &hKeyAdapter);
2573 if (lrc == ERROR_SUCCESS)
2574 {
2575 HKEY hKeyConnection = NULL;
2576 lrc = RegOpenKeyEx(hKeyAdapter, L"Connection", 0, KEY_ALL_ACCESS, &hKeyConnection);
2577 if (lrc == ERROR_SUCCESS)
2578 {
2579 WCHAR wszCurName[MAX_PATH + 1];
2580 DWORD cbCurName = sizeof(wszCurName) - sizeof(WCHAR);
2581 DWORD dwType = REG_SZ;
2582 lrc = RegQueryValueEx(hKeyConnection, L"Name", NULL, NULL, (LPBYTE)wszCurName, &cbCurName);
2583 if ( lrc == ERROR_SUCCESS
2584 /** @todo r=bird: The original code didn't do any value type checks, thus allowing all SZ types. */
2585 && (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ))
2586 {
2587 wszCurName[MAX_PATH] = '\0'; /* returned values doesn't necessarily need to be terminated */
2588
2589 if (RTUtf16ICmp(pwszName, pwszName) == 0)
2590 fFailureImminent = true;
2591 }
2592 RegCloseKey(hKeyConnection);
2593 }
2594 RegCloseKey(hKeyAdapter);
2595 }
2596 }
2597 RegCloseKey(hKeyAdapters);
2598
2599 return fFailureImminent;
2600}
2601
2602VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(LPWSTR pwszGuid, PCWSTR NewName)
2603{
2604 /*
2605 * Before attempting to rename the connection, check if there is a stale
2606 * connection with the same name. We must return ok, so the rest of
2607 * configuration process proceeds normally.
2608 */
2609 if (vboxNetCfgWinDetectStaleConnection(NewName))
2610 return S_OK;
2611
2612 /* First try the IShellFolder interface, which was unimplemented
2613 * for the network connections folder before XP. */
2614 HRESULT hrc = rename_shellfolder(pwszGuid, NewName);
2615 if (hrc == E_NOTIMPL)
2616 {
2617/** @todo that code doesn't seem to work! */
2618 /* The IShellFolder interface is not implemented on this platform.
2619 * Try the (undocumented) HrRenameConnection API in the netshell
2620 * library. */
2621 CLSID clsid;
2622 hrc = CLSIDFromString((LPOLESTR)pwszGuid, &clsid);
2623 if (FAILED(hrc))
2624 return E_FAIL;
2625
2626 HINSTANCE hNetShell = loadSystemDll(L"netshell.dll");
2627 if (hNetShell == NULL)
2628 return E_FAIL;
2629
2630 typedef HRESULT (WINAPI *PFNHRRENAMECONNECTION)(const GUID *, PCWSTR);
2631 PFNHRRENAMECONNECTION pfnRenameConnection = (PFNHRRENAMECONNECTION)GetProcAddress(hNetShell, "HrRenameConnection");
2632 if (pfnRenameConnection != NULL)
2633 hrc = pfnRenameConnection(&clsid, NewName);
2634 else
2635 hrc = E_FAIL;
2636
2637 FreeLibrary(hNetShell);
2638 }
2639 if (FAILED(hrc))
2640 return hrc;
2641 return S_OK;
2642}
2643
2644
2645VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pBstrErrMsg)
2646{
2647 HRESULT hrc = S_OK;
2648 com::Bstr bstrError;
2649
2650 do /* break non-loop */
2651 {
2652 WCHAR wszPnPInstanceId[512] = {0};
2653
2654 /*
2655 * We have to find the device instance ID through a registry search
2656 */
2657 HKEY hkeyNetwork = NULL;
2658 HKEY hkeyConnection = NULL;
2659 do /* another non-loop for breaking out of */
2660 {
2661 WCHAR wszGuid[50];
2662 int cwcGuid = StringFromGUID2(*pGUID, wszGuid, RT_ELEMENTS(wszGuid));
2663 if (!cwcGuid)
2664 SetErrBreak(("Failed to create a Guid string"));
2665
2666 WCHAR wszRegLocation[128 + RT_ELEMENTS(wszGuid)];
2667 RTUtf16Printf(wszRegLocation, RT_ELEMENTS(wszRegLocation),
2668 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%ls", wszGuid);
2669
2670 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegLocation, 0, KEY_READ, &hkeyNetwork);
2671 if (lrc != ERROR_SUCCESS || !hkeyNetwork)
2672 SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u [1]", wszRegLocation, lrc));
2673
2674 lrc = RegOpenKeyExW(hkeyNetwork, L"Connection", 0, KEY_READ, &hkeyConnection);
2675 if (lrc != ERROR_SUCCESS || !hkeyConnection)
2676 SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u [2]", wszRegLocation, lrc));
2677
2678 DWORD cbValue = sizeof(wszPnPInstanceId) - sizeof(WCHAR);
2679 DWORD dwType = ~0U;
2680 lrc = RegQueryValueExW(hkeyConnection, L"PnPInstanceID", NULL, &dwType, (LPBYTE)wszPnPInstanceId, &cbValue);
2681 if (lrc != ERROR_SUCCESS || dwType != REG_SZ)
2682 SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u, dwType=%u [3]",
2683 wszRegLocation, lrc, dwType));
2684 } while (0);
2685
2686 if (hkeyConnection)
2687 RegCloseKey(hkeyConnection);
2688 if (hkeyNetwork)
2689 RegCloseKey(hkeyNetwork);
2690 if (FAILED(hrc))
2691 break;
2692
2693 /*
2694 * Now we are going to enumerate all network devices and
2695 * wait until we encounter the right device instance ID
2696 */
2697 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2698 do /* break-only, not-a-loop */
2699 {
2700 BOOL ok;
2701
2702 /* initialize the structure size */
2703 SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
2704
2705 /* copy the net class GUID */
2706 GUID netGuid;
2707 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2708
2709 /* return a device info set contains all installed devices of the Net class */
2710 hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
2711 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2712 SetErrBreak(("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2713
2714 /* Enumerate the driver info list. */
2715 bool fFound = false;
2716 for (DWORD index = 0; !fFound; index++)
2717 {
2718 if (!SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData))
2719 {
2720 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2721 break;
2722 continue;
2723 }
2724
2725 /* try to get the hardware ID registry property */
2726 DWORD cbValue = 0;
2727 if (SetupDiGetDeviceRegistryPropertyW(hDeviceInfo,
2728 &DeviceInfoData,
2729 SPDRP_HARDWAREID,
2730 NULL,
2731 NULL,
2732 0,
2733 &cbValue))
2734 continue; /* Something is wrong. This shouldn't have worked with a NULL buffer! */
2735 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2736 continue;
2737
2738 WCHAR *pwszzDeviceHwId = (WCHAR *)RTMemAllocZ(cbValue + sizeof(WCHAR) * 2);
2739 if (!pwszzDeviceHwId)
2740 break;
2741 if (SetupDiGetDeviceRegistryPropertyW(hDeviceInfo,
2742 &DeviceInfoData,
2743 SPDRP_HARDWAREID,
2744 NULL,
2745 (PBYTE)pwszzDeviceHwId,
2746 cbValue,
2747 &cbValue))
2748 {
2749 /* search the string list. */
2750 for (WCHAR *pwszCurHwId = pwszzDeviceHwId;
2751 (uintptr_t)pwszCurHwId - (uintptr_t)pwszzDeviceHwId < cbValue && *pwszCurHwId != L'\0';
2752 pwszCurHwId += RTUtf16Len(pwszCurHwId) + 1)
2753 if (RTUtf16ICmp(DRIVERHWID, pwszCurHwId) == 0)
2754 {
2755 /* get the device instance ID */
2756 WCHAR wszDevId[MAX_DEVICE_ID_LEN];
2757 if (CM_Get_Device_IDW(DeviceInfoData.DevInst, wszDevId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2758 {
2759 /* compare to what we determined before */
2760 if (RTUtf16Cmp(wszDevId, wszPnPInstanceId) == 0)
2761 {
2762 fFound = true;
2763 break;
2764 }
2765 }
2766 }
2767 }
2768 RTMemFree(pwszzDeviceHwId);
2769 }
2770
2771 if (!fFound)
2772 SetErrBreak(("Host Interface Network driver not found (0x%08X)", GetLastError()));
2773
2774 ok = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
2775 if (!ok)
2776 SetErrBreak(("SetupDiSetSelectedDevice failed (0x%08X)", GetLastError()));
2777
2778 ok = SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2779 if (!ok)
2780 SetErrBreak(("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)", GetLastError()));
2781 } while (0);
2782
2783 /* clean up the device info set */
2784 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2785 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2786 } while (0);
2787
2788 if (pBstrErrMsg)
2789 {
2790 *pBstrErrMsg = NULL;
2791 if (bstrError.isNotEmpty())
2792 bstrError.detachToEx(pBstrErrMsg);
2793 }
2794 return hrc;
2795}
2796
2797VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pfRebootRequired, LPCWSTR pcsxwId)
2798{
2799 return VBoxDrvCfgDrvUpdate(pcsxwId, pcsxwInf, pfRebootRequired);
2800}
2801
2802static const char *vboxNetCfgWinGetStateText(DWORD dwState)
2803{
2804 switch (dwState)
2805 {
2806 case SERVICE_STOPPED: return "is not running";
2807 case SERVICE_STOP_PENDING: return "is stopping";
2808 case SERVICE_CONTINUE_PENDING: return "continue is pending";
2809 case SERVICE_PAUSE_PENDING: return "pause is pending";
2810 case SERVICE_PAUSED: return "is paused";
2811 case SERVICE_RUNNING: return "is running";
2812 case SERVICE_START_PENDING: return "is starting";
2813 }
2814 return "state is invalid";
2815}
2816
2817static DWORD vboxNetCfgWinGetNetSetupState(SC_HANDLE hService)
2818{
2819 SERVICE_STATUS status;
2820 status.dwCurrentState = SERVICE_RUNNING;
2821 if (hService) {
2822 if (QueryServiceStatus(hService, &status))
2823 NonStandardLogFlow(("NetSetupSvc %s\n", vboxNetCfgWinGetStateText(status.dwCurrentState)));
2824 else
2825 NonStandardLogFlow(("QueryServiceStatus failed (0x%x)\n", GetLastError()));
2826 }
2827 return status.dwCurrentState;
2828}
2829
2830DECLINLINE(bool) vboxNetCfgWinIsNetSetupRunning(SC_HANDLE hService)
2831{
2832 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_RUNNING;
2833}
2834
2835DECLINLINE(bool) vboxNetCfgWinIsNetSetupStopped(SC_HANDLE hService)
2836{
2837 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_STOPPED;
2838}
2839
2840typedef struct
2841{
2842 BSTR bstrName;
2843 GUID *pGuid;
2844 HRESULT hr;
2845} RENAMING_CONTEXT;
2846
2847static BOOL vboxNetCfgWinRenameHostOnlyNetworkInterface(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
2848{
2849 RT_NOREF1(pNc);
2850 RENAMING_CONTEXT *pParams = (RENAMING_CONTEXT *)pContext;
2851
2852 GUID guid;
2853 pParams->hr = pNcc->GetInstanceGuid(&guid);
2854 if ( pParams->hr == S_OK && guid == *pParams->pGuid)
2855 {
2856 /* Located our component, rename it */
2857 pParams->hr = pNcc->SetDisplayName(pParams->bstrName);
2858 return FALSE;
2859 }
2860 return TRUE;
2861}
2862
2863/**
2864 * Enumerate all host-only adapters collecting their names into a set, then
2865 * come up with the next available name by taking the first unoccupied index.
2866 */
2867static HRESULT vboxNetCfgWinNextAvailableDevName(com::Bstr *pbstrName)
2868{
2869 SP_DEVINFO_DATA DeviceInfoData = { sizeof(SP_DEVINFO_DATA) };
2870 HDEVINFO hDeviceInfoSet = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT);
2871 if (hDeviceInfoSet == INVALID_HANDLE_VALUE)
2872 return HRESULT_FROM_WIN32(GetLastError());
2873
2874 typedef struct VBOXDEVNAMEENTRY
2875 {
2876 RTLISTNODE ListEntry;
2877 WCHAR wszDevName[64];
2878 WCHAR wcZeroParanoia;
2879 } VBOXDEVNAMEENTRY;
2880
2881#if 0
2882 /*
2883 * Build a list of names starting with HOSTONLY_ADAPTER_NAME_WSZ belonging to our device.
2884 */
2885 RTLISTANCHOR Head; /* VBOXDEVNAMEENTRY */
2886 RTListInit(&Head);
2887 HRESULT hrc = S_OK;
2888#else
2889 /*
2890 * Build a bitmap of in-use index values of devices starting with HOSTONLY_ADAPTER_NAME_WSZ.
2891 * Reserving 0 for one w/o a suffix, and marking 1 as unusable.
2892 */
2893 uint64_t bmIndexes[_32K / 64]; /* 4KB - 32767 device should be sufficient. */
2894 RT_ZERO(bmIndexes);
2895 ASMBitSet(&bmIndexes, 1);
2896#endif
2897 for (DWORD i = 0; SetupDiEnumDeviceInfo(hDeviceInfoSet, i, &DeviceInfoData); ++i)
2898 {
2899 /* Should be more than enough for both our device id and our device name, we do not care about the rest */
2900 VBOXDEVNAMEENTRY Entry = { { 0, 0 }, L"", 0 }; /* (initialize it to avoid the wrath of asan) */
2901 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID,
2902 NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL))
2903 continue;
2904
2905 /* Ignore everything except our host-only adapters */
2906 if (RTUtf16ICmp(Entry.wszDevName, DRIVERHWID) == 0)
2907 {
2908 if ( SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_FRIENDLYNAME,
2909 NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL)
2910 || SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_DEVICEDESC,
2911 NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL))
2912 {
2913 /* We can ignore any host-only adapter with a non-standard name. */
2914 if (RTUtf16NICmp(Entry.wszDevName, HOSTONLY_ADAPTER_NAME_WSZ,
2915 RT_ELEMENTS(HOSTONLY_ADAPTER_NAME_WSZ) - 1) == 0)
2916 {
2917#if 0
2918 VBOXDEVNAMEENTRY *pEntry = (VBOXDEVNAMEENTRY *)RTMemDup(&Entry, sizeof(Entry));
2919 if (pEntry)
2920 RTListAppend(&Head, &pEntry->ListEntry);
2921 else
2922 {
2923 hrc = E_OUTOFMEMORY;
2924 break;
2925 }
2926#else
2927 WCHAR const *pwc = &Entry.wszDevName[RT_ELEMENTS(HOSTONLY_ADAPTER_NAME_WSZ) - 1];
2928
2929 /* skip leading space */
2930 WCHAR wc = *pwc;
2931 while (wc == L' ' || wc == L'\t' || wc == L'\n' || wc == L'\r')
2932 wc = *++pwc;
2933
2934 /* If end of string, use index 0. */
2935 if (wc == L'\0')
2936 ASMBitSet(bmIndexes, 0);
2937
2938 /* Hash and digit? */
2939 else if (wc == L'#')
2940 {
2941 wc = *++pwc;
2942 while (wc == L' ' || wc == L'\t' || wc == L'\n' || wc == L'\r') /* just in case */
2943 wc = *++pwc;
2944 if (wc >= L'0' && wc <= L'9')
2945 {
2946 /* Convert what we can to a number and mark it as allocated in the bitmap. */
2947 uint64_t uIndex = wc - L'0';
2948 while ((wc = *++pwc) >= L'0' && wc <= L'9')
2949 uIndex = uIndex * 10 + wc - L'0';
2950 if (uIndex < sizeof(bmIndexes) * 8 && uIndex > 0)
2951 ASMBitSet(bmIndexes, (int32_t)uIndex);
2952 }
2953 }
2954#endif
2955 }
2956 }
2957 }
2958 }
2959#if 0
2960 if (SUCCEEDED(hrc))
2961 {
2962 /*
2963 * First try a name w/o an index, then try index #2 and up.
2964 *
2965 * Note! We have to use ASCII/UTF-8 strings here as Bstr will confuse WCHAR
2966 * with BSTR/OLECHAR strings and use SysAllocString to duplicate it .
2967 */
2968 char szName[sizeof(HOSTONLY_ADAPTER_NAME_SZ " #4294967296") + 32] = HOSTONLY_ADAPTER_NAME_SZ;
2969 size_t const cchBase = sizeof(HOSTONLY_ADAPTER_NAME_SZ) - 1;
2970 for (DWORD idx = 2;; idx++)
2971 {
2972 bool fFound = false;
2973 VBOXDEVNAMEENTRY *pCur;
2974 RTListForEach(&Head, pCur, VBOXDEVNAMEENTRY, ListEntry)
2975 {
2976 fFound = RTUtf16ICmpAscii(pCur->wszDevName, szName) == 0;
2977 if (fFound)
2978 {
2979 hrc = pbstrName->assignEx(szName);
2980 break;
2981 }
2982 }
2983 if (fFound)
2984 break;
2985 RTStrPrintf(&szName[cchBase], sizeof(szName) - cchBase, " #%u", idx);
2986 }
2987 }
2988
2989 VBOXDEVNAMEENTRY *pFirst;
2990 while ((pFirst = RTListRemoveFirst(&Head, VBOXDEVNAMEENTRY, ListEntry)) != NULL)
2991 RTMemFree(pFirst);
2992
2993#else
2994 /*
2995 * Find an unused index value and format the corresponding name.
2996 */
2997 HRESULT hrc;
2998 int32_t iBit = ASMBitFirstClear(bmIndexes, sizeof(bmIndexes) * 8);
2999 if (iBit >= 0)
3000 {
3001 if (iBit == 0)
3002 hrc = pbstrName->assignEx(HOSTONLY_ADAPTER_NAME_SZ); /* Not _WSZ! */
3003 else
3004 hrc = pbstrName->printfNoThrow(HOSTONLY_ADAPTER_NAME_SZ " #%u", iBit);
3005 }
3006 else
3007 {
3008 NonStandardLogFlow(("vboxNetCfgWinNextAvailableDevName: no unused index in the first 32K!\n"));
3009 hrc = E_FAIL;
3010 }
3011#endif
3012
3013 if (hDeviceInfoSet)
3014 SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
3015 return hrc;
3016}
3017
3018static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile,
3019 IN BSTR pBstrDesiredName,
3020 OUT GUID *pGuid, OUT BSTR *pBstrName, OUT BSTR *pBstrErrMsg)
3021{
3022 com::Bstr bstrError;
3023
3024 /* Determine the interface name. We make a copy of the input here for
3025 renaming reasons, see futher down. */
3026 com::Bstr bstrNewInterfaceName;
3027 HRESULT hrc;
3028 if (SysStringLen(pBstrDesiredName) != 0)
3029 hrc = bstrNewInterfaceName.assignEx(pBstrDesiredName);
3030 else
3031 {
3032 hrc = vboxNetCfgWinNextAvailableDevName(&bstrNewInterfaceName);
3033 if (FAILED(hrc))
3034 NonStandardLogFlow(("vboxNetCfgWinNextAvailableDevName failed with 0x%x\n", hrc));
3035 }
3036 if (FAILED(hrc))
3037 return hrc;
3038
3039 WCHAR wszCfgGuidString[50] = {0};
3040 WCHAR wszDevName[256 + 1] = {0};
3041 SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
3042 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
3043 PVOID pQueueCallbackContext = NULL;
3044 BOOL fRegistered = FALSE;
3045 BOOL destroyList = FALSE;
3046 HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
3047 LSTATUS lrcRet = ERROR_SUCCESS; /* the */
3048
3049 do /* non-loop, for breaking. */
3050 {
3051 /* copy the net class GUID */
3052 GUID netGuid;
3053 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
3054
3055 /* Create an empty device info set associated with the net class GUID: */
3056 hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
3057 if (hDeviceInfo == INVALID_HANDLE_VALUE)
3058 SetErrBreak(("SetupDiCreateDeviceInfoList failed (%Rwc)", GetLastError()));
3059
3060 /* Translate the GUID to a class name: */
3061 WCHAR wszClassName[MAX_PATH];
3062 if (!SetupDiClassNameFromGuid(&netGuid, wszClassName, MAX_PATH, NULL))
3063 SetErrBreak(("SetupDiClassNameFromGuid failed (%Rwc)", GetLastError()));
3064
3065 /* Create a device info element and add the new device instance key to registry: */
3066 if (!SetupDiCreateDeviceInfo(hDeviceInfo, wszClassName, &netGuid, NULL, NULL, DICD_GENERATE_ID, &DeviceInfoData))
3067 SetErrBreak(("SetupDiCreateDeviceInfo failed (%Rwc)", GetLastError()));
3068
3069 /* Select the newly created device info to be the currently selected member: */
3070 if (!SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData))
3071 SetErrBreak(("SetupDiSetSelectedDevice failed (%Rwc)", GetLastError()));
3072
3073 SP_DEVINSTALL_PARAMS DeviceInstallParams;
3074 if (pwszInfPath)
3075 {
3076 /* get the device install parameters and disable filecopy */
3077 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3078 if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3079 {
3080 memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
3081 size_t pathLenght = wcslen(pwszInfPath) + 1/* null terminator */;
3082 if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
3083 {
3084 memcpy(DeviceInstallParams.DriverPath, pwszInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
3085
3086 if (fIsInfPathFile)
3087 DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
3088
3089 if (!SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3090 {
3091 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed (%Rwc)\n", GetLastError()));
3092 break;
3093 }
3094 }
3095 else
3096 {
3097 NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
3098 break;
3099 }
3100 }
3101 else
3102 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed (%Rwc)\n", GetLastError()));
3103 }
3104
3105 /* build a list of class drivers */
3106 if (!SetupDiBuildDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER))
3107 SetErrBreak(("SetupDiBuildDriverInfoList failed (%Rwc)", GetLastError()));
3108
3109 destroyList = TRUE;
3110
3111 /*
3112 * Enumerate the driver info list.
3113 */
3114 /* For our purposes, 2k buffer is more than enough to obtain the
3115 hardware ID of the VBoxNetAdp driver. */ /** @todo r=bird: The buffer isn't 2KB, it's 8KB, but whatever. */
3116 DWORD detailBuf[2048];
3117 SP_DRVINFO_DATA DriverInfoData = { sizeof(DriverInfoData) };
3118 bool fFound = false;
3119 for (DWORD index = 0; !fFound; index++)
3120 {
3121 /* If the function fails with last error set to ERROR_NO_MORE_ITEMS,
3122 then we have reached the end of the list. Otherwise there was
3123 something wrong with this particular driver. */
3124 if (!SetupDiEnumDriverInfo(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER, index, &DriverInfoData))
3125 {
3126 if (GetLastError() == ERROR_NO_MORE_ITEMS)
3127 break;
3128 continue;
3129 }
3130
3131 /* if we successfully find the hardware ID and it turns out to
3132 * be the one for the loopback driver, then we are done. */
3133 PSP_DRVINFO_DETAIL_DATA_W pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA_W)detailBuf;
3134 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
3135 DWORD cbValue = 0;
3136 if (SetupDiGetDriverInfoDetailW(hDeviceInfo,
3137 &DeviceInfoData,
3138 &DriverInfoData,
3139 pDriverInfoDetail,
3140 sizeof(detailBuf) - sizeof(detailBuf[0]),
3141 &cbValue))
3142 {
3143 /* Sure that the HardwareID string list is properly zero terminated (paranoia). */
3144 detailBuf[RT_ELEMENTS(detailBuf) - 1] = 0; AssertCompile(sizeof(detailBuf[0]) == sizeof(WCHAR) * 2);
3145
3146 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the whole
3147 list and see if there is a match somewhere: */
3148 for (WCHAR *pwszCurHwId = pDriverInfoDetail->HardwareID;
3149 (uintptr_t)pwszCurHwId - (uintptr_t)pDriverInfoDetail < cbValue && *pwszCurHwId != L'\0';
3150 pwszCurHwId += RTUtf16Len(pwszCurHwId) + 1)
3151 if (RTUtf16ICmp(DRIVERHWID, pwszCurHwId) == 0)
3152 {
3153 fFound = true;
3154 break;
3155 }
3156 }
3157 }
3158
3159 if (!fFound)
3160 SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
3161
3162 /* set the loopback driver to be the currently selected */
3163 if (!SetupDiSetSelectedDriver(hDeviceInfo, &DeviceInfoData, &DriverInfoData))
3164 SetErrBreak(("SetupDiSetSelectedDriver failed (%u)", GetLastError()));
3165
3166 /* register the phantom device to prepare for install */
3167 if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDeviceInfo, &DeviceInfoData))
3168 SetErrBreak(("SetupDiCallClassInstaller failed (%u)", GetLastError()));
3169
3170 /* registered, but remove if errors occur in the following code */
3171 fRegistered = TRUE;
3172
3173 /* ask the installer if we can install the device */
3174 if (!SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, hDeviceInfo, &DeviceInfoData))
3175 {
3176 if (GetLastError() != ERROR_DI_DO_DEFAULT)
3177 SetErrBreak(("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (%u)", GetLastError()));
3178 /* that's fine */
3179 }
3180
3181 /* get the device install parameters and disable filecopy */
3182 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3183 if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3184 {
3185 pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
3186 if (pQueueCallbackContext)
3187 {
3188 DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
3189 DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
3190 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3191 {
3192 DWORD winEr = GetLastError();
3193 NonStandardLogFlow(("SetupDiSetDeviceInstallParamsW failed, winEr (%d)\n", winEr));
3194 Assert(0);
3195 }
3196 }
3197 else
3198 {
3199 DWORD winEr = GetLastError();
3200 NonStandardLogFlow(("SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr));
3201 }
3202 }
3203 else
3204 {
3205 DWORD winEr = GetLastError();
3206 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
3207 }
3208
3209 /* install the files first */
3210 if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, hDeviceInfo, &DeviceInfoData))
3211 SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (%Rwc)", GetLastError()));
3212
3213 /* get the device install parameters and disable filecopy */
3214 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3215 if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3216 {
3217 DeviceInstallParams.Flags |= DI_NOFILECOPY;
3218 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3219 SetErrBreak(("SetupDiSetDeviceInstallParamsW failed (%Rwc)", GetLastError()));
3220 }
3221 /** @todo r=bird: Why isn't SetupDiGetDeviceInstallParams failure fatal here? */
3222
3223 /*
3224 * Register any device-specific co-installers for this device,
3225 */
3226 if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, hDeviceInfo, &DeviceInfoData))
3227 SetErrBreak(("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (%Rwc)", GetLastError()));
3228
3229 /*
3230 * install any installer-specified interfaces.
3231 * and then do the real install
3232 */
3233 if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, hDeviceInfo, &DeviceInfoData))
3234 SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (%Rwc)", GetLastError()));
3235
3236 if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, hDeviceInfo, &DeviceInfoData))
3237 SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (%Rwc)", GetLastError()));
3238
3239 /*
3240 * Query the instance ID; on Windows 10, the registry key may take a short
3241 * while to appear. Microsoft recommends waiting for up to 5 seconds, but
3242 * we want to be on the safe side, so let's wait for 20 seconds. Waiting
3243 * longer is harmful as network setup service will shut down after a period
3244 * of inactivity.
3245 */
3246 for (int retries = 0; retries < 2 * 20; ++retries)
3247 {
3248 Sleep(500); /* half second */
3249
3250 /* Figure out NetCfgInstanceId */
3251 hkey = SetupDiOpenDevRegKey(hDeviceInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ);
3252 if (hkey == INVALID_HANDLE_VALUE)
3253 break;
3254
3255 DWORD cbSize = sizeof(wszCfgGuidString);
3256 DWORD dwValueType = 0;
3257 lrcRet = RegQueryValueExW(hkey, L"NetCfgInstanceId", NULL, &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
3258 /* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
3259 if (lrcRet != ERROR_FILE_NOT_FOUND)
3260 break;
3261
3262 RegCloseKey(hkey);
3263 hkey = (HKEY)INVALID_HANDLE_VALUE;
3264 }
3265
3266 if (lrcRet == ERROR_FILE_NOT_FOUND)
3267 {
3268 hrc = E_ABORT;
3269 break;
3270 }
3271
3272 /*
3273 * We need to check 'hkey' after we check 'lrcRet' to distinguish the case
3274 * of failed SetupDiOpenDevRegKey from the case when we timed out.
3275 */
3276 if (hkey == INVALID_HANDLE_VALUE)
3277 SetErrBreak(("SetupDiOpenDevRegKey failed (%Rwc)", GetLastError()));
3278
3279 if (lrcRet != ERROR_SUCCESS)
3280 SetErrBreak(("Querying NetCfgInstanceId failed (%Rwc)", lrcRet));
3281
3282 NET_LUID luid;
3283 HRESULT hrcSMRes = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
3284
3285 /* Close the key as soon as possible. See @bugref{7973}. */
3286 RegCloseKey(hkey);
3287 hkey = (HKEY)INVALID_HANDLE_VALUE;
3288
3289 if (FAILED(hrcSMRes))
3290 {
3291 /*
3292 * The setting of Metric is not very important functionality,
3293 * So we will not break installation process due to this error.
3294 */
3295 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface: Warning! "
3296 "vboxNetCfgWinGetInterfaceLUID failed, default metric for new interface will not be set: %Rhrc\n",
3297 hrcSMRes));
3298 }
3299 else
3300 {
3301 /*
3302 * Set default metric value of interface to fix multicast issue
3303 * See @bugref{6379} for details.
3304 */
3305 hrcSMRes = vboxNetCfgWinSetupMetric(&luid);
3306 if (FAILED(hrcSMRes))
3307 {
3308 /*
3309 * The setting of Metric is not very important functionality,
3310 * So we will not break installation process due to this error.
3311 */
3312 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface: Warning! "
3313 "vboxNetCfgWinSetupMetric failed, default metric for new interface will not be set: %Rhrc\n",
3314 hrcSMRes));
3315 }
3316 }
3317
3318 /*
3319 * We need to query the device name after we have succeeded in querying its
3320 * instance ID to avoid similar waiting-and-retrying loop (see @bugref{7973}).
3321 */
3322 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3323 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
3324 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3325 (PBYTE)wszDevName, /*OUT PBYTE PropertyBuffer,*/
3326 sizeof(wszDevName) - sizeof(WCHAR), /* IN DWORD PropertyBufferSize,*/
3327 NULL /*OUT PDWORD RequiredSize OPTIONAL*/ ))
3328 {
3329 DWORD dwErr = GetLastError();
3330 if (dwErr != ERROR_INVALID_DATA)
3331 SetErrBreak(("SetupDiGetDeviceRegistryProperty failed (%Rwc)", dwErr));
3332
3333 RT_ZERO(wszDevName);
3334 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3335 SPDRP_DEVICEDESC, /* IN DWORD Property,*/
3336 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3337 (PBYTE)wszDevName, /*OUT PBYTE PropertyBuffer,*/
3338 sizeof(wszDevName) - sizeof(WCHAR), /* IN DWORD PropertyBufferSize,*/
3339 NULL /*OUT PDWORD RequiredSize OPTIONAL*/ ))
3340 SetErrBreak(("SetupDiGetDeviceRegistryProperty failed (%Rwc)", GetLastError()));
3341 }
3342
3343 /* No need to rename the device if the names match. */
3344 if (RTUtf16Cmp(bstrNewInterfaceName.raw(), wszDevName) == 0)
3345 bstrNewInterfaceName.setNull();
3346
3347#ifdef VBOXNETCFG_DELAYEDRENAME
3348 /* Re-use wszDevName for device instance id retrieval. */
3349 DWORD cwcReturned = 0;
3350 RT_ZERO(wszDevName);
3351 if (!SetupDiGetDeviceInstanceIdW(hDeviceInfo, &DeviceInfoData, wszDevName, RT_ELEMENTS(wszDevName) - 1, &cwcReturned))
3352 SetErrBreak(("SetupDiGetDeviceInstanceId failed (%Rwc)", GetLastError()));
3353#endif /* VBOXNETCFG_DELAYEDRENAME */
3354 } while (0);
3355
3356 /*
3357 * Cleanup.
3358 */
3359 if (hkey != INVALID_HANDLE_VALUE)
3360 RegCloseKey(hkey);
3361
3362 if (pQueueCallbackContext)
3363 SetupTermDefaultQueueCallback(pQueueCallbackContext);
3364
3365 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3366 {
3367 /* an error has occurred, but the device is registered, we must remove it */
3368 if (lrcRet != ERROR_SUCCESS && fRegistered)
3369 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
3370
3371 SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
3372
3373 /* destroy the driver info list */
3374#if 0
3375 /* I've remove this, as I was consistently getting crashes in
3376 * SetupDiDestroyDeviceInfoList otherwise during MSI installation
3377 * (W10 build 19044, VBox r153431 + nocrt changes).
3378 *
3379 * Some details from windbg:
3380 *
3381 * (175e8.1596c): Access violation - code c0000005 (first chance)
3382 * First chance exceptions are reported before any exception handling.
3383 * This exception may be expected and handled.
3384 * SETUPAPI!DereferenceClassDriverList+0x4e:
3385 * 00007ffa`83e2a42a 834008ff add dword ptr [rax+8],0FFFFFFFFh ds:00000000`00000008=????????
3386 * 0:006> k
3387 * # Child-SP RetAddr Call Site
3388 * 00 0000007e`ccd7c070 00007ffa`83e2a287 SETUPAPI!DereferenceClassDriverList+0x4e
3389 * 01 0000007e`ccd7c0a0 00007ffa`56b96bd3 SETUPAPI!SetupDiDestroyDriverInfoList+0x117
3390 * 02 0000007e`ccd7c0f0 00007ffa`56b982a3 MSIF170!vboxNetCfgWinCreateHostOnlyNetworkInterface+0xb23 [E:\vbox\svn\trunk\src\VBox\HostDrivers\VBoxNetFlt\win\cfg\VBoxNetCfg.cpp @ 3378]
3391 * 03 0000007e`ccd7ef10 00007ffa`56b92cb8 MSIF170!VBoxNetCfgWinCreateHostOnlyNetworkInterface+0x53 [E:\vbox\svn\trunk\src\VBox\HostDrivers\VBoxNetFlt\win\cfg\VBoxNetCfg.cpp @ 3479]
3392 * 04 0000007e`ccd7efc0 00007ffa`610f59d3 MSIF170!_createHostOnlyInterface+0x218 [E:\vbox\svn\trunk\src\VBox\Installer\win\InstallHelper\VBoxInstallHelper.cpp @ 1453]
3393 * 05 0000007e`ccd7f260 00007ffa`610d80ac msi!CallCustomDllEntrypoint+0x2b
3394 * 06 0000007e`ccd7f2d0 00007ffa`84567034 msi!CMsiCustomAction::CustomActionThread+0x34c
3395 * 07 0000007e`ccd7f8c0 00007ffa`849a2651 KERNEL32!BaseThreadInitThunk+0x14
3396 * 08 0000007e`ccd7f8f0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
3397 * 0:006> r
3398 * rax=0000000000000000 rbx=0000025f4f03af90 rcx=00007ffa83f23b40
3399 * rdx=0000025f4f03af90 rsi=0000025f5108be50 rdi=0000025f4f066f10
3400 * rip=00007ffa83e2a42a rsp=0000007eccd7c070 rbp=00007ffa83f23000
3401 * r8=0000007eccd7c0a8 r9=0000007eccd7c1f0 r10=0000000000000000
3402 * r11=0000007eccd7c020 r12=0000007eccd7c3d0 r13=00007ffa83f23000
3403 * r14=0000000000000000 r15=0000025f4f03af90
3404 * iopl=0 nv up ei pl nz na po nc
3405 * cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
3406 * SETUPAPI!DereferenceClassDriverList+0x4e:
3407 * 00007ffa`83e2a42a 834008ff add dword ptr [rax+8],0FFFFFFFFh ds:00000000`00000008=????????
3408 *
3409 */
3410 if (destroyList)
3411 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER);
3412#else
3413 RT_NOREF(destroyList);
3414#endif
3415
3416 /* clean up the device info set */
3417 SetupDiDestroyDeviceInfoList(hDeviceInfo);
3418 }
3419
3420 /*
3421 * Return the network connection GUID on success.
3422 */
3423 if (SUCCEEDED(hrc))
3424 {
3425 /** @todo r=bird: Some please explain this mess. It's not just returning a
3426 * GUID here, it's a bit more than that. */
3427 RENAMING_CONTEXT context;
3428 context.hr = E_FAIL;
3429
3430 if (pGuid)
3431 {
3432 hrc = CLSIDFromString(wszCfgGuidString, (LPCLSID)pGuid);
3433 if (FAILED(hrc))
3434 NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
3435 }
3436
3437 INetCfg *pNetCfg = NULL;
3438 LPWSTR pwszApp = NULL;
3439 HRESULT hrc2 = VBoxNetCfgWinQueryINetCfg(&pNetCfg, TRUE, L"VirtualBox Host-Only Creation",
3440 30 * 1000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec. */
3441 /** @todo special handling for 6to4svc.dll ???, i.e. several retrieves */
3442 &pwszApp);
3443 if (hrc2 == S_OK)
3444 {
3445 if (bstrNewInterfaceName.isNotEmpty())
3446 {
3447 /* The assigned name does not match the desired one, rename the device */
3448 context.bstrName = bstrNewInterfaceName.raw();
3449 context.pGuid = pGuid;
3450 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NET,
3451 vboxNetCfgWinRenameHostOnlyNetworkInterface, &context);
3452 }
3453 if (SUCCEEDED(hrc2))
3454 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETSERVICE,
3455 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
3456 if (SUCCEEDED(hrc2))
3457 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETTRANS,
3458 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
3459 if (SUCCEEDED(hrc2))
3460 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETCLIENT,
3461 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
3462 if (SUCCEEDED(hrc2))
3463 hrc2 = pNetCfg->Apply();
3464 else
3465 NonStandardLogFlow(("Enumeration failed, hrc2=%Rhrc\n", hrc2));
3466
3467 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
3468 }
3469 else if (hrc2 == NETCFG_E_NO_WRITE_LOCK && pwszApp)
3470 {
3471 NonStandardLogFlow(("Application '%ls' is holding the lock, failed\n", pwszApp));
3472 CoTaskMemFree(pwszApp);
3473 pwszApp = NULL;
3474 }
3475 else
3476 NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hrc2=%Rhrc\n", hrc2));
3477
3478#ifndef VBOXNETCFG_DELAYEDRENAME
3479 /* If the device has been successfully renamed, replace the name now. */
3480 if (SUCCEEDED(hrc2) && SUCCEEDED(context.hr))
3481 RTUtf16Copy(wszDevName, RT_ELEMENTS(wszDevName), pBstrDesiredName);
3482
3483 WCHAR wszConnectionName[128];
3484 hrc2 = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionName, RT_ELEMENTS(wszConnectionName), NULL);
3485 if (SUCCEEDED(hrc2))
3486 hrc2 = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszConnectionName);
3487#endif
3488
3489 /*
3490 * Now, return the network connection GUID/name.
3491 */
3492 if (pBstrName)
3493 {
3494 *pBstrName = SysAllocString((const OLECHAR *)wszDevName);
3495 if (!*pBstrName)
3496 {
3497 NonStandardLogFlow(("SysAllocString failed\n"));
3498 hrc = E_OUTOFMEMORY;
3499 }
3500 }
3501 }
3502
3503 if (pBstrErrMsg)
3504 {
3505 *pBstrErrMsg = NULL;
3506 if (bstrError.isNotEmpty())
3507 bstrError.detachToEx(pBstrErrMsg);
3508 }
3509 return hrc;
3510}
3511
3512VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile,
3513 IN BSTR pwszDesiredName, OUT GUID *pGuid,
3514 OUT BSTR *pBstrName, OUT BSTR *pBstrErrMsg)
3515{
3516 HRESULT hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
3517 pGuid, pBstrName, pBstrErrMsg);
3518 if (hrc == E_ABORT)
3519 {
3520 NonStandardLogFlow(("Timed out while waiting for NetCfgInstanceId, try again immediately...\n"));
3521
3522 /*
3523 * This is the first time we fail to obtain NetCfgInstanceId, let us
3524 * retry it once. It is needed to handle the situation when network
3525 * setup fails to recognize the arrival of our device node while it
3526 * is busy removing another host-only interface, and it gets stuck
3527 * with no matching network interface created for our device node.
3528 * See @bugref{7973} for details.
3529 */
3530 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
3531 pGuid, pBstrName, pBstrErrMsg);
3532 if (hrc == E_ABORT)
3533 {
3534 NonStandardLogFlow(("Timed out again while waiting for NetCfgInstanceId, try again after a while...\n"));
3535
3536 /*
3537 * This is the second time we fail to obtain NetCfgInstanceId, let us
3538 * retry it once more. This time we wait to network setup service
3539 * to go down before retrying. Hopefully it will resolve all error
3540 * conditions. See @bugref{7973} for details.
3541 */
3542 SC_HANDLE hSCM = OpenSCManagerW(NULL, NULL, GENERIC_READ);
3543 if (hSCM)
3544 {
3545 SC_HANDLE hService = OpenServiceW(hSCM, L"NetSetupSvc", GENERIC_READ);
3546 if (hService)
3547 {
3548 for (int retries = 0; retries < 60 && !vboxNetCfgWinIsNetSetupStopped(hService); ++retries)
3549 Sleep(1000);
3550 CloseServiceHandle(hService);
3551 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
3552 pGuid, pBstrName, pBstrErrMsg);
3553 }
3554 else
3555 NonStandardLogFlow(("OpenService failed (%Rwc)\n", GetLastError()));
3556 CloseServiceHandle(hSCM);
3557 }
3558 else
3559 NonStandardLogFlow(("OpenSCManager failed (%Rwc)", GetLastError()));
3560
3561 /* Give up and report the error. */
3562 if (hrc == E_ABORT)
3563 {
3564 if (pBstrErrMsg)
3565 {
3566 com::Bstr bstrError;
3567 bstrError.printfNoThrow("Querying NetCfgInstanceId failed (ERROR_FILE_NOT_FOUND)");
3568 bstrError.detachToEx(pBstrErrMsg);
3569 }
3570 hrc = E_FAIL;
3571 }
3572 }
3573 }
3574 return hrc;
3575}
3576
3577static HRESULT vboxNetCfgWinGetLoopbackMetric(OUT DWORD *Metric)
3578{
3579 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3580 Assert(g_pfnGetIpInterfaceEntry != NULL);
3581
3582 MIB_IPINTERFACE_ROW row;
3583 RT_ZERO(row); /* paranoia */
3584 g_pfnInitializeIpInterfaceEntry(&row);
3585
3586 row.Family = AF_INET;
3587 row.InterfaceLuid.Info.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
3588
3589 NETIO_STATUS dwErr = g_pfnGetIpInterfaceEntry(&row);
3590 if (dwErr == NO_ERROR)
3591 {
3592 *Metric = row.Metric;
3593 return S_OK;
3594 }
3595 return HRESULT_FROM_WIN32(dwErr);
3596}
3597
3598static HRESULT vboxNetCfgWinSetInterfaceMetric(IN NET_LUID *pInterfaceLuid, IN DWORD metric)
3599{
3600 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3601 Assert(g_pfnSetIpInterfaceEntry != NULL);
3602
3603 MIB_IPINTERFACE_ROW newRow;
3604 RT_ZERO(newRow); /* paranoia */
3605 g_pfnInitializeIpInterfaceEntry(&newRow);
3606
3607 // identificate the interface to change
3608 newRow.InterfaceLuid = *pInterfaceLuid;
3609 newRow.Family = AF_INET;
3610
3611 // changed settings
3612 newRow.UseAutomaticMetric = false;
3613 newRow.Metric = metric;
3614
3615 // change settings
3616 NETIO_STATUS dwErr = g_pfnSetIpInterfaceEntry(&newRow);
3617 if (dwErr == NO_ERROR)
3618 return S_OK;
3619 return HRESULT_FROM_WIN32(dwErr);
3620}
3621
3622static HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid)
3623{
3624 HRESULT hrc = E_FAIL;
3625 HMODULE hmod = loadSystemDll(L"Iphlpapi.dll");
3626 if (hmod)
3627 {
3628 g_pfnInitializeIpInterfaceEntry = (PFNINITIALIZEIPINTERFACEENTRY)GetProcAddress(hmod, "InitializeIpInterfaceEntry");
3629 g_pfnGetIpInterfaceEntry = (PFNGETIPINTERFACEENTRY) GetProcAddress(hmod, "GetIpInterfaceEntry");
3630 g_pfnSetIpInterfaceEntry = (PFNSETIPINTERFACEENTRY) GetProcAddress(hmod, "SetIpInterfaceEntry");
3631 Assert(g_pfnInitializeIpInterfaceEntry);
3632 Assert(g_pfnGetIpInterfaceEntry);
3633 Assert(g_pfnSetIpInterfaceEntry);
3634
3635 if ( g_pfnInitializeIpInterfaceEntry
3636 && g_pfnGetIpInterfaceEntry
3637 && g_pfnSetIpInterfaceEntry)
3638 {
3639 DWORD loopbackMetric = 0;
3640 hrc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
3641 if (SUCCEEDED(hrc))
3642 hrc = vboxNetCfgWinSetInterfaceMetric(pLuid, loopbackMetric - 1);
3643 }
3644
3645 g_pfnInitializeIpInterfaceEntry = NULL;
3646 g_pfnSetIpInterfaceEntry = NULL;
3647 g_pfnGetIpInterfaceEntry = NULL;
3648
3649 FreeLibrary(hmod);
3650 }
3651 return hrc;
3652}
3653
3654static HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID *pLUID)
3655{
3656 if (pLUID == NULL)
3657 return E_INVALIDARG;
3658
3659 DWORD dwLuidIndex = 0;
3660 DWORD cbSize = sizeof(dwLuidIndex);
3661 DWORD dwValueType = REG_DWORD; /** @todo r=bird: This is output only. No checked after the call. So, only for debugging? */
3662 LSTATUS lrc = RegQueryValueExW(hKey, L"NetLuidIndex", NULL, &dwValueType, (LPBYTE)&dwLuidIndex, &cbSize);
3663 if (lrc == ERROR_SUCCESS)
3664 {
3665 DWORD dwIfType = 0;
3666 cbSize = sizeof(dwIfType);
3667 dwValueType = REG_DWORD; /** @todo r=bird: This is output only. No checked after the call. So, only for debugging? */
3668 lrc = RegQueryValueExW(hKey, L"*IfType", NULL, &dwValueType, (LPBYTE)&dwIfType, &cbSize);
3669 if (lrc == ERROR_SUCCESS)
3670 {
3671 RT_ZERO(*pLUID);
3672 pLUID->Info.IfType = dwIfType;
3673 pLUID->Info.NetLuidIndex = dwLuidIndex;
3674 return S_OK;
3675 }
3676 }
3677
3678 RT_ZERO(*pLUID);
3679 return HRESULT_FROM_WIN32(lrc);
3680}
3681
3682
3683#ifdef VBOXNETCFG_DELAYEDRENAME
3684VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pwszId, OUT BSTR *pDevName)
3685{
3686 if (pDevName)
3687 *pDevName = NULL;
3688
3689 HRESULT hr = S_OK; /** @todo r=bird: ODD return status for SetupDiCreateDeviceInfoList failures! */
3690 HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
3691 if (hDevInfo != INVALID_HANDLE_VALUE)
3692 {
3693 SP_DEVINFO_DATA DevInfoData = { sizeof(SP_DEVINFO_DATA) };
3694 if (SetupDiOpenDeviceInfo(hDevInfo, pwszId, NULL, 0, &DevInfoData))
3695 {
3696 WCHAR wszDevName[256 + 1] = {0};
3697 DWORD err = ERROR_SUCCESS;
3698 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, SPDRP_FRIENDLYNAME, NULL /*PropertyRegDataType*/,
3699 (PBYTE)wszDevName, sizeof(wszDevName) - sizeof(WCHAR) /*yes, bytes*/,
3700 NULL /*RequiredSize*/))
3701 {
3702 err = GetLastError();
3703 if (err == ERROR_INVALID_DATA)
3704 {
3705 RT_ZERO(wszDevName);
3706 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, SPDRP_DEVICEDESC, NULL /*PropertyRegDataType*/,
3707 (PBYTE)wszDevName, sizeof(wszDevName) - sizeof(WCHAR) /*yes, bytes*/,
3708 NULL /*RequiredSize*/))
3709 err = ERROR_SUCCESS;
3710 else
3711 err = GetLastError();
3712 }
3713 }
3714 if (err == ERROR_SUCCESS)
3715 {
3716 WCHAR wszConnectionNewName[128] = {0};
3717 hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionNewName,
3718 RT_ELEMENTS(wszConnectionNewName), NULL);
3719 if (SUCCEEDED(hr))
3720 {
3721 WCHAR wszGuid[50];
3722 int cbWGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
3723 if (cbWGuid)
3724 {
3725 hr = VBoxNetCfgWinRenameConnection(wszGuid, wszConnectionNewName);
3726 if (FAILED(hr))
3727 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinRenameConnection failed (0x%x)\n", hr));
3728 }
3729 else
3730 {
3731 err = GetLastError();
3732 hr = HRESULT_FROM_WIN32(err);
3733 if (SUCCEEDED(hr))
3734 hr = E_FAIL;
3735 NonStandardLogFlow(("StringFromGUID2 failed err=%u, hr=0x%x\n", err, hr));
3736 }
3737 }
3738 else
3739 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinGenHostonlyConnectionName failed (0x%x)\n", hr));
3740 if (SUCCEEDED(hr) && pDevName)
3741 {
3742 *pDevName = SysAllocString((const OLECHAR *)wszDevName);
3743 if (!*pDevName)
3744 {
3745 NonStandardLogFlow(("SysAllocString failed\n"));
3746 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3747 }
3748 }
3749 }
3750 else
3751 {
3752 hr = HRESULT_FROM_WIN32(err);
3753 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiGetDeviceRegistryPropertyW failed (0x%x)\n", err));
3754 }
3755 }
3756 else
3757 {
3758 DWORD err = GetLastError();
3759 hr = HRESULT_FROM_WIN32(err);
3760 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiOpenDeviceInfo failed (0x%x)\n", err));
3761 }
3762 SetupDiDestroyDeviceInfoList(hDevInfo);
3763 }
3764
3765 return hr;
3766}
3767#endif /* VBOXNETCFG_DELAYEDRENAME */
3768
3769#undef SetErrBreak
3770
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette