VirtualBox

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

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

HostDrivers/VBoxNetCfg.cpp: Check for valid pointer in VBoxNetCfgWinReleaseINetCfg().

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