VirtualBox

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

Last change on this file since 41010 was 41007, checked in by vboxsync, 13 years ago

netcfg/win: fix failure branch

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

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