VirtualBox

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

Last change on this file since 59046 was 59046, checked in by vboxsync, 9 years ago

NetCfg/win: Bind bridging LWF to host-only adapters (bugref:8140)

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

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