VirtualBox

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

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

NetFlt/LwfWin: NDIS6 filter driver (#7231)

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

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