VirtualBox

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

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

Build fix.

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