VirtualBox

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

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

NetAdp/Win: (bugref:9409) Work around host-only adapter naming issue after Windows upgrade.

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