VirtualBox

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

Last change on this file since 77804 was 77804, checked in by vboxsync, 6 years ago

NetAdp/Win: (bugref:9409) Store host-only adapter configuration in extra data. Create missing adapters when listing/creating/removing adapters.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 131.3 KB
Line 
1/* $Id: VBoxNetCfg.cpp 77804 2019-03-20 08:05:37Z vboxsync $ */
2/** @file
3 * VBoxNetCfg.cpp - Network Configuration API.
4 */
5/*
6 * Copyright (C) 2011-2019 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
52#ifndef Assert /** @todo r=bird: where would this be defined? */
53//# ifdef DEBUG
54//# define Assert(_expr) assert(_expr)
55//# else
56//# define Assert(_expr) do{ }while (0)
57//# endif
58# define Assert _ASSERT
59# define AssertMsg(expr, msg) do{}while (0)
60#endif
61static LOG_ROUTINE g_Logger = NULL;
62
63static VOID DoLogging(LPCSTR szString, ...);
64#define NonStandardLog DoLogging
65#define NonStandardLogFlow(x) DoLogging x
66
67#define DbgLog /** @todo r=bird: What does this do? */
68
69#define VBOX_NETCFG_LOCK_TIME_OUT 5000 /** @todo r=bird: What does this do? */
70
71#define VBOXNETCFGWIN_NETADP_ID L"sun_VBoxNetAdp"
72
73/*
74* Wrappers for HelpAPI functions
75*/
76typedef void FNINITIALIZEIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
77typedef FNINITIALIZEIPINTERFACEENTRY *PFNINITIALIZEIPINTERFACEENTRY;
78
79typedef NETIOAPI_API FNGETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
80typedef FNGETIPINTERFACEENTRY *PFNGETIPINTERFACEENTRY;
81
82typedef NETIOAPI_API FNSETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
83typedef FNSETIPINTERFACEENTRY *PFNSETIPINTERFACEENTRY;
84
85static PFNINITIALIZEIPINTERFACEENTRY g_pfnInitializeIpInterfaceEntry = NULL;
86static PFNGETIPINTERFACEENTRY g_pfnGetIpInterfaceEntry = NULL;
87static PFNSETIPINTERFACEENTRY g_pfnSetIpInterfaceEntry = NULL;
88
89
90/*
91* Forward declaration for using vboxNetCfgWinSetupMetric()
92*/
93HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid);
94HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID);
95
96
97/*
98 * For some weird reason we do not want to use IPRT here, hence the following
99 * function provides a replacement for BstrFmt.
100 */
101static bstr_t bstr_printf(const char *cszFmt, ...)
102{
103 char szBuffer[4096];
104 szBuffer[sizeof(szBuffer) - 1] = 0; /* Make sure the string will be null-terminated */
105 va_list va;
106 va_start(va, cszFmt);
107 _vsnprintf(szBuffer, sizeof(szBuffer) - 1, cszFmt, va);
108 va_end(va);
109 return bstr_t(szBuffer);
110}
111
112static HRESULT vboxNetCfgWinINetCfgLock(IN INetCfg *pNetCfg,
113 IN LPCWSTR pszwClientDescription,
114 IN DWORD cmsTimeout,
115 OUT LPWSTR *ppszwClientDescription)
116{
117 INetCfgLock *pLock;
118 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
119 if (FAILED(hr))
120 {
121 NonStandardLogFlow(("QueryInterface failed, hr (0x%x)\n", hr));
122 return hr;
123 }
124
125 hr = pLock->AcquireWriteLock(cmsTimeout, pszwClientDescription, ppszwClientDescription);
126 if (hr == S_FALSE)
127 {
128 NonStandardLogFlow(("Write lock busy\n"));
129 }
130 else if (FAILED(hr))
131 {
132 NonStandardLogFlow(("AcquireWriteLock failed, hr (0x%x)\n", hr));
133 }
134
135 pLock->Release();
136 return hr;
137}
138
139static HRESULT vboxNetCfgWinINetCfgUnlock(IN INetCfg *pNetCfg)
140{
141 INetCfgLock *pLock;
142 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
143 if (FAILED(hr))
144 {
145 NonStandardLogFlow(("QueryInterface failed, hr (0x%x)\n", hr));
146 return hr;
147 }
148
149 hr = pLock->ReleaseWriteLock();
150 if (FAILED(hr))
151 NonStandardLogFlow(("ReleaseWriteLock failed, hr (0x%x)\n", hr));
152
153 pLock->Release();
154 return hr;
155}
156
157VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(OUT INetCfg **ppNetCfg,
158 IN BOOL fGetWriteLock,
159 IN LPCWSTR pszwClientDescription,
160 IN DWORD cmsTimeout,
161 OUT LPWSTR *ppszwClientDescription)
162{
163 INetCfg *pNetCfg;
164 HRESULT hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (PVOID*)&pNetCfg);
165 if (FAILED(hr))
166 {
167 NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\n", hr));
168 return hr;
169 }
170
171 if (fGetWriteLock)
172 {
173 hr = vboxNetCfgWinINetCfgLock(pNetCfg, pszwClientDescription, cmsTimeout, ppszwClientDescription);
174 if (hr == S_FALSE)
175 {
176 NonStandardLogFlow(("Write lock is busy\n", hr));
177 hr = NETCFG_E_NO_WRITE_LOCK;
178 }
179 }
180
181 if (SUCCEEDED(hr))
182 {
183 hr = pNetCfg->Initialize(NULL);
184 if (SUCCEEDED(hr))
185 {
186 *ppNetCfg = pNetCfg;
187 return S_OK;
188 }
189 else
190 NonStandardLogFlow(("Initialize failed, hr (0x%x)\n", hr));
191 }
192
193 pNetCfg->Release();
194 return hr;
195}
196
197VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pNetCfg, IN BOOL fHasWriteLock)
198{
199 if (!pNetCfg) /* If network config has been released already, just bail out. */
200 {
201 NonStandardLogFlow(("Warning: No network config given but write lock is set to TRUE\n"));
202 return S_OK;
203 }
204
205 HRESULT hr = pNetCfg->Uninitialize();
206 if (FAILED(hr))
207 {
208 NonStandardLogFlow(("Uninitialize failed, hr (0x%x)\n", hr));
209 /* Try to release the write lock below. */
210 }
211
212 if (fHasWriteLock)
213 {
214 HRESULT hr2 = vboxNetCfgWinINetCfgUnlock(pNetCfg);
215 if (FAILED(hr2))
216 NonStandardLogFlow(("vboxNetCfgWinINetCfgUnlock failed, hr (0x%x)\n", hr2));
217 if (SUCCEEDED(hr))
218 hr = hr2;
219 }
220
221 pNetCfg->Release();
222 return hr;
223}
224
225static HRESULT vboxNetCfgWinGetComponentByGuidEnum(IEnumNetCfgComponent *pEnumNcc,
226 IN const GUID *pGuid,
227 OUT INetCfgComponent **ppNcc)
228{
229 HRESULT hr = pEnumNcc->Reset();
230 if (FAILED(hr))
231 {
232 NonStandardLogFlow(("Reset failed, hr (0x%x)\n", hr));
233 return hr;
234 }
235
236 INetCfgComponent *pNcc;
237 while ((hr = pEnumNcc->Next(1, &pNcc, NULL)) == S_OK)
238 {
239 ULONG uComponentStatus;
240 hr = pNcc->GetDeviceStatus(&uComponentStatus);
241 if (SUCCEEDED(hr))
242 {
243 if (uComponentStatus == 0)
244 {
245 GUID NccGuid;
246 hr = pNcc->GetInstanceGuid(&NccGuid);
247
248 if (SUCCEEDED(hr))
249 {
250 if (NccGuid == *pGuid)
251 {
252 /* found the needed device */
253 *ppNcc = pNcc;
254 break;
255 }
256 }
257 else
258 NonStandardLogFlow(("GetInstanceGuid failed, hr (0x%x)\n", hr));
259 }
260 }
261
262 pNcc->Release();
263 }
264 return hr;
265}
266
267VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc,
268 IN const GUID *pguidClass,
269 IN const GUID * pComponentGuid,
270 OUT INetCfgComponent **ppncc)
271{
272 IEnumNetCfgComponent *pEnumNcc;
273 HRESULT hr = pNc->EnumComponents(pguidClass, &pEnumNcc);
274
275 if (SUCCEEDED(hr))
276 {
277 hr = vboxNetCfgWinGetComponentByGuidEnum(pEnumNcc, pComponentGuid, ppncc);
278 if (hr == S_FALSE)
279 {
280 NonStandardLogFlow(("Component not found\n"));
281 }
282 else if (FAILED(hr))
283 {
284 NonStandardLogFlow(("vboxNetCfgWinGetComponentByGuidEnum failed, hr (0x%x)\n", hr));
285 }
286 pEnumNcc->Release();
287 }
288 else
289 NonStandardLogFlow(("EnumComponents failed, hr (0x%x)\n", hr));
290 return hr;
291}
292
293static HRESULT vboxNetCfgWinQueryInstaller(IN INetCfg *pNetCfg, IN const GUID *pguidClass, INetCfgClassSetup **ppSetup)
294{
295 HRESULT hr = pNetCfg->QueryNetCfgClass(pguidClass, IID_INetCfgClassSetup, (void**)ppSetup);
296 if (FAILED(hr))
297 NonStandardLogFlow(("QueryNetCfgClass failed, hr (0x%x)\n", hr));
298 return hr;
299}
300
301VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
302 OUT INetCfgComponent **ppComponent)
303{
304 INetCfgClassSetup *pSetup;
305 HRESULT hr = vboxNetCfgWinQueryInstaller(pNetCfg, pguidClass, &pSetup);
306 if (FAILED(hr))
307 {
308 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed, hr (0x%x)\n", hr));
309 return hr;
310 }
311
312 OBO_TOKEN Token;
313 ZeroMemory(&Token, sizeof (Token));
314 Token.Type = OBO_USER;
315 INetCfgComponent* pTempComponent = NULL;
316
317 hr = pSetup->Install(pszwComponentId, &Token,
318 0, /* IN DWORD dwSetupFlags */
319 0, /* IN DWORD dwUpgradeFromBuildNo */
320 NULL, /* IN LPCWSTR pszwAnswerFile */
321 NULL, /* IN LPCWSTR pszwAnswerSections */
322 &pTempComponent);
323 if (SUCCEEDED(hr))
324 {
325 if (pTempComponent != NULL)
326 {
327 HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
328 HRESULT res;
329
330 /*
331 * Set default metric value of interface to fix multicast issue
332 * See @bugref{6379} for details.
333 */
334 res = pTempComponent->OpenParamKey(&hkey);
335
336 /* Set default metric value for host-only interface only */
337 if ( SUCCEEDED(res)
338 && hkey != INVALID_HANDLE_VALUE
339 && wcsnicmp(pszwComponentId, VBOXNETCFGWIN_NETADP_ID, 256) == 0)
340 {
341 NET_LUID luid;
342 res = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
343
344 /* Close the key as soon as possible. See @bugref{7973}. */
345 RegCloseKey (hkey);
346 hkey = (HKEY)INVALID_HANDLE_VALUE;
347
348 if (FAILED(res))
349 {
350 /*
351 * The setting of Metric is not very important functionality,
352 * So we will not break installation process due to this error.
353 */
354 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! "
355 "vboxNetCfgWinGetInterfaceLUID failed, default metric "
356 "for new interface will not be set, hr (0x%x)\n", res));
357 }
358 else
359 {
360 res = vboxNetCfgWinSetupMetric(&luid);
361 if (FAILED(res))
362 {
363 /*
364 * The setting of Metric is not very important functionality,
365 * So we will not break installation process due to this error.
366 */
367 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! "
368 "vboxNetCfgWinSetupMetric failed, default metric "
369 "for new interface will not be set, hr (0x%x)\n", res));
370 }
371 }
372 }
373 if (hkey != INVALID_HANDLE_VALUE)
374 {
375 RegCloseKey (hkey);
376 hkey = (HKEY)INVALID_HANDLE_VALUE;
377 }
378 if (ppComponent != NULL)
379 *ppComponent = pTempComponent;
380 else
381 pTempComponent->Release();
382 }
383
384 /* ignore the apply failure */
385 HRESULT tmpHr = pNetCfg->Apply();
386 Assert(tmpHr == S_OK);
387 if (tmpHr != S_OK)
388 NonStandardLogFlow(("Apply failed, hr (0x%x)\n", tmpHr));
389 }
390 else
391 NonStandardLogFlow(("Install failed, hr (0x%x)\n", hr));
392
393 pSetup->Release();
394 return hr;
395}
396
397static HRESULT vboxNetCfgWinInstallInfAndComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
398 IN LPCWSTR const *apInfPaths, IN UINT cInfPaths,
399 OUT INetCfgComponent **ppComponent)
400{
401 HRESULT hr = S_OK;
402 UINT cFilesProcessed = 0;
403
404 NonStandardLogFlow(("Installing %u INF files ...\n", cInfPaths));
405
406 for (; cFilesProcessed < cInfPaths; cFilesProcessed++)
407 {
408 NonStandardLogFlow(("Installing INF file \"%ws\" ...\n", apInfPaths[cFilesProcessed]));
409 hr = VBoxDrvCfgInfInstall(apInfPaths[cFilesProcessed]);
410 if (FAILED(hr))
411 {
412 NonStandardLogFlow(("VBoxNetCfgWinInfInstall failed, hr (0x%x)\n", hr));
413 break;
414 }
415 }
416
417 if (SUCCEEDED(hr))
418 {
419 hr = VBoxNetCfgWinInstallComponent(pNetCfg, pszwComponentId, pguidClass, ppComponent);
420 if (FAILED(hr))
421 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent failed, hr (0x%x)\n", hr));
422 }
423
424 if (FAILED(hr))
425 {
426 NonStandardLogFlow(("Installation failed, rolling back installation set ...\n"));
427
428 do
429 {
430 HRESULT hr2 = VBoxDrvCfgInfUninstall(apInfPaths[cFilesProcessed], 0);
431 if (FAILED(hr2))
432 NonStandardLogFlow(("VBoxDrvCfgInfUninstall failed, hr (0x%x)\n", hr2));
433 /* Keep going. */
434 if (!cFilesProcessed)
435 break;
436 } while (cFilesProcessed--);
437
438 NonStandardLogFlow(("Rollback complete\n"));
439 }
440
441 return hr;
442}
443
444VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUninstallComponent(IN INetCfg *pNetCfg, IN INetCfgComponent *pComponent)
445{
446 GUID GuidClass;
447 HRESULT hr = pComponent->GetClassGuid(&GuidClass);
448 if (FAILED(hr))
449 {
450 NonStandardLogFlow(("GetClassGuid failed, hr (0x%x)\n", hr));
451 return hr;
452 }
453
454 INetCfgClassSetup *pSetup = NULL;
455 hr = vboxNetCfgWinQueryInstaller(pNetCfg, &GuidClass, &pSetup);
456 if (FAILED(hr))
457 {
458 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed, hr (0x%x)\n", hr));
459 return hr;
460 }
461
462 OBO_TOKEN Token;
463 ZeroMemory(&Token, sizeof(Token));
464 Token.Type = OBO_USER;
465
466 hr = pSetup->DeInstall(pComponent, &Token, NULL /* OUT LPWSTR *pmszwRefs */);
467 if (SUCCEEDED(hr))
468 {
469 hr = pNetCfg->Apply();
470 if (FAILED(hr))
471 NonStandardLogFlow(("Apply failed, hr (0x%x)\n", hr));
472 }
473 else
474 NonStandardLogFlow(("DeInstall failed, hr (0x%x)\n", hr));
475
476 if (pSetup)
477 pSetup->Release();
478 return hr;
479}
480
481typedef BOOL (*VBOXNETCFGWIN_NETCFGENUM_CALLBACK) (IN INetCfg *pNetCfg, IN INetCfgComponent *pNetCfgComponent, PVOID pContext);
482
483static HRESULT vboxNetCfgWinEnumNetCfgComponents(IN INetCfg *pNetCfg,
484 IN const GUID *pguidClass,
485 VBOXNETCFGWIN_NETCFGENUM_CALLBACK callback,
486 PVOID pContext)
487{
488 IEnumNetCfgComponent *pEnumComponent;
489 HRESULT hr = pNetCfg->EnumComponents(pguidClass, &pEnumComponent);
490 if (SUCCEEDED(hr))
491 {
492 INetCfgComponent *pNetCfgComponent;
493 hr = pEnumComponent->Reset();
494 do
495 {
496 hr = pEnumComponent->Next(1, &pNetCfgComponent, NULL);
497 if (hr == S_OK)
498 {
499// ULONG uComponentStatus;
500// hr = pNcc->GetDeviceStatus(&uComponentStatus);
501// if (SUCCEEDED(hr))
502 BOOL fResult = FALSE;
503 if (pNetCfgComponent)
504 {
505 if (pContext)
506 fResult = callback(pNetCfg, pNetCfgComponent, pContext);
507 pNetCfgComponent->Release();
508 }
509
510 if (!fResult)
511 break;
512 }
513 else
514 {
515 if (hr == S_FALSE)
516 {
517 hr = S_OK;
518 }
519 else
520 NonStandardLogFlow(("Next failed, hr (0x%x)\n", hr));
521 break;
522 }
523 } while (true);
524 pEnumComponent->Release();
525 }
526 return hr;
527}
528
529/*
530 * Forward declarations of functions used in vboxNetCfgWinRemoveAllNetDevicesOfIdCallback.
531 */
532VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf);
533VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(LPWSTR pGuid, PCWSTR NewName);
534
535static BOOL vboxNetCfgWinRemoveAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pvContext)
536{
537 RT_NOREF1(pvContext);
538 SP_REMOVEDEVICE_PARAMS rmdParams;
539 memset(&rmdParams, 0, sizeof(SP_REMOVEDEVICE_PARAMS));
540 rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
541 rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
542 rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
543
544 if (SetupDiSetClassInstallParams(hDevInfo,pDev,
545 &rmdParams.ClassInstallHeader, sizeof(rmdParams)))
546 {
547 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
548 {
549#ifndef VBOXNETCFG_DELAYEDRENAME
550 /* Figure out NetCfgInstanceId. */
551 HKEY hKey = SetupDiOpenDevRegKey(hDevInfo,
552 pDev,
553 DICS_FLAG_GLOBAL,
554 0,
555 DIREG_DRV,
556 KEY_READ);
557 if (hKey == INVALID_HANDLE_VALUE)
558 {
559 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiOpenDevRegKey failed with error %ld\n",
560 GetLastError()));
561 }
562 else
563 {
564 WCHAR wszCfgGuidString[50] = { L'' };
565 DWORD cbSize = sizeof(wszCfgGuidString);
566 DWORD dwValueType;
567 DWORD ret = RegQueryValueExW(hKey, L"NetCfgInstanceId", NULL,
568 &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
569 if (ret == ERROR_SUCCESS)
570 {
571 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Processing device ID \"%S\"\n",
572 wszCfgGuidString));
573
574 /* Figure out device name. */
575 WCHAR wszDevName[256], wszTempName[256];
576 ULONG cbName = sizeof(wszTempName);
577
578 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev,
579 SPDRP_FRIENDLYNAME, /* IN DWORD Property,*/
580 NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL*/
581 (PBYTE)wszDevName, /* OUT PBYTE PropertyBuffer,*/
582 sizeof(wszDevName), /* IN DWORD PropertyBufferSize,*/
583 NULL /* OUT PDWORD RequiredSize OPTIONAL*/))
584 {
585 /*
586 * Rename the connection before removing the device. This will
587 * hopefully prevent an error when we will be attempting
588 * to rename a newly created connection (see @bugref{6740}).
589 */
590 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszTempName, &cbName);
591 wcscat_s(wszTempName, sizeof(wszTempName), L" removed");
592 if (SUCCEEDED(hr))
593 hr = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszTempName);
594 //NonStandardLogFlow(("VBoxNetCfgWinRenameConnection(%S,%S) => 0x%x\n", pWCfgGuidString, TempName, hr_tmp));
595 }
596 else
597 {
598 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Failed to get friendly name for device \"%S\"\n",
599 wszCfgGuidString));
600 }
601 }
602 else
603 {
604 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Querying instance ID failed with %d\n",
605 ret));
606 }
607
608 RegCloseKey(hKey);
609 }
610#endif /* VBOXNETCFG_DELAYEDRENAME */
611
612 if (SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, pDev))
613 {
614 SP_DEVINSTALL_PARAMS devParams;
615 memset(&devParams, 0, sizeof(SP_DEVINSTALL_PARAMS));
616 devParams.cbSize = sizeof(devParams);
617
618 if (SetupDiGetDeviceInstallParams(hDevInfo, pDev, &devParams))
619 {
620 if ( (devParams.Flags & DI_NEEDRESTART)
621 || (devParams.Flags & DI_NEEDREBOOT))
622 {
623 NonStandardLog(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: A reboot is required\n"));
624 }
625 }
626 else
627 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %ld\n",
628 GetLastError()));
629 }
630 else
631 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
632 GetLastError()));
633 }
634 else
635 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetSelectedDevice failed with %ld\n",
636 GetLastError()));
637 }
638 else
639 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetClassInstallParams failed with %ld\n",
640 GetLastError()));
641
642 /* Continue enumeration. */
643 return TRUE;
644}
645
646typedef struct VBOXNECTFGWINPROPCHANGE
647{
648 VBOXNECTFGWINPROPCHANGE_TYPE enmPcType;
649 HRESULT hr;
650} VBOXNECTFGWINPROPCHANGE ,*PVBOXNECTFGWINPROPCHANGE;
651
652static BOOL vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
653{
654 PVBOXNECTFGWINPROPCHANGE pPc = (PVBOXNECTFGWINPROPCHANGE)pContext;
655
656 SP_PROPCHANGE_PARAMS PcParams;
657 memset (&PcParams, 0, sizeof (PcParams));
658 PcParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
659 PcParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
660 PcParams.Scope = DICS_FLAG_GLOBAL;
661
662 switch(pPc->enmPcType)
663 {
664 case VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE:
665 PcParams.StateChange = DICS_DISABLE;
666 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_DISABLE): %d\n", pPc->enmPcType));
667 break;
668 case VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE:
669 PcParams.StateChange = DICS_ENABLE;
670 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_ENABLE): %d\n", pPc->enmPcType));
671 break;
672 default:
673 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Unexpected prop change type: %d\n", pPc->enmPcType));
674 pPc->hr = E_INVALIDARG;
675 return FALSE;
676 }
677
678 if (SetupDiSetClassInstallParams(hDevInfo, pDev, &PcParams.ClassInstallHeader, sizeof(PcParams)))
679 {
680 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
681 {
682 if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, pDev))
683 {
684 SP_DEVINSTALL_PARAMS devParams;
685 devParams.cbSize = sizeof(devParams);
686 if (SetupDiGetDeviceInstallParams(hDevInfo,pDev,&devParams))
687 {
688 if ( (devParams.Flags & DI_NEEDRESTART)
689 || (devParams.Flags & DI_NEEDREBOOT))
690 {
691 NonStandardLog(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: A reboot is required\n"));
692 }
693 }
694 else
695 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %ld\n",
696 GetLastError()));
697 }
698 else
699 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
700 GetLastError()));
701 }
702 else
703 NonStandardLogFlow(("SetupDiSetSelectedDevice failed with %ld\n", GetLastError()));
704 }
705 else
706 NonStandardLogFlow(("SetupDiSetClassInstallParams failed with %ld\n", GetLastError()));
707
708 /* Continue enumeration. */
709 return TRUE;
710}
711
712typedef BOOL (*PFNVBOXNETCFGWINNETENUMCALLBACK)(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext);
713VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnumNetDevices(LPCWSTR pwszPnPId,
714 PFNVBOXNETCFGWINNETENUMCALLBACK pfnCallback, PVOID pvContext)
715{
716 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Searching for: %S\n", pwszPnPId));
717
718 HRESULT hr;
719 HDEVINFO hDevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET,
720 NULL, /* IN PCTSTR Enumerator, OPTIONAL */
721 NULL, /* IN HWND hwndParent, OPTIONAL */
722 DIGCF_PRESENT, /* IN DWORD Flags,*/
723 NULL, /* IN HDEVINFO DeviceInfoSet, OPTIONAL */
724 NULL, /* IN PCTSTR MachineName, OPTIONAL */
725 NULL /* IN PVOID Reserved */);
726 if (hDevInfo != INVALID_HANDLE_VALUE)
727 {
728 DWORD winEr = NO_ERROR;
729
730 DWORD dwDevId = 0;
731 size_t cPnPId = wcslen(pwszPnPId);
732
733 PBYTE pBuffer = NULL;
734
735 for (;;)
736 {
737 SP_DEVINFO_DATA Dev;
738 memset(&Dev, 0, sizeof(SP_DEVINFO_DATA));
739 Dev.cbSize = sizeof(SP_DEVINFO_DATA);
740
741 if (!SetupDiEnumDeviceInfo(hDevInfo, dwDevId, &Dev))
742 {
743 winEr = GetLastError();
744 if (winEr == ERROR_NO_MORE_ITEMS)
745 winEr = ERROR_SUCCESS;
746 break;
747 }
748
749 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Enumerating device %ld ... \n", dwDevId));
750 dwDevId++;
751
752 if (pBuffer)
753 free(pBuffer);
754 pBuffer = NULL;
755 DWORD cbBuffer = 0;
756 DWORD cbRequired = 0;
757
758 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
759 SPDRP_HARDWAREID, /* IN DWORD Property */
760 NULL, /* OUT PDWORD PropertyRegDataType OPTIONAL */
761 pBuffer, /* OUT PBYTE PropertyBuffer */
762 cbBuffer, /* IN DWORD PropertyBufferSize */
763 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
764 {
765 winEr = GetLastError();
766 if (winEr != ERROR_INSUFFICIENT_BUFFER)
767 {
768 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with %ld\n", winEr));
769 break;
770 }
771
772 pBuffer = (PBYTE)malloc(cbRequired);
773 if (!pBuffer)
774 {
775 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Out of memory allocating %ld bytes\n",
776 cbRequired));
777 winEr = ERROR_OUTOFMEMORY;
778 break;
779 }
780
781 cbBuffer = cbRequired;
782
783 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo,&Dev,
784 SPDRP_HARDWAREID, /* IN DWORD Property */
785 NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL */
786 pBuffer, /* OUT PBYTE PropertyBuffer */
787 cbBuffer, /* IN DWORD PropertyBufferSize */
788 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
789 {
790 winEr = GetLastError();
791 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (2) failed with %ld\n",
792 winEr));
793 break;
794 }
795 }
796
797 PWSTR pCurId = (PWSTR)pBuffer;
798 size_t cCurId = wcslen(pCurId);
799
800 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Device %ld: %S\n", dwDevId, pCurId));
801
802 if (cCurId >= cPnPId)
803 {
804 NonStandardLogFlow(("!wcsnicmp(pCurId = (%S), pwszPnPId = (%S), cPnPId = (%d))\n", pCurId, pwszPnPId, cPnPId));
805
806 pCurId += cCurId - cPnPId;
807 if (!wcsnicmp(pCurId, pwszPnPId, cPnPId))
808 {
809 if (!pfnCallback(hDevInfo, &Dev, pvContext))
810 break;
811 }
812 }
813 }
814
815 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Found %ld devices total\n", dwDevId));
816
817 if (pBuffer)
818 free(pBuffer);
819
820 hr = HRESULT_FROM_WIN32(winEr);
821
822 SetupDiDestroyDeviceInfoList(hDevInfo);
823 }
824 else
825 {
826 DWORD winEr = GetLastError();
827 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetClassDevsExW failed with %ld\n", winEr));
828 hr = HRESULT_FROM_WIN32(winEr);
829 }
830
831 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Ended with hr (0x%x)\n", hr));
832 return hr;
833}
834
835VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR lpszPnPId)
836{
837 return VBoxNetCfgWinEnumNetDevices(lpszPnPId, vboxNetCfgWinRemoveAllNetDevicesOfIdCallback, NULL);
838}
839
840VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR lpszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE enmPcType)
841{
842 VBOXNECTFGWINPROPCHANGE Pc;
843 Pc.enmPcType = enmPcType;
844 Pc.hr = S_OK;
845 NonStandardLogFlow(("Calling VBoxNetCfgWinEnumNetDevices with lpszPnPId =(%S) and vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback\n", lpszPnPId));
846
847 HRESULT hr = VBoxNetCfgWinEnumNetDevices(lpszPnPId, vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback, &Pc);
848 if (!SUCCEEDED(hr))
849 {
850 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices failed 0x%x\n", hr));
851 return hr;
852 }
853
854 if (!SUCCEEDED(Pc.hr))
855 {
856 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback failed 0x%x\n", Pc.hr));
857 return Pc.hr;
858 }
859
860 return S_OK;
861}
862
863/*
864 * logging
865 */
866static VOID DoLogging(LPCSTR szString, ...)
867{
868 LOG_ROUTINE pfnRoutine = (LOG_ROUTINE)(*((void * volatile *)&g_Logger));
869 if (pfnRoutine)
870 {
871 char szBuffer[4096] = {0};
872 va_list va;
873 va_start(va, szString);
874 _vsnprintf(szBuffer, RT_ELEMENTS(szBuffer), szString, va);
875 va_end(va);
876
877 pfnRoutine(szBuffer);
878 }
879}
880
881VBOXNETCFGWIN_DECL(VOID) VBoxNetCfgWinSetLogging(IN LOG_ROUTINE pfnLog)
882{
883 *((void * volatile *)&g_Logger) = pfnLog;
884}
885
886/*
887 * IP configuration API
888 */
889/* network settings config */
890/**
891 * Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
892 */
893template <class C>
894class ComStrongRef
895{
896protected:
897
898 static void addref (C *p) { p->AddRef(); }
899 static void release (C *p) { p->Release(); }
900};
901
902
903/**
904 * Base template for smart COM pointers. Not intended to be used directly.
905 */
906template <class C, template <class> class RefOps = ComStrongRef>
907class ComPtrBase : protected RefOps <C>
908{
909public:
910
911 /* special template to disable AddRef()/Release() */
912 template <class I>
913 class NoAddRefRelease : public I
914 {
915 private:
916#if !defined (VBOX_WITH_XPCOM)
917 STDMETHOD_(ULONG, AddRef)() = 0;
918 STDMETHOD_(ULONG, Release)() = 0;
919#else /* !defined (VBOX_WITH_XPCOM) */
920 NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
921 NS_IMETHOD_(nsrefcnt) Release(void) = 0;
922#endif /* !defined (VBOX_WITH_XPCOM) */
923 };
924
925protected:
926
927 ComPtrBase () : p (NULL) {}
928 ComPtrBase (const ComPtrBase &that) : p (that.p) { addref(); }
929 ComPtrBase (C *that_p) : p (that_p) { addref(); }
930
931 ~ComPtrBase() { release(); }
932
933 ComPtrBase &operator= (const ComPtrBase &that)
934 {
935 safe_assign (that.p);
936 return *this;
937 }
938
939 ComPtrBase &operator= (C *that_p)
940 {
941 safe_assign (that_p);
942 return *this;
943 }
944
945public:
946
947 void setNull()
948 {
949 release();
950 p = NULL;
951 }
952
953 bool isNull() const
954 {
955 return (p == NULL);
956 }
957
958 bool operator! () const { return isNull(); }
959
960 bool operator< (C* that_p) const { return p < that_p; }
961 bool operator== (C* that_p) const { return p == that_p; }
962
963 template <class I>
964 bool equalsTo (I *aThat) const
965 {
966 return ComPtrEquals (p, aThat);
967 }
968
969 template <class OC>
970 bool equalsTo (const ComPtrBase <OC> &oc) const
971 {
972 return equalsTo ((OC *) oc);
973 }
974
975 /** Intended to pass instances as in parameters to interface methods */
976 operator C* () const { return p; }
977
978 /**
979 * Dereferences the instance (redirects the -> operator to the managed
980 * pointer).
981 */
982 NoAddRefRelease <C> *operator-> () const
983 {
984 AssertMsg (p, ("Managed pointer must not be null\n"));
985 return (NoAddRefRelease <C> *) p;
986 }
987
988 template <class I>
989 HRESULT queryInterfaceTo (I **pp) const
990 {
991 if (pp)
992 {
993 if (p)
994 {
995 return p->QueryInterface (COM_IIDOF (I), (void **) pp);
996 }
997 else
998 {
999 *pp = NULL;
1000 return S_OK;
1001 }
1002 }
1003
1004 return E_INVALIDARG;
1005 }
1006
1007 /** Intended to pass instances as out parameters to interface methods */
1008 C **asOutParam()
1009 {
1010 setNull();
1011 return &p;
1012 }
1013
1014private:
1015
1016 void addref()
1017 {
1018 if (p)
1019 RefOps <C>::addref (p);
1020 }
1021
1022 void release()
1023 {
1024 if (p)
1025 RefOps <C>::release (p);
1026 }
1027
1028 void safe_assign (C *that_p)
1029 {
1030 /* be aware of self-assignment */
1031 if (that_p)
1032 RefOps <C>::addref (that_p);
1033 release();
1034 p = that_p;
1035 }
1036
1037 C *p;
1038};
1039
1040/**
1041 * Smart COM pointer wrapper that automatically manages refcounting of
1042 * interface pointers.
1043 *
1044 * @param I COM interface class
1045 */
1046template <class I, template <class> class RefOps = ComStrongRef>
1047class ComPtr : public ComPtrBase <I, RefOps>
1048{
1049 typedef ComPtrBase <I, RefOps> Base;
1050
1051public:
1052
1053 ComPtr () : Base() {}
1054 ComPtr (const ComPtr &that) : Base(that) {}
1055 ComPtr &operator= (const ComPtr &that)
1056 {
1057 Base::operator= (that);
1058 return *this;
1059 }
1060
1061 template <class OI>
1062 ComPtr (OI *that_p) : Base () { operator= (that_p); }
1063
1064 /* specialization for I */
1065 ComPtr (I *that_p) : Base (that_p) {}
1066
1067 template <class OC>
1068 ComPtr (const ComPtr <OC, RefOps> &oc) : Base () { operator= ((OC *) oc); }
1069
1070 template <class OI>
1071 ComPtr &operator= (OI *that_p)
1072 {
1073 if (that_p)
1074 that_p->QueryInterface (COM_IIDOF (I), (void **) Base::asOutParam());
1075 else
1076 Base::setNull();
1077 return *this;
1078 }
1079
1080 /* specialization for I */
1081 ComPtr &operator=(I *that_p)
1082 {
1083 Base::operator= (that_p);
1084 return *this;
1085 }
1086
1087 template <class OC>
1088 ComPtr &operator= (const ComPtr <OC, RefOps> &oc)
1089 {
1090 return operator= ((OC *) oc);
1091 }
1092};
1093
1094static HRESULT netIfWinFindAdapterClassById(IWbemServices * pSvc, const GUID * pGuid, IWbemClassObject **pAdapterConfig)
1095{
1096 HRESULT hr;
1097 WCHAR wszQuery[256];
1098 WCHAR wszGuid[50];
1099
1100 int length = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
1101 if (length)
1102 {
1103 swprintf(wszQuery, L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"%s\"", wszGuid);
1104 IEnumWbemClassObject* pEnumerator = NULL;
1105 hr = pSvc->ExecQuery(bstr_t("WQL"), bstr_t(wszQuery), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
1106 NULL, &pEnumerator);
1107 if (SUCCEEDED(hr))
1108 {
1109 if (pEnumerator)
1110 {
1111 IWbemClassObject *pclsObj;
1112 ULONG uReturn = 0;
1113 hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
1114 NonStandardLogFlow(("netIfWinFindAdapterClassById: IEnumWbemClassObject::Next -> hr=0x%x pclsObj=%p uReturn=%u 42=%u\n",
1115 hr, (void *)pclsObj, uReturn, 42));
1116 if (SUCCEEDED(hr))
1117 {
1118 if (uReturn && pclsObj != NULL)
1119 {
1120 *pAdapterConfig = pclsObj;
1121 pEnumerator->Release();
1122 NonStandardLogFlow(("netIfWinFindAdapterClassById: S_OK and %p\n", *pAdapterConfig));
1123 return S_OK;
1124 }
1125
1126 hr = E_FAIL;
1127 }
1128
1129 pEnumerator->Release();
1130 }
1131 else
1132 {
1133 NonStandardLogFlow(("ExecQuery returned no enumerator\n"));
1134 hr = E_FAIL;
1135 }
1136 }
1137 else
1138 NonStandardLogFlow(("ExecQuery failed (0x%x)\n", hr));
1139 }
1140 else
1141 {
1142 DWORD winEr = GetLastError();
1143 hr = HRESULT_FROM_WIN32( winEr );
1144 if (SUCCEEDED(hr))
1145 hr = E_FAIL;
1146 NonStandardLogFlow(("StringFromGUID2 failed winEr=%u, hr=0x%x\n", winEr, hr));
1147 }
1148
1149 NonStandardLogFlow(("netIfWinFindAdapterClassById: 0x%x and %p\n", hr, *pAdapterConfig));
1150 return hr;
1151}
1152
1153static HRESULT netIfWinIsHostOnly(IWbemClassObject * pAdapterConfig, BOOL * pbIsHostOnly)
1154{
1155 VARIANT vtServiceName;
1156 VariantInit(&vtServiceName);
1157
1158 HRESULT hr = pAdapterConfig->Get(L"ServiceName", 0 /*lFlags*/, &vtServiceName, NULL /*pvtType*/, NULL /*plFlavor*/);
1159 if (SUCCEEDED(hr))
1160 {
1161 *pbIsHostOnly = bstr_t(vtServiceName.bstrVal) == bstr_t("VBoxNetAdp");
1162
1163 VariantClear(&vtServiceName);
1164 }
1165
1166 return hr;
1167}
1168
1169static HRESULT netIfWinGetIpSettings(IWbemClassObject * pAdapterConfig, ULONG *pIpv4, ULONG *pMaskv4)
1170{
1171 VARIANT vtIp;
1172 HRESULT hr;
1173 VariantInit(&vtIp);
1174
1175 *pIpv4 = 0;
1176 *pMaskv4 = 0;
1177
1178 hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1179 if (SUCCEEDED(hr))
1180 {
1181 if (vtIp.vt == (VT_ARRAY | VT_BSTR))
1182 {
1183 VARIANT vtMask;
1184 VariantInit(&vtMask);
1185 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1186 if (SUCCEEDED(hr))
1187 {
1188 if (vtMask.vt == (VT_ARRAY | VT_BSTR))
1189 {
1190 SAFEARRAY * pIpArray = vtIp.parray;
1191 SAFEARRAY * pMaskArray = vtMask.parray;
1192 if (pIpArray && pMaskArray)
1193 {
1194 BSTR pCurIp;
1195 BSTR pCurMask;
1196 for (LONG i = 0;
1197 SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
1198 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
1199 i++)
1200 {
1201 bstr_t ip(pCurIp);
1202
1203 ULONG Ipv4 = inet_addr((char*)(ip));
1204 if (Ipv4 != INADDR_NONE)
1205 {
1206 *pIpv4 = Ipv4;
1207 bstr_t mask(pCurMask);
1208 *pMaskv4 = inet_addr((char*)(mask));
1209 break;
1210 }
1211 }
1212 }
1213 }
1214 else
1215 {
1216 *pIpv4 = 0;
1217 *pMaskv4 = 0;
1218 }
1219
1220 VariantClear(&vtMask);
1221 }
1222 }
1223 else
1224 {
1225 *pIpv4 = 0;
1226 *pMaskv4 = 0;
1227 }
1228
1229 VariantClear(&vtIp);
1230 }
1231
1232 return hr;
1233}
1234
1235#if 0 /* unused */
1236
1237static HRESULT netIfWinHasIpSettings(IWbemClassObject * pAdapterConfig, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, bool *pFound)
1238{
1239 VARIANT vtIp;
1240 HRESULT hr;
1241 VariantInit(&vtIp);
1242
1243 *pFound = false;
1244
1245 hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1246 if (SUCCEEDED(hr))
1247 {
1248 VARIANT vtMask;
1249 VariantInit(&vtMask);
1250 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1251 if (SUCCEEDED(hr))
1252 {
1253 SAFEARRAY * pIpArray = vtIp.parray;
1254 SAFEARRAY * pMaskArray = vtMask.parray;
1255 if (pIpArray && pMaskArray)
1256 {
1257 BSTR pIp, pMask;
1258 for (LONG k = 0;
1259 SafeArrayGetElement(pCheckIp, &k, (PVOID)&pIp) == S_OK
1260 && SafeArrayGetElement(pCheckMask, &k, (PVOID)&pMask) == S_OK;
1261 k++)
1262 {
1263 BSTR pCurIp;
1264 BSTR pCurMask;
1265 for (LONG i = 0;
1266 SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
1267 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
1268 i++)
1269 {
1270 if (!wcsicmp(pCurIp, pIp))
1271 {
1272 if (!wcsicmp(pCurMask, pMask))
1273 *pFound = true;
1274 break;
1275 }
1276 }
1277 }
1278 }
1279
1280
1281 VariantClear(&vtMask);
1282 }
1283
1284 VariantClear(&vtIp);
1285 }
1286
1287 return hr;
1288}
1289
1290static HRESULT netIfWinWaitIpSettings(IWbemServices *pSvc, const GUID * pGuid, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, ULONG sec2Wait, bool *pFound)
1291{
1292 /* on Vista we need to wait for the address to get applied */
1293 /* wait for the address to appear in the list */
1294 HRESULT hr = S_OK;
1295 ULONG i;
1296 *pFound = false;
1297 ComPtr <IWbemClassObject> pAdapterConfig;
1298 for (i = 0;
1299 (hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam())) == S_OK
1300 && (hr = netIfWinHasIpSettings(pAdapterConfig, pCheckIp, pCheckMask, pFound)) == S_OK
1301 && !(*pFound)
1302 && i < sec2Wait/6;
1303 i++)
1304 {
1305 Sleep(6000);
1306 }
1307
1308 return hr;
1309}
1310
1311#endif /* unused */
1312
1313static HRESULT netIfWinCreateIWbemServices(IWbemServices ** ppSvc)
1314{
1315 IWbemLocator *pLoc = NULL;
1316 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
1317 if (SUCCEEDED(hr))
1318 {
1319 IWbemServices *pSvc = NULL;
1320 hr = pLoc->ConnectServer(bstr_t(L"ROOT\\CIMV2"), /* [in] const BSTR strNetworkResource */
1321 NULL, /* [in] const BSTR strUser */
1322 NULL, /* [in] const BSTR strPassword */
1323 0, /* [in] const BSTR strLocale */
1324 NULL, /* [in] LONG lSecurityFlags */
1325 0, /* [in] const BSTR strAuthority */
1326 0, /* [in] IWbemContext* pCtx */
1327 &pSvc /* [out] IWbemServices** ppNamespace */);
1328 if (SUCCEEDED(hr))
1329 {
1330 hr = CoSetProxyBlanket(pSvc, /* IUnknown * pProxy */
1331 RPC_C_AUTHN_WINNT, /* DWORD dwAuthnSvc */
1332 RPC_C_AUTHZ_NONE, /* DWORD dwAuthzSvc */
1333 NULL, /* WCHAR * pServerPrincName */
1334 RPC_C_AUTHN_LEVEL_CALL, /* DWORD dwAuthnLevel */
1335 RPC_C_IMP_LEVEL_IMPERSONATE, /* DWORD dwImpLevel */
1336 NULL, /* RPC_AUTH_IDENTITY_HANDLE pAuthInfo */
1337 EOAC_NONE /* DWORD dwCapabilities */
1338 );
1339 if (SUCCEEDED(hr))
1340 {
1341 *ppSvc = pSvc;
1342 /* do not need it any more */
1343 pLoc->Release();
1344 return hr;
1345 }
1346 else
1347 NonStandardLogFlow(("CoSetProxyBlanket failed, hr (0x%x)\n", hr));
1348
1349 pSvc->Release();
1350 }
1351 else
1352 NonStandardLogFlow(("ConnectServer failed, hr (0x%x)\n", hr));
1353 pLoc->Release();
1354 }
1355 else
1356 NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\n", hr));
1357 return hr;
1358}
1359
1360static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, BSTR * pStr)
1361{
1362 VARIANT index;
1363 HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
1364 if (SUCCEEDED(hr))
1365 {
1366 WCHAR strIndex[8];
1367 swprintf(strIndex, L"%u", index.uintVal);
1368 *pStr = (bstr_t(L"Win32_NetworkAdapterConfiguration.Index='") + strIndex + "'").copy();
1369 }
1370 else
1371 NonStandardLogFlow(("Get failed, hr (0x%x)\n", hr));
1372 return hr;
1373}
1374
1375static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, BSTR ObjPath,
1376 BSTR MethodName, LPWSTR *pArgNames, LPVARIANT *pArgs, UINT cArgs,
1377 IWbemClassObject** ppOutParams
1378 )
1379{
1380 HRESULT hr = S_OK;
1381 ComPtr<IWbemClassObject> pInParamsDefinition;
1382 ComPtr<IWbemClassObject> pClassInstance;
1383
1384 if (cArgs)
1385 {
1386 hr = pClass->GetMethod(MethodName, 0, pInParamsDefinition.asOutParam(), NULL);
1387 if (SUCCEEDED(hr))
1388 {
1389 hr = pInParamsDefinition->SpawnInstance(0, pClassInstance.asOutParam());
1390 if (SUCCEEDED(hr))
1391 {
1392 for (UINT i = 0; i < cArgs; i++)
1393 {
1394 hr = pClassInstance->Put(pArgNames[i], 0,
1395 pArgs[i], 0);
1396 if (FAILED(hr))
1397 break;
1398 }
1399 }
1400 }
1401 }
1402
1403 if (SUCCEEDED(hr))
1404 {
1405 IWbemClassObject* pOutParams = NULL;
1406 hr = pSvc->ExecMethod(ObjPath, MethodName, 0, NULL, pClassInstance, &pOutParams, NULL);
1407 if (SUCCEEDED(hr))
1408 {
1409 *ppOutParams = pOutParams;
1410 }
1411 }
1412
1413 return hr;
1414}
1415
1416static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr* aIp, UINT cIp)
1417{
1418 HRESULT hr = S_OK; /* MSC maybe used uninitialized */
1419 SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIp);
1420 if (pIpArray)
1421 {
1422 for (UINT i = 0; i < cIp; i++)
1423 {
1424 char* addr = inet_ntoa(aIp[i]);
1425 BSTR val = bstr_t(addr).copy();
1426 long aIndex[1];
1427 aIndex[0] = i;
1428 hr = SafeArrayPutElement(pIpArray, aIndex, val);
1429 if (FAILED(hr))
1430 {
1431 SysFreeString(val);
1432 SafeArrayDestroy(pIpArray);
1433 break;
1434 }
1435 }
1436
1437 if (SUCCEEDED(hr))
1438 {
1439 *ppArray = pIpArray;
1440 }
1441 }
1442 else
1443 hr = HRESULT_FROM_WIN32(GetLastError());
1444
1445 return hr;
1446}
1447
1448#if 0 /* unused */
1449static HRESULT netIfWinCreateIpArrayV4V6(SAFEARRAY **ppArray, BSTR Ip)
1450{
1451 HRESULT hr;
1452 SAFEARRAY *pIpArray = SafeArrayCreateVector(VT_BSTR, 0, 1);
1453 if (pIpArray)
1454 {
1455 BSTR val = bstr_t(Ip, false).copy();
1456 long aIndex[1];
1457 aIndex[0] = 0;
1458 hr = SafeArrayPutElement(pIpArray, aIndex, val);
1459 if (FAILED(hr))
1460 {
1461 SysFreeString(val);
1462 SafeArrayDestroy(pIpArray);
1463 }
1464
1465 if (SUCCEEDED(hr))
1466 {
1467 *ppArray = pIpArray;
1468 }
1469 }
1470 else
1471 hr = HRESULT_FROM_WIN32(GetLastError());
1472
1473 return hr;
1474}
1475#endif
1476
1477
1478static HRESULT netIfWinCreateIpArrayVariantV4(VARIANT * pIpAddresses, in_addr* aIp, UINT cIp)
1479{
1480 HRESULT hr;
1481 VariantInit(pIpAddresses);
1482 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1483 SAFEARRAY *pIpArray;
1484 hr = netIfWinCreateIpArray(&pIpArray, aIp, cIp);
1485 if (SUCCEEDED(hr))
1486 {
1487 pIpAddresses->parray = pIpArray;
1488 }
1489 return hr;
1490}
1491
1492#if 0 /* unused */
1493static HRESULT netIfWinCreateIpArrayVariantV4V6(VARIANT * pIpAddresses, BSTR Ip)
1494{
1495 HRESULT hr;
1496 VariantInit(pIpAddresses);
1497 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1498 SAFEARRAY *pIpArray;
1499 hr = netIfWinCreateIpArrayV4V6(&pIpArray, Ip);
1500 if (SUCCEEDED(hr))
1501 {
1502 pIpAddresses->parray = pIpArray;
1503 }
1504 return hr;
1505}
1506#endif
1507
1508static HRESULT netIfWinEnableStatic(IWbemServices *pSvc, const GUID *pGuid, BSTR ObjPath, VARIANT *pIp, VARIANT *pMask)
1509{
1510 ComPtr<IWbemClassObject> pClass;
1511 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1512 HRESULT hr;
1513 if (ClassName)
1514 {
1515 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1516 if (SUCCEEDED(hr))
1517 {
1518 LPWSTR argNames[] = {L"IPAddress", L"SubnetMask"};
1519 LPVARIANT args[] = {pIp, pMask};
1520 ComPtr<IWbemClassObject> pOutParams;
1521
1522 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableStatic"), argNames, args, 2, pOutParams.asOutParam());
1523 if (SUCCEEDED(hr))
1524 {
1525 VARIANT varReturnValue;
1526 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
1527 &varReturnValue, NULL, 0);
1528 Assert(SUCCEEDED(hr));
1529 if (SUCCEEDED(hr))
1530 {
1531// Assert(varReturnValue.vt == VT_UINT);
1532 int winEr = varReturnValue.uintVal;
1533 switch (winEr)
1534 {
1535 case 0:
1536 {
1537 hr = S_OK;
1538// bool bFound;
1539// HRESULT tmpHr = netIfWinWaitIpSettings(pSvc, pGuid, pIp->parray, pMask->parray, 180, &bFound);
1540 NOREF(pGuid);
1541 break;
1542 }
1543 default:
1544 hr = HRESULT_FROM_WIN32( winEr );
1545 break;
1546 }
1547 }
1548 }
1549 }
1550 SysFreeString(ClassName);
1551 }
1552 else
1553 hr = HRESULT_FROM_WIN32(GetLastError());
1554
1555 return hr;
1556}
1557
1558
1559static HRESULT netIfWinEnableStaticV4(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, in_addr* aIp, in_addr * aMask, UINT cIp)
1560{
1561 VARIANT ipAddresses;
1562 HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, aIp, cIp);
1563 if (SUCCEEDED(hr))
1564 {
1565 VARIANT ipMasks;
1566 hr = netIfWinCreateIpArrayVariantV4(&ipMasks, aMask, cIp);
1567 if (SUCCEEDED(hr))
1568 {
1569 hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
1570 VariantClear(&ipMasks);
1571 }
1572 VariantClear(&ipAddresses);
1573 }
1574 return hr;
1575}
1576
1577#if 0 /* unused */
1578
1579static HRESULT netIfWinEnableStaticV4V6(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, BSTR Ip, BSTR Mask)
1580{
1581 VARIANT ipAddresses;
1582 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&ipAddresses, Ip);
1583 if (SUCCEEDED(hr))
1584 {
1585 VARIANT ipMasks;
1586 hr = netIfWinCreateIpArrayVariantV4V6(&ipMasks, Mask);
1587 if (SUCCEEDED(hr))
1588 {
1589 hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
1590 VariantClear(&ipMasks);
1591 }
1592 VariantClear(&ipAddresses);
1593 }
1594 return hr;
1595}
1596
1597/* win API allows to set gw metrics as well, we are not setting them */
1598static HRESULT netIfWinSetGateways(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pGw)
1599{
1600 ComPtr<IWbemClassObject> pClass;
1601 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1602 HRESULT hr;
1603 if (ClassName)
1604 {
1605 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1606 if (SUCCEEDED(hr))
1607 {
1608 LPWSTR argNames[] = {L"DefaultIPGateway"};
1609 LPVARIANT args[] = {pGw};
1610 ComPtr<IWbemClassObject> pOutParams;
1611
1612 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
1613 if (SUCCEEDED(hr))
1614 {
1615 VARIANT varReturnValue;
1616 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1617 Assert(SUCCEEDED(hr));
1618 if (SUCCEEDED(hr))
1619 {
1620// Assert(varReturnValue.vt == VT_UINT);
1621 int winEr = varReturnValue.uintVal;
1622 switch (winEr)
1623 {
1624 case 0:
1625 hr = S_OK;
1626 break;
1627 default:
1628 hr = HRESULT_FROM_WIN32( winEr );
1629 break;
1630 }
1631 }
1632 }
1633 }
1634 SysFreeString(ClassName);
1635 }
1636 else
1637 hr = HRESULT_FROM_WIN32(GetLastError());
1638
1639 return hr;
1640}
1641
1642/* win API allows to set gw metrics as well, we are not setting them */
1643static HRESULT netIfWinSetGatewaysV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aGw, UINT cGw)
1644{
1645 VARIANT gwais;
1646 HRESULT hr = netIfWinCreateIpArrayVariantV4(&gwais, aGw, cGw);
1647 if (SUCCEEDED(hr))
1648 {
1649 netIfWinSetGateways(pSvc, ObjPath, &gwais);
1650 VariantClear(&gwais);
1651 }
1652 return hr;
1653}
1654
1655/* win API allows to set gw metrics as well, we are not setting them */
1656static HRESULT netIfWinSetGatewaysV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Gw)
1657{
1658 VARIANT vGw;
1659 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&vGw, Gw);
1660 if (SUCCEEDED(hr))
1661 {
1662 netIfWinSetGateways(pSvc, ObjPath, &vGw);
1663 VariantClear(&vGw);
1664 }
1665 return hr;
1666}
1667
1668#endif /* unused */
1669
1670static HRESULT netIfWinEnableDHCP(IWbemServices * pSvc, BSTR ObjPath)
1671{
1672 ComPtr<IWbemClassObject> pClass;
1673 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1674 HRESULT hr;
1675 if (ClassName)
1676 {
1677 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1678 if (SUCCEEDED(hr))
1679 {
1680 ComPtr<IWbemClassObject> pOutParams;
1681
1682 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableDHCP"), NULL, NULL, 0, pOutParams.asOutParam());
1683 if (SUCCEEDED(hr))
1684 {
1685 VARIANT varReturnValue;
1686 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
1687 &varReturnValue, NULL, 0);
1688 Assert(SUCCEEDED(hr));
1689 if (SUCCEEDED(hr))
1690 {
1691// Assert(varReturnValue.vt == VT_UINT);
1692 int winEr = varReturnValue.uintVal;
1693 switch (winEr)
1694 {
1695 case 0:
1696 hr = S_OK;
1697 break;
1698 default:
1699 hr = HRESULT_FROM_WIN32( winEr );
1700 break;
1701 }
1702 }
1703 }
1704 }
1705 SysFreeString(ClassName);
1706 }
1707 else
1708 hr = HRESULT_FROM_WIN32(GetLastError());
1709
1710 return hr;
1711}
1712
1713static HRESULT netIfWinDhcpRediscover(IWbemServices * pSvc, BSTR ObjPath)
1714{
1715 ComPtr<IWbemClassObject> pClass;
1716 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1717 HRESULT hr;
1718 if (ClassName)
1719 {
1720 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1721 if (SUCCEEDED(hr))
1722 {
1723 ComPtr<IWbemClassObject> pOutParams;
1724
1725 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"ReleaseDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
1726 if (SUCCEEDED(hr))
1727 {
1728 VARIANT varReturnValue;
1729 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1730 Assert(SUCCEEDED(hr));
1731 if (SUCCEEDED(hr))
1732 {
1733// Assert(varReturnValue.vt == VT_UINT);
1734 int winEr = varReturnValue.uintVal;
1735 if (winEr == 0)
1736 {
1737 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"RenewDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
1738 if (SUCCEEDED(hr))
1739 {
1740 VARIANT varReturnValue;
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 int 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 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(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
2953static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile, IN BSTR bstrDesiredName,
2954 OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
2955{
2956 HRESULT hrc = S_OK;
2957
2958 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2959 SP_DEVINFO_DATA DeviceInfoData;
2960 PVOID pQueueCallbackContext = NULL;
2961 DWORD ret = 0;
2962 BOOL registered = FALSE;
2963 BOOL destroyList = FALSE;
2964 WCHAR pWCfgGuidString [50];
2965 WCHAR DevName[256];
2966 HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
2967 bstr_t bstrError;
2968
2969 do
2970 {
2971 BOOL found = FALSE;
2972 GUID netGuid;
2973 SP_DRVINFO_DATA DriverInfoData;
2974 SP_DEVINSTALL_PARAMS DeviceInstallParams;
2975 TCHAR className [MAX_PATH];
2976 DWORD index = 0;
2977 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
2978 /* for our purposes, 2k buffer is more
2979 * than enough to obtain the hardware ID
2980 * of the VBoxNetAdp driver. */
2981 DWORD detailBuf [2048];
2982
2983 DWORD cbSize;
2984 DWORD dwValueType;
2985
2986 /* initialize the structure size */
2987 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2988 DriverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
2989
2990 /* copy the net class GUID */
2991 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2992
2993 /* create an empty device info set associated with the net class GUID */
2994 hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
2995 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2996 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
2997 GetLastError()));
2998
2999 /* get the class name from GUID */
3000 BOOL fResult = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
3001 if (!fResult)
3002 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
3003 GetLastError()));
3004
3005 /* create a device info element and add the new device instance
3006 * key to registry */
3007 fResult = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
3008 DICD_GENERATE_ID, &DeviceInfoData);
3009 if (!fResult)
3010 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
3011 GetLastError()));
3012
3013 /* select the newly created device info to be the currently
3014 selected member */
3015 fResult = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
3016 if (!fResult)
3017 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
3018 GetLastError()));
3019
3020 if (pInfPath)
3021 {
3022 /* get the device install parameters and disable filecopy */
3023 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3024 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3025 &DeviceInstallParams);
3026 if (fResult)
3027 {
3028 memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
3029 size_t pathLenght = wcslen(pInfPath) + 1/* null terminator */;
3030 if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
3031 {
3032 memcpy(DeviceInstallParams.DriverPath, pInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
3033
3034 if (bIsInfPathFile)
3035 {
3036 DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
3037 }
3038
3039 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
3040 &DeviceInstallParams);
3041 if (!fResult)
3042 {
3043 DWORD winEr = GetLastError();
3044 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
3045 break;
3046 }
3047 }
3048 else
3049 {
3050 NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
3051 break;
3052 }
3053 }
3054 else
3055 {
3056 DWORD winEr = GetLastError();
3057 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
3058 }
3059 }
3060
3061 /* build a list of class drivers */
3062 fResult = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
3063 SPDIT_CLASSDRIVER);
3064 if (!fResult)
3065 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
3066 GetLastError()));
3067
3068 destroyList = TRUE;
3069
3070 /* enumerate the driver info list */
3071 while (TRUE)
3072 {
3073 BOOL ret;
3074
3075 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
3076 SPDIT_CLASSDRIVER, index, &DriverInfoData);
3077
3078 /* if the function failed and GetLastError() returned
3079 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
3080 * list. Otherwise there was something wrong with this
3081 * particular driver. */
3082 if (!ret)
3083 {
3084 if (GetLastError() == ERROR_NO_MORE_ITEMS)
3085 break;
3086 else
3087 {
3088 index++;
3089 continue;
3090 }
3091 }
3092
3093 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
3094 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
3095
3096 /* if we successfully find the hardware ID and it turns out to
3097 * be the one for the loopback driver, then we are done. */
3098 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
3099 &DeviceInfoData,
3100 &DriverInfoData,
3101 pDriverInfoDetail,
3102 sizeof (detailBuf),
3103 NULL))
3104 {
3105 TCHAR * t;
3106
3107 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
3108 * whole list and see if there is a match somewhere. */
3109 t = pDriverInfoDetail->HardwareID;
3110 while (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
3111 {
3112 if (!_tcsicmp(t, DRIVERHWID))
3113 break;
3114
3115 t += _tcslen(t) + 1;
3116 }
3117
3118 if (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
3119 {
3120 found = TRUE;
3121 break;
3122 }
3123 }
3124
3125 index ++;
3126 }
3127
3128 if (!found)
3129 SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
3130
3131 /* set the loopback driver to be the currently selected */
3132 fResult = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
3133 &DriverInfoData);
3134 if (!fResult)
3135 SetErrBreak(("SetupDiSetSelectedDriver failed (0x%08X)",
3136 GetLastError()));
3137
3138 /* register the phantom device to prepare for install */
3139 fResult = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
3140 &DeviceInfoData);
3141 if (!fResult)
3142 {
3143 DWORD err = GetLastError();
3144 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
3145 err));
3146 }
3147
3148 /* registered, but remove if errors occur in the following code */
3149 registered = TRUE;
3150
3151 /* ask the installer if we can install the device */
3152 fResult = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
3153 &DeviceInfoData);
3154 if (!fResult)
3155 {
3156 if (GetLastError() != ERROR_DI_DO_DEFAULT)
3157 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
3158 GetLastError()));
3159 /* that's fine */
3160 }
3161
3162 /* get the device install parameters and disable filecopy */
3163 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3164 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3165 &DeviceInstallParams);
3166 if (fResult)
3167 {
3168 pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
3169 if (pQueueCallbackContext)
3170 {
3171 DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
3172 DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
3173 fResult = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3174 &DeviceInstallParams);
3175 if (!fResult)
3176 {
3177 DWORD winEr = GetLastError();
3178 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
3179 }
3180 Assert(fResult);
3181 }
3182 else
3183 {
3184 DWORD winEr = GetLastError();
3185 NonStandardLogFlow(("SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr));
3186 }
3187 }
3188 else
3189 {
3190 DWORD winEr = GetLastError();
3191 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
3192 }
3193
3194 /* install the files first */
3195 fResult = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
3196 &DeviceInfoData);
3197 if (!fResult)
3198 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
3199 GetLastError()));
3200 /* get the device install parameters and disable filecopy */
3201 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3202 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3203 &DeviceInstallParams);
3204 if (fResult)
3205 {
3206 DeviceInstallParams.Flags |= DI_NOFILECOPY;
3207 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
3208 &DeviceInstallParams);
3209 if (!fResult)
3210 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
3211 GetLastError()));
3212 }
3213
3214 /*
3215 * Register any device-specific co-installers for this device,
3216 */
3217 fResult = SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
3218 hDeviceInfo,
3219 &DeviceInfoData);
3220 if (!fResult)
3221 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
3222 GetLastError()));
3223
3224 /*
3225 * install any installer-specified interfaces.
3226 * and then do the real install
3227 */
3228 fResult = SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
3229 hDeviceInfo,
3230 &DeviceInfoData);
3231 if (!fResult)
3232 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
3233 GetLastError()));
3234
3235 fResult = SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
3236 hDeviceInfo,
3237 &DeviceInfoData);
3238 if (!fResult)
3239 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
3240 GetLastError()));
3241
3242 /* Query the instance ID; on Windows 10, the registry key may take a short
3243 * while to appear. Microsoft recommends waiting for up to 5 seconds, but
3244 * we want to be on the safe side, so let's wait for 20 seconds. Waiting
3245 * longer is harmful as network setup service will shut down after a period
3246 * of inactivity.
3247 */
3248 for (int retries = 0; retries < 2 * 20; ++retries)
3249 {
3250 Sleep(500); /* half second */
3251
3252 /* Figure out NetCfgInstanceId */
3253 hkey = SetupDiOpenDevRegKey(hDeviceInfo,
3254 &DeviceInfoData,
3255 DICS_FLAG_GLOBAL,
3256 0,
3257 DIREG_DRV,
3258 KEY_READ);
3259 if (hkey == INVALID_HANDLE_VALUE)
3260 break;
3261
3262 cbSize = sizeof(pWCfgGuidString);
3263 ret = RegQueryValueExW (hkey, L"NetCfgInstanceId", NULL,
3264 &dwValueType, (LPBYTE) pWCfgGuidString, &cbSize);
3265 /* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
3266 if (ret != ERROR_FILE_NOT_FOUND)
3267 break;
3268
3269 RegCloseKey (hkey);
3270 hkey = (HKEY)INVALID_HANDLE_VALUE;
3271 }
3272
3273 if (ret == ERROR_FILE_NOT_FOUND)
3274 {
3275 hrc = E_ABORT;
3276 break;
3277 }
3278
3279 /*
3280 * We need to check 'hkey' after we check 'ret' to distinguish the case
3281 * of failed SetupDiOpenDevRegKey from the case when we timed out.
3282 */
3283 if (hkey == INVALID_HANDLE_VALUE)
3284 SetErrBreak(("SetupDiOpenDevRegKey failed (0x%08X)", GetLastError()));
3285
3286 if (ret != ERROR_SUCCESS)
3287 SetErrBreak(("Querying NetCfgInstanceId failed (0x%08X)", ret));
3288
3289 NET_LUID luid;
3290 HRESULT hSMRes = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
3291
3292 /* Close the key as soon as possible. See @bugref{7973}. */
3293 RegCloseKey (hkey);
3294 hkey = (HKEY)INVALID_HANDLE_VALUE;
3295
3296 if (FAILED(hSMRes))
3297 {
3298 /*
3299 * The setting of Metric is not very important functionality,
3300 * So we will not break installation process due to this error.
3301 */
3302 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface Warning! "
3303 "vboxNetCfgWinGetInterfaceLUID failed, default metric "
3304 "for new interface will not be set, hr (0x%x)\n", hSMRes));
3305 }
3306 else
3307 {
3308 /*
3309 * Set default metric value of interface to fix multicast issue
3310 * See @bugref{6379} for details.
3311 */
3312 hSMRes = vboxNetCfgWinSetupMetric(&luid);
3313 if (FAILED(hSMRes))
3314 {
3315 /*
3316 * The setting of Metric is not very important functionality,
3317 * So we will not break installation process due to this error.
3318 */
3319 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface Warning! "
3320 "vboxNetCfgWinSetupMetric failed, default metric "
3321 "for new interface will not be set, hr (0x%x)\n", hSMRes));
3322 }
3323 }
3324
3325
3326#ifndef VBOXNETCFG_DELAYEDRENAME
3327 /*
3328 * We need to query the device name after we have succeeded in querying its
3329 * instance ID to avoid similar waiting-and-retrying loop (see @bugref{7973}).
3330 */
3331 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3332 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
3333 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3334 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
3335 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
3336 NULL /*OUT PDWORD RequiredSize OPTIONAL*/))
3337 {
3338 int err = GetLastError();
3339 if (err != ERROR_INVALID_DATA)
3340 {
3341 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
3342 err));
3343 }
3344
3345 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3346 SPDRP_DEVICEDESC, /* IN DWORD Property,*/
3347 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3348 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
3349 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
3350 NULL /*OUT PDWORD RequiredSize OPTIONAL*/
3351 ))
3352 {
3353 err = GetLastError();
3354 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
3355 err));
3356 }
3357 }
3358#else /* !VBOXNETCFG_DELAYEDRENAME */
3359 /* Re-use DevName for device instance id retrieval. */
3360 if (!SetupDiGetDeviceInstanceId(hDeviceInfo, &DeviceInfoData, DevName, RT_ELEMENTS(DevName), &cbSize))
3361 SetErrBreak (("SetupDiGetDeviceInstanceId failed (0x%08X)",
3362 GetLastError()));
3363#endif /* !VBOXNETCFG_DELAYEDRENAME */
3364 }
3365 while (0);
3366
3367 /*
3368 * cleanup
3369 */
3370 if (hkey != INVALID_HANDLE_VALUE)
3371 RegCloseKey (hkey);
3372
3373 if (pQueueCallbackContext)
3374 SetupTermDefaultQueueCallback(pQueueCallbackContext);
3375
3376 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3377 {
3378 /* an error has occurred, but the device is registered, we must remove it */
3379 if (ret != 0 && registered)
3380 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
3381
3382 SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
3383
3384 /* destroy the driver info list */
3385 if (destroyList)
3386 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData,
3387 SPDIT_CLASSDRIVER);
3388 /* clean up the device info set */
3389 SetupDiDestroyDeviceInfoList (hDeviceInfo);
3390 }
3391
3392 /* return the network connection GUID on success */
3393 if (SUCCEEDED(hrc))
3394 {
3395 HRESULT hr;
3396 INetCfg *pNetCfg = NULL;
3397 LPWSTR lpszApp = NULL;
3398
3399 RENAMING_CONTEXT context;
3400 context.hr = E_FAIL;
3401
3402 if (pGuid)
3403 {
3404 hrc = CLSIDFromString(pWCfgGuidString, (LPCLSID)pGuid);
3405 if (FAILED(hrc))
3406 NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
3407 }
3408
3409 hr = VBoxNetCfgWinQueryINetCfg(&pNetCfg, TRUE, L"VirtualBox Host-Only Creation",
3410 30 * 1000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec. */
3411 /** @todo special handling for 6to4svc.dll ???, i.e. several retrieves */
3412 &lpszApp);
3413 if (hr == S_OK)
3414 {
3415 if (SysStringLen(bstrDesiredName) != 0)
3416 {
3417 /* Rename only if the desired name has been provided */
3418 context.bstrName = bstrDesiredName;
3419 context.pGuid = pGuid;
3420 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3421 &GUID_DEVCLASS_NET,
3422 vboxNetCfgWinRenameHostOnlyNetworkInterface,
3423 &context);
3424 }
3425 if (SUCCEEDED(hr))
3426 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3427 &GUID_DEVCLASS_NETSERVICE,
3428 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3429 pGuid);
3430 if (SUCCEEDED(hr))
3431 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3432 &GUID_DEVCLASS_NETTRANS,
3433 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3434 pGuid);
3435 if (SUCCEEDED(hr))
3436 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3437 &GUID_DEVCLASS_NETCLIENT,
3438 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3439 pGuid);
3440 if (SUCCEEDED(hr))
3441 {
3442 hr = pNetCfg->Apply();
3443 }
3444 else
3445 NonStandardLogFlow(("Enumeration failed, hr 0x%x\n", hr));
3446 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
3447 }
3448 else if (hr == NETCFG_E_NO_WRITE_LOCK && lpszApp)
3449 {
3450 NonStandardLogFlow(("Application %ws is holding the lock, failed\n", lpszApp));
3451 CoTaskMemFree(lpszApp);
3452 }
3453 else
3454 NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hr 0x%x\n", hr));
3455
3456#ifndef VBOXNETCFG_DELAYEDRENAME
3457 if (SUCCEEDED(hr) && SUCCEEDED(context.hr))
3458 {
3459 /* The device has been successfully renamed, replace the name now. */
3460 wcscpy_s(DevName, RT_ELEMENTS(DevName), bstrDesiredName);
3461 }
3462
3463 WCHAR ConnectionName[128];
3464 ULONG cbName = sizeof(ConnectionName);
3465
3466 hr = VBoxNetCfgWinGenHostonlyConnectionName(DevName, ConnectionName, &cbName);
3467 if (SUCCEEDED(hr))
3468 hr = VBoxNetCfgWinRenameConnection(pWCfgGuidString, ConnectionName);
3469#endif
3470 if (lppszName)
3471 {
3472 *lppszName = SysAllocString((const OLECHAR *) DevName);
3473 if (!*lppszName)
3474 {
3475 NonStandardLogFlow(("SysAllocString failed\n"));
3476 hrc = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3477 }
3478 }
3479 }
3480
3481 if (pErrMsg && bstrError.length())
3482 *pErrMsg = bstrError.Detach();
3483
3484 return hrc;
3485}
3486
3487VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile, IN BSTR pwsDesiredName,
3488 OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
3489{
3490 HRESULT hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pwsDesiredName, pGuid, lppszName, pErrMsg);
3491 if (hrc == E_ABORT)
3492 {
3493 NonStandardLogFlow(("Timed out while waiting for NetCfgInstanceId, try again immediately...\n"));
3494 /*
3495 * This is the first time we fail to obtain NetCfgInstanceId, let us
3496 * retry it once. It is needed to handle the situation when network
3497 * setup fails to recognize the arrival of our device node while it
3498 * is busy removing another host-only interface, and it gets stuck
3499 * with no matching network interface created for our device node.
3500 * See @bugref{7973} for details.
3501 */
3502 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pwsDesiredName, pGuid, lppszName, pErrMsg);
3503 if (hrc == E_ABORT)
3504 {
3505 NonStandardLogFlow(("Timed out again while waiting for NetCfgInstanceId, try again after a while...\n"));
3506 /*
3507 * This is the second time we fail to obtain NetCfgInstanceId, let us
3508 * retry it once more. This time we wait to network setup service
3509 * to go down before retrying. Hopefully it will resolve all error
3510 * conditions. See @bugref{7973} for details.
3511 */
3512
3513 SC_HANDLE hSCM = NULL;
3514 SC_HANDLE hService = NULL;
3515
3516 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
3517 if (hSCM)
3518 {
3519 hService = OpenService(hSCM, _T("NetSetupSvc"), GENERIC_READ);
3520 if (hService)
3521 {
3522 for (int retries = 0; retries < 60 && !vboxNetCfgWinIsNetSetupStopped(hService); ++retries)
3523 Sleep(1000);
3524 CloseServiceHandle(hService);
3525 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pwsDesiredName, pGuid, lppszName, pErrMsg);
3526 }
3527 else
3528 NonStandardLogFlow(("OpenService failed (0x%x)\n", GetLastError()));
3529 CloseServiceHandle(hSCM);
3530 }
3531 else
3532 NonStandardLogFlow(("OpenSCManager failed (0x%x)", GetLastError()));
3533 /* Give up and report the error. */
3534 if (hrc == E_ABORT)
3535 {
3536 if (pErrMsg)
3537 {
3538 bstr_t bstrError = bstr_printf("Querying NetCfgInstanceId failed (0x%08X)", ERROR_FILE_NOT_FOUND);
3539 *pErrMsg = bstrError.Detach();
3540 }
3541 hrc = E_FAIL;
3542 }
3543 }
3544 }
3545 return hrc;
3546}
3547
3548
3549HRESULT vboxLoadIpHelpFunctions(HINSTANCE& pIpHlpInstance)
3550{
3551 Assert(pIpHlpInstance != NULL);
3552
3553 pIpHlpInstance = loadSystemDll("Iphlpapi.dll");
3554 if (pIpHlpInstance == NULL)
3555 return E_FAIL;
3556
3557 g_pfnInitializeIpInterfaceEntry =
3558 (PFNINITIALIZEIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "InitializeIpInterfaceEntry");
3559 Assert(g_pfnInitializeIpInterfaceEntry);
3560
3561 if (g_pfnInitializeIpInterfaceEntry)
3562 {
3563 g_pfnGetIpInterfaceEntry =
3564 (PFNGETIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "GetIpInterfaceEntry");
3565 Assert(g_pfnGetIpInterfaceEntry);
3566 }
3567
3568 if (g_pfnGetIpInterfaceEntry)
3569 {
3570 g_pfnSetIpInterfaceEntry =
3571 (PFNSETIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "SetIpInterfaceEntry");
3572 Assert(g_pfnSetIpInterfaceEntry);
3573 }
3574
3575 if (g_pfnInitializeIpInterfaceEntry == NULL)
3576 {
3577 FreeLibrary(pIpHlpInstance);
3578 pIpHlpInstance = NULL;
3579 return E_FAIL;
3580 }
3581
3582 return S_OK;
3583}
3584
3585
3586HRESULT vboxNetCfgWinGetLoopbackMetric(OUT int* Metric)
3587{
3588 HRESULT rc = S_OK;
3589 MIB_IPINTERFACE_ROW row;
3590
3591 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3592 Assert(g_pfnGetIpInterfaceEntry != NULL);
3593
3594 g_pfnInitializeIpInterfaceEntry(&row);
3595 row.Family = AF_INET;
3596 row.InterfaceLuid.Info.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
3597
3598 rc = g_pfnGetIpInterfaceEntry(&row);
3599 if (rc != NO_ERROR)
3600 return HRESULT_FROM_WIN32(rc);
3601
3602 *Metric = row.Metric;
3603
3604 return rc;
3605}
3606
3607
3608HRESULT vboxNetCfgWinSetInterfaceMetric(
3609 IN NET_LUID* pInterfaceLuid,
3610 IN DWORD metric)
3611{
3612 MIB_IPINTERFACE_ROW newRow;
3613
3614 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3615 Assert(g_pfnSetIpInterfaceEntry != NULL);
3616
3617 g_pfnInitializeIpInterfaceEntry(&newRow);
3618 // identificate the interface to change
3619 newRow.InterfaceLuid = *pInterfaceLuid;
3620 newRow.Family = AF_INET;
3621 // changed settings
3622 newRow.UseAutomaticMetric = false;
3623 newRow.Metric = metric;
3624
3625 // change settings
3626 return HRESULT_FROM_WIN32(g_pfnSetIpInterfaceEntry(&newRow));
3627}
3628
3629
3630HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID)
3631{
3632 HRESULT res = S_OK;
3633 DWORD luidIndex = 0;
3634 DWORD ifType = 0;
3635 DWORD cbSize = sizeof(luidIndex);
3636 DWORD dwValueType = REG_DWORD;
3637
3638 if (pLUID == NULL)
3639 return E_INVALIDARG;
3640
3641 res = RegQueryValueExW(hKey, L"NetLuidIndex", NULL,
3642 &dwValueType, (LPBYTE)&luidIndex, &cbSize);
3643 if (res != 0)
3644 return HRESULT_FROM_WIN32(res);
3645
3646 cbSize = sizeof(ifType);
3647 dwValueType = REG_DWORD;
3648 res = RegQueryValueExW(hKey, L"*IfType", NULL,
3649 &dwValueType, (LPBYTE)&ifType, &cbSize);
3650 if (res != 0)
3651 return HRESULT_FROM_WIN32(res);
3652
3653 ZeroMemory(pLUID, sizeof(NET_LUID));
3654 pLUID->Info.IfType = ifType;
3655 pLUID->Info.NetLuidIndex = luidIndex;
3656
3657 return res;
3658}
3659
3660
3661HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid)
3662{
3663 HINSTANCE hModule = NULL;
3664 HRESULT rc = vboxLoadIpHelpFunctions(hModule);
3665 if (SUCCEEDED(rc))
3666 {
3667 int loopbackMetric;
3668 rc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
3669 if (SUCCEEDED(rc))
3670 rc = vboxNetCfgWinSetInterfaceMetric(pLuid, loopbackMetric - 1);
3671 }
3672
3673 g_pfnInitializeIpInterfaceEntry = NULL;
3674 g_pfnSetIpInterfaceEntry = NULL;
3675 g_pfnGetIpInterfaceEntry = NULL;
3676
3677 FreeLibrary(hModule);
3678 return rc;
3679}
3680#ifdef VBOXNETCFG_DELAYEDRENAME
3681VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pwszId, OUT BSTR *pDevName)
3682{
3683 HRESULT hr = S_OK;
3684 WCHAR wszDevName[256];
3685 WCHAR wszConnectionNewName[128];
3686 ULONG cbName = sizeof(wszConnectionNewName);
3687
3688 HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
3689 if (hDevInfo != INVALID_HANDLE_VALUE)
3690 {
3691 SP_DEVINFO_DATA DevInfoData;
3692
3693 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
3694 if (SetupDiOpenDeviceInfo(hDevInfo, pwszId, NULL, 0, &DevInfoData))
3695 {
3696 DWORD err = ERROR_SUCCESS;
3697 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData,
3698 SPDRP_FRIENDLYNAME, NULL,
3699 (PBYTE)wszDevName, RT_ELEMENTS(wszDevName), NULL))
3700 {
3701 err = GetLastError();
3702 if (err == ERROR_INVALID_DATA)
3703 {
3704 err = SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData,
3705 SPDRP_DEVICEDESC, NULL,
3706 (PBYTE)wszDevName, RT_ELEMENTS(wszDevName), NULL)
3707 ? ERROR_SUCCESS
3708 : GetLastError();
3709 }
3710 }
3711 if (err == ERROR_SUCCESS)
3712 {
3713 hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionNewName, &cbName);
3714 if (SUCCEEDED(hr))
3715 {
3716 WCHAR wszGuid[50];
3717 int cbWGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
3718 if (cbWGuid)
3719 {
3720 hr = VBoxNetCfgWinRenameConnection(wszGuid, wszConnectionNewName);
3721 if (FAILED(hr))
3722 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinRenameConnection failed (0x%x)\n", hr));
3723 }
3724 else
3725 {
3726 err = GetLastError();
3727 hr = HRESULT_FROM_WIN32(err);
3728 if (SUCCEEDED(hr))
3729 hr = E_FAIL;
3730 NonStandardLogFlow(("StringFromGUID2 failed err=%u, hr=0x%x\n", err, hr));
3731 }
3732 }
3733 else
3734 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinGenHostonlyConnectionName failed (0x%x)\n", hr));
3735 if (SUCCEEDED(hr) && pDevName)
3736 {
3737 *pDevName = SysAllocString((const OLECHAR *)wszDevName);
3738 if (!*pDevName)
3739 {
3740 NonStandardLogFlow(("SysAllocString failed\n"));
3741 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3742 }
3743 }
3744 }
3745 else
3746 {
3747 hr = HRESULT_FROM_WIN32(err);
3748 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiGetDeviceRegistryPropertyW failed (0x%x)\n", err));
3749 }
3750 }
3751 else
3752 {
3753 DWORD err = GetLastError();
3754 hr = HRESULT_FROM_WIN32(err);
3755 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiOpenDeviceInfo failed (0x%x)\n", err));
3756 }
3757 SetupDiDestroyDeviceInfoList(hDevInfo);
3758 }
3759
3760 return hr;
3761}
3762#endif /* VBOXNETCFG_DELAYEDRENAME */
3763
3764#undef SetErrBreak
3765
Note: See TracBrowser for help on using the repository browser.

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