VirtualBox

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

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

NetCfg/win: Retry creation of host-only adapter device if network connection not created properly (#7973)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 115.4 KB
Line 
1/* $Id: VBoxNetCfg.cpp 58956 2015-12-02 16:57:40Z 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 }
2308 pNetCfgCompo->Release();
2309 }
2310 else
2311 NonStandardLogFlow(("GetLowerComponent failed, hr (0x%x)\n", hr));
2312 pNetCfgBindIfce->Release();
2313 }
2314 else
2315 {
2316 if (hr == S_FALSE) /* No more binding interfaces? */
2317 hr = S_OK;
2318 else
2319 NonStandardLogFlow(("Next binding interface failed, hr (0x%x)\n", hr));
2320 break;
2321 }
2322 } while (!bFoundIface);
2323 pEnumNetCfgBindIface->Release();
2324 }
2325 else
2326 NonStandardLogFlow(("EnumBindingInterfaces failed, hr (0x%x)\n", hr));
2327 pNetCfgBindPath->Release();
2328 }
2329 else
2330 {
2331 if (hr == S_FALSE) /* No more binding paths? */
2332 hr = S_OK;
2333 else
2334 NonStandardLogFlow(("Next bind path failed, hr (0x%x)\n", hr));
2335 break;
2336 }
2337 } while (!bFoundIface);
2338 pEnumNetCfgBindPath->Release();
2339 }
2340 else
2341 NonStandardLogFlow(("EnumBindingPaths failed, hr (0x%x)\n", hr));
2342 pNetCfgBindings->Release();
2343 }
2344 else
2345 NonStandardLogFlow(("QueryInterface for IID_INetCfgComponentBindings failed, hr (0x%x)\n", hr));
2346 return TRUE;
2347}
2348
2349static UINT WINAPI vboxNetCfgWinPspFileCallback(
2350 PVOID Context,
2351 UINT Notification,
2352 UINT_PTR Param1,
2353 UINT_PTR Param2
2354 )
2355{
2356 switch (Notification)
2357 {
2358 case SPFILENOTIFY_TARGETNEWER:
2359 case SPFILENOTIFY_TARGETEXISTS:
2360 return TRUE;
2361 }
2362 return SetupDefaultQueueCallback(Context, Notification, Param1, Param2);
2363}
2364
2365/* The original source of the VBoxNetAdp adapter creation/destruction code has the following copyright */
2366/*
2367 Copyright 2004 by the Massachusetts Institute of Technology
2368
2369 All rights reserved.
2370
2371 Permission to use, copy, modify, and distribute this software and its
2372 documentation for any purpose and without fee is hereby granted,
2373 provided that the above copyright notice appear in all copies and that
2374 both that copyright notice and this permission notice appear in
2375 supporting documentation, and that the name of the Massachusetts
2376 Institute of Technology (M.I.T.) not be used in advertising or publicity
2377 pertaining to distribution of the software without specific, written
2378 prior permission.
2379
2380 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2381 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2382 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2383 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2384 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2385 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2386 SOFTWARE.
2387*/
2388
2389
2390/**
2391 * Use the IShellFolder API to rename the connection.
2392 */
2393static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
2394{
2395 /* This is the GUID for the network connections folder. It is constant.
2396 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2397 const GUID CLSID_NetworkConnections = {
2398 0x7007ACC7, 0x3202, 0x11D1, {
2399 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2400 }
2401 };
2402
2403 LPITEMIDLIST pidl = NULL;
2404 IShellFolder *pShellFolder = NULL;
2405 HRESULT hr;
2406
2407 /* Build the display name in the form "::{GUID}". */
2408 if (wcslen(wGuid) >= MAX_PATH)
2409 return E_INVALIDARG;
2410 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
2411 swprintf(szAdapterGuid, L"::%ls", wGuid);
2412
2413 /* Create an instance of the network connections folder. */
2414 hr = CoCreateInstance(CLSID_NetworkConnections, NULL,
2415 CLSCTX_INPROC_SERVER, IID_IShellFolder,
2416 reinterpret_cast<LPVOID *>(&pShellFolder));
2417 /* Parse the display name. */
2418 if (SUCCEEDED (hr))
2419 {
2420 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
2421 &pidl, NULL);
2422 }
2423 if (SUCCEEDED (hr))
2424 {
2425 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
2426 &pidl);
2427 }
2428
2429 CoTaskMemFree (pidl);
2430
2431 if (pShellFolder)
2432 pShellFolder->Release();
2433
2434 return hr;
2435}
2436
2437/**
2438 * Loads a system DLL.
2439 *
2440 * @returns Module handle or NULL
2441 * @param pszName The DLL name.
2442 */
2443static HMODULE loadSystemDll(const char *pszName)
2444{
2445 char szPath[MAX_PATH];
2446 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
2447 size_t cbName = strlen(pszName) + 1;
2448 if (cchPath + 1 + cbName > sizeof(szPath))
2449 return NULL;
2450 szPath[cchPath] = '\\';
2451 memcpy(&szPath[cchPath + 1], pszName, cbName);
2452 return LoadLibraryA(szPath);
2453}
2454
2455VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection (LPWSTR pGuid, PCWSTR NewName)
2456{
2457 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
2458 lpHrRenameConnection RenameConnectionFunc = NULL;
2459 HRESULT status;
2460
2461 /* First try the IShellFolder interface, which was unimplemented
2462 * for the network connections folder before XP. */
2463 status = rename_shellfolder (pGuid, NewName);
2464 if (status == E_NOTIMPL)
2465 {
2466/** @todo that code doesn't seem to work! */
2467 /* The IShellFolder interface is not implemented on this platform.
2468 * Try the (undocumented) HrRenameConnection API in the netshell
2469 * library. */
2470 CLSID clsid;
2471 HINSTANCE hNetShell;
2472 status = CLSIDFromString ((LPOLESTR) pGuid, &clsid);
2473 if (FAILED(status))
2474 return E_FAIL;
2475 hNetShell = loadSystemDll("netshell.dll");
2476 if (hNetShell == NULL)
2477 return E_FAIL;
2478 RenameConnectionFunc =
2479 (lpHrRenameConnection) GetProcAddress (hNetShell,
2480 "HrRenameConnection");
2481 if (RenameConnectionFunc == NULL)
2482 {
2483 FreeLibrary (hNetShell);
2484 return E_FAIL;
2485 }
2486 status = RenameConnectionFunc (&clsid, NewName);
2487 FreeLibrary (hNetShell);
2488 }
2489 if (FAILED (status))
2490 return status;
2491
2492 return S_OK;
2493}
2494
2495static const char *vboxNetCfgWinGetStateText(DWORD dwState)
2496{
2497 switch (dwState)
2498 {
2499 case SERVICE_STOPPED: return "is not running";
2500 case SERVICE_STOP_PENDING: return "is stopping";
2501 case SERVICE_CONTINUE_PENDING: return "continue is pending";
2502 case SERVICE_PAUSE_PENDING: return "pause is pending";
2503 case SERVICE_PAUSED: return "is paused";
2504 case SERVICE_RUNNING: return "is running";
2505 case SERVICE_START_PENDING: return "is starting";
2506 }
2507 return "state is invalid";
2508}
2509
2510static DWORD vboxNetCfgWinGetNetSetupState(SC_HANDLE hService)
2511{
2512 SERVICE_STATUS status;
2513 status.dwCurrentState = SERVICE_RUNNING;
2514 if (hService) {
2515 if (QueryServiceStatus(hService, &status))
2516 NonStandardLogFlow(("NetSetupSvc %s\n", vboxNetCfgWinGetStateText(status.dwCurrentState)));
2517 else
2518 NonStandardLogFlow(("QueryServiceStatus failed (0x%x)\n", GetLastError()));
2519 }
2520 return status.dwCurrentState;
2521}
2522
2523DECLINLINE(bool) vboxNetCfgWinIsNetSetupRunning(SC_HANDLE hService)
2524{
2525 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_RUNNING;
2526}
2527
2528DECLINLINE(bool) vboxNetCfgWinIsNetSetupStopped(SC_HANDLE hService)
2529{
2530 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_STOPPED;
2531}
2532
2533#define DRIVERHWID _T("sun_VBoxNetAdp")
2534
2535#define SetErrBreak(strAndArgs) \
2536 if (1) { \
2537 hrc = E_FAIL; \
2538 NonStandardLog strAndArgs; \
2539 bstrError = bstr_printf strAndArgs; \
2540 break; \
2541 } else do {} while (0)
2542
2543VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pErrMsg)
2544{
2545 HRESULT hrc = S_OK;
2546 bstr_t bstrError;
2547
2548 do
2549 {
2550 TCHAR lszPnPInstanceId [512] = {0};
2551
2552 /* We have to find the device instance ID through a registry search */
2553
2554 HKEY hkeyNetwork = 0;
2555 HKEY hkeyConnection = 0;
2556
2557 do
2558 {
2559 WCHAR strRegLocation [256];
2560 WCHAR wszGuid[50];
2561
2562 int length = StringFromGUID2(*pGUID, wszGuid, RT_ELEMENTS(wszGuid));
2563 if (!length)
2564 SetErrBreak(("Failed to create a Guid string"));
2565
2566 swprintf (strRegLocation,
2567 L"SYSTEM\\CurrentControlSet\\Control\\Network\\"
2568 L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
2569 wszGuid);
2570
2571 LONG status;
2572 status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, strRegLocation, 0,
2573 KEY_READ, &hkeyNetwork);
2574 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
2575 SetErrBreak (("Host interface network is not found in registry (%S) [1]",
2576 strRegLocation));
2577
2578 status = RegOpenKeyExW (hkeyNetwork, L"Connection", 0,
2579 KEY_READ, &hkeyConnection);
2580 if ((status != ERROR_SUCCESS) || !hkeyConnection)
2581 SetErrBreak (("Host interface network is not found in registry (%S) [2]",
2582 strRegLocation));
2583
2584 DWORD len = sizeof (lszPnPInstanceId);
2585 DWORD dwKeyType;
2586 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
2587 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
2588 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
2589 SetErrBreak (("Host interface network is not found in registry (%S) [3]",
2590 strRegLocation));
2591 }
2592 while (0);
2593
2594 if (hkeyConnection)
2595 RegCloseKey (hkeyConnection);
2596 if (hkeyNetwork)
2597 RegCloseKey (hkeyNetwork);
2598
2599 if (FAILED (hrc))
2600 break;
2601
2602 /*
2603 * Now we are going to enumerate all network devices and
2604 * wait until we encounter the right device instance ID
2605 */
2606
2607 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2608
2609 do
2610 {
2611 BOOL ok;
2612 DWORD ret = 0;
2613 GUID netGuid;
2614 SP_DEVINFO_DATA DeviceInfoData;
2615 DWORD index = 0;
2616 BOOL found = FALSE;
2617 DWORD size = 0;
2618
2619 /* initialize the structure size */
2620 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2621
2622 /* copy the net class GUID */
2623 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2624
2625 /* return a device info set contains all installed devices of the Net class */
2626 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
2627
2628 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2629 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2630
2631 /* enumerate the driver info list */
2632 while (TRUE)
2633 {
2634 TCHAR *deviceHwid;
2635
2636 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
2637
2638 if (!ok)
2639 {
2640 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2641 break;
2642 else
2643 {
2644 index++;
2645 continue;
2646 }
2647 }
2648
2649 /* try to get the hardware ID registry property */
2650 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2651 &DeviceInfoData,
2652 SPDRP_HARDWAREID,
2653 NULL,
2654 NULL,
2655 0,
2656 &size);
2657 if (!ok)
2658 {
2659 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2660 {
2661 index++;
2662 continue;
2663 }
2664
2665 deviceHwid = (TCHAR *) malloc (size);
2666 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2667 &DeviceInfoData,
2668 SPDRP_HARDWAREID,
2669 NULL,
2670 (PBYTE)deviceHwid,
2671 size,
2672 NULL);
2673 if (!ok)
2674 {
2675 free (deviceHwid);
2676 deviceHwid = NULL;
2677 index++;
2678 continue;
2679 }
2680 }
2681 else
2682 {
2683 /* something is wrong. This shouldn't have worked with a NULL buffer */
2684 index++;
2685 continue;
2686 }
2687
2688 for (TCHAR *t = deviceHwid;
2689 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
2690 t += _tcslen (t) + 1)
2691 {
2692 if (!_tcsicmp (DRIVERHWID, t))
2693 {
2694 /* get the device instance ID */
2695 TCHAR devId[MAX_DEVICE_ID_LEN];
2696 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
2697 devId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2698 {
2699 /* compare to what we determined before */
2700 if (wcscmp(devId, lszPnPInstanceId) == 0)
2701 {
2702 found = TRUE;
2703 break;
2704 }
2705 }
2706 }
2707 }
2708
2709 if (deviceHwid)
2710 {
2711 free (deviceHwid);
2712 deviceHwid = NULL;
2713 }
2714
2715 if (found)
2716 break;
2717
2718 index++;
2719 }
2720
2721 if (found == FALSE)
2722 SetErrBreak (("Host Interface Network driver not found (0x%08X)",
2723 GetLastError()));
2724
2725 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2726 if (!ok)
2727 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2728 GetLastError()));
2729
2730 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2731 if (!ok)
2732 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
2733 GetLastError()));
2734 }
2735 while (0);
2736
2737 /* clean up the device info set */
2738 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2739 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2740
2741 if (FAILED (hrc))
2742 break;
2743 }
2744 while (0);
2745
2746 if (pErrMsg && bstrError.length())
2747 *pErrMsg = bstrError.Detach();
2748
2749 return hrc;
2750}
2751
2752VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pbRebootRequired, LPCWSTR pcsxwId)
2753{
2754 return VBoxDrvCfgDrvUpdate(pcsxwId, pcsxwInf, pbRebootRequired);
2755}
2756
2757VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile,
2758 OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
2759{
2760 HRESULT hrc = S_OK;
2761
2762 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2763 SP_DEVINFO_DATA DeviceInfoData;
2764 PVOID pQueueCallbackContext = NULL;
2765 DWORD ret = 0;
2766 BOOL registered = FALSE;
2767 BOOL destroyList = FALSE;
2768 WCHAR pWCfgGuidString [50];
2769 WCHAR DevName[256];
2770 HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
2771 bstr_t bstrError;
2772 INetCfg *pNetCfg = NULL;
2773 LPWSTR lpszApp = NULL;
2774
2775 for (int attempt = 0; attempt < 2; ++attempt)
2776 {
2777 BOOL found = FALSE;
2778 GUID netGuid;
2779 SP_DRVINFO_DATA DriverInfoData;
2780 SP_DEVINSTALL_PARAMS DeviceInstallParams;
2781 TCHAR className [MAX_PATH];
2782 DWORD index = 0;
2783 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
2784 /* for our purposes, 2k buffer is more
2785 * than enough to obtain the hardware ID
2786 * of the VBoxNetAdp driver. */
2787 DWORD detailBuf [2048];
2788
2789 DWORD cbSize;
2790 DWORD dwValueType;
2791
2792 /* initialize the structure size */
2793 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2794 DriverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
2795
2796 /* copy the net class GUID */
2797 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
2798
2799 /* create an empty device info set associated with the net class GUID */
2800 hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
2801 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2802 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
2803 GetLastError()));
2804
2805 /* get the class name from GUID */
2806 BOOL fResult = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
2807 if (!fResult)
2808 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
2809 GetLastError()));
2810
2811 /* create a device info element and add the new device instance
2812 * key to registry */
2813 fResult = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
2814 DICD_GENERATE_ID, &DeviceInfoData);
2815 if (!fResult)
2816 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
2817 GetLastError()));
2818
2819 /* select the newly created device info to be the currently
2820 selected member */
2821 fResult = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2822 if (!fResult)
2823 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2824 GetLastError()));
2825
2826 if (pInfPath)
2827 {
2828 /* get the device install parameters and disable filecopy */
2829 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2830 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2831 &DeviceInstallParams);
2832 if (fResult)
2833 {
2834 memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
2835 size_t pathLenght = wcslen(pInfPath) + 1/* null terminator */;
2836 if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
2837 {
2838 memcpy(DeviceInstallParams.DriverPath, pInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
2839
2840 if (bIsInfPathFile)
2841 {
2842 DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
2843 }
2844
2845 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
2846 &DeviceInstallParams);
2847 if (!fResult)
2848 {
2849 DWORD winEr = GetLastError();
2850 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
2851 break;
2852 }
2853 }
2854 else
2855 {
2856 NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
2857 break;
2858 }
2859 }
2860 else
2861 {
2862 DWORD winEr = GetLastError();
2863 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
2864 }
2865 }
2866
2867 /* build a list of class drivers */
2868 fResult = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
2869 SPDIT_CLASSDRIVER);
2870 if (!fResult)
2871 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
2872 GetLastError()));
2873
2874 destroyList = TRUE;
2875
2876 /* enumerate the driver info list */
2877 while (TRUE)
2878 {
2879 BOOL ret;
2880
2881 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
2882 SPDIT_CLASSDRIVER, index, &DriverInfoData);
2883
2884 /* if the function failed and GetLastError() returned
2885 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
2886 * list. Otherwise there was something wrong with this
2887 * particular driver. */
2888 if (!ret)
2889 {
2890 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2891 break;
2892 else
2893 {
2894 index++;
2895 continue;
2896 }
2897 }
2898
2899 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
2900 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
2901
2902 /* if we successfully find the hardware ID and it turns out to
2903 * be the one for the loopback driver, then we are done. */
2904 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
2905 &DeviceInfoData,
2906 &DriverInfoData,
2907 pDriverInfoDetail,
2908 sizeof (detailBuf),
2909 NULL))
2910 {
2911 TCHAR * t;
2912
2913 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
2914 * whole list and see if there is a match somewhere. */
2915 t = pDriverInfoDetail->HardwareID;
2916 while (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
2917 {
2918 if (!_tcsicmp(t, DRIVERHWID))
2919 break;
2920
2921 t += _tcslen(t) + 1;
2922 }
2923
2924 if (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
2925 {
2926 found = TRUE;
2927 break;
2928 }
2929 }
2930
2931 index ++;
2932 }
2933
2934 if (!found)
2935 SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
2936
2937 /* set the loopback driver to be the currently selected */
2938 fResult = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
2939 &DriverInfoData);
2940 if (!fResult)
2941 SetErrBreak(("SetupDiSetSelectedDriver failed (0x%08X)",
2942 GetLastError()));
2943
2944 /* register the phantom device to prepare for install */
2945 fResult = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
2946 &DeviceInfoData);
2947 if (!fResult)
2948 {
2949 DWORD err = GetLastError();
2950 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
2951 err));
2952 }
2953
2954 /* registered, but remove if errors occur in the following code */
2955 registered = TRUE;
2956
2957 /* ask the installer if we can install the device */
2958 fResult = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
2959 &DeviceInfoData);
2960 if (!fResult)
2961 {
2962 if (GetLastError() != ERROR_DI_DO_DEFAULT)
2963 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
2964 GetLastError()));
2965 /* that's fine */
2966 }
2967
2968 /* get the device install parameters and disable filecopy */
2969 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2970 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2971 &DeviceInstallParams);
2972 if (fResult)
2973 {
2974 pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
2975 if (pQueueCallbackContext)
2976 {
2977 DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
2978 DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
2979 fResult = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2980 &DeviceInstallParams);
2981 if (!fResult)
2982 {
2983 DWORD winEr = GetLastError();
2984 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
2985 }
2986 Assert(fResult);
2987 }
2988 else
2989 {
2990 DWORD winEr = GetLastError();
2991 NonStandardLogFlow(("SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr));
2992 }
2993 }
2994 else
2995 {
2996 DWORD winEr = GetLastError();
2997 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
2998 }
2999
3000 /* install the files first */
3001 fResult = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
3002 &DeviceInfoData);
3003 if (!fResult)
3004 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
3005 GetLastError()));
3006 /* get the device install parameters and disable filecopy */
3007 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3008 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3009 &DeviceInstallParams);
3010 if (fResult)
3011 {
3012 DeviceInstallParams.Flags |= DI_NOFILECOPY;
3013 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
3014 &DeviceInstallParams);
3015 if (!fResult)
3016 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
3017 GetLastError()));
3018 }
3019
3020 /*
3021 * Register any device-specific co-installers for this device,
3022 */
3023 fResult = SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
3024 hDeviceInfo,
3025 &DeviceInfoData);
3026 if (!fResult)
3027 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
3028 GetLastError()));
3029
3030 /*
3031 * install any installer-specified interfaces.
3032 * and then do the real install
3033 */
3034 fResult = SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
3035 hDeviceInfo,
3036 &DeviceInfoData);
3037 if (!fResult)
3038 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
3039 GetLastError()));
3040
3041 fResult = SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
3042 hDeviceInfo,
3043 &DeviceInfoData);
3044 if (!fResult)
3045 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
3046 GetLastError()));
3047
3048 /* Figure out NetCfgInstanceId */
3049 hkey = SetupDiOpenDevRegKey(hDeviceInfo,
3050 &DeviceInfoData,
3051 DICS_FLAG_GLOBAL,
3052 0,
3053 DIREG_DRV,
3054 KEY_READ);
3055 if (hkey == INVALID_HANDLE_VALUE)
3056 SetErrBreak(("SetupDiOpenDevRegKey failed (0x%08X)", GetLastError()));
3057
3058 /* Query the instance ID; on Windows 10, the registry key may take a short
3059 * while to appear. Microsoft recommends waiting for up to 5 seconds, but
3060 * we want to be on the safe side, so let's wait for 20 seconds. Waiting
3061 * longer is harmful as network setup service will shut down after a period
3062 * of inactivity.
3063 */
3064 for (int retries = 0; retries < 2 * 20; ++retries)
3065 {
3066 cbSize = sizeof(pWCfgGuidString);
3067 ret = RegQueryValueExW (hkey, L"NetCfgInstanceId", NULL,
3068 &dwValueType, (LPBYTE) pWCfgGuidString, &cbSize);
3069 /* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
3070 if (ret == ERROR_FILE_NOT_FOUND)
3071 Sleep(500); /* half second */
3072 else
3073 break;
3074 }
3075
3076 if (ret == ERROR_FILE_NOT_FOUND && attempt == 0)
3077 {
3078 /*
3079 * This is the first time we fail to obtain NetCfgInstanceId, let us
3080 * retry it once. It is needed to handle the situation when network
3081 * setup fails to recognize the arrival of our device node while it
3082 * is busy removing another host-only interface, and it gets stuck
3083 * with no matching network interface created for our device node.
3084 * See @bugref{7973} for details.
3085 */
3086 NonStandardLogFlow(("Timed out while waiting for NetCfgInstanceId, remove the device and try again...\n"));
3087 if (hkey != INVALID_HANDLE_VALUE)
3088 {
3089 RegCloseKey (hkey);
3090 hkey = (HKEY)INVALID_HANDLE_VALUE;
3091 }
3092 if (pQueueCallbackContext)
3093 {
3094 SetupTermDefaultQueueCallback(pQueueCallbackContext);
3095 pQueueCallbackContext = NULL;
3096 }
3097 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
3098 SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
3099 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData,
3100 SPDIT_CLASSDRIVER);
3101 SetupDiDestroyDeviceInfoList(hDeviceInfo);
3102 destroyList = FALSE;
3103 registered = FALSE;
3104 continue;
3105 }
3106
3107 if (ret != ERROR_SUCCESS)
3108 SetErrBreak(("Querying NetCfgInstanceId failed (0x%08X)", ret));
3109
3110#ifndef VBOXNETCFG_DELAYEDRENAME
3111 /*
3112 * We need to query the device name after we have succeeded in querying its
3113 * instance ID to avoid similar waiting-and-retrying loop (see @bugref{7973}).
3114 */
3115 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3116 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
3117 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3118 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
3119 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
3120 NULL /*OUT PDWORD RequiredSize OPTIONAL*/))
3121 {
3122 int err = GetLastError();
3123 if (err != ERROR_INVALID_DATA)
3124 {
3125 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
3126 err));
3127 }
3128
3129 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3130 SPDRP_DEVICEDESC, /* IN DWORD Property,*/
3131 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3132 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
3133 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
3134 NULL /*OUT PDWORD RequiredSize OPTIONAL*/
3135 ))
3136 {
3137 err = GetLastError();
3138 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
3139 err));
3140 }
3141 }
3142#else /* !VBOXNETCFG_DELAYEDRENAME */
3143 /* Re-use DevName for device instance id retrieval. */
3144 if (!SetupDiGetDeviceInstanceId(hDeviceInfo, &DeviceInfoData, DevName, RT_ELEMENTS(DevName), &cbSize))
3145 SetErrBreak (("SetupDiGetDeviceInstanceId failed (0x%08X)",
3146 GetLastError()));
3147#endif /* !VBOXNETCFG_DELAYEDRENAME */
3148
3149 /* Success, don't need another attempt */
3150 break;
3151 }
3152
3153 /*
3154 * cleanup
3155 */
3156 if (hkey != INVALID_HANDLE_VALUE)
3157 RegCloseKey (hkey);
3158
3159 if (pQueueCallbackContext)
3160 SetupTermDefaultQueueCallback(pQueueCallbackContext);
3161
3162 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3163 {
3164 /* an error has occurred, but the device is registered, we must remove it */
3165 if (ret != 0 && registered)
3166 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
3167
3168 SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
3169
3170 /* destroy the driver info list */
3171 if (destroyList)
3172 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData,
3173 SPDIT_CLASSDRIVER);
3174 /* clean up the device info set */
3175 SetupDiDestroyDeviceInfoList (hDeviceInfo);
3176 }
3177
3178 /* return the network connection GUID on success */
3179 if (SUCCEEDED(hrc))
3180 {
3181 HRESULT hr;
3182#ifndef VBOXNETCFG_DELAYEDRENAME
3183 WCHAR ConnectionName[128];
3184 ULONG cbName = sizeof(ConnectionName);
3185
3186 hr = VBoxNetCfgWinGenHostonlyConnectionName(DevName, ConnectionName, &cbName);
3187 if (SUCCEEDED(hr))
3188 hr = VBoxNetCfgWinRenameConnection(pWCfgGuidString, ConnectionName);
3189#endif
3190 if (lppszName)
3191 {
3192 *lppszName = SysAllocString((const OLECHAR *) DevName);
3193 if (!*lppszName)
3194 {
3195 NonStandardLogFlow(("SysAllocString failed\n"));
3196 hrc = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3197 }
3198 }
3199
3200 if (pGuid)
3201 {
3202 hrc = CLSIDFromString(pWCfgGuidString, (LPCLSID)pGuid);
3203 if (FAILED(hrc))
3204 NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
3205 }
3206
3207 /* Check if INetCfg has been queried already, query if it hasn't been. */
3208 if (pNetCfg == NULL)
3209 hr = VBoxNetCfgWinQueryINetCfg(&pNetCfg, TRUE, L"VirtualBox Host-Only Creation",
3210 30 * 1000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec. */
3211 /* TODO: special handling for 6to4svc.dll ???, i.e. several retrieves */
3212 &lpszApp);
3213 else
3214 hr = S_OK;
3215 if (hr == S_OK)
3216 {
3217 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3218 &GUID_DEVCLASS_NETSERVICE,
3219 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3220 pGuid);
3221 if (SUCCEEDED(hr))
3222 {
3223 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3224 &GUID_DEVCLASS_NETTRANS,
3225 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3226 pGuid);
3227 if (SUCCEEDED(hr))
3228 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3229 &GUID_DEVCLASS_NETCLIENT,
3230 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3231 pGuid);
3232 }
3233
3234 if (SUCCEEDED(hr))
3235 {
3236 hr = pNetCfg->Apply();
3237 }
3238 else
3239 NonStandardLogFlow(("Enumeration failed, hr 0x%x\n", hr));
3240 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
3241 }
3242 else if (hr == NETCFG_E_NO_WRITE_LOCK && lpszApp)
3243 {
3244 NonStandardLogFlow(("Application %ws is holding the lock, failed\n", lpszApp));
3245 CoTaskMemFree(lpszApp);
3246 }
3247 else
3248 NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hr 0x%x\n", hr));
3249 }
3250
3251 if (pErrMsg && bstrError.length())
3252 *pErrMsg = bstrError.Detach();
3253
3254 return hrc;
3255}
3256
3257#ifdef VBOXNETCFG_DELAYEDRENAME
3258VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pwszId, OUT BSTR *pDevName)
3259{
3260 HRESULT hr = S_OK;
3261 WCHAR wszDevName[256];
3262 WCHAR wszConnectionNewName[128];
3263 ULONG cbName = sizeof(wszConnectionNewName);
3264
3265 HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
3266 if (hDevInfo != INVALID_HANDLE_VALUE)
3267 {
3268 SP_DEVINFO_DATA DevInfoData;
3269
3270 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
3271 if (SetupDiOpenDeviceInfo(hDevInfo, pwszId, NULL, 0, &DevInfoData))
3272 {
3273 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData,
3274 SPDRP_FRIENDLYNAME, NULL,
3275 (PBYTE)wszDevName, RT_ELEMENTS(wszDevName), NULL))
3276 {
3277 hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionNewName, &cbName);
3278 if (SUCCEEDED(hr))
3279 {
3280 WCHAR wszGuid[50];
3281 int cbWGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
3282 if (cbWGuid)
3283 {
3284 hr = VBoxNetCfgWinRenameConnection(wszGuid, wszConnectionNewName);
3285 if (FAILED(hr))
3286 NonStandardLogFlow(("NetIf: VBoxNetCfgWinRenameConnection failed (0x%x)\n", hr));
3287 }
3288 else
3289 {
3290 DWORD winEr = GetLastError();
3291 hr = HRESULT_FROM_WIN32(winEr);
3292 if (SUCCEEDED(hr))
3293 hr = E_FAIL;
3294 NonStandardLogFlow(("StringFromGUID2 failed winEr=%u, hr=0x%x\n", winEr, hr));
3295 }
3296 }
3297 else
3298 NonStandardLogFlow(("NetIf: VBoxNetCfgWinGenHostonlyConnectionName failed (0x%x)\n", hr));
3299 if (SUCCEEDED(hr) && pDevName)
3300 {
3301 *pDevName = SysAllocString((const OLECHAR *)wszDevName);
3302 if (!*pDevName)
3303 {
3304 NonStandardLogFlow(("SysAllocString failed\n"));
3305 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3306 }
3307 }
3308 }
3309 else
3310 {
3311 DWORD winEr = GetLastError();
3312 hr = HRESULT_FROM_WIN32(winEr);
3313 NonStandardLogFlow(("NetIf: SetupDiGetDeviceRegistryPropertyW failed (0x%x)\n", winEr));
3314 }
3315 }
3316 else
3317 {
3318 DWORD winEr = GetLastError();
3319 hr = HRESULT_FROM_WIN32(winEr);
3320 NonStandardLogFlow(("NetIf: SetupDiOpenDeviceInfo failed (0x%x)\n", winEr));
3321 }
3322 SetupDiDestroyDeviceInfoList(hDevInfo);
3323 }
3324
3325 return hr;
3326}
3327#endif /* VBOXNETCFG_DELAYEDRENAME */
3328
3329#undef SetErrBreak
3330
Note: See TracBrowser for help on using the repository browser.

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