VirtualBox

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

Last change on this file since 83786 was 83786, checked in by vboxsync, 5 years ago

HostDrivers/VBoxNetCfg.cpp: VC++ 14.1 adjustments. bugref:8489

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