VirtualBox

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

Last change on this file since 48641 was 48641, checked in by vboxsync, 11 years ago

VBoxNetCfg: rename host-only connection before removing adapter (#6740)

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