VirtualBox

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

Last change on this file since 108459 was 108459, checked in by vboxsync, 3 months ago

VBoxNetCfg.cpp: Changed confusing message in vboxNetCfgWinNetAdpUninstall() and pass back rc. bugref:10873

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 144.2 KB
Line 
1/* $Id: VBoxNetCfg.cpp 108459 2025-03-05 17:14:53Z vboxsync $ */
2/** @file
3 * VBoxNetCfg.cpp - Network Configuration API.
4 */
5
6/*
7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
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
2199 NonStandardLog("Finding NetAdp driver package and trying to uninstall it ...\n");
2200
2201 HRESULT const hr = VBoxDrvCfgInfUninstallAllF(L"Net", pwszId, InfRmFlags);
2202
2203 NonStandardLog("Finding NetAdp driver package and trying to uninstall done: %Rhrc\n", hr);
2204 return hr;
2205}
2206
2207VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, IN LPCWSTR pwszId)
2208{
2209 return vboxNetCfgWinNetAdpUninstall(pNc, pwszId, SUOI_FORCEDELETE);
2210}
2211
2212VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpInstall(IN INetCfg *pNc,
2213 IN LPCWSTR const pwszInfFullPath)
2214{
2215 NonStandardLog("NetAdp will be installed ...\n");
2216 HRESULT hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETADP_ID_WSZ,
2217 &GUID_DEVCLASS_NET,
2218 &pwszInfFullPath,
2219 1,
2220 NULL);
2221 return hr;
2222}
2223
2224
2225static HRESULT vboxNetCfgWinNetLwfUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
2226{
2227 INetCfgComponent * pNcc = NULL;
2228 HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETLWF_ID, &pNcc);
2229 if (hr == S_OK)
2230 {
2231 NonStandardLog("NetLwf is installed currently, uninstalling ...\n");
2232
2233 hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
2234
2235 pNcc->Release();
2236 }
2237 else if (hr == S_FALSE)
2238 {
2239 NonStandardLog("NetLwf is not installed currently\n");
2240 hr = S_OK;
2241 }
2242 else
2243 {
2244 NonStandardLogFlow(("FindComponent failed: %Rhrc\n", hr));
2245 hr = S_OK;
2246 }
2247
2248 VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETLWF_ID, InfRmFlags);
2249
2250 return hr;
2251}
2252
2253VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfUninstall(IN INetCfg *pNc)
2254{
2255 return vboxNetCfgWinNetLwfUninstall(pNc, 0);
2256}
2257
2258static void VBoxNetCfgWinFilterLimitWorkaround(void)
2259{
2260 /*
2261 * Need to check if the system has a limit of installed filter drivers. If it
2262 * has, bump the limit to 14, which the maximum value supported by Windows 7.
2263 * Note that we only touch the limit if it is set to the default value (8).
2264 * See @bugref{7899}.
2265 */
2266 /** @todo r=bird: This code was mixing HRESULT and LSTATUS, checking the return
2267 * codes using SUCCEEDED(lrc) instead of lrc == ERROR_SUCCESS. So, it might
2268 * have misbehaved on bogus registry content, but worked fine on sane values. */
2269 HKEY hKeyNet = NULL;
2270 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Network", 0,
2271 KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyNet);
2272 if (lrc == ERROR_SUCCESS)
2273 {
2274 DWORD dwMaxNumFilters = 0;
2275 DWORD cbMaxNumFilters = sizeof(dwMaxNumFilters);
2276 lrc = RegQueryValueExW(hKeyNet, L"MaxNumFilters", NULL, NULL, (LPBYTE)&dwMaxNumFilters, &cbMaxNumFilters);
2277 if (lrc == ERROR_SUCCESS && cbMaxNumFilters == sizeof(dwMaxNumFilters) && dwMaxNumFilters == 8)
2278 {
2279 dwMaxNumFilters = 14;
2280 lrc = RegSetValueExW(hKeyNet, L"MaxNumFilters", 0, REG_DWORD, (LPBYTE)&dwMaxNumFilters, sizeof(dwMaxNumFilters));
2281 if (lrc == ERROR_SUCCESS)
2282 NonStandardLog("Adjusted the installed filter limit to 14...\n");
2283 else
2284 NonStandardLog("Failed to set MaxNumFilters, error code %d\n", lrc);
2285 }
2286 RegCloseKey(hKeyNet);
2287 }
2288 else
2289 NonStandardLog("Failed to open network key, error code %d\n", lrc);
2290
2291}
2292
2293VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc, IN LPCWSTR const pwszInfFullPath)
2294{
2295 HRESULT hr = vboxNetCfgWinNetLwfUninstall(pNc, SUOI_FORCEDELETE);
2296 if (SUCCEEDED(hr))
2297 {
2298 VBoxNetCfgWinFilterLimitWorkaround();
2299 NonStandardLog("NetLwf will be installed ...\n");
2300 hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETLWF_ID,
2301 &GUID_DEVCLASS_NETSERVICE,
2302 &pwszInfFullPath,
2303 1,
2304 NULL);
2305 }
2306 return hr;
2307}
2308
2309VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(IN PCWSTR pwszDevName, OUT WCHAR *pwszBuf,
2310 IN ULONG cwcBuf, OUT PULONG pcwcNeeded)
2311{
2312 /* Look for a suffix that we need to preserve. */
2313 size_t const cwcDevName = RTUtf16Len(pwszDevName);
2314 size_t offSuffix = cwcDevName;
2315 while (offSuffix > 0 && pwszDevName[offSuffix - 1] != '#')
2316 offSuffix--;
2317 size_t const cwcSuffix = pwszDevName[offSuffix] != '#' ? 0 : cwcDevName - offSuffix;
2318
2319 /* Calculate required buffer size: */
2320 size_t cwcNeeded = sizeof(VBOX_CONNECTION_NAME_WSZ) / sizeof(wchar_t) /* includes terminator */
2321 + !!cwcSuffix /*space*/ + cwcSuffix;
2322 if (pcwcNeeded)
2323 *pcwcNeeded = (ULONG)cwcNeeded;
2324
2325 if (cwcNeeded <= cwcBuf)
2326 {
2327 memcpy(pwszBuf, VBOX_CONNECTION_NAME_WSZ, sizeof(VBOX_CONNECTION_NAME_WSZ));
2328 if (cwcSuffix > 0)
2329 {
2330 size_t offDst = sizeof(VBOX_CONNECTION_NAME_WSZ) / sizeof(wchar_t) - 1;
2331 pwszBuf[offDst++] = ' ';
2332 memcpy(&pwszBuf[offDst], &pwszDevName[offSuffix], cwcSuffix * sizeof(wchar_t));
2333 pwszBuf[offDst + cwcSuffix] = '\0';
2334 }
2335 return S_OK;
2336 }
2337 return E_FAIL;
2338}
2339
2340static BOOL vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
2341{
2342 GUID * const pGuid = (GUID*)pContext;
2343 RT_NOREF1(pNc);
2344
2345 /* Get component's binding. */
2346 INetCfgComponentBindings *pNetCfgBindings = NULL;
2347 HRESULT hr = pNcc->QueryInterface(IID_INetCfgComponentBindings, (PVOID *)&pNetCfgBindings);
2348 if (SUCCEEDED(hr))
2349 {
2350 /* Get binding path enumerator reference. */
2351 IEnumNetCfgBindingPath *pEnumNetCfgBindPath = NULL;
2352 hr = pNetCfgBindings->EnumBindingPaths(EBP_BELOW, &pEnumNetCfgBindPath);
2353 if (SUCCEEDED(hr))
2354 {
2355 bool fFoundIface = false;
2356 hr = pEnumNetCfgBindPath->Reset();
2357 do
2358 {
2359 INetCfgBindingPath *pNetCfgBindPath = NULL;
2360 hr = pEnumNetCfgBindPath->Next(1, &pNetCfgBindPath, NULL);
2361 if (hr == S_OK)
2362 {
2363 IEnumNetCfgBindingInterface *pEnumNetCfgBindIface;
2364 hr = pNetCfgBindPath->EnumBindingInterfaces(&pEnumNetCfgBindIface);
2365 if (hr == S_OK)
2366 {
2367 pEnumNetCfgBindIface->Reset();
2368 do
2369 {
2370 INetCfgBindingInterface *pNetCfgBindIfce;
2371 hr = pEnumNetCfgBindIface->Next(1, &pNetCfgBindIfce, NULL);
2372 if (hr == S_OK)
2373 {
2374 INetCfgComponent *pNetCfgCompo;
2375 hr = pNetCfgBindIfce->GetLowerComponent(&pNetCfgCompo);
2376 if (hr == S_OK)
2377 {
2378 ULONG uComponentStatus;
2379 hr = pNetCfgCompo->GetDeviceStatus(&uComponentStatus);
2380 if (hr == S_OK)
2381 {
2382 GUID guid;
2383 hr = pNetCfgCompo->GetInstanceGuid(&guid);
2384 if ( hr == S_OK
2385 && guid == *pGuid)
2386 {
2387 hr = pNetCfgBindings->MoveAfter(pNetCfgBindPath, NULL);
2388 if (FAILED(hr))
2389 NonStandardLogFlow(("Unable to move interface: %Rhrc\n", hr));
2390 fFoundIface = true;
2391
2392 /*
2393 * Enable binding paths for host-only adapters bound to bridged filter
2394 * (see @bugref{8140}).
2395 */
2396 HRESULT hr2;
2397 LPWSTR pwszHwId = NULL;
2398 if ((hr2 = pNcc->GetId(&pwszHwId)) != S_OK)
2399 NonStandardLogFlow(("Failed to get HW ID: %Rhrc\n", hr2));
2400 else
2401 {
2402 /** @todo r=bird: Original was:
2403 * _wcsnicmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID, sizeof(VBOXNETCFGWIN_NETLWF_ID)/2)
2404 * which is the same as _wcsicmp. Not sure if this was accidental, but it's not the
2405 * only one in this code area (VBoxNetFltNobj.cpp had some too IIRC). */
2406 if (RTUtf16ICmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID) != 0)
2407 NonStandardLogFlow(("Ignoring component %ls\n", pwszHwId));
2408 else if ((hr2 = pNetCfgBindPath->IsEnabled()) != S_FALSE)
2409 NonStandardLogFlow(("Already enabled binding path: %Rhrc\n", hr2));
2410 else if ((hr2 = pNetCfgBindPath->Enable(TRUE)) != S_OK)
2411 NonStandardLogFlow(("Failed to enable binding path: %Rhrc\n", hr2));
2412 else
2413 NonStandardLogFlow(("Enabled binding path\n"));
2414 CoTaskMemFree(pwszHwId);
2415 }
2416 }
2417 }
2418 pNetCfgCompo->Release();
2419 }
2420 else
2421 NonStandardLogFlow(("GetLowerComponent failed: %Rhrc\n", hr));
2422 pNetCfgBindIfce->Release();
2423 }
2424 else
2425 {
2426 if (hr == S_FALSE) /* No more binding interfaces? */
2427 hr = S_OK;
2428 else
2429 NonStandardLogFlow(("Next binding interface failed: %Rhrc\n", hr));
2430 break;
2431 }
2432 } while (!fFoundIface);
2433 pEnumNetCfgBindIface->Release();
2434 }
2435 else
2436 NonStandardLogFlow(("EnumBindingInterfaces failed: %Rhrc\n", hr));
2437 pNetCfgBindPath->Release();
2438 }
2439 else
2440 {
2441 if (hr == S_FALSE) /* No more binding paths? */
2442 hr = S_OK;
2443 else
2444 NonStandardLogFlow(("Next bind path failed: %Rhrc\n", hr));
2445 break;
2446 }
2447 } while (!fFoundIface);
2448 pEnumNetCfgBindPath->Release();
2449 }
2450 else
2451 NonStandardLogFlow(("EnumBindingPaths failed: %Rhrc\n", hr));
2452 pNetCfgBindings->Release();
2453 }
2454 else
2455 NonStandardLogFlow(("QueryInterface for IID_INetCfgComponentBindings failed: %Rhrc\n", hr));
2456 return TRUE;
2457}
2458
2459/** Callback for SetupDiSetDeviceInstallParams used by
2460 * vboxNetCfgWinCreateHostOnlyNetworkInterface */
2461static UINT WINAPI vboxNetCfgWinPspFileCallback(PVOID Context, UINT Notification, UINT_PTR Param1, UINT_PTR Param2)
2462{
2463 switch (Notification)
2464 {
2465 case SPFILENOTIFY_TARGETNEWER:
2466 case SPFILENOTIFY_TARGETEXISTS:
2467 return TRUE;
2468 }
2469 return SetupDefaultQueueCallbackW(Context, Notification, Param1, Param2);
2470}
2471
2472
2473
2474
2475/* The original source of the VBoxNetAdp adapter creation/destruction code has the following copyright: */
2476/*
2477 Copyright 2004 by the Massachusetts Institute of Technology
2478
2479 All rights reserved.
2480
2481 Permission to use, copy, modify, and distribute this software and its
2482 documentation for any purpose and without fee is hereby granted,
2483 provided that the above copyright notice appear in all copies and that
2484 both that copyright notice and this permission notice appear in
2485 supporting documentation, and that the name of the Massachusetts
2486 Institute of Technology (M.I.T.) not be used in advertising or publicity
2487 pertaining to distribution of the software without specific, written
2488 prior permission.
2489
2490 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2491 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2492 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2493 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2494 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2495 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2496 SOFTWARE.
2497*/
2498
2499
2500/**
2501 * Use the IShellFolder API to rename the connection.
2502 */
2503static HRESULT rename_shellfolder(PCWSTR pwszGuid, PCWSTR pwszNewName)
2504{
2505 /* Build the display name in the form "::{GUID}". Do this first in case it overflows. */
2506 WCHAR wszAdapterGuid[MAX_PATH + 2] = {0};
2507 ssize_t cwc = RTUtf16Printf(wszAdapterGuid, RT_ELEMENTS(wszAdapterGuid), "::%ls", pwszGuid);
2508 if (cwc < 0)
2509 return E_INVALIDARG;
2510
2511 /* This is the GUID for the network connections folder. It is constant.
2512 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2513 const GUID MY_CLSID_NetworkConnections = {
2514 0x7007ACC7, 0x3202, 0x11D1, {
2515 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2516 }
2517 };
2518
2519 /* Create an instance of the network connections folder. */
2520 IShellFolder *pShellFolder = NULL;
2521 HRESULT hr = CoCreateInstance(MY_CLSID_NetworkConnections, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder,
2522 reinterpret_cast<LPVOID *>(&pShellFolder));
2523 if (SUCCEEDED(hr))
2524 {
2525 /* Parse the display name. */
2526 LPITEMIDLIST pidl = NULL;
2527 hr = pShellFolder->ParseDisplayName(NULL, NULL, wszAdapterGuid, NULL, &pidl, NULL);
2528 if (SUCCEEDED(hr))
2529 hr = pShellFolder->SetNameOf(NULL, pidl, pwszNewName, SHGDN_NORMAL, &pidl);
2530 CoTaskMemFree(pidl);
2531 pShellFolder->Release();
2532 }
2533 return hr;
2534}
2535
2536/**
2537 * Loads a system DLL.
2538 *
2539 * @returns Module handle or NULL
2540 * @param pwszName The DLL name.
2541 */
2542static HMODULE loadSystemDll(const wchar_t *pwszName)
2543{
2544 WCHAR wszPath[MAX_PATH];
2545 UINT cwcPath = GetSystemDirectoryW(wszPath, RT_ELEMENTS(wszPath));
2546 size_t cwcName = RTUtf16Len(pwszName) + 1;
2547 if (cwcPath + 1 + cwcName > RT_ELEMENTS(wszPath))
2548 return NULL;
2549
2550 wszPath[cwcPath++] = '\\';
2551 memcpy(&wszPath[cwcPath], pwszName, cwcName * sizeof(wszPath[0]));
2552 return LoadLibraryW(wszPath);
2553}
2554
2555static bool vboxNetCfgWinDetectStaleConnection(PCWSTR pwszName)
2556{
2557 HKEY hKeyAdapters = NULL;
2558 LSTATUS lrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2559 L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
2560 0 /*ulOptions*/, KEY_ALL_ACCESS, &hKeyAdapters);
2561 if (lrc != ERROR_SUCCESS)
2562 return false;
2563
2564 bool fFailureImminent = false;
2565 for (DWORD i = 0; !fFailureImminent; ++i)
2566 {
2567 WCHAR wszAdapterSubKeyName[MAX_PATH];
2568 DWORD cwcAdapterSubKeyName = MAX_PATH;
2569 lrc = RegEnumKeyEx(hKeyAdapters, i, wszAdapterSubKeyName, &cwcAdapterSubKeyName, NULL, NULL, NULL, NULL);
2570 if (lrc != ERROR_SUCCESS)
2571 break;
2572
2573 HKEY hKeyAdapter = NULL;
2574 lrc = RegOpenKeyEx(hKeyAdapters, wszAdapterSubKeyName, 0, KEY_ALL_ACCESS, &hKeyAdapter);
2575 if (lrc == ERROR_SUCCESS)
2576 {
2577 HKEY hKeyConnection = NULL;
2578 lrc = RegOpenKeyEx(hKeyAdapter, L"Connection", 0, KEY_ALL_ACCESS, &hKeyConnection);
2579 if (lrc == ERROR_SUCCESS)
2580 {
2581 WCHAR wszCurName[MAX_PATH + 1];
2582 DWORD cbCurName = sizeof(wszCurName) - sizeof(WCHAR);
2583 DWORD dwType = REG_SZ;
2584 lrc = RegQueryValueEx(hKeyConnection, L"Name", NULL, NULL, (LPBYTE)wszCurName, &cbCurName);
2585 if ( lrc == ERROR_SUCCESS
2586 /** @todo r=bird: The original code didn't do any value type checks, thus allowing all SZ types. */
2587 && (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ))
2588 {
2589 wszCurName[MAX_PATH] = '\0'; /* returned values doesn't necessarily need to be terminated */
2590
2591 if (RTUtf16ICmp(pwszName, pwszName) == 0)
2592 fFailureImminent = true;
2593 }
2594 RegCloseKey(hKeyConnection);
2595 }
2596 RegCloseKey(hKeyAdapter);
2597 }
2598 }
2599 RegCloseKey(hKeyAdapters);
2600
2601 return fFailureImminent;
2602}
2603
2604VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(LPWSTR pwszGuid, PCWSTR NewName)
2605{
2606 /*
2607 * Before attempting to rename the connection, check if there is a stale
2608 * connection with the same name. We must return ok, so the rest of
2609 * configuration process proceeds normally.
2610 */
2611 if (vboxNetCfgWinDetectStaleConnection(NewName))
2612 return S_OK;
2613
2614 /* First try the IShellFolder interface, which was unimplemented
2615 * for the network connections folder before XP. */
2616 HRESULT hrc = rename_shellfolder(pwszGuid, NewName);
2617 if (hrc == E_NOTIMPL)
2618 {
2619/** @todo that code doesn't seem to work! */
2620 /* The IShellFolder interface is not implemented on this platform.
2621 * Try the (undocumented) HrRenameConnection API in the netshell
2622 * library. */
2623 CLSID clsid;
2624 hrc = CLSIDFromString((LPOLESTR)pwszGuid, &clsid);
2625 if (FAILED(hrc))
2626 return E_FAIL;
2627
2628 HINSTANCE hNetShell = loadSystemDll(L"netshell.dll");
2629 if (hNetShell == NULL)
2630 return E_FAIL;
2631
2632 typedef HRESULT (WINAPI *PFNHRRENAMECONNECTION)(const GUID *, PCWSTR);
2633 PFNHRRENAMECONNECTION pfnRenameConnection = (PFNHRRENAMECONNECTION)GetProcAddress(hNetShell, "HrRenameConnection");
2634 if (pfnRenameConnection != NULL)
2635 hrc = pfnRenameConnection(&clsid, NewName);
2636 else
2637 hrc = E_FAIL;
2638
2639 FreeLibrary(hNetShell);
2640 }
2641 if (FAILED(hrc))
2642 return hrc;
2643 return S_OK;
2644}
2645
2646
2647VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pBstrErrMsg)
2648{
2649 HRESULT hrc = S_OK;
2650 com::Bstr bstrError;
2651
2652 do /* break non-loop */
2653 {
2654 WCHAR wszPnPInstanceId[512] = {0};
2655
2656 /*
2657 * We have to find the device instance ID through a registry search
2658 */
2659 HKEY hkeyNetwork = NULL;
2660 HKEY hkeyConnection = NULL;
2661 do /* another non-loop for breaking out of */
2662 {
2663 WCHAR wszGuid[50];
2664 int cwcGuid = StringFromGUID2(*pGUID, wszGuid, RT_ELEMENTS(wszGuid));
2665 if (!cwcGuid)
2666 SetErrBreak(("Failed to create a Guid string"));
2667
2668 WCHAR wszRegLocation[128 + RT_ELEMENTS(wszGuid)];
2669 RTUtf16Printf(wszRegLocation, RT_ELEMENTS(wszRegLocation),
2670 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%ls", wszGuid);
2671
2672 LSTATUS lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegLocation, 0, KEY_READ, &hkeyNetwork);
2673 if (lrc != ERROR_SUCCESS || !hkeyNetwork)
2674 SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u [1]", wszRegLocation, lrc));
2675
2676 lrc = RegOpenKeyExW(hkeyNetwork, L"Connection", 0, KEY_READ, &hkeyConnection);
2677 if (lrc != ERROR_SUCCESS || !hkeyConnection)
2678 SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u [2]", wszRegLocation, lrc));
2679
2680 DWORD cbValue = sizeof(wszPnPInstanceId) - sizeof(WCHAR);
2681 DWORD dwType = ~0U;
2682 lrc = RegQueryValueExW(hkeyConnection, L"PnPInstanceID", NULL, &dwType, (LPBYTE)wszPnPInstanceId, &cbValue);
2683 if (lrc != ERROR_SUCCESS || dwType != REG_SZ)
2684 SetErrBreak(("Host interface network is not found in registry (%S): lrc=%u, dwType=%u [3]",
2685 wszRegLocation, lrc, dwType));
2686 } while (0);
2687
2688 if (hkeyConnection)
2689 RegCloseKey(hkeyConnection);
2690 if (hkeyNetwork)
2691 RegCloseKey(hkeyNetwork);
2692 if (FAILED(hrc))
2693 break;
2694
2695 /*
2696 * Now we are going to enumerate all network devices and
2697 * wait until we encounter the right device instance ID
2698 */
2699 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2700 do /* break-only, not-a-loop */
2701 {
2702 BOOL ok;
2703
2704 /* initialize the structure size */
2705 SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
2706
2707 /* copy the net class GUID */
2708 GUID netGuid;
2709 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2710
2711 /* return a device info set contains all installed devices of the Net class */
2712 hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
2713 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2714 SetErrBreak(("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2715
2716 /* Enumerate the driver info list. */
2717 bool fFound = false;
2718 for (DWORD index = 0; !fFound; index++)
2719 {
2720 if (!SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData))
2721 {
2722 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2723 break;
2724 continue;
2725 }
2726
2727 /* try to get the hardware ID registry property */
2728 DWORD cbValue = 0;
2729 if (SetupDiGetDeviceRegistryPropertyW(hDeviceInfo,
2730 &DeviceInfoData,
2731 SPDRP_HARDWAREID,
2732 NULL,
2733 NULL,
2734 0,
2735 &cbValue))
2736 continue; /* Something is wrong. This shouldn't have worked with a NULL buffer! */
2737 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2738 continue;
2739
2740 WCHAR *pwszzDeviceHwId = (WCHAR *)RTMemAllocZ(cbValue + sizeof(WCHAR) * 2);
2741 if (!pwszzDeviceHwId)
2742 break;
2743 if (SetupDiGetDeviceRegistryPropertyW(hDeviceInfo,
2744 &DeviceInfoData,
2745 SPDRP_HARDWAREID,
2746 NULL,
2747 (PBYTE)pwszzDeviceHwId,
2748 cbValue,
2749 &cbValue))
2750 {
2751 /* search the string list. */
2752 for (WCHAR *pwszCurHwId = pwszzDeviceHwId;
2753 (uintptr_t)pwszCurHwId - (uintptr_t)pwszzDeviceHwId < cbValue && *pwszCurHwId != L'\0';
2754 pwszCurHwId += RTUtf16Len(pwszCurHwId) + 1)
2755 if (RTUtf16ICmp(DRIVERHWID, pwszCurHwId) == 0)
2756 {
2757 /* get the device instance ID */
2758 WCHAR wszDevId[MAX_DEVICE_ID_LEN];
2759 if (CM_Get_Device_IDW(DeviceInfoData.DevInst, wszDevId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2760 {
2761 /* compare to what we determined before */
2762 if (RTUtf16Cmp(wszDevId, wszPnPInstanceId) == 0)
2763 {
2764 fFound = true;
2765 break;
2766 }
2767 }
2768 }
2769 }
2770 RTMemFree(pwszzDeviceHwId);
2771 }
2772
2773 if (!fFound)
2774 SetErrBreak(("Host Interface Network driver not found (0x%08X)", GetLastError()));
2775
2776 ok = SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData);
2777 if (!ok)
2778 SetErrBreak(("SetupDiSetSelectedDevice failed (0x%08X)", GetLastError()));
2779
2780 ok = SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2781 if (!ok)
2782 SetErrBreak(("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)", GetLastError()));
2783 } while (0);
2784
2785 /* clean up the device info set */
2786 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2787 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2788 } while (0);
2789
2790 if (pBstrErrMsg)
2791 {
2792 *pBstrErrMsg = NULL;
2793 if (bstrError.isNotEmpty())
2794 bstrError.detachToEx(pBstrErrMsg);
2795 }
2796 return hrc;
2797}
2798
2799VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pfRebootRequired, LPCWSTR pcsxwId)
2800{
2801 return VBoxDrvCfgDrvUpdate(pcsxwId, pcsxwInf, pfRebootRequired);
2802}
2803
2804static const char *vboxNetCfgWinGetStateText(DWORD dwState)
2805{
2806 switch (dwState)
2807 {
2808 case SERVICE_STOPPED: return "is not running";
2809 case SERVICE_STOP_PENDING: return "is stopping";
2810 case SERVICE_CONTINUE_PENDING: return "continue is pending";
2811 case SERVICE_PAUSE_PENDING: return "pause is pending";
2812 case SERVICE_PAUSED: return "is paused";
2813 case SERVICE_RUNNING: return "is running";
2814 case SERVICE_START_PENDING: return "is starting";
2815 }
2816 return "state is invalid";
2817}
2818
2819static DWORD vboxNetCfgWinGetNetSetupState(SC_HANDLE hService)
2820{
2821 SERVICE_STATUS status;
2822 status.dwCurrentState = SERVICE_RUNNING;
2823 if (hService) {
2824 if (QueryServiceStatus(hService, &status))
2825 NonStandardLogFlow(("NetSetupSvc %s\n", vboxNetCfgWinGetStateText(status.dwCurrentState)));
2826 else
2827 NonStandardLogFlow(("QueryServiceStatus failed (0x%x)\n", GetLastError()));
2828 }
2829 return status.dwCurrentState;
2830}
2831
2832DECLINLINE(bool) vboxNetCfgWinIsNetSetupRunning(SC_HANDLE hService)
2833{
2834 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_RUNNING;
2835}
2836
2837DECLINLINE(bool) vboxNetCfgWinIsNetSetupStopped(SC_HANDLE hService)
2838{
2839 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_STOPPED;
2840}
2841
2842typedef struct
2843{
2844 BSTR bstrName;
2845 GUID *pGuid;
2846 HRESULT hr;
2847} RENAMING_CONTEXT;
2848
2849static BOOL vboxNetCfgWinRenameHostOnlyNetworkInterface(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
2850{
2851 RT_NOREF1(pNc);
2852 RENAMING_CONTEXT *pParams = (RENAMING_CONTEXT *)pContext;
2853
2854 GUID guid;
2855 pParams->hr = pNcc->GetInstanceGuid(&guid);
2856 if ( pParams->hr == S_OK && guid == *pParams->pGuid)
2857 {
2858 /* Located our component, rename it */
2859 pParams->hr = pNcc->SetDisplayName(pParams->bstrName);
2860 return FALSE;
2861 }
2862 return TRUE;
2863}
2864
2865/**
2866 * Enumerate all host-only adapters collecting their names into a set, then
2867 * come up with the next available name by taking the first unoccupied index.
2868 */
2869static HRESULT vboxNetCfgWinNextAvailableDevName(com::Bstr *pbstrName)
2870{
2871 SP_DEVINFO_DATA DeviceInfoData = { sizeof(SP_DEVINFO_DATA) };
2872 HDEVINFO hDeviceInfoSet = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT);
2873 if (hDeviceInfoSet == INVALID_HANDLE_VALUE)
2874 return HRESULT_FROM_WIN32(GetLastError());
2875
2876 typedef struct VBOXDEVNAMEENTRY
2877 {
2878 RTLISTNODE ListEntry;
2879 WCHAR wszDevName[64];
2880 WCHAR wcZeroParanoia;
2881 } VBOXDEVNAMEENTRY;
2882
2883#if 0
2884 /*
2885 * Build a list of names starting with HOSTONLY_ADAPTER_NAME_WSZ belonging to our device.
2886 */
2887 RTLISTANCHOR Head; /* VBOXDEVNAMEENTRY */
2888 RTListInit(&Head);
2889 HRESULT hrc = S_OK;
2890#else
2891 /*
2892 * Build a bitmap of in-use index values of devices starting with HOSTONLY_ADAPTER_NAME_WSZ.
2893 * Reserving 0 for one w/o a suffix, and marking 1 as unusable.
2894 */
2895 uint64_t bmIndexes[_32K / 64]; /* 4KB - 32767 device should be sufficient. */
2896 RT_ZERO(bmIndexes);
2897 ASMBitSet(&bmIndexes, 1);
2898#endif
2899 for (DWORD i = 0; SetupDiEnumDeviceInfo(hDeviceInfoSet, i, &DeviceInfoData); ++i)
2900 {
2901 /* Should be more than enough for both our device id and our device name, we do not care about the rest */
2902 VBOXDEVNAMEENTRY Entry = { { 0, 0 }, L"", 0 }; /* (initialize it to avoid the wrath of asan) */
2903 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID,
2904 NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL))
2905 continue;
2906
2907 /* Ignore everything except our host-only adapters */
2908 if (RTUtf16ICmp(Entry.wszDevName, DRIVERHWID) == 0)
2909 {
2910 if ( SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_FRIENDLYNAME,
2911 NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL)
2912 || SetupDiGetDeviceRegistryPropertyW(hDeviceInfoSet, &DeviceInfoData, SPDRP_DEVICEDESC,
2913 NULL, (PBYTE)Entry.wszDevName, sizeof(Entry.wszDevName), NULL))
2914 {
2915 /* We can ignore any host-only adapter with a non-standard name. */
2916 if (RTUtf16NICmp(Entry.wszDevName, HOSTONLY_ADAPTER_NAME_WSZ,
2917 RT_ELEMENTS(HOSTONLY_ADAPTER_NAME_WSZ) - 1) == 0)
2918 {
2919#if 0
2920 VBOXDEVNAMEENTRY *pEntry = (VBOXDEVNAMEENTRY *)RTMemDup(&Entry, sizeof(Entry));
2921 if (pEntry)
2922 RTListAppend(&Head, &pEntry->ListEntry);
2923 else
2924 {
2925 hrc = E_OUTOFMEMORY;
2926 break;
2927 }
2928#else
2929 WCHAR const *pwc = &Entry.wszDevName[RT_ELEMENTS(HOSTONLY_ADAPTER_NAME_WSZ) - 1];
2930
2931 /* skip leading space */
2932 WCHAR wc = *pwc;
2933 while (wc == L' ' || wc == L'\t' || wc == L'\n' || wc == L'\r')
2934 wc = *++pwc;
2935
2936 /* If end of string, use index 0. */
2937 if (wc == L'\0')
2938 ASMBitSet(bmIndexes, 0);
2939
2940 /* Hash and digit? */
2941 else if (wc == L'#')
2942 {
2943 wc = *++pwc;
2944 while (wc == L' ' || wc == L'\t' || wc == L'\n' || wc == L'\r') /* just in case */
2945 wc = *++pwc;
2946 if (wc >= L'0' && wc <= L'9')
2947 {
2948 /* Convert what we can to a number and mark it as allocated in the bitmap. */
2949 uint64_t uIndex = wc - L'0';
2950 while ((wc = *++pwc) >= L'0' && wc <= L'9')
2951 uIndex = uIndex * 10 + wc - L'0';
2952 if (uIndex < sizeof(bmIndexes) * 8 && uIndex > 0)
2953 ASMBitSet(bmIndexes, (int32_t)uIndex);
2954 }
2955 }
2956#endif
2957 }
2958 }
2959 }
2960 }
2961#if 0
2962 if (SUCCEEDED(hrc))
2963 {
2964 /*
2965 * First try a name w/o an index, then try index #2 and up.
2966 *
2967 * Note! We have to use ASCII/UTF-8 strings here as Bstr will confuse WCHAR
2968 * with BSTR/OLECHAR strings and use SysAllocString to duplicate it .
2969 */
2970 char szName[sizeof(HOSTONLY_ADAPTER_NAME_SZ " #4294967296") + 32] = HOSTONLY_ADAPTER_NAME_SZ;
2971 size_t const cchBase = sizeof(HOSTONLY_ADAPTER_NAME_SZ) - 1;
2972 for (DWORD idx = 2;; idx++)
2973 {
2974 bool fFound = false;
2975 VBOXDEVNAMEENTRY *pCur;
2976 RTListForEach(&Head, pCur, VBOXDEVNAMEENTRY, ListEntry)
2977 {
2978 fFound = RTUtf16ICmpAscii(pCur->wszDevName, szName) == 0;
2979 if (fFound)
2980 {
2981 hrc = pbstrName->assignEx(szName);
2982 break;
2983 }
2984 }
2985 if (fFound)
2986 break;
2987 RTStrPrintf(&szName[cchBase], sizeof(szName) - cchBase, " #%u", idx);
2988 }
2989 }
2990
2991 VBOXDEVNAMEENTRY *pFirst;
2992 while ((pFirst = RTListRemoveFirst(&Head, VBOXDEVNAMEENTRY, ListEntry)) != NULL)
2993 RTMemFree(pFirst);
2994
2995#else
2996 /*
2997 * Find an unused index value and format the corresponding name.
2998 */
2999 HRESULT hrc;
3000 int32_t iBit = ASMBitFirstClear(bmIndexes, sizeof(bmIndexes) * 8);
3001 if (iBit >= 0)
3002 {
3003 if (iBit == 0)
3004 hrc = pbstrName->assignEx(HOSTONLY_ADAPTER_NAME_SZ); /* Not _WSZ! */
3005 else
3006 hrc = pbstrName->printfNoThrow(HOSTONLY_ADAPTER_NAME_SZ " #%u", iBit);
3007 }
3008 else
3009 {
3010 NonStandardLogFlow(("vboxNetCfgWinNextAvailableDevName: no unused index in the first 32K!\n"));
3011 hrc = E_FAIL;
3012 }
3013#endif
3014
3015 if (hDeviceInfoSet)
3016 SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
3017 return hrc;
3018}
3019
3020static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile,
3021 IN BSTR pBstrDesiredName,
3022 OUT GUID *pGuid, OUT BSTR *pBstrName, OUT BSTR *pBstrErrMsg)
3023{
3024 com::Bstr bstrError;
3025
3026 /* Determine the interface name. We make a copy of the input here for
3027 renaming reasons, see futher down. */
3028 com::Bstr bstrNewInterfaceName;
3029 HRESULT hrc;
3030 if (SysStringLen(pBstrDesiredName) != 0)
3031 hrc = bstrNewInterfaceName.assignEx(pBstrDesiredName);
3032 else
3033 {
3034 hrc = vboxNetCfgWinNextAvailableDevName(&bstrNewInterfaceName);
3035 if (FAILED(hrc))
3036 NonStandardLogFlow(("vboxNetCfgWinNextAvailableDevName failed with 0x%x\n", hrc));
3037 }
3038 if (FAILED(hrc))
3039 return hrc;
3040
3041 WCHAR wszCfgGuidString[50] = {0};
3042 WCHAR wszDevName[256 + 1] = {0};
3043 SP_DEVINFO_DATA DeviceInfoData = { sizeof(DeviceInfoData) };
3044 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
3045 PVOID pQueueCallbackContext = NULL;
3046 BOOL fRegistered = FALSE;
3047 BOOL destroyList = FALSE;
3048 HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
3049 LSTATUS lrcRet = ERROR_SUCCESS; /* the */
3050
3051 do /* non-loop, for breaking. */
3052 {
3053 /* copy the net class GUID */
3054 GUID netGuid;
3055 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
3056
3057 /* Create an empty device info set associated with the net class GUID: */
3058 hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
3059 if (hDeviceInfo == INVALID_HANDLE_VALUE)
3060 SetErrBreak(("SetupDiCreateDeviceInfoList failed (%Rwc)", GetLastError()));
3061
3062 /* Translate the GUID to a class name: */
3063 WCHAR wszClassName[MAX_PATH];
3064 if (!SetupDiClassNameFromGuid(&netGuid, wszClassName, MAX_PATH, NULL))
3065 SetErrBreak(("SetupDiClassNameFromGuid failed (%Rwc)", GetLastError()));
3066
3067 /* Create a device info element and add the new device instance key to registry: */
3068 if (!SetupDiCreateDeviceInfo(hDeviceInfo, wszClassName, &netGuid, NULL, NULL, DICD_GENERATE_ID, &DeviceInfoData))
3069 SetErrBreak(("SetupDiCreateDeviceInfo failed (%Rwc)", GetLastError()));
3070
3071 /* Select the newly created device info to be the currently selected member: */
3072 if (!SetupDiSetSelectedDevice(hDeviceInfo, &DeviceInfoData))
3073 SetErrBreak(("SetupDiSetSelectedDevice failed (%Rwc)", GetLastError()));
3074
3075 SP_DEVINSTALL_PARAMS DeviceInstallParams;
3076 if (pwszInfPath)
3077 {
3078 /* get the device install parameters and disable filecopy */
3079 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3080 if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3081 {
3082 memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
3083 size_t pathLenght = wcslen(pwszInfPath) + 1/* null terminator */;
3084 if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
3085 {
3086 memcpy(DeviceInstallParams.DriverPath, pwszInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
3087
3088 if (fIsInfPathFile)
3089 DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
3090
3091 if (!SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3092 {
3093 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed (%Rwc)\n", GetLastError()));
3094 break;
3095 }
3096 }
3097 else
3098 {
3099 NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
3100 break;
3101 }
3102 }
3103 else
3104 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed (%Rwc)\n", GetLastError()));
3105 }
3106
3107 /* build a list of class drivers */
3108 if (!SetupDiBuildDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER))
3109 SetErrBreak(("SetupDiBuildDriverInfoList failed (%Rwc)", GetLastError()));
3110
3111 destroyList = TRUE;
3112
3113 /*
3114 * Enumerate the driver info list.
3115 */
3116 /* For our purposes, 2k buffer is more than enough to obtain the
3117 hardware ID of the VBoxNetAdp driver. */ /** @todo r=bird: The buffer isn't 2KB, it's 8KB, but whatever. */
3118 DWORD detailBuf[2048];
3119 SP_DRVINFO_DATA DriverInfoData = { sizeof(DriverInfoData) };
3120 bool fFound = false;
3121 for (DWORD index = 0; !fFound; index++)
3122 {
3123 /* If the function fails with last error set to ERROR_NO_MORE_ITEMS,
3124 then we have reached the end of the list. Otherwise there was
3125 something wrong with this particular driver. */
3126 if (!SetupDiEnumDriverInfo(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER, index, &DriverInfoData))
3127 {
3128 if (GetLastError() == ERROR_NO_MORE_ITEMS)
3129 break;
3130 continue;
3131 }
3132
3133 /* if we successfully find the hardware ID and it turns out to
3134 * be the one for the loopback driver, then we are done. */
3135 PSP_DRVINFO_DETAIL_DATA_W pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA_W)detailBuf;
3136 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
3137 DWORD cbValue = 0;
3138 if (SetupDiGetDriverInfoDetailW(hDeviceInfo,
3139 &DeviceInfoData,
3140 &DriverInfoData,
3141 pDriverInfoDetail,
3142 sizeof(detailBuf) - sizeof(detailBuf[0]),
3143 &cbValue))
3144 {
3145 /* Sure that the HardwareID string list is properly zero terminated (paranoia). */
3146 detailBuf[RT_ELEMENTS(detailBuf) - 1] = 0; AssertCompile(sizeof(detailBuf[0]) == sizeof(WCHAR) * 2);
3147
3148 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the whole
3149 list and see if there is a match somewhere: */
3150 for (WCHAR *pwszCurHwId = pDriverInfoDetail->HardwareID;
3151 (uintptr_t)pwszCurHwId - (uintptr_t)pDriverInfoDetail < cbValue && *pwszCurHwId != L'\0';
3152 pwszCurHwId += RTUtf16Len(pwszCurHwId) + 1)
3153 if (RTUtf16ICmp(DRIVERHWID, pwszCurHwId) == 0)
3154 {
3155 fFound = true;
3156 break;
3157 }
3158 }
3159 }
3160
3161 if (!fFound)
3162 SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
3163
3164 /* set the loopback driver to be the currently selected */
3165 if (!SetupDiSetSelectedDriver(hDeviceInfo, &DeviceInfoData, &DriverInfoData))
3166 SetErrBreak(("SetupDiSetSelectedDriver failed (%u)", GetLastError()));
3167
3168 /* register the phantom device to prepare for install */
3169 if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hDeviceInfo, &DeviceInfoData))
3170 SetErrBreak(("SetupDiCallClassInstaller failed (%u)", GetLastError()));
3171
3172 /* registered, but remove if errors occur in the following code */
3173 fRegistered = TRUE;
3174
3175 /* ask the installer if we can install the device */
3176 if (!SetupDiCallClassInstaller(DIF_ALLOW_INSTALL, hDeviceInfo, &DeviceInfoData))
3177 {
3178 if (GetLastError() != ERROR_DI_DO_DEFAULT)
3179 SetErrBreak(("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (%u)", GetLastError()));
3180 /* that's fine */
3181 }
3182
3183 /* get the device install parameters and disable filecopy */
3184 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3185 if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3186 {
3187 pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
3188 if (pQueueCallbackContext)
3189 {
3190 DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
3191 DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
3192 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3193 {
3194 DWORD winEr = GetLastError();
3195 NonStandardLogFlow(("SetupDiSetDeviceInstallParamsW failed, winEr (%d)\n", winEr));
3196 Assert(0);
3197 }
3198 }
3199 else
3200 {
3201 DWORD winEr = GetLastError();
3202 NonStandardLogFlow(("SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr));
3203 }
3204 }
3205 else
3206 {
3207 DWORD winEr = GetLastError();
3208 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
3209 }
3210
3211 /* install the files first */
3212 if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, hDeviceInfo, &DeviceInfoData))
3213 SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (%Rwc)", GetLastError()));
3214
3215 /* get the device install parameters and disable filecopy */
3216 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3217 if (SetupDiGetDeviceInstallParams(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3218 {
3219 DeviceInstallParams.Flags |= DI_NOFILECOPY;
3220 if (!SetupDiSetDeviceInstallParamsW(hDeviceInfo, &DeviceInfoData, &DeviceInstallParams))
3221 SetErrBreak(("SetupDiSetDeviceInstallParamsW failed (%Rwc)", GetLastError()));
3222 }
3223 /** @todo r=bird: Why isn't SetupDiGetDeviceInstallParams failure fatal here? */
3224
3225 /*
3226 * Register any device-specific co-installers for this device,
3227 */
3228 if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, hDeviceInfo, &DeviceInfoData))
3229 SetErrBreak(("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (%Rwc)", GetLastError()));
3230
3231 /*
3232 * install any installer-specified interfaces.
3233 * and then do the real install
3234 */
3235 if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, hDeviceInfo, &DeviceInfoData))
3236 SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (%Rwc)", GetLastError()));
3237
3238 if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, hDeviceInfo, &DeviceInfoData))
3239 SetErrBreak(("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (%Rwc)", GetLastError()));
3240
3241 /*
3242 * Query the instance ID; on Windows 10, the registry key may take a short
3243 * while to appear. Microsoft recommends waiting for up to 5 seconds, but
3244 * we want to be on the safe side, so let's wait for 20 seconds. Waiting
3245 * longer is harmful as network setup service will shut down after a period
3246 * of inactivity.
3247 */
3248 for (int retries = 0; retries < 2 * 20; ++retries)
3249 {
3250 Sleep(500); /* half second */
3251
3252 /* Figure out NetCfgInstanceId */
3253 hkey = SetupDiOpenDevRegKey(hDeviceInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ);
3254 if (hkey == INVALID_HANDLE_VALUE)
3255 break;
3256
3257 DWORD cbSize = sizeof(wszCfgGuidString);
3258 DWORD dwValueType = 0;
3259 lrcRet = RegQueryValueExW(hkey, L"NetCfgInstanceId", NULL, &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
3260 /* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
3261 if (lrcRet != ERROR_FILE_NOT_FOUND)
3262 break;
3263
3264 RegCloseKey(hkey);
3265 hkey = (HKEY)INVALID_HANDLE_VALUE;
3266 }
3267
3268 if (lrcRet == ERROR_FILE_NOT_FOUND)
3269 {
3270 hrc = E_ABORT;
3271 break;
3272 }
3273
3274 /*
3275 * We need to check 'hkey' after we check 'lrcRet' to distinguish the case
3276 * of failed SetupDiOpenDevRegKey from the case when we timed out.
3277 */
3278 if (hkey == INVALID_HANDLE_VALUE)
3279 SetErrBreak(("SetupDiOpenDevRegKey failed (%Rwc)", GetLastError()));
3280
3281 if (lrcRet != ERROR_SUCCESS)
3282 SetErrBreak(("Querying NetCfgInstanceId failed (%Rwc)", lrcRet));
3283
3284 NET_LUID luid;
3285 HRESULT hrcSMRes = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
3286
3287 /* Close the key as soon as possible. See @bugref{7973}. */
3288 RegCloseKey(hkey);
3289 hkey = (HKEY)INVALID_HANDLE_VALUE;
3290
3291 if (FAILED(hrcSMRes))
3292 {
3293 /*
3294 * The setting of Metric is not very important functionality,
3295 * So we will not break installation process due to this error.
3296 */
3297 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface: Warning! "
3298 "vboxNetCfgWinGetInterfaceLUID failed, default metric for new interface will not be set: %Rhrc\n",
3299 hrcSMRes));
3300 }
3301 else
3302 {
3303 /*
3304 * Set default metric value of interface to fix multicast issue
3305 * See @bugref{6379} for details.
3306 */
3307 hrcSMRes = vboxNetCfgWinSetupMetric(&luid);
3308 if (FAILED(hrcSMRes))
3309 {
3310 /*
3311 * The setting of Metric is not very important functionality,
3312 * So we will not break installation process due to this error.
3313 */
3314 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface: Warning! "
3315 "vboxNetCfgWinSetupMetric failed, default metric for new interface will not be set: %Rhrc\n",
3316 hrcSMRes));
3317 }
3318 }
3319
3320 /*
3321 * We need to query the device name after we have succeeded in querying its
3322 * instance ID to avoid similar waiting-and-retrying loop (see @bugref{7973}).
3323 */
3324 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3325 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
3326 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3327 (PBYTE)wszDevName, /*OUT PBYTE PropertyBuffer,*/
3328 sizeof(wszDevName) - sizeof(WCHAR), /* IN DWORD PropertyBufferSize,*/
3329 NULL /*OUT PDWORD RequiredSize OPTIONAL*/ ))
3330 {
3331 DWORD dwErr = GetLastError();
3332 if (dwErr != ERROR_INVALID_DATA)
3333 SetErrBreak(("SetupDiGetDeviceRegistryProperty failed (%Rwc)", dwErr));
3334
3335 RT_ZERO(wszDevName);
3336 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3337 SPDRP_DEVICEDESC, /* IN DWORD Property,*/
3338 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3339 (PBYTE)wszDevName, /*OUT PBYTE PropertyBuffer,*/
3340 sizeof(wszDevName) - sizeof(WCHAR), /* IN DWORD PropertyBufferSize,*/
3341 NULL /*OUT PDWORD RequiredSize OPTIONAL*/ ))
3342 SetErrBreak(("SetupDiGetDeviceRegistryProperty failed (%Rwc)", GetLastError()));
3343 }
3344
3345 /* No need to rename the device if the names match. */
3346 if (RTUtf16Cmp(bstrNewInterfaceName.raw(), wszDevName) == 0)
3347 bstrNewInterfaceName.setNull();
3348
3349#ifdef VBOXNETCFG_DELAYEDRENAME
3350 /* Re-use wszDevName for device instance id retrieval. */
3351 DWORD cwcReturned = 0;
3352 RT_ZERO(wszDevName);
3353 if (!SetupDiGetDeviceInstanceIdW(hDeviceInfo, &DeviceInfoData, wszDevName, RT_ELEMENTS(wszDevName) - 1, &cwcReturned))
3354 SetErrBreak(("SetupDiGetDeviceInstanceId failed (%Rwc)", GetLastError()));
3355#endif /* VBOXNETCFG_DELAYEDRENAME */
3356 } while (0);
3357
3358 /*
3359 * Cleanup.
3360 */
3361 if (hkey != INVALID_HANDLE_VALUE)
3362 RegCloseKey(hkey);
3363
3364 if (pQueueCallbackContext)
3365 SetupTermDefaultQueueCallback(pQueueCallbackContext);
3366
3367 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3368 {
3369 /* an error has occurred, but the device is registered, we must remove it */
3370 if (lrcRet != ERROR_SUCCESS && fRegistered)
3371 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
3372
3373 SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
3374
3375 /* destroy the driver info list */
3376#if 0
3377 /* I've remove this, as I was consistently getting crashes in
3378 * SetupDiDestroyDeviceInfoList otherwise during MSI installation
3379 * (W10 build 19044, VBox r153431 + nocrt changes).
3380 *
3381 * Some details from windbg:
3382 *
3383 * (175e8.1596c): Access violation - code c0000005 (first chance)
3384 * First chance exceptions are reported before any exception handling.
3385 * This exception may be expected and handled.
3386 * SETUPAPI!DereferenceClassDriverList+0x4e:
3387 * 00007ffa`83e2a42a 834008ff add dword ptr [rax+8],0FFFFFFFFh ds:00000000`00000008=????????
3388 * 0:006> k
3389 * # Child-SP RetAddr Call Site
3390 * 00 0000007e`ccd7c070 00007ffa`83e2a287 SETUPAPI!DereferenceClassDriverList+0x4e
3391 * 01 0000007e`ccd7c0a0 00007ffa`56b96bd3 SETUPAPI!SetupDiDestroyDriverInfoList+0x117
3392 * 02 0000007e`ccd7c0f0 00007ffa`56b982a3 MSIF170!vboxNetCfgWinCreateHostOnlyNetworkInterface+0xb23 [E:\vbox\svn\trunk\src\VBox\HostDrivers\VBoxNetFlt\win\cfg\VBoxNetCfg.cpp @ 3378]
3393 * 03 0000007e`ccd7ef10 00007ffa`56b92cb8 MSIF170!VBoxNetCfgWinCreateHostOnlyNetworkInterface+0x53 [E:\vbox\svn\trunk\src\VBox\HostDrivers\VBoxNetFlt\win\cfg\VBoxNetCfg.cpp @ 3479]
3394 * 04 0000007e`ccd7efc0 00007ffa`610f59d3 MSIF170!_createHostOnlyInterface+0x218 [E:\vbox\svn\trunk\src\VBox\Installer\win\InstallHelper\VBoxInstallHelper.cpp @ 1453]
3395 * 05 0000007e`ccd7f260 00007ffa`610d80ac msi!CallCustomDllEntrypoint+0x2b
3396 * 06 0000007e`ccd7f2d0 00007ffa`84567034 msi!CMsiCustomAction::CustomActionThread+0x34c
3397 * 07 0000007e`ccd7f8c0 00007ffa`849a2651 KERNEL32!BaseThreadInitThunk+0x14
3398 * 08 0000007e`ccd7f8f0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
3399 * 0:006> r
3400 * rax=0000000000000000 rbx=0000025f4f03af90 rcx=00007ffa83f23b40
3401 * rdx=0000025f4f03af90 rsi=0000025f5108be50 rdi=0000025f4f066f10
3402 * rip=00007ffa83e2a42a rsp=0000007eccd7c070 rbp=00007ffa83f23000
3403 * r8=0000007eccd7c0a8 r9=0000007eccd7c1f0 r10=0000000000000000
3404 * r11=0000007eccd7c020 r12=0000007eccd7c3d0 r13=00007ffa83f23000
3405 * r14=0000000000000000 r15=0000025f4f03af90
3406 * iopl=0 nv up ei pl nz na po nc
3407 * cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
3408 * SETUPAPI!DereferenceClassDriverList+0x4e:
3409 * 00007ffa`83e2a42a 834008ff add dword ptr [rax+8],0FFFFFFFFh ds:00000000`00000008=????????
3410 *
3411 */
3412 if (destroyList)
3413 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER);
3414#else
3415 RT_NOREF(destroyList);
3416#endif
3417
3418 /* clean up the device info set */
3419 SetupDiDestroyDeviceInfoList(hDeviceInfo);
3420 }
3421
3422 /*
3423 * Return the network connection GUID on success.
3424 */
3425 if (SUCCEEDED(hrc))
3426 {
3427 /** @todo r=bird: Some please explain this mess. It's not just returning a
3428 * GUID here, it's a bit more than that. */
3429 RENAMING_CONTEXT context;
3430 context.hr = E_FAIL;
3431
3432 if (pGuid)
3433 {
3434 hrc = CLSIDFromString(wszCfgGuidString, (LPCLSID)pGuid);
3435 if (FAILED(hrc))
3436 NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
3437 }
3438
3439 INetCfg *pNetCfg = NULL;
3440 LPWSTR pwszApp = NULL;
3441 HRESULT hrc2 = VBoxNetCfgWinQueryINetCfg(&pNetCfg, TRUE, L"VirtualBox Host-Only Creation",
3442 30 * 1000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec. */
3443 /** @todo special handling for 6to4svc.dll ???, i.e. several retrieves */
3444 &pwszApp);
3445 if (hrc2 == S_OK)
3446 {
3447 if (bstrNewInterfaceName.isNotEmpty())
3448 {
3449 /* The assigned name does not match the desired one, rename the device */
3450 context.bstrName = bstrNewInterfaceName.raw();
3451 context.pGuid = pGuid;
3452 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NET,
3453 vboxNetCfgWinRenameHostOnlyNetworkInterface, &context);
3454 }
3455 if (SUCCEEDED(hrc2))
3456 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETSERVICE,
3457 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
3458 if (SUCCEEDED(hrc2))
3459 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETTRANS,
3460 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
3461 if (SUCCEEDED(hrc2))
3462 hrc2 = vboxNetCfgWinEnumNetCfgComponents(pNetCfg, &GUID_DEVCLASS_NETCLIENT,
3463 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority, pGuid);
3464 if (SUCCEEDED(hrc2))
3465 hrc2 = pNetCfg->Apply();
3466 else
3467 NonStandardLogFlow(("Enumeration failed, hrc2=%Rhrc\n", hrc2));
3468
3469 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
3470 }
3471 else if (hrc2 == NETCFG_E_NO_WRITE_LOCK && pwszApp)
3472 {
3473 NonStandardLogFlow(("Application '%ls' is holding the lock, failed\n", pwszApp));
3474 CoTaskMemFree(pwszApp);
3475 pwszApp = NULL;
3476 }
3477 else
3478 NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hrc2=%Rhrc\n", hrc2));
3479
3480#ifndef VBOXNETCFG_DELAYEDRENAME
3481 /* If the device has been successfully renamed, replace the name now. */
3482 if (SUCCEEDED(hrc2) && SUCCEEDED(context.hr))
3483 RTUtf16Copy(wszDevName, RT_ELEMENTS(wszDevName), pBstrDesiredName);
3484
3485 WCHAR wszConnectionName[128];
3486 hrc2 = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionName, RT_ELEMENTS(wszConnectionName), NULL);
3487 if (SUCCEEDED(hrc2))
3488 hrc2 = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszConnectionName);
3489#endif
3490
3491 /*
3492 * Now, return the network connection GUID/name.
3493 */
3494 if (pBstrName)
3495 {
3496 *pBstrName = SysAllocString((const OLECHAR *)wszDevName);
3497 if (!*pBstrName)
3498 {
3499 NonStandardLogFlow(("SysAllocString failed\n"));
3500 hrc = E_OUTOFMEMORY;
3501 }
3502 }
3503 }
3504
3505 if (pBstrErrMsg)
3506 {
3507 *pBstrErrMsg = NULL;
3508 if (bstrError.isNotEmpty())
3509 bstrError.detachToEx(pBstrErrMsg);
3510 }
3511 return hrc;
3512}
3513
3514VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile,
3515 IN BSTR pwszDesiredName, OUT GUID *pGuid,
3516 OUT BSTR *pBstrName, OUT BSTR *pBstrErrMsg)
3517{
3518 HRESULT hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
3519 pGuid, pBstrName, pBstrErrMsg);
3520 if (hrc == E_ABORT)
3521 {
3522 NonStandardLogFlow(("Timed out while waiting for NetCfgInstanceId, try again immediately...\n"));
3523
3524 /*
3525 * This is the first time we fail to obtain NetCfgInstanceId, let us
3526 * retry it once. It is needed to handle the situation when network
3527 * setup fails to recognize the arrival of our device node while it
3528 * is busy removing another host-only interface, and it gets stuck
3529 * with no matching network interface created for our device node.
3530 * See @bugref{7973} for details.
3531 */
3532 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
3533 pGuid, pBstrName, pBstrErrMsg);
3534 if (hrc == E_ABORT)
3535 {
3536 NonStandardLogFlow(("Timed out again while waiting for NetCfgInstanceId, try again after a while...\n"));
3537
3538 /*
3539 * This is the second time we fail to obtain NetCfgInstanceId, let us
3540 * retry it once more. This time we wait to network setup service
3541 * to go down before retrying. Hopefully it will resolve all error
3542 * conditions. See @bugref{7973} for details.
3543 */
3544 SC_HANDLE hSCM = OpenSCManagerW(NULL, NULL, GENERIC_READ);
3545 if (hSCM)
3546 {
3547 SC_HANDLE hService = OpenServiceW(hSCM, L"NetSetupSvc", GENERIC_READ);
3548 if (hService)
3549 {
3550 for (int retries = 0; retries < 60 && !vboxNetCfgWinIsNetSetupStopped(hService); ++retries)
3551 Sleep(1000);
3552 CloseServiceHandle(hService);
3553 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pwszInfPath, fIsInfPathFile, pwszDesiredName,
3554 pGuid, pBstrName, pBstrErrMsg);
3555 }
3556 else
3557 NonStandardLogFlow(("OpenService failed (%Rwc)\n", GetLastError()));
3558 CloseServiceHandle(hSCM);
3559 }
3560 else
3561 NonStandardLogFlow(("OpenSCManager failed (%Rwc)", GetLastError()));
3562
3563 /* Give up and report the error. */
3564 if (hrc == E_ABORT)
3565 {
3566 if (pBstrErrMsg)
3567 {
3568 com::Bstr bstrError;
3569 bstrError.printfNoThrow("Querying NetCfgInstanceId failed (ERROR_FILE_NOT_FOUND)");
3570 bstrError.detachToEx(pBstrErrMsg);
3571 }
3572 hrc = E_FAIL;
3573 }
3574 }
3575 }
3576 return hrc;
3577}
3578
3579static HRESULT vboxNetCfgWinGetLoopbackMetric(OUT DWORD *Metric)
3580{
3581 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3582 Assert(g_pfnGetIpInterfaceEntry != NULL);
3583
3584 MIB_IPINTERFACE_ROW row;
3585 RT_ZERO(row); /* paranoia */
3586 g_pfnInitializeIpInterfaceEntry(&row);
3587
3588 row.Family = AF_INET;
3589 row.InterfaceLuid.Info.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
3590
3591 NETIO_STATUS dwErr = g_pfnGetIpInterfaceEntry(&row);
3592 if (dwErr == NO_ERROR)
3593 {
3594 *Metric = row.Metric;
3595 return S_OK;
3596 }
3597 return HRESULT_FROM_WIN32(dwErr);
3598}
3599
3600static HRESULT vboxNetCfgWinSetInterfaceMetric(IN NET_LUID *pInterfaceLuid, IN DWORD metric)
3601{
3602 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3603 Assert(g_pfnSetIpInterfaceEntry != NULL);
3604
3605 MIB_IPINTERFACE_ROW newRow;
3606 RT_ZERO(newRow); /* paranoia */
3607 g_pfnInitializeIpInterfaceEntry(&newRow);
3608
3609 // identificate the interface to change
3610 newRow.InterfaceLuid = *pInterfaceLuid;
3611 newRow.Family = AF_INET;
3612
3613 // changed settings
3614 newRow.UseAutomaticMetric = false;
3615 newRow.Metric = metric;
3616
3617 // change settings
3618 NETIO_STATUS dwErr = g_pfnSetIpInterfaceEntry(&newRow);
3619 if (dwErr == NO_ERROR)
3620 return S_OK;
3621 return HRESULT_FROM_WIN32(dwErr);
3622}
3623
3624static HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid)
3625{
3626 HRESULT hrc = E_FAIL;
3627 HMODULE hmod = loadSystemDll(L"Iphlpapi.dll");
3628 if (hmod)
3629 {
3630 g_pfnInitializeIpInterfaceEntry = (PFNINITIALIZEIPINTERFACEENTRY)GetProcAddress(hmod, "InitializeIpInterfaceEntry");
3631 g_pfnGetIpInterfaceEntry = (PFNGETIPINTERFACEENTRY) GetProcAddress(hmod, "GetIpInterfaceEntry");
3632 g_pfnSetIpInterfaceEntry = (PFNSETIPINTERFACEENTRY) GetProcAddress(hmod, "SetIpInterfaceEntry");
3633 Assert(g_pfnInitializeIpInterfaceEntry);
3634 Assert(g_pfnGetIpInterfaceEntry);
3635 Assert(g_pfnSetIpInterfaceEntry);
3636
3637 if ( g_pfnInitializeIpInterfaceEntry
3638 && g_pfnGetIpInterfaceEntry
3639 && g_pfnSetIpInterfaceEntry)
3640 {
3641 DWORD loopbackMetric = 0;
3642 hrc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
3643 if (SUCCEEDED(hrc))
3644 hrc = vboxNetCfgWinSetInterfaceMetric(pLuid, loopbackMetric - 1);
3645 }
3646
3647 g_pfnInitializeIpInterfaceEntry = NULL;
3648 g_pfnSetIpInterfaceEntry = NULL;
3649 g_pfnGetIpInterfaceEntry = NULL;
3650
3651 FreeLibrary(hmod);
3652 }
3653 return hrc;
3654}
3655
3656static HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID *pLUID)
3657{
3658 if (pLUID == NULL)
3659 return E_INVALIDARG;
3660
3661 DWORD dwLuidIndex = 0;
3662 DWORD cbSize = sizeof(dwLuidIndex);
3663 DWORD dwValueType = REG_DWORD; /** @todo r=bird: This is output only. No checked after the call. So, only for debugging? */
3664 LSTATUS lrc = RegQueryValueExW(hKey, L"NetLuidIndex", NULL, &dwValueType, (LPBYTE)&dwLuidIndex, &cbSize);
3665 if (lrc == ERROR_SUCCESS)
3666 {
3667 DWORD dwIfType = 0;
3668 cbSize = sizeof(dwIfType);
3669 dwValueType = REG_DWORD; /** @todo r=bird: This is output only. No checked after the call. So, only for debugging? */
3670 lrc = RegQueryValueExW(hKey, L"*IfType", NULL, &dwValueType, (LPBYTE)&dwIfType, &cbSize);
3671 if (lrc == ERROR_SUCCESS)
3672 {
3673 RT_ZERO(*pLUID);
3674 pLUID->Info.IfType = dwIfType;
3675 pLUID->Info.NetLuidIndex = dwLuidIndex;
3676 return S_OK;
3677 }
3678 }
3679
3680 RT_ZERO(*pLUID);
3681 return HRESULT_FROM_WIN32(lrc);
3682}
3683
3684
3685#ifdef VBOXNETCFG_DELAYEDRENAME
3686VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pwszId, OUT BSTR *pDevName)
3687{
3688 if (pDevName)
3689 *pDevName = NULL;
3690
3691 HRESULT hr = S_OK; /** @todo r=bird: ODD return status for SetupDiCreateDeviceInfoList failures! */
3692 HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
3693 if (hDevInfo != INVALID_HANDLE_VALUE)
3694 {
3695 SP_DEVINFO_DATA DevInfoData = { sizeof(SP_DEVINFO_DATA) };
3696 if (SetupDiOpenDeviceInfo(hDevInfo, pwszId, NULL, 0, &DevInfoData))
3697 {
3698 WCHAR wszDevName[256 + 1] = {0};
3699 DWORD err = ERROR_SUCCESS;
3700 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, SPDRP_FRIENDLYNAME, NULL /*PropertyRegDataType*/,
3701 (PBYTE)wszDevName, sizeof(wszDevName) - sizeof(WCHAR) /*yes, bytes*/,
3702 NULL /*RequiredSize*/))
3703 {
3704 err = GetLastError();
3705 if (err == ERROR_INVALID_DATA)
3706 {
3707 RT_ZERO(wszDevName);
3708 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData, SPDRP_DEVICEDESC, NULL /*PropertyRegDataType*/,
3709 (PBYTE)wszDevName, sizeof(wszDevName) - sizeof(WCHAR) /*yes, bytes*/,
3710 NULL /*RequiredSize*/))
3711 err = ERROR_SUCCESS;
3712 else
3713 err = GetLastError();
3714 }
3715 }
3716 if (err == ERROR_SUCCESS)
3717 {
3718 WCHAR wszConnectionNewName[128] = {0};
3719 hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionNewName,
3720 RT_ELEMENTS(wszConnectionNewName), NULL);
3721 if (SUCCEEDED(hr))
3722 {
3723 WCHAR wszGuid[50];
3724 int cbWGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
3725 if (cbWGuid)
3726 {
3727 hr = VBoxNetCfgWinRenameConnection(wszGuid, wszConnectionNewName);
3728 if (FAILED(hr))
3729 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinRenameConnection failed (0x%x)\n", hr));
3730 }
3731 else
3732 {
3733 err = GetLastError();
3734 hr = HRESULT_FROM_WIN32(err);
3735 if (SUCCEEDED(hr))
3736 hr = E_FAIL;
3737 NonStandardLogFlow(("StringFromGUID2 failed err=%u, hr=0x%x\n", err, hr));
3738 }
3739 }
3740 else
3741 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinGenHostonlyConnectionName failed (0x%x)\n", hr));
3742 if (SUCCEEDED(hr) && pDevName)
3743 {
3744 *pDevName = SysAllocString((const OLECHAR *)wszDevName);
3745 if (!*pDevName)
3746 {
3747 NonStandardLogFlow(("SysAllocString failed\n"));
3748 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3749 }
3750 }
3751 }
3752 else
3753 {
3754 hr = HRESULT_FROM_WIN32(err);
3755 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiGetDeviceRegistryPropertyW failed (0x%x)\n", err));
3756 }
3757 }
3758 else
3759 {
3760 DWORD err = GetLastError();
3761 hr = HRESULT_FROM_WIN32(err);
3762 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiOpenDeviceInfo failed (0x%x)\n", err));
3763 }
3764 SetupDiDestroyDeviceInfoList(hDevInfo);
3765 }
3766
3767 return hr;
3768}
3769#endif /* VBOXNETCFG_DELAYEDRENAME */
3770
3771#undef SetErrBreak
3772
Note: See TracBrowser for help on using the repository browser.

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