VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 134.3 KB
Line 
1/* $Id: VBoxNetCfg.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBoxNetCfg.cpp - Network Configuration API.
4 */
5/*
6 * Copyright (C) 2011-2022 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35#include "VBox/VBoxNetCfg-win.h"
36#include "VBox/VBoxDrvCfg-win.h"
37
38#define _WIN32_DCOM
39
40#include <devguid.h>
41#include <stdio.h>
42#include <regstr.h>
43#include <iprt/win/shlobj.h>
44#include <cfgmgr32.h>
45#include <tchar.h>
46#include <iprt/win/objbase.h>
47
48#include <crtdbg.h>
49#include <stdlib.h>
50#include <string.h>
51
52#include <Wbemidl.h>
53#include <comutil.h>
54
55#include <iprt/win/winsock2.h>
56#include <iprt/win/ws2tcpip.h>
57#include <ws2ipdef.h>
58#include <iprt/win/netioapi.h>
59#include <iprt/win/iphlpapi.h>
60
61#include <set>
62
63#ifndef Assert /** @todo r=bird: where would this be defined? */
64//# ifdef DEBUG
65//# define Assert(_expr) assert(_expr)
66//# else
67//# define Assert(_expr) do{ }while (0)
68//# endif
69# define Assert _ASSERT
70# define AssertMsg(expr, msg) do{}while (0)
71#endif
72static PFNVBOXNETCFGLOGGER volatile g_pfnLogger = NULL;
73
74static void DoLogging(const char *pszString, ...);
75#define NonStandardLog DoLogging
76#define NonStandardLogFlow(x) DoLogging x
77
78#define DbgLog /** @todo r=bird: What does this do? */
79
80#define VBOX_NETCFG_LOCK_TIME_OUT 5000 /** @todo r=bird: What does this do? */
81
82#define VBOXNETCFGWIN_NETADP_ID L"sun_VBoxNetAdp"
83
84/*
85* Wrappers for HelpAPI functions
86*/
87typedef void FNINITIALIZEIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
88typedef FNINITIALIZEIPINTERFACEENTRY *PFNINITIALIZEIPINTERFACEENTRY;
89
90typedef NETIOAPI_API FNGETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
91typedef FNGETIPINTERFACEENTRY *PFNGETIPINTERFACEENTRY;
92
93typedef NETIOAPI_API FNSETIPINTERFACEENTRY( _Inout_ PMIB_IPINTERFACE_ROW row);
94typedef FNSETIPINTERFACEENTRY *PFNSETIPINTERFACEENTRY;
95
96static PFNINITIALIZEIPINTERFACEENTRY g_pfnInitializeIpInterfaceEntry = NULL;
97static PFNGETIPINTERFACEENTRY g_pfnGetIpInterfaceEntry = NULL;
98static PFNSETIPINTERFACEENTRY g_pfnSetIpInterfaceEntry = NULL;
99
100
101/*
102* Forward declaration for using vboxNetCfgWinSetupMetric()
103*/
104HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid);
105HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID);
106
107
108/*
109 * For some weird reason we do not want to use IPRT here, hence the following
110 * function provides a replacement for BstrFmt.
111 */
112static bstr_t bstr_printf(const char *cszFmt, ...)
113{
114 char szBuffer[4096];
115 szBuffer[sizeof(szBuffer) - 1] = 0; /* Make sure the string will be null-terminated */
116 va_list va;
117 va_start(va, cszFmt);
118 _vsnprintf(szBuffer, sizeof(szBuffer) - 1, cszFmt, va);
119 va_end(va);
120 return bstr_t(szBuffer);
121}
122
123static HRESULT vboxNetCfgWinINetCfgLock(IN INetCfg *pNetCfg,
124 IN LPCWSTR pszwClientDescription,
125 IN DWORD cmsTimeout,
126 OUT LPWSTR *ppszwClientDescription)
127{
128 INetCfgLock *pLock;
129 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
130 if (FAILED(hr))
131 {
132 NonStandardLogFlow(("QueryInterface failed, hr (0x%x)\n", hr));
133 return hr;
134 }
135
136 hr = pLock->AcquireWriteLock(cmsTimeout, pszwClientDescription, ppszwClientDescription);
137 if (hr == S_FALSE)
138 {
139 NonStandardLogFlow(("Write lock busy\n"));
140 }
141 else if (FAILED(hr))
142 {
143 NonStandardLogFlow(("AcquireWriteLock failed, hr (0x%x)\n", hr));
144 }
145
146 pLock->Release();
147 return hr;
148}
149
150static HRESULT vboxNetCfgWinINetCfgUnlock(IN INetCfg *pNetCfg)
151{
152 INetCfgLock *pLock;
153 HRESULT hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
154 if (FAILED(hr))
155 {
156 NonStandardLogFlow(("QueryInterface failed, hr (0x%x)\n", hr));
157 return hr;
158 }
159
160 hr = pLock->ReleaseWriteLock();
161 if (FAILED(hr))
162 NonStandardLogFlow(("ReleaseWriteLock failed, hr (0x%x)\n", hr));
163
164 pLock->Release();
165 return hr;
166}
167
168VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(OUT INetCfg **ppNetCfg,
169 IN BOOL fGetWriteLock,
170 IN LPCWSTR pszwClientDescription,
171 IN DWORD cmsTimeout,
172 OUT LPWSTR *ppszwClientDescription)
173{
174 INetCfg *pNetCfg;
175 HRESULT hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (PVOID*)&pNetCfg);
176 if (FAILED(hr))
177 {
178 NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\n", hr));
179 return hr;
180 }
181
182 if (fGetWriteLock)
183 {
184 hr = vboxNetCfgWinINetCfgLock(pNetCfg, pszwClientDescription, cmsTimeout, ppszwClientDescription);
185 if (hr == S_FALSE)
186 {
187 NonStandardLogFlow(("Write lock is busy\n", hr));
188 hr = NETCFG_E_NO_WRITE_LOCK;
189 }
190 }
191
192 if (SUCCEEDED(hr))
193 {
194 hr = pNetCfg->Initialize(NULL);
195 if (SUCCEEDED(hr))
196 {
197 *ppNetCfg = pNetCfg;
198 return S_OK;
199 }
200 else
201 NonStandardLogFlow(("Initialize failed, hr (0x%x)\n", hr));
202 }
203
204 pNetCfg->Release();
205 return hr;
206}
207
208VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pNetCfg, IN BOOL fHasWriteLock)
209{
210 if (!pNetCfg) /* If network config has been released already, just bail out. */
211 {
212 NonStandardLogFlow(("Warning: No network config given but write lock is set to TRUE\n"));
213 return S_OK;
214 }
215
216 HRESULT hr = pNetCfg->Uninitialize();
217 if (FAILED(hr))
218 {
219 NonStandardLogFlow(("Uninitialize failed, hr (0x%x)\n", hr));
220 /* Try to release the write lock below. */
221 }
222
223 if (fHasWriteLock)
224 {
225 HRESULT hr2 = vboxNetCfgWinINetCfgUnlock(pNetCfg);
226 if (FAILED(hr2))
227 NonStandardLogFlow(("vboxNetCfgWinINetCfgUnlock failed, hr (0x%x)\n", hr2));
228 if (SUCCEEDED(hr))
229 hr = hr2;
230 }
231
232 pNetCfg->Release();
233 return hr;
234}
235
236static HRESULT vboxNetCfgWinGetComponentByGuidEnum(IEnumNetCfgComponent *pEnumNcc,
237 IN const GUID *pGuid,
238 OUT INetCfgComponent **ppNcc)
239{
240 HRESULT hr = pEnumNcc->Reset();
241 if (FAILED(hr))
242 {
243 NonStandardLogFlow(("Reset failed, hr (0x%x)\n", hr));
244 return hr;
245 }
246
247 INetCfgComponent *pNcc;
248 while ((hr = pEnumNcc->Next(1, &pNcc, NULL)) == S_OK)
249 {
250 ULONG uComponentStatus;
251 hr = pNcc->GetDeviceStatus(&uComponentStatus);
252 if (SUCCEEDED(hr))
253 {
254 if (uComponentStatus == 0)
255 {
256 GUID NccGuid;
257 hr = pNcc->GetInstanceGuid(&NccGuid);
258
259 if (SUCCEEDED(hr))
260 {
261 if (NccGuid == *pGuid)
262 {
263 /* found the needed device */
264 *ppNcc = pNcc;
265 break;
266 }
267 }
268 else
269 NonStandardLogFlow(("GetInstanceGuid failed, hr (0x%x)\n", hr));
270 }
271 }
272
273 pNcc->Release();
274 }
275 return hr;
276}
277
278VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc,
279 IN const GUID *pguidClass,
280 IN const GUID * pComponentGuid,
281 OUT INetCfgComponent **ppncc)
282{
283 IEnumNetCfgComponent *pEnumNcc;
284 HRESULT hr = pNc->EnumComponents(pguidClass, &pEnumNcc);
285
286 if (SUCCEEDED(hr))
287 {
288 hr = vboxNetCfgWinGetComponentByGuidEnum(pEnumNcc, pComponentGuid, ppncc);
289 if (hr == S_FALSE)
290 {
291 NonStandardLogFlow(("Component not found\n"));
292 }
293 else if (FAILED(hr))
294 {
295 NonStandardLogFlow(("vboxNetCfgWinGetComponentByGuidEnum failed, hr (0x%x)\n", hr));
296 }
297 pEnumNcc->Release();
298 }
299 else
300 NonStandardLogFlow(("EnumComponents failed, hr (0x%x)\n", hr));
301 return hr;
302}
303
304static HRESULT vboxNetCfgWinQueryInstaller(IN INetCfg *pNetCfg, IN const GUID *pguidClass, INetCfgClassSetup **ppSetup)
305{
306 HRESULT hr = pNetCfg->QueryNetCfgClass(pguidClass, IID_INetCfgClassSetup, (void**)ppSetup);
307 if (FAILED(hr))
308 NonStandardLogFlow(("QueryNetCfgClass failed, hr (0x%x)\n", hr));
309 return hr;
310}
311
312VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
313 OUT INetCfgComponent **ppComponent)
314{
315 INetCfgClassSetup *pSetup;
316 HRESULT hr = vboxNetCfgWinQueryInstaller(pNetCfg, pguidClass, &pSetup);
317 if (FAILED(hr))
318 {
319 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed, hr (0x%x)\n", hr));
320 return hr;
321 }
322
323 OBO_TOKEN Token;
324 ZeroMemory(&Token, sizeof (Token));
325 Token.Type = OBO_USER;
326 INetCfgComponent* pTempComponent = NULL;
327
328 hr = pSetup->Install(pszwComponentId, &Token,
329 0, /* IN DWORD dwSetupFlags */
330 0, /* IN DWORD dwUpgradeFromBuildNo */
331 NULL, /* IN LPCWSTR pszwAnswerFile */
332 NULL, /* IN LPCWSTR pszwAnswerSections */
333 &pTempComponent);
334 if (SUCCEEDED(hr))
335 {
336 if (pTempComponent != NULL)
337 {
338 HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
339 HRESULT res;
340
341 /*
342 * Set default metric value of interface to fix multicast issue
343 * See @bugref{6379} for details.
344 */
345 res = pTempComponent->OpenParamKey(&hkey);
346
347 /* Set default metric value for host-only interface only */
348 if ( SUCCEEDED(res)
349 && hkey != INVALID_HANDLE_VALUE
350 && wcsnicmp(pszwComponentId, VBOXNETCFGWIN_NETADP_ID, 256) == 0)
351 {
352 NET_LUID luid;
353 res = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
354
355 /* Close the key as soon as possible. See @bugref{7973}. */
356 RegCloseKey (hkey);
357 hkey = (HKEY)INVALID_HANDLE_VALUE;
358
359 if (FAILED(res))
360 {
361 /*
362 * The setting of Metric is not very important functionality,
363 * So we will not break installation process due to this error.
364 */
365 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! "
366 "vboxNetCfgWinGetInterfaceLUID failed, default metric "
367 "for new interface will not be set, hr (0x%x)\n", res));
368 }
369 else
370 {
371 res = vboxNetCfgWinSetupMetric(&luid);
372 if (FAILED(res))
373 {
374 /*
375 * The setting of Metric is not very important functionality,
376 * So we will not break installation process due to this error.
377 */
378 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! "
379 "vboxNetCfgWinSetupMetric failed, default metric "
380 "for new interface will not be set, hr (0x%x)\n", res));
381 }
382 }
383 }
384 if (hkey != INVALID_HANDLE_VALUE)
385 {
386 RegCloseKey (hkey);
387 hkey = (HKEY)INVALID_HANDLE_VALUE;
388 }
389 if (ppComponent != NULL)
390 *ppComponent = pTempComponent;
391 else
392 pTempComponent->Release();
393 }
394
395 /* ignore the apply failure */
396 HRESULT tmpHr = pNetCfg->Apply();
397 Assert(tmpHr == S_OK);
398 if (tmpHr != S_OK)
399 NonStandardLogFlow(("Apply failed, hr (0x%x)\n", tmpHr));
400 }
401 else
402 NonStandardLogFlow(("Install failed, hr (0x%x)\n", hr));
403
404 pSetup->Release();
405 return hr;
406}
407
408static HRESULT vboxNetCfgWinInstallInfAndComponent(IN INetCfg *pNetCfg, IN LPCWSTR pszwComponentId, IN const GUID *pguidClass,
409 IN LPCWSTR const *apInfPaths, IN UINT cInfPaths,
410 OUT INetCfgComponent **ppComponent)
411{
412 HRESULT hr = S_OK;
413 UINT cFilesProcessed = 0;
414
415 NonStandardLogFlow(("Installing %u INF files ...\n", cInfPaths));
416
417 for (; cFilesProcessed < cInfPaths; cFilesProcessed++)
418 {
419 NonStandardLogFlow(("Installing INF file \"%ws\" ...\n", apInfPaths[cFilesProcessed]));
420 hr = VBoxDrvCfgInfInstall(apInfPaths[cFilesProcessed]);
421 if (FAILED(hr))
422 {
423 NonStandardLogFlow(("VBoxNetCfgWinInfInstall failed, hr (0x%x)\n", hr));
424 break;
425 }
426 }
427
428 if (SUCCEEDED(hr))
429 {
430 hr = VBoxNetCfgWinInstallComponent(pNetCfg, pszwComponentId, pguidClass, ppComponent);
431 if (FAILED(hr))
432 NonStandardLogFlow(("VBoxNetCfgWinInstallComponent failed, hr (0x%x)\n", hr));
433 }
434
435 if (FAILED(hr))
436 {
437 NonStandardLogFlow(("Installation failed, rolling back installation set ...\n"));
438
439 do
440 {
441 HRESULT hr2 = VBoxDrvCfgInfUninstall(apInfPaths[cFilesProcessed], 0);
442 if (FAILED(hr2))
443 NonStandardLogFlow(("VBoxDrvCfgInfUninstall failed, hr (0x%x)\n", hr2));
444 /* Keep going. */
445 if (!cFilesProcessed)
446 break;
447 } while (cFilesProcessed--);
448
449 NonStandardLogFlow(("Rollback complete\n"));
450 }
451
452 return hr;
453}
454
455VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUninstallComponent(IN INetCfg *pNetCfg, IN INetCfgComponent *pComponent)
456{
457 GUID GuidClass;
458 HRESULT hr = pComponent->GetClassGuid(&GuidClass);
459 if (FAILED(hr))
460 {
461 NonStandardLogFlow(("GetClassGuid failed, hr (0x%x)\n", hr));
462 return hr;
463 }
464
465 INetCfgClassSetup *pSetup = NULL;
466 hr = vboxNetCfgWinQueryInstaller(pNetCfg, &GuidClass, &pSetup);
467 if (FAILED(hr))
468 {
469 NonStandardLogFlow(("vboxNetCfgWinQueryInstaller failed, hr (0x%x)\n", hr));
470 return hr;
471 }
472
473 OBO_TOKEN Token;
474 ZeroMemory(&Token, sizeof(Token));
475 Token.Type = OBO_USER;
476
477 hr = pSetup->DeInstall(pComponent, &Token, NULL /* OUT LPWSTR *pmszwRefs */);
478 if (SUCCEEDED(hr))
479 {
480 hr = pNetCfg->Apply();
481 if (FAILED(hr))
482 NonStandardLogFlow(("Apply failed, hr (0x%x)\n", hr));
483 }
484 else
485 NonStandardLogFlow(("DeInstall failed, hr (0x%x)\n", hr));
486
487 if (pSetup)
488 pSetup->Release();
489 return hr;
490}
491
492typedef BOOL (*VBOXNETCFGWIN_NETCFGENUM_CALLBACK) (IN INetCfg *pNetCfg, IN INetCfgComponent *pNetCfgComponent, PVOID pContext);
493
494static HRESULT vboxNetCfgWinEnumNetCfgComponents(IN INetCfg *pNetCfg,
495 IN const GUID *pguidClass,
496 VBOXNETCFGWIN_NETCFGENUM_CALLBACK callback,
497 PVOID pContext)
498{
499 IEnumNetCfgComponent *pEnumComponent;
500 HRESULT hr = pNetCfg->EnumComponents(pguidClass, &pEnumComponent);
501 if (SUCCEEDED(hr))
502 {
503 INetCfgComponent *pNetCfgComponent;
504 hr = pEnumComponent->Reset();
505 do
506 {
507 hr = pEnumComponent->Next(1, &pNetCfgComponent, NULL);
508 if (hr == S_OK)
509 {
510// ULONG uComponentStatus;
511// hr = pNcc->GetDeviceStatus(&uComponentStatus);
512// if (SUCCEEDED(hr))
513 BOOL fResult = FALSE;
514 if (pNetCfgComponent)
515 {
516 if (pContext)
517 fResult = callback(pNetCfg, pNetCfgComponent, pContext);
518 pNetCfgComponent->Release();
519 }
520
521 if (!fResult)
522 break;
523 }
524 else
525 {
526 if (hr == S_FALSE)
527 {
528 hr = S_OK;
529 }
530 else
531 NonStandardLogFlow(("Next failed, hr (0x%x)\n", hr));
532 break;
533 }
534 } while (true);
535 pEnumComponent->Release();
536 }
537 return hr;
538}
539
540/*
541 * Forward declarations of functions used in vboxNetCfgWinRemoveAllNetDevicesOfIdCallback.
542 */
543VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf);
544VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(LPWSTR pGuid, PCWSTR NewName);
545
546static BOOL vboxNetCfgWinRemoveAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pvContext)
547{
548 RT_NOREF1(pvContext);
549 SP_REMOVEDEVICE_PARAMS rmdParams;
550 memset(&rmdParams, 0, sizeof(SP_REMOVEDEVICE_PARAMS));
551 rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
552 rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
553 rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
554
555 if (SetupDiSetClassInstallParams(hDevInfo,pDev,
556 &rmdParams.ClassInstallHeader, sizeof(rmdParams)))
557 {
558 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
559 {
560#ifndef VBOXNETCFG_DELAYEDRENAME
561 /* Figure out NetCfgInstanceId. */
562 HKEY hKey = SetupDiOpenDevRegKey(hDevInfo,
563 pDev,
564 DICS_FLAG_GLOBAL,
565 0,
566 DIREG_DRV,
567 KEY_READ);
568 if (hKey == INVALID_HANDLE_VALUE)
569 {
570 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiOpenDevRegKey failed with error %ld\n",
571 GetLastError()));
572 }
573 else
574 {
575 WCHAR wszCfgGuidString[50] = { L'' };
576 DWORD cbSize = sizeof(wszCfgGuidString);
577 DWORD dwValueType;
578 DWORD ret = RegQueryValueExW(hKey, L"NetCfgInstanceId", NULL,
579 &dwValueType, (LPBYTE)wszCfgGuidString, &cbSize);
580 if (ret == ERROR_SUCCESS)
581 {
582 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Processing device ID \"%S\"\n",
583 wszCfgGuidString));
584
585 /* Figure out device name. */
586 WCHAR wszDevName[256], wszTempName[256];
587 ULONG cbName = sizeof(wszTempName);
588
589 if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, pDev,
590 SPDRP_FRIENDLYNAME, /* IN DWORD Property,*/
591 NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL*/
592 (PBYTE)wszDevName, /* OUT PBYTE PropertyBuffer,*/
593 sizeof(wszDevName), /* IN DWORD PropertyBufferSize,*/
594 NULL /* OUT PDWORD RequiredSize OPTIONAL*/))
595 {
596 /*
597 * Rename the connection before removing the device. This will
598 * hopefully prevent an error when we will be attempting
599 * to rename a newly created connection (see @bugref{6740}).
600 */
601 HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszTempName, &cbName);
602 wcscat_s(wszTempName, sizeof(wszTempName), L" removed");
603 if (SUCCEEDED(hr))
604 hr = VBoxNetCfgWinRenameConnection(wszCfgGuidString, wszTempName);
605 //NonStandardLogFlow(("VBoxNetCfgWinRenameConnection(%S,%S) => 0x%x\n", pWCfgGuidString, TempName, hr_tmp));
606 }
607 else
608 {
609 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Failed to get friendly name for device \"%S\"\n",
610 wszCfgGuidString));
611 }
612 }
613 else
614 {
615 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: Querying instance ID failed with %d\n",
616 ret));
617 }
618
619 RegCloseKey(hKey);
620 }
621#endif /* VBOXNETCFG_DELAYEDRENAME */
622
623 if (SetupDiCallClassInstaller(DIF_REMOVE, hDevInfo, pDev))
624 {
625 SP_DEVINSTALL_PARAMS devParams;
626 memset(&devParams, 0, sizeof(SP_DEVINSTALL_PARAMS));
627 devParams.cbSize = sizeof(devParams);
628
629 if (SetupDiGetDeviceInstallParams(hDevInfo, pDev, &devParams))
630 {
631 if ( (devParams.Flags & DI_NEEDRESTART)
632 || (devParams.Flags & DI_NEEDREBOOT))
633 {
634 NonStandardLog(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: A reboot is required\n"));
635 }
636 }
637 else
638 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %ld\n",
639 GetLastError()));
640 }
641 else
642 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
643 GetLastError()));
644 }
645 else
646 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetSelectedDevice failed with %ld\n",
647 GetLastError()));
648 }
649 else
650 NonStandardLogFlow(("vboxNetCfgWinRemoveAllNetDevicesOfIdCallback: SetupDiSetClassInstallParams failed with %ld\n",
651 GetLastError()));
652
653 /* Continue enumeration. */
654 return TRUE;
655}
656
657typedef struct VBOXNECTFGWINPROPCHANGE
658{
659 VBOXNECTFGWINPROPCHANGE_TYPE enmPcType;
660 HRESULT hr;
661} VBOXNECTFGWINPROPCHANGE ,*PVBOXNECTFGWINPROPCHANGE;
662
663static BOOL vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
664{
665 PVBOXNECTFGWINPROPCHANGE pPc = (PVBOXNECTFGWINPROPCHANGE)pContext;
666
667 SP_PROPCHANGE_PARAMS PcParams;
668 memset (&PcParams, 0, sizeof (PcParams));
669 PcParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
670 PcParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
671 PcParams.Scope = DICS_FLAG_GLOBAL;
672
673 switch(pPc->enmPcType)
674 {
675 case VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE:
676 PcParams.StateChange = DICS_DISABLE;
677 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_DISABLE): %d\n", pPc->enmPcType));
678 break;
679 case VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE:
680 PcParams.StateChange = DICS_ENABLE;
681 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Change type (DICS_ENABLE): %d\n", pPc->enmPcType));
682 break;
683 default:
684 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: Unexpected prop change type: %d\n", pPc->enmPcType));
685 pPc->hr = E_INVALIDARG;
686 return FALSE;
687 }
688
689 if (SetupDiSetClassInstallParams(hDevInfo, pDev, &PcParams.ClassInstallHeader, sizeof(PcParams)))
690 {
691 if (SetupDiSetSelectedDevice(hDevInfo, pDev))
692 {
693 if (SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, pDev))
694 {
695 SP_DEVINSTALL_PARAMS devParams;
696 devParams.cbSize = sizeof(devParams);
697 if (SetupDiGetDeviceInstallParams(hDevInfo,pDev,&devParams))
698 {
699 if ( (devParams.Flags & DI_NEEDRESTART)
700 || (devParams.Flags & DI_NEEDREBOOT))
701 {
702 NonStandardLog(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: A reboot is required\n"));
703 }
704 }
705 else
706 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiGetDeviceInstallParams failed with %ld\n",
707 GetLastError()));
708 }
709 else
710 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback: SetupDiCallClassInstaller failed with %ld\n",
711 GetLastError()));
712 }
713 else
714 NonStandardLogFlow(("SetupDiSetSelectedDevice failed with %ld\n", GetLastError()));
715 }
716 else
717 NonStandardLogFlow(("SetupDiSetClassInstallParams failed with %ld\n", GetLastError()));
718
719 /* Continue enumeration. */
720 return TRUE;
721}
722
723typedef BOOL (*PFNVBOXNETCFGWINNETENUMCALLBACK)(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext);
724VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnumNetDevices(LPCWSTR pwszPnPId,
725 PFNVBOXNETCFGWINNETENUMCALLBACK pfnCallback, PVOID pvContext)
726{
727 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Searching for: %S\n", pwszPnPId));
728
729 HRESULT hr;
730 HDEVINFO hDevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET,
731 NULL, /* IN PCTSTR Enumerator, OPTIONAL */
732 NULL, /* IN HWND hwndParent, OPTIONAL */
733 DIGCF_PRESENT, /* IN DWORD Flags,*/
734 NULL, /* IN HDEVINFO DeviceInfoSet, OPTIONAL */
735 NULL, /* IN PCTSTR MachineName, OPTIONAL */
736 NULL /* IN PVOID Reserved */);
737 if (hDevInfo != INVALID_HANDLE_VALUE)
738 {
739 DWORD winEr = NO_ERROR;
740
741 DWORD dwDevId = 0;
742 size_t cPnPId = wcslen(pwszPnPId);
743
744 PBYTE pBuffer = NULL;
745
746 for (;;)
747 {
748 SP_DEVINFO_DATA Dev;
749 memset(&Dev, 0, sizeof(SP_DEVINFO_DATA));
750 Dev.cbSize = sizeof(SP_DEVINFO_DATA);
751
752 if (!SetupDiEnumDeviceInfo(hDevInfo, dwDevId, &Dev))
753 {
754 winEr = GetLastError();
755 if (winEr == ERROR_NO_MORE_ITEMS)
756 winEr = ERROR_SUCCESS;
757 break;
758 }
759
760 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Enumerating device %ld ... \n", dwDevId));
761 dwDevId++;
762
763 if (pBuffer)
764 free(pBuffer);
765 pBuffer = NULL;
766 DWORD cbBuffer = 0;
767 DWORD cbRequired = 0;
768
769 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &Dev,
770 SPDRP_HARDWAREID, /* IN DWORD Property */
771 NULL, /* OUT PDWORD PropertyRegDataType OPTIONAL */
772 pBuffer, /* OUT PBYTE PropertyBuffer */
773 cbBuffer, /* IN DWORD PropertyBufferSize */
774 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
775 {
776 winEr = GetLastError();
777 if (winEr != ERROR_INSUFFICIENT_BUFFER)
778 {
779 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (1) failed with %ld\n", winEr));
780 break;
781 }
782
783 pBuffer = (PBYTE)malloc(cbRequired);
784 if (!pBuffer)
785 {
786 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Out of memory allocating %ld bytes\n",
787 cbRequired));
788 winEr = ERROR_OUTOFMEMORY;
789 break;
790 }
791
792 cbBuffer = cbRequired;
793
794 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo,&Dev,
795 SPDRP_HARDWAREID, /* IN DWORD Property */
796 NULL, /* OUT PDWORD PropertyRegDataType, OPTIONAL */
797 pBuffer, /* OUT PBYTE PropertyBuffer */
798 cbBuffer, /* IN DWORD PropertyBufferSize */
799 &cbRequired /* OUT PDWORD RequiredSize OPTIONAL */))
800 {
801 winEr = GetLastError();
802 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetDeviceRegistryPropertyW (2) failed with %ld\n",
803 winEr));
804 break;
805 }
806 }
807
808 PWSTR pCurId = (PWSTR)pBuffer;
809 size_t cCurId = wcslen(pCurId);
810
811 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Device %ld: %S\n", dwDevId, pCurId));
812
813 if (cCurId >= cPnPId)
814 {
815 NonStandardLogFlow(("!wcsnicmp(pCurId = (%S), pwszPnPId = (%S), cPnPId = (%d))\n", pCurId, pwszPnPId, cPnPId));
816
817 pCurId += cCurId - cPnPId;
818 if (!wcsnicmp(pCurId, pwszPnPId, cPnPId))
819 {
820 if (!pfnCallback(hDevInfo, &Dev, pvContext))
821 break;
822 }
823 }
824 }
825
826 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Found %ld devices total\n", dwDevId));
827
828 if (pBuffer)
829 free(pBuffer);
830
831 hr = HRESULT_FROM_WIN32(winEr);
832
833 SetupDiDestroyDeviceInfoList(hDevInfo);
834 }
835 else
836 {
837 DWORD winEr = GetLastError();
838 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: SetupDiGetClassDevsExW failed with %ld\n", winEr));
839 hr = HRESULT_FROM_WIN32(winEr);
840 }
841
842 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices: Ended with hr (0x%x)\n", hr));
843 return hr;
844}
845
846VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR lpszPnPId)
847{
848 return VBoxNetCfgWinEnumNetDevices(lpszPnPId, vboxNetCfgWinRemoveAllNetDevicesOfIdCallback, NULL);
849}
850
851VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR lpszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE enmPcType)
852{
853 VBOXNECTFGWINPROPCHANGE Pc;
854 Pc.enmPcType = enmPcType;
855 Pc.hr = S_OK;
856 NonStandardLogFlow(("Calling VBoxNetCfgWinEnumNetDevices with lpszPnPId =(%S) and vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback\n", lpszPnPId));
857
858 HRESULT hr = VBoxNetCfgWinEnumNetDevices(lpszPnPId, vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback, &Pc);
859 if (!SUCCEEDED(hr))
860 {
861 NonStandardLogFlow(("VBoxNetCfgWinEnumNetDevices failed 0x%x\n", hr));
862 return hr;
863 }
864
865 if (!SUCCEEDED(Pc.hr))
866 {
867 NonStandardLogFlow(("vboxNetCfgWinPropChangeAllNetDevicesOfIdCallback failed 0x%x\n", Pc.hr));
868 return Pc.hr;
869 }
870
871 return S_OK;
872}
873
874/*
875 * logging
876 */
877static void DoLogging(const char *pszString, ...)
878{
879 PFNVBOXNETCFGLOGGER pfnLogger = g_pfnLogger;
880 if (pfnLogger)
881 {
882 char szBuffer[4096] = {0};
883 va_list va;
884 va_start(va, pszString);
885 _vsnprintf(szBuffer, RT_ELEMENTS(szBuffer), pszString, va);
886 va_end(va);
887
888 pfnLogger(szBuffer);
889 }
890}
891
892VBOXNETCFGWIN_DECL(void) VBoxNetCfgWinSetLogging(IN PFNVBOXNETCFGLOGGER pfnLogger)
893{
894 g_pfnLogger = pfnLogger;
895}
896
897/*
898 * IP configuration API
899 */
900/* network settings config */
901/**
902 * Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
903 */
904template <class C>
905class ComStrongRef
906{
907protected:
908
909 static void addref (C *p) { p->AddRef(); }
910 static void release (C *p) { p->Release(); }
911};
912
913
914/**
915 * Base template for smart COM pointers. Not intended to be used directly.
916 */
917template <class C, template <class> class RefOps = ComStrongRef>
918class ComPtrBase : protected RefOps <C>
919{
920public:
921
922 /* special template to disable AddRef()/Release() */
923 template <class I>
924 class NoAddRefRelease : public I
925 {
926 public:
927 virtual ~NoAddRefRelease() { /* Make VC++ 19.2 happy. */ }
928 private:
929#ifndef VBOX_WITH_XPCOM
930 STDMETHOD_(ULONG, AddRef)() = 0;
931 STDMETHOD_(ULONG, Release)() = 0;
932#else
933 NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
934 NS_IMETHOD_(nsrefcnt) Release(void) = 0;
935#endif
936 };
937
938protected:
939
940 ComPtrBase () : p (NULL) {}
941 ComPtrBase (const ComPtrBase &that) : p (that.p) { addref(); }
942 ComPtrBase (C *that_p) : p (that_p) { addref(); }
943
944 ~ComPtrBase() { release(); }
945
946 ComPtrBase &operator= (const ComPtrBase &that)
947 {
948 safe_assign (that.p);
949 return *this;
950 }
951
952 ComPtrBase &operator= (C *that_p)
953 {
954 safe_assign (that_p);
955 return *this;
956 }
957
958public:
959
960 void setNull()
961 {
962 release();
963 p = NULL;
964 }
965
966 bool isNull() const
967 {
968 return (p == NULL);
969 }
970
971 bool operator! () const { return isNull(); }
972
973 bool operator< (C* that_p) const { return p < that_p; }
974 bool operator== (C* that_p) const { return p == that_p; }
975
976 template <class I>
977 bool equalsTo (I *aThat) const
978 {
979 return ComPtrEquals (p, aThat);
980 }
981
982 template <class OC>
983 bool equalsTo (const ComPtrBase <OC> &oc) const
984 {
985 return equalsTo ((OC *) oc);
986 }
987
988 /** Intended to pass instances as in parameters to interface methods */
989 operator C* () const { return p; }
990
991 /**
992 * Dereferences the instance (redirects the -> operator to the managed
993 * pointer).
994 */
995 NoAddRefRelease <C> *operator-> () const
996 {
997 AssertMsg (p, ("Managed pointer must not be null\n"));
998 return (NoAddRefRelease <C> *) p;
999 }
1000
1001 template <class I>
1002 HRESULT queryInterfaceTo (I **pp) const
1003 {
1004 if (pp)
1005 {
1006 if (p)
1007 {
1008 return p->QueryInterface (COM_IIDOF (I), (void **) pp);
1009 }
1010 else
1011 {
1012 *pp = NULL;
1013 return S_OK;
1014 }
1015 }
1016
1017 return E_INVALIDARG;
1018 }
1019
1020 /** Intended to pass instances as out parameters to interface methods */
1021 C **asOutParam()
1022 {
1023 setNull();
1024 return &p;
1025 }
1026
1027private:
1028
1029 void addref()
1030 {
1031 if (p)
1032 RefOps <C>::addref (p);
1033 }
1034
1035 void release()
1036 {
1037 if (p)
1038 RefOps <C>::release (p);
1039 }
1040
1041 void safe_assign (C *that_p)
1042 {
1043 /* be aware of self-assignment */
1044 if (that_p)
1045 RefOps <C>::addref (that_p);
1046 release();
1047 p = that_p;
1048 }
1049
1050 C *p;
1051};
1052
1053/**
1054 * Smart COM pointer wrapper that automatically manages refcounting of
1055 * interface pointers.
1056 *
1057 * @param I COM interface class
1058 */
1059template <class I, template <class> class RefOps = ComStrongRef>
1060class ComPtr : public ComPtrBase <I, RefOps>
1061{
1062 typedef ComPtrBase <I, RefOps> Base;
1063
1064public:
1065
1066 ComPtr () : Base() {}
1067 ComPtr (const ComPtr &that) : Base(that) {}
1068 ComPtr &operator= (const ComPtr &that)
1069 {
1070 Base::operator= (that);
1071 return *this;
1072 }
1073
1074 template <class OI>
1075 ComPtr (OI *that_p) : Base () { operator= (that_p); }
1076
1077 /* specialization for I */
1078 ComPtr (I *that_p) : Base (that_p) {}
1079
1080 template <class OC>
1081 ComPtr (const ComPtr <OC, RefOps> &oc) : Base () { operator= ((OC *) oc); }
1082
1083 template <class OI>
1084 ComPtr &operator= (OI *that_p)
1085 {
1086 if (that_p)
1087 that_p->QueryInterface (COM_IIDOF (I), (void **) Base::asOutParam());
1088 else
1089 Base::setNull();
1090 return *this;
1091 }
1092
1093 /* specialization for I */
1094 ComPtr &operator=(I *that_p)
1095 {
1096 Base::operator= (that_p);
1097 return *this;
1098 }
1099
1100 template <class OC>
1101 ComPtr &operator= (const ComPtr <OC, RefOps> &oc)
1102 {
1103 return operator= ((OC *) oc);
1104 }
1105};
1106
1107static HRESULT netIfWinFindAdapterClassById(IWbemServices * pSvc, const GUID * pGuid, IWbemClassObject **pAdapterConfig)
1108{
1109 HRESULT hr;
1110 WCHAR wszQuery[256];
1111 WCHAR wszGuid[50];
1112
1113 int length = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
1114 if (length)
1115 {
1116 swprintf(wszQuery, L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"%s\"", wszGuid);
1117 IEnumWbemClassObject* pEnumerator = NULL;
1118 hr = pSvc->ExecQuery(bstr_t("WQL"), bstr_t(wszQuery), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
1119 NULL, &pEnumerator);
1120 if (SUCCEEDED(hr))
1121 {
1122 if (pEnumerator)
1123 {
1124 IWbemClassObject *pclsObj;
1125 ULONG uReturn = 0;
1126 hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
1127 NonStandardLogFlow(("netIfWinFindAdapterClassById: IEnumWbemClassObject::Next -> hr=0x%x pclsObj=%p uReturn=%u 42=%u\n",
1128 hr, (void *)pclsObj, uReturn, 42));
1129 if (SUCCEEDED(hr))
1130 {
1131 if (uReturn && pclsObj != NULL)
1132 {
1133 *pAdapterConfig = pclsObj;
1134 pEnumerator->Release();
1135 NonStandardLogFlow(("netIfWinFindAdapterClassById: S_OK and %p\n", *pAdapterConfig));
1136 return S_OK;
1137 }
1138
1139 hr = E_FAIL;
1140 }
1141
1142 pEnumerator->Release();
1143 }
1144 else
1145 {
1146 NonStandardLogFlow(("ExecQuery returned no enumerator\n"));
1147 hr = E_FAIL;
1148 }
1149 }
1150 else
1151 NonStandardLogFlow(("ExecQuery failed (0x%x)\n", hr));
1152 }
1153 else
1154 {
1155 DWORD winEr = GetLastError();
1156 hr = HRESULT_FROM_WIN32( winEr );
1157 if (SUCCEEDED(hr))
1158 hr = E_FAIL;
1159 NonStandardLogFlow(("StringFromGUID2 failed winEr=%u, hr=0x%x\n", winEr, hr));
1160 }
1161
1162 NonStandardLogFlow(("netIfWinFindAdapterClassById: 0x%x and %p\n", hr, *pAdapterConfig));
1163 return hr;
1164}
1165
1166static HRESULT netIfWinIsHostOnly(IWbemClassObject * pAdapterConfig, BOOL * pbIsHostOnly)
1167{
1168 VARIANT vtServiceName;
1169 VariantInit(&vtServiceName);
1170
1171 HRESULT hr = pAdapterConfig->Get(L"ServiceName", 0 /*lFlags*/, &vtServiceName, NULL /*pvtType*/, NULL /*plFlavor*/);
1172 if (SUCCEEDED(hr))
1173 {
1174 *pbIsHostOnly = bstr_t(vtServiceName.bstrVal) == bstr_t("VBoxNetAdp");
1175
1176 VariantClear(&vtServiceName);
1177 }
1178
1179 return hr;
1180}
1181
1182static HRESULT netIfWinGetIpSettings(IWbemClassObject * pAdapterConfig, ULONG *pIpv4, ULONG *pMaskv4)
1183{
1184 VARIANT vtIp;
1185 HRESULT hr;
1186 VariantInit(&vtIp);
1187
1188 *pIpv4 = 0;
1189 *pMaskv4 = 0;
1190
1191 hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1192 if (SUCCEEDED(hr))
1193 {
1194 if (vtIp.vt == (VT_ARRAY | VT_BSTR))
1195 {
1196 VARIANT vtMask;
1197 VariantInit(&vtMask);
1198 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1199 if (SUCCEEDED(hr))
1200 {
1201 if (vtMask.vt == (VT_ARRAY | VT_BSTR))
1202 {
1203 SAFEARRAY * pIpArray = vtIp.parray;
1204 SAFEARRAY * pMaskArray = vtMask.parray;
1205 if (pIpArray && pMaskArray)
1206 {
1207 BSTR pCurIp;
1208 BSTR pCurMask;
1209 for (LONG i = 0;
1210 SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
1211 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
1212 i++)
1213 {
1214 bstr_t ip(pCurIp);
1215
1216 ULONG Ipv4 = inet_addr((char*)(ip));
1217 if (Ipv4 != INADDR_NONE)
1218 {
1219 *pIpv4 = Ipv4;
1220 bstr_t mask(pCurMask);
1221 *pMaskv4 = inet_addr((char*)(mask));
1222 break;
1223 }
1224 }
1225 }
1226 }
1227 else
1228 {
1229 *pIpv4 = 0;
1230 *pMaskv4 = 0;
1231 }
1232
1233 VariantClear(&vtMask);
1234 }
1235 }
1236 else
1237 {
1238 *pIpv4 = 0;
1239 *pMaskv4 = 0;
1240 }
1241
1242 VariantClear(&vtIp);
1243 }
1244
1245 return hr;
1246}
1247
1248#if 0 /* unused */
1249
1250static HRESULT netIfWinHasIpSettings(IWbemClassObject * pAdapterConfig, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, bool *pFound)
1251{
1252 VARIANT vtIp;
1253 HRESULT hr;
1254 VariantInit(&vtIp);
1255
1256 *pFound = false;
1257
1258 hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
1259 if (SUCCEEDED(hr))
1260 {
1261 VARIANT vtMask;
1262 VariantInit(&vtMask);
1263 hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
1264 if (SUCCEEDED(hr))
1265 {
1266 SAFEARRAY * pIpArray = vtIp.parray;
1267 SAFEARRAY * pMaskArray = vtMask.parray;
1268 if (pIpArray && pMaskArray)
1269 {
1270 BSTR pIp, pMask;
1271 for (LONG k = 0;
1272 SafeArrayGetElement(pCheckIp, &k, (PVOID)&pIp) == S_OK
1273 && SafeArrayGetElement(pCheckMask, &k, (PVOID)&pMask) == S_OK;
1274 k++)
1275 {
1276 BSTR pCurIp;
1277 BSTR pCurMask;
1278 for (LONG i = 0;
1279 SafeArrayGetElement(pIpArray, &i, (PVOID)&pCurIp) == S_OK
1280 && SafeArrayGetElement(pMaskArray, &i, (PVOID)&pCurMask) == S_OK;
1281 i++)
1282 {
1283 if (!wcsicmp(pCurIp, pIp))
1284 {
1285 if (!wcsicmp(pCurMask, pMask))
1286 *pFound = true;
1287 break;
1288 }
1289 }
1290 }
1291 }
1292
1293
1294 VariantClear(&vtMask);
1295 }
1296
1297 VariantClear(&vtIp);
1298 }
1299
1300 return hr;
1301}
1302
1303static HRESULT netIfWinWaitIpSettings(IWbemServices *pSvc, const GUID * pGuid, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, ULONG sec2Wait, bool *pFound)
1304{
1305 /* on Vista we need to wait for the address to get applied */
1306 /* wait for the address to appear in the list */
1307 HRESULT hr = S_OK;
1308 ULONG i;
1309 *pFound = false;
1310 ComPtr <IWbemClassObject> pAdapterConfig;
1311 for (i = 0;
1312 (hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam())) == S_OK
1313 && (hr = netIfWinHasIpSettings(pAdapterConfig, pCheckIp, pCheckMask, pFound)) == S_OK
1314 && !(*pFound)
1315 && i < sec2Wait/6;
1316 i++)
1317 {
1318 Sleep(6000);
1319 }
1320
1321 return hr;
1322}
1323
1324#endif /* unused */
1325
1326static HRESULT netIfWinCreateIWbemServices(IWbemServices ** ppSvc)
1327{
1328 IWbemLocator *pLoc = NULL;
1329 HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
1330 if (SUCCEEDED(hr))
1331 {
1332 IWbemServices *pSvc = NULL;
1333 hr = pLoc->ConnectServer(bstr_t(L"ROOT\\CIMV2"), /* [in] const BSTR strNetworkResource */
1334 NULL, /* [in] const BSTR strUser */
1335 NULL, /* [in] const BSTR strPassword */
1336 0, /* [in] const BSTR strLocale */
1337 NULL, /* [in] LONG lSecurityFlags */
1338 0, /* [in] const BSTR strAuthority */
1339 0, /* [in] IWbemContext* pCtx */
1340 &pSvc /* [out] IWbemServices** ppNamespace */);
1341 if (SUCCEEDED(hr))
1342 {
1343 hr = CoSetProxyBlanket(pSvc, /* IUnknown * pProxy */
1344 RPC_C_AUTHN_WINNT, /* DWORD dwAuthnSvc */
1345 RPC_C_AUTHZ_NONE, /* DWORD dwAuthzSvc */
1346 NULL, /* WCHAR * pServerPrincName */
1347 RPC_C_AUTHN_LEVEL_CALL, /* DWORD dwAuthnLevel */
1348 RPC_C_IMP_LEVEL_IMPERSONATE, /* DWORD dwImpLevel */
1349 NULL, /* RPC_AUTH_IDENTITY_HANDLE pAuthInfo */
1350 EOAC_NONE /* DWORD dwCapabilities */
1351 );
1352 if (SUCCEEDED(hr))
1353 {
1354 *ppSvc = pSvc;
1355 /* do not need it any more */
1356 pLoc->Release();
1357 return hr;
1358 }
1359 else
1360 NonStandardLogFlow(("CoSetProxyBlanket failed, hr (0x%x)\n", hr));
1361
1362 pSvc->Release();
1363 }
1364 else
1365 NonStandardLogFlow(("ConnectServer failed, hr (0x%x)\n", hr));
1366 pLoc->Release();
1367 }
1368 else
1369 NonStandardLogFlow(("CoCreateInstance failed, hr (0x%x)\n", hr));
1370 return hr;
1371}
1372
1373static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, BSTR * pStr)
1374{
1375 VARIANT index;
1376 HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
1377 if (SUCCEEDED(hr))
1378 {
1379 WCHAR strIndex[8];
1380 swprintf(strIndex, L"%u", index.uintVal);
1381 *pStr = (bstr_t(L"Win32_NetworkAdapterConfiguration.Index='") + strIndex + "'").copy();
1382 }
1383 else
1384 NonStandardLogFlow(("Get failed, hr (0x%x)\n", hr));
1385 return hr;
1386}
1387
1388static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, BSTR ObjPath,
1389 BSTR MethodName, LPWSTR *pArgNames, LPVARIANT *pArgs, UINT cArgs,
1390 IWbemClassObject** ppOutParams
1391 )
1392{
1393 HRESULT hr = S_OK;
1394 ComPtr<IWbemClassObject> pInParamsDefinition;
1395 ComPtr<IWbemClassObject> pClassInstance;
1396
1397 if (cArgs)
1398 {
1399 hr = pClass->GetMethod(MethodName, 0, pInParamsDefinition.asOutParam(), NULL);
1400 if (SUCCEEDED(hr))
1401 {
1402 hr = pInParamsDefinition->SpawnInstance(0, pClassInstance.asOutParam());
1403 if (SUCCEEDED(hr))
1404 {
1405 for (UINT i = 0; i < cArgs; i++)
1406 {
1407 hr = pClassInstance->Put(pArgNames[i], 0,
1408 pArgs[i], 0);
1409 if (FAILED(hr))
1410 break;
1411 }
1412 }
1413 }
1414 }
1415
1416 if (SUCCEEDED(hr))
1417 {
1418 IWbemClassObject* pOutParams = NULL;
1419 hr = pSvc->ExecMethod(ObjPath, MethodName, 0, NULL, pClassInstance, &pOutParams, NULL);
1420 if (SUCCEEDED(hr))
1421 {
1422 *ppOutParams = pOutParams;
1423 }
1424 }
1425
1426 return hr;
1427}
1428
1429static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr* aIp, UINT cIp)
1430{
1431 HRESULT hr = S_OK; /* MSC maybe used uninitialized */
1432 SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIp);
1433 if (pIpArray)
1434 {
1435 for (UINT i = 0; i < cIp; i++)
1436 {
1437 char* addr = inet_ntoa(aIp[i]);
1438 BSTR val = bstr_t(addr).copy();
1439 long aIndex[1];
1440 aIndex[0] = i;
1441 hr = SafeArrayPutElement(pIpArray, aIndex, val);
1442 if (FAILED(hr))
1443 {
1444 SysFreeString(val);
1445 SafeArrayDestroy(pIpArray);
1446 break;
1447 }
1448 }
1449
1450 if (SUCCEEDED(hr))
1451 {
1452 *ppArray = pIpArray;
1453 }
1454 }
1455 else
1456 hr = HRESULT_FROM_WIN32(GetLastError());
1457
1458 return hr;
1459}
1460
1461#if 0 /* unused */
1462static HRESULT netIfWinCreateIpArrayV4V6(SAFEARRAY **ppArray, BSTR Ip)
1463{
1464 HRESULT hr;
1465 SAFEARRAY *pIpArray = SafeArrayCreateVector(VT_BSTR, 0, 1);
1466 if (pIpArray)
1467 {
1468 BSTR val = bstr_t(Ip, false).copy();
1469 long aIndex[1];
1470 aIndex[0] = 0;
1471 hr = SafeArrayPutElement(pIpArray, aIndex, val);
1472 if (FAILED(hr))
1473 {
1474 SysFreeString(val);
1475 SafeArrayDestroy(pIpArray);
1476 }
1477
1478 if (SUCCEEDED(hr))
1479 {
1480 *ppArray = pIpArray;
1481 }
1482 }
1483 else
1484 hr = HRESULT_FROM_WIN32(GetLastError());
1485
1486 return hr;
1487}
1488#endif
1489
1490
1491static HRESULT netIfWinCreateIpArrayVariantV4(VARIANT * pIpAddresses, in_addr* aIp, UINT cIp)
1492{
1493 HRESULT hr;
1494 VariantInit(pIpAddresses);
1495 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1496 SAFEARRAY *pIpArray;
1497 hr = netIfWinCreateIpArray(&pIpArray, aIp, cIp);
1498 if (SUCCEEDED(hr))
1499 {
1500 pIpAddresses->parray = pIpArray;
1501 }
1502 return hr;
1503}
1504
1505#if 0 /* unused */
1506static HRESULT netIfWinCreateIpArrayVariantV4V6(VARIANT * pIpAddresses, BSTR Ip)
1507{
1508 HRESULT hr;
1509 VariantInit(pIpAddresses);
1510 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
1511 SAFEARRAY *pIpArray;
1512 hr = netIfWinCreateIpArrayV4V6(&pIpArray, Ip);
1513 if (SUCCEEDED(hr))
1514 {
1515 pIpAddresses->parray = pIpArray;
1516 }
1517 return hr;
1518}
1519#endif
1520
1521static HRESULT netIfWinEnableStatic(IWbemServices *pSvc, const GUID *pGuid, BSTR ObjPath, VARIANT *pIp, VARIANT *pMask)
1522{
1523 ComPtr<IWbemClassObject> pClass;
1524 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1525 HRESULT hr;
1526 if (ClassName)
1527 {
1528 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1529 if (SUCCEEDED(hr))
1530 {
1531 LPWSTR argNames[] = {L"IPAddress", L"SubnetMask"};
1532 LPVARIANT args[] = {pIp, pMask};
1533 ComPtr<IWbemClassObject> pOutParams;
1534
1535 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableStatic"), argNames, args, 2, pOutParams.asOutParam());
1536 if (SUCCEEDED(hr))
1537 {
1538 VARIANT varReturnValue;
1539 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
1540 &varReturnValue, NULL, 0);
1541 Assert(SUCCEEDED(hr));
1542 if (SUCCEEDED(hr))
1543 {
1544// Assert(varReturnValue.vt == VT_UINT);
1545 int winEr = varReturnValue.uintVal;
1546 switch (winEr)
1547 {
1548 case 0:
1549 {
1550 hr = S_OK;
1551// bool bFound;
1552// HRESULT tmpHr = netIfWinWaitIpSettings(pSvc, pGuid, pIp->parray, pMask->parray, 180, &bFound);
1553 NOREF(pGuid);
1554 break;
1555 }
1556 default:
1557 hr = HRESULT_FROM_WIN32( winEr );
1558 break;
1559 }
1560 }
1561 }
1562 }
1563 SysFreeString(ClassName);
1564 }
1565 else
1566 hr = HRESULT_FROM_WIN32(GetLastError());
1567
1568 return hr;
1569}
1570
1571
1572static HRESULT netIfWinEnableStaticV4(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, in_addr* aIp, in_addr * aMask, UINT cIp)
1573{
1574 VARIANT ipAddresses;
1575 HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, aIp, cIp);
1576 if (SUCCEEDED(hr))
1577 {
1578 VARIANT ipMasks;
1579 hr = netIfWinCreateIpArrayVariantV4(&ipMasks, aMask, cIp);
1580 if (SUCCEEDED(hr))
1581 {
1582 hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
1583 VariantClear(&ipMasks);
1584 }
1585 VariantClear(&ipAddresses);
1586 }
1587 return hr;
1588}
1589
1590#if 0 /* unused */
1591
1592static HRESULT netIfWinEnableStaticV4V6(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, BSTR Ip, BSTR Mask)
1593{
1594 VARIANT ipAddresses;
1595 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&ipAddresses, Ip);
1596 if (SUCCEEDED(hr))
1597 {
1598 VARIANT ipMasks;
1599 hr = netIfWinCreateIpArrayVariantV4V6(&ipMasks, Mask);
1600 if (SUCCEEDED(hr))
1601 {
1602 hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
1603 VariantClear(&ipMasks);
1604 }
1605 VariantClear(&ipAddresses);
1606 }
1607 return hr;
1608}
1609
1610/* win API allows to set gw metrics as well, we are not setting them */
1611static HRESULT netIfWinSetGateways(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pGw)
1612{
1613 ComPtr<IWbemClassObject> pClass;
1614 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1615 HRESULT hr;
1616 if (ClassName)
1617 {
1618 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1619 if (SUCCEEDED(hr))
1620 {
1621 LPWSTR argNames[] = {L"DefaultIPGateway"};
1622 LPVARIANT args[] = {pGw};
1623 ComPtr<IWbemClassObject> pOutParams;
1624
1625 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
1626 if (SUCCEEDED(hr))
1627 {
1628 VARIANT varReturnValue;
1629 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1630 Assert(SUCCEEDED(hr));
1631 if (SUCCEEDED(hr))
1632 {
1633// Assert(varReturnValue.vt == VT_UINT);
1634 int winEr = varReturnValue.uintVal;
1635 switch (winEr)
1636 {
1637 case 0:
1638 hr = S_OK;
1639 break;
1640 default:
1641 hr = HRESULT_FROM_WIN32( winEr );
1642 break;
1643 }
1644 }
1645 }
1646 }
1647 SysFreeString(ClassName);
1648 }
1649 else
1650 hr = HRESULT_FROM_WIN32(GetLastError());
1651
1652 return hr;
1653}
1654
1655/* win API allows to set gw metrics as well, we are not setting them */
1656static HRESULT netIfWinSetGatewaysV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aGw, UINT cGw)
1657{
1658 VARIANT gwais;
1659 HRESULT hr = netIfWinCreateIpArrayVariantV4(&gwais, aGw, cGw);
1660 if (SUCCEEDED(hr))
1661 {
1662 netIfWinSetGateways(pSvc, ObjPath, &gwais);
1663 VariantClear(&gwais);
1664 }
1665 return hr;
1666}
1667
1668/* win API allows to set gw metrics as well, we are not setting them */
1669static HRESULT netIfWinSetGatewaysV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Gw)
1670{
1671 VARIANT vGw;
1672 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&vGw, Gw);
1673 if (SUCCEEDED(hr))
1674 {
1675 netIfWinSetGateways(pSvc, ObjPath, &vGw);
1676 VariantClear(&vGw);
1677 }
1678 return hr;
1679}
1680
1681#endif /* unused */
1682
1683static HRESULT netIfWinEnableDHCP(IWbemServices * pSvc, BSTR ObjPath)
1684{
1685 ComPtr<IWbemClassObject> pClass;
1686 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1687 HRESULT hr;
1688 if (ClassName)
1689 {
1690 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1691 if (SUCCEEDED(hr))
1692 {
1693 ComPtr<IWbemClassObject> pOutParams;
1694
1695 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"EnableDHCP"), NULL, NULL, 0, pOutParams.asOutParam());
1696 if (SUCCEEDED(hr))
1697 {
1698 VARIANT varReturnValue;
1699 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
1700 &varReturnValue, NULL, 0);
1701 Assert(SUCCEEDED(hr));
1702 if (SUCCEEDED(hr))
1703 {
1704// Assert(varReturnValue.vt == VT_UINT);
1705 int winEr = varReturnValue.uintVal;
1706 switch (winEr)
1707 {
1708 case 0:
1709 hr = S_OK;
1710 break;
1711 default:
1712 hr = HRESULT_FROM_WIN32( winEr );
1713 break;
1714 }
1715 }
1716 }
1717 }
1718 SysFreeString(ClassName);
1719 }
1720 else
1721 hr = HRESULT_FROM_WIN32(GetLastError());
1722
1723 return hr;
1724}
1725
1726static HRESULT netIfWinDhcpRediscover(IWbemServices * pSvc, BSTR ObjPath)
1727{
1728 ComPtr<IWbemClassObject> pClass;
1729 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
1730 HRESULT hr;
1731 if (ClassName)
1732 {
1733 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
1734 if (SUCCEEDED(hr))
1735 {
1736 ComPtr<IWbemClassObject> pOutParams;
1737
1738 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"ReleaseDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
1739 if (SUCCEEDED(hr))
1740 {
1741 VARIANT varReturnValue;
1742 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1743 Assert(SUCCEEDED(hr));
1744 if (SUCCEEDED(hr))
1745 {
1746// Assert(varReturnValue.vt == VT_UINT);
1747 int winEr = varReturnValue.uintVal;
1748 if (winEr == 0)
1749 {
1750 hr = netIfExecMethod(pSvc, pClass, ObjPath, bstr_t(L"RenewDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
1751 if (SUCCEEDED(hr))
1752 {
1753 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0, &varReturnValue, NULL, 0);
1754 Assert(SUCCEEDED(hr));
1755 if (SUCCEEDED(hr))
1756 {
1757 // Assert(varReturnValue.vt == VT_UINT);
1758 winEr = varReturnValue.uintVal;
1759 if (winEr == 0)
1760 hr = S_OK;
1761 else
1762 hr = HRESULT_FROM_WIN32( winEr );
1763 }
1764 }
1765 }
1766 else
1767 hr = HRESULT_FROM_WIN32( winEr );
1768 }
1769 }
1770 }
1771 SysFreeString(ClassName);
1772 }
1773 else
1774 hr = HRESULT_FROM_WIN32(GetLastError());
1775
1776 return hr;
1777}
1778
1779static HRESULT vboxNetCfgWinIsDhcpEnabled(IWbemClassObject * pAdapterConfig, BOOL *pEnabled)
1780{
1781 VARIANT vtEnabled;
1782 HRESULT hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
1783 if (SUCCEEDED(hr))
1784 *pEnabled = vtEnabled.boolVal;
1785 return hr;
1786}
1787
1788VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(IN const GUID * pGuid, OUT PADAPTER_SETTINGS pSettings)
1789{
1790 HRESULT hr;
1791 ComPtr <IWbemServices> pSvc;
1792 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1793 if (SUCCEEDED(hr))
1794 {
1795 ComPtr<IWbemClassObject> pAdapterConfig;
1796 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1797 if (SUCCEEDED(hr))
1798 {
1799 hr = vboxNetCfgWinIsDhcpEnabled(pAdapterConfig, &pSettings->bDhcp);
1800 if (SUCCEEDED(hr))
1801 hr = netIfWinGetIpSettings(pAdapterConfig, &pSettings->ip, &pSettings->mask);
1802 }
1803 }
1804
1805 return hr;
1806}
1807
1808VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinIsDhcpEnabled(const GUID * pGuid, BOOL *pEnabled)
1809{
1810 HRESULT hr;
1811 ComPtr <IWbemServices> pSvc;
1812 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1813 if (SUCCEEDED(hr))
1814 {
1815 ComPtr<IWbemClassObject> pAdapterConfig;
1816 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1817 if (SUCCEEDED(hr))
1818 {
1819 VARIANT vtEnabled;
1820 hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
1821 if (SUCCEEDED(hr))
1822 *pEnabled = vtEnabled.boolVal;
1823 }
1824 }
1825
1826 return hr;
1827}
1828
1829VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(IN const GUID *pGuid, IN ULONG ip, IN ULONG mask)
1830{
1831 NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: ip=0x%x mask=0x%x\n", ip, mask));
1832 ComPtr<IWbemServices> pSvc;
1833 HRESULT hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1834 if (SUCCEEDED(hr))
1835 {
1836 ComPtr<IWbemClassObject> pAdapterConfig;
1837 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1838 if (SUCCEEDED(hr))
1839 {
1840 BOOL bIsHostOnly;
1841 hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
1842 if (SUCCEEDED(hr))
1843 {
1844 if (bIsHostOnly)
1845 {
1846 in_addr aIp[1];
1847 in_addr aMask[1];
1848 aIp[0].S_un.S_addr = ip;
1849 aMask[0].S_un.S_addr = mask;
1850
1851 BSTR ObjPath;
1852 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1853 if (SUCCEEDED(hr))
1854 {
1855 hr = netIfWinEnableStaticV4(pSvc, pGuid, ObjPath, aIp, aMask, ip != 0 ? 1 : 0);
1856 if (SUCCEEDED(hr))
1857 {
1858#if 0
1859 in_addr aGw[1];
1860 aGw[0].S_un.S_addr = gw;
1861 hr = netIfWinSetGatewaysV4(pSvc, ObjPath, aGw, 1);
1862 if (SUCCEEDED(hr))
1863#endif
1864 {
1865 }
1866 }
1867 SysFreeString(ObjPath);
1868 }
1869 }
1870 else
1871 {
1872 hr = E_FAIL;
1873 }
1874 }
1875 }
1876 }
1877
1878 NonStandardLogFlow(("VBoxNetCfgWinEnableStaticIpConfig: returns 0x%x\n", hr));
1879 return hr;
1880}
1881
1882#if 0
1883static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, IN_BSTR aIPV6Mask, IN_BSTR aIPV6DefaultGateway)
1884{
1885 HRESULT hr;
1886 ComPtr <IWbemServices> pSvc;
1887 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1888 if (SUCCEEDED(hr))
1889 {
1890 ComPtr<IWbemClassObject> pAdapterConfig;
1891 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1892 if (SUCCEEDED(hr))
1893 {
1894 BSTR ObjPath;
1895 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1896 if (SUCCEEDED(hr))
1897 {
1898 hr = netIfWinEnableStaticV4V6(pSvc, pAdapterConfig, ObjPath, aIPV6Address, aIPV6Mask);
1899 if (SUCCEEDED(hr))
1900 {
1901 if (aIPV6DefaultGateway)
1902 {
1903 hr = netIfWinSetGatewaysV4V6(pSvc, ObjPath, aIPV6DefaultGateway);
1904 }
1905 if (SUCCEEDED(hr))
1906 {
1907// hr = netIfWinUpdateConfig(pIf);
1908 }
1909 }
1910 SysFreeString(ObjPath);
1911 }
1912 }
1913 }
1914
1915 return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
1916}
1917
1918static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
1919{
1920 RTNETADDRIPV6 Mask;
1921 int rc = RTNetPrefixToMaskIPv6(aIPV6MaskPrefixLength, &Mask);
1922 if (RT_SUCCESS(rc))
1923 {
1924 Bstr maskStr = composeIPv6Address(&Mask);
1925 rc = netIfEnableStaticIpConfigV6(pGuid, aIPV6Address, maskStr, NULL);
1926 }
1927 return rc;
1928}
1929#endif
1930
1931VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(IN const GUID *pGuid)
1932{
1933 HRESULT hr;
1934 ComPtr <IWbemServices> pSvc;
1935 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1936 if (SUCCEEDED(hr))
1937 {
1938 ComPtr<IWbemClassObject> pAdapterConfig;
1939 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1940 if (SUCCEEDED(hr))
1941 {
1942 BOOL bIsHostOnly;
1943 hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
1944 if (SUCCEEDED(hr))
1945 {
1946 if (bIsHostOnly)
1947 {
1948 BSTR ObjPath;
1949 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1950 if (SUCCEEDED(hr))
1951 {
1952 hr = netIfWinEnableDHCP(pSvc, ObjPath);
1953 if (SUCCEEDED(hr))
1954 {
1955// hr = netIfWinUpdateConfig(pIf);
1956 }
1957 SysFreeString(ObjPath);
1958 }
1959 }
1960 else
1961 {
1962 hr = E_FAIL;
1963 }
1964 }
1965 }
1966 }
1967
1968
1969 return hr;
1970}
1971
1972VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(IN const GUID *pGuid)
1973{
1974 HRESULT hr;
1975 ComPtr <IWbemServices> pSvc;
1976 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
1977 if (SUCCEEDED(hr))
1978 {
1979 ComPtr<IWbemClassObject> pAdapterConfig;
1980 hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
1981 if (SUCCEEDED(hr))
1982 {
1983 BOOL bIsHostOnly;
1984 hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
1985 if (SUCCEEDED(hr))
1986 {
1987 if (bIsHostOnly)
1988 {
1989 BSTR ObjPath;
1990 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
1991 if (SUCCEEDED(hr))
1992 {
1993 hr = netIfWinDhcpRediscover(pSvc, ObjPath);
1994 if (SUCCEEDED(hr))
1995 {
1996 //hr = netIfWinUpdateConfig(pIf);
1997 }
1998 SysFreeString(ObjPath);
1999 }
2000 }
2001 else
2002 {
2003 hr = E_FAIL;
2004 }
2005 }
2006 }
2007 }
2008
2009
2010 return hr;
2011}
2012
2013static const char *vboxNetCfgWinAddrToStr(char *pszBuf, LPSOCKADDR pAddr)
2014{
2015 switch (pAddr->sa_family)
2016 {
2017 case AF_INET:
2018 sprintf(pszBuf, "%d.%d.%d.%d",
2019 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b1,
2020 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b2,
2021 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b3,
2022 ((PSOCKADDR_IN)pAddr)->sin_addr.S_un.S_un_b.s_b4);
2023 break;
2024 case AF_INET6:
2025 sprintf(pszBuf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
2026 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[0], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[1],
2027 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[2], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[3],
2028 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[4], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[5],
2029 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[6], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[7],
2030 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[8], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[9],
2031 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[10], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[11],
2032 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[12], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[13],
2033 ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[14], ((PSOCKADDR_IN6)pAddr)->sin6_addr.s6_addr[15]);
2034 break;
2035 default:
2036 strcpy(pszBuf, "unknown");
2037 break;
2038 }
2039 return pszBuf;
2040}
2041
2042typedef bool (*PFNVBOXNETCFG_IPSETTINGS_CALLBACK) (ULONG ip, ULONG mask, PVOID pContext);
2043
2044static void vboxNetCfgWinEnumIpConfig(PIP_ADAPTER_ADDRESSES pAddresses, PFNVBOXNETCFG_IPSETTINGS_CALLBACK pfnCallback, PVOID pContext)
2045{
2046 PIP_ADAPTER_ADDRESSES pAdapter;
2047 for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next)
2048 {
2049 char szBuf[80];
2050
2051 NonStandardLogFlow(("+- Enumerating adapter '%ls' %s\n", pAdapter->FriendlyName, pAdapter->AdapterName));
2052 for (PIP_ADAPTER_PREFIX pPrefix = pAdapter->FirstPrefix; pPrefix; pPrefix = pPrefix->Next)
2053 {
2054 const char *pcszAddress = vboxNetCfgWinAddrToStr(szBuf, pPrefix->Address.lpSockaddr);
2055 /* We are concerned with IPv4 only, ignore the rest. */
2056 if (pPrefix->Address.lpSockaddr->sa_family != AF_INET)
2057 {
2058 NonStandardLogFlow(("| +- %s %d: not IPv4, ignoring\n", pcszAddress, pPrefix->PrefixLength));
2059 continue;
2060 }
2061 /* Ignore invalid prefixes as well as host addresses. */
2062 if (pPrefix->PrefixLength < 1 || pPrefix->PrefixLength > 31)
2063 {
2064 NonStandardLogFlow(("| +- %s %d: host or broadcast, ignoring\n", pcszAddress, pPrefix->PrefixLength));
2065 continue;
2066 }
2067 /* Ignore multicast and beyond. */
2068 ULONG ip = ((struct sockaddr_in *)pPrefix->Address.lpSockaddr)->sin_addr.s_addr;
2069 if ((ip & 0xF0) > 224)
2070 {
2071 NonStandardLogFlow(("| +- %s %d: multicast, ignoring\n", pcszAddress, pPrefix->PrefixLength));
2072 continue;
2073 }
2074 ULONG mask = htonl((~(((ULONG)~0) >> pPrefix->PrefixLength)));
2075 bool fContinue = pfnCallback(ip, mask, pContext);
2076 if (!fContinue)
2077 {
2078 NonStandardLogFlow(("| +- %s %d: CONFLICT!\n", pcszAddress, pPrefix->PrefixLength));
2079 return;
2080 }
2081 else
2082 NonStandardLogFlow(("| +- %s %d: no conflict, moving on\n", pcszAddress, pPrefix->PrefixLength));
2083 }
2084 }
2085}
2086
2087typedef struct _IPPROBE_CONTEXT
2088{
2089 ULONG Prefix;
2090 bool bConflict;
2091}IPPROBE_CONTEXT, *PIPPROBE_CONTEXT;
2092
2093#define IPPROBE_INIT(_pContext, _addr) \
2094 ((_pContext)->bConflict = false, \
2095 (_pContext)->Prefix = _addr)
2096
2097#define IPPROBE_INIT_STR(_pContext, _straddr) \
2098 IPROBE_INIT(_pContext, inet_addr(_straddr))
2099
2100static bool vboxNetCfgWinIpProbeCallback (ULONG ip, ULONG mask, PVOID pContext)
2101{
2102 PIPPROBE_CONTEXT pProbe = (PIPPROBE_CONTEXT)pContext;
2103
2104 if ((ip & mask) == (pProbe->Prefix & mask))
2105 {
2106 pProbe->bConflict = true;
2107 return false;
2108 }
2109
2110 return true;
2111}
2112
2113VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(OUT PULONG pNetIp, OUT PULONG pNetMask)
2114{
2115 DWORD dwRc;
2116 HRESULT hr = S_OK;
2117 /*
2118 * MSDN recommends to pre-allocate a 15KB buffer.
2119 */
2120 ULONG uBufLen = 15 * 1024;
2121 PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
2122 if (!pAddresses)
2123 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
2124 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
2125 if (dwRc == ERROR_BUFFER_OVERFLOW)
2126 {
2127 /* Impressive! More than 10 adapters! Get more memory and try again. */
2128 free(pAddresses);
2129 pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
2130 if (!pAddresses)
2131 return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
2132 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
2133 }
2134 if (dwRc == NO_ERROR)
2135 {
2136 IPPROBE_CONTEXT Context;
2137 const ULONG ip192168 = inet_addr("192.168.0.0");
2138 srand(GetTickCount());
2139
2140 *pNetIp = 0;
2141 *pNetMask = 0;
2142
2143 for (int i = 0; i < 255; i++)
2144 {
2145 ULONG ipProbe = rand()*255/RAND_MAX;
2146 ipProbe = ip192168 | (ipProbe << 16);
2147 unsigned char *a = (unsigned char *)&ipProbe;
2148 NonStandardLogFlow(("probing %d.%d.%d.%d\n", a[0], a[1], a[2], a[3]));
2149 IPPROBE_INIT(&Context, ipProbe);
2150 vboxNetCfgWinEnumIpConfig(pAddresses, vboxNetCfgWinIpProbeCallback, &Context);
2151 if (!Context.bConflict)
2152 {
2153 NonStandardLogFlow(("found unused net %d.%d.%d.%d\n", a[0], a[1], a[2], a[3]));
2154 *pNetIp = ipProbe;
2155 *pNetMask = inet_addr("255.255.255.0");
2156 break;
2157 }
2158 }
2159 if (*pNetIp == 0)
2160 dwRc = ERROR_DHCP_ADDRESS_CONFLICT;
2161 }
2162 else
2163 NonStandardLogFlow(("GetAdaptersAddresses err (%d)\n", dwRc));
2164
2165 if (pAddresses)
2166 free(pAddresses);
2167
2168 if (dwRc != NO_ERROR)
2169 {
2170 hr = HRESULT_FROM_WIN32(dwRc);
2171 }
2172
2173 return hr;
2174}
2175
2176/*
2177 * convenience functions to perform netflt/adp manipulations
2178 */
2179#define VBOXNETCFGWIN_NETFLT_ID L"sun_VBoxNetFlt"
2180#define VBOXNETCFGWIN_NETFLT_MP_ID L"sun_VBoxNetFltmp"
2181
2182static HRESULT vboxNetCfgWinNetFltUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
2183{
2184 INetCfgComponent *pNcc = NULL;
2185 HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETFLT_ID, &pNcc);
2186 if (hr == S_OK)
2187 {
2188 NonStandardLog("NetFlt is installed currently, uninstalling ...\n");
2189
2190 hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
2191 NonStandardLogFlow(("NetFlt component uninstallation ended with hr (0x%x)\n", hr));
2192
2193 pNcc->Release();
2194 }
2195 else if (hr == S_FALSE)
2196 {
2197 NonStandardLog("NetFlt is not installed currently\n");
2198 }
2199 else
2200 {
2201 NonStandardLogFlow(("FindComponent failed, hr (0x%x)\n", hr));
2202 }
2203
2204 VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETFLT_ID, InfRmFlags);
2205 VBoxDrvCfgInfUninstallAllF(L"Net", VBOXNETCFGWIN_NETFLT_MP_ID, InfRmFlags);
2206
2207 return hr;
2208}
2209
2210VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc)
2211{
2212 return vboxNetCfgWinNetFltUninstall(pNc, 0);
2213}
2214
2215VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc,
2216 IN LPCWSTR const *apInfFullPaths, IN UINT cInfFullPaths)
2217{
2218 HRESULT hr = vboxNetCfgWinNetFltUninstall(pNc, SUOI_FORCEDELETE);
2219 if (SUCCEEDED(hr))
2220 {
2221 NonStandardLog("NetFlt will be installed ...\n");
2222 hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETFLT_ID,
2223 &GUID_DEVCLASS_NETSERVICE,
2224 apInfFullPaths,
2225 cInfFullPaths,
2226 NULL);
2227 }
2228 return hr;
2229}
2230
2231static HRESULT vboxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, LPCWSTR pwszId, DWORD InfRmFlags)
2232{
2233 NOREF(pNc);
2234 NonStandardLog("Finding NetAdp driver package and trying to uninstall it ...\n");
2235
2236 VBoxDrvCfgInfUninstallAllF(L"Net", pwszId, InfRmFlags);
2237 NonStandardLog("NetAdp is not installed currently\n");
2238 return S_OK;
2239}
2240
2241VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, IN LPCWSTR pwszId)
2242{
2243 return vboxNetCfgWinNetAdpUninstall(pNc, pwszId, SUOI_FORCEDELETE);
2244}
2245
2246VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpInstall(IN INetCfg *pNc,
2247 IN LPCWSTR const pInfFullPath)
2248{
2249 NonStandardLog("NetAdp will be installed ...\n");
2250 HRESULT hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETADP_ID,
2251 &GUID_DEVCLASS_NET,
2252 &pInfFullPath,
2253 1,
2254 NULL);
2255 return hr;
2256}
2257
2258#define VBOXNETCFGWIN_NETLWF_ID L"oracle_VBoxNetLwf"
2259
2260static HRESULT vboxNetCfgWinNetLwfUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
2261{
2262 INetCfgComponent * pNcc = NULL;
2263 HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETLWF_ID, &pNcc);
2264 if (hr == S_OK)
2265 {
2266 NonStandardLog("NetLwf is installed currently, uninstalling ...\n");
2267
2268 hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
2269
2270 pNcc->Release();
2271 }
2272 else if (hr == S_FALSE)
2273 {
2274 NonStandardLog("NetLwf is not installed currently\n");
2275 hr = S_OK;
2276 }
2277 else
2278 {
2279 NonStandardLogFlow(("FindComponent failed, hr (0x%x)\n", hr));
2280 hr = S_OK;
2281 }
2282
2283 VBoxDrvCfgInfUninstallAllF(L"NetService", VBOXNETCFGWIN_NETLWF_ID, InfRmFlags);
2284
2285 return hr;
2286}
2287
2288VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfUninstall(IN INetCfg *pNc)
2289{
2290 return vboxNetCfgWinNetLwfUninstall(pNc, 0);
2291}
2292
2293static void VBoxNetCfgWinFilterLimitWorkaround(void)
2294{
2295 /*
2296 * Need to check if the system has a limit of installed filter drivers. If it
2297 * has, bump the limit to 14, which the maximum value supported by Windows 7.
2298 * Note that we only touch the limit if it is set to the default value (8).
2299 * See @bugref{7899}.
2300 */
2301 HKEY hNetKey;
2302 DWORD dwMaxNumFilters = 0;
2303 DWORD cbMaxNumFilters = sizeof(dwMaxNumFilters);
2304 LONG hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
2305 _T("SYSTEM\\CurrentControlSet\\Control\\Network"),
2306 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hNetKey);
2307 if (SUCCEEDED(hr))
2308 {
2309 hr = RegQueryValueEx(hNetKey, _T("MaxNumFilters"), NULL, NULL,
2310 (LPBYTE)&dwMaxNumFilters, &cbMaxNumFilters);
2311 if (SUCCEEDED(hr) && cbMaxNumFilters == sizeof(dwMaxNumFilters) && dwMaxNumFilters == 8)
2312 {
2313 dwMaxNumFilters = 14;
2314 hr = RegSetValueEx(hNetKey, _T("MaxNumFilters"), 0, REG_DWORD,
2315 (LPBYTE)&dwMaxNumFilters, sizeof(dwMaxNumFilters));
2316 if (SUCCEEDED(hr))
2317 NonStandardLog("Adjusted the installed filter limit to 14...\n");
2318 else
2319 NonStandardLog("Failed to set MaxNumFilters, error code 0x%x\n", hr);
2320 }
2321 RegCloseKey(hNetKey);
2322 }
2323 else
2324 {
2325 NonStandardLog("Failed to open network key, error code 0x%x\n", hr);
2326 }
2327
2328}
2329
2330VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc,
2331 IN LPCWSTR const pInfFullPath)
2332{
2333 HRESULT hr = vboxNetCfgWinNetLwfUninstall(pNc, SUOI_FORCEDELETE);
2334 if (SUCCEEDED(hr))
2335 {
2336 VBoxNetCfgWinFilterLimitWorkaround();
2337 NonStandardLog("NetLwf will be installed ...\n");
2338 hr = vboxNetCfgWinInstallInfAndComponent(pNc, VBOXNETCFGWIN_NETLWF_ID,
2339 &GUID_DEVCLASS_NETSERVICE,
2340 &pInfFullPath,
2341 1,
2342 NULL);
2343 }
2344 return hr;
2345}
2346
2347#define VBOX_CONNECTION_NAME L"VirtualBox Host-Only Network"
2348VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf)
2349{
2350 const WCHAR * pSuffix = wcsrchr( DevName, L'#' );
2351 ULONG cbSize = sizeof(VBOX_CONNECTION_NAME);
2352
2353 if (pSuffix)
2354 {
2355 cbSize += (ULONG)wcslen(pSuffix) * 2;
2356 cbSize += 2; /* for space */
2357 }
2358
2359 if (*pcbBuf < cbSize)
2360 {
2361 *pcbBuf = cbSize;
2362 return E_FAIL;
2363 }
2364
2365 wcscpy(pBuf, VBOX_CONNECTION_NAME);
2366 if (pSuffix)
2367 {
2368 wcscat(pBuf, L" ");
2369 wcscat(pBuf, pSuffix);
2370 }
2371
2372 return S_OK;
2373}
2374
2375static BOOL vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
2376{
2377 RT_NOREF1(pNc);
2378 INetCfgComponentBindings *pNetCfgBindings;
2379 GUID *pGuid = (GUID*)pContext;
2380
2381 /* Get component's binding. */
2382 HRESULT hr = pNcc->QueryInterface(IID_INetCfgComponentBindings, (PVOID*)&pNetCfgBindings);
2383 if (SUCCEEDED(hr))
2384 {
2385 /* Get binding path enumerator reference. */
2386 IEnumNetCfgBindingPath *pEnumNetCfgBindPath;
2387 hr = pNetCfgBindings->EnumBindingPaths(EBP_BELOW, &pEnumNetCfgBindPath);
2388 if (SUCCEEDED(hr))
2389 {
2390 bool bFoundIface = false;
2391 hr = pEnumNetCfgBindPath->Reset();
2392 do
2393 {
2394 INetCfgBindingPath *pNetCfgBindPath;
2395 hr = pEnumNetCfgBindPath->Next(1, &pNetCfgBindPath, NULL);
2396 if (hr == S_OK)
2397 {
2398 IEnumNetCfgBindingInterface *pEnumNetCfgBindIface;
2399 hr = pNetCfgBindPath->EnumBindingInterfaces(&pEnumNetCfgBindIface);
2400 if (hr == S_OK)
2401 {
2402 pEnumNetCfgBindIface->Reset();
2403 do
2404 {
2405 INetCfgBindingInterface *pNetCfgBindIfce;
2406 hr = pEnumNetCfgBindIface->Next(1, &pNetCfgBindIfce, NULL);
2407 if (hr == S_OK)
2408 {
2409 INetCfgComponent *pNetCfgCompo;
2410 hr = pNetCfgBindIfce->GetLowerComponent(&pNetCfgCompo);
2411 if (hr == S_OK)
2412 {
2413 ULONG uComponentStatus;
2414 hr = pNetCfgCompo->GetDeviceStatus(&uComponentStatus);
2415 if (hr == S_OK)
2416 {
2417 GUID guid;
2418 hr = pNetCfgCompo->GetInstanceGuid(&guid);
2419 if ( hr == S_OK
2420 && guid == *pGuid)
2421 {
2422 hr = pNetCfgBindings->MoveAfter(pNetCfgBindPath, NULL);
2423 if (FAILED(hr))
2424 NonStandardLogFlow(("Unable to move interface, hr (0x%x)\n", hr));
2425 bFoundIface = true;
2426 /*
2427 * Enable binding paths for host-only adapters bound to bridged filter
2428 * (see @bugref{8140}).
2429 */
2430 HRESULT hr2;
2431 LPWSTR pwszHwId = NULL;
2432 if ((hr2 = pNcc->GetId(&pwszHwId)) != S_OK)
2433 NonStandardLogFlow(("Failed to get HW ID, hr (0x%x)\n", hr2));
2434 else if (_wcsnicmp(pwszHwId, VBOXNETCFGWIN_NETLWF_ID,
2435 sizeof(VBOXNETCFGWIN_NETLWF_ID)/2))
2436 NonStandardLogFlow(("Ignoring component %ls\n", pwszHwId));
2437 else if ((hr2 = pNetCfgBindPath->IsEnabled()) != S_FALSE)
2438 NonStandardLogFlow(("Already enabled binding path, hr (0x%x)\n", hr2));
2439 else if ((hr2 = pNetCfgBindPath->Enable(TRUE)) != S_OK)
2440 NonStandardLogFlow(("Failed to enable binding path, hr (0x%x)\n", hr2));
2441 else
2442 NonStandardLogFlow(("Enabled binding path\n"));
2443 if (pwszHwId)
2444 CoTaskMemFree(pwszHwId);
2445 }
2446 }
2447 pNetCfgCompo->Release();
2448 }
2449 else
2450 NonStandardLogFlow(("GetLowerComponent failed, hr (0x%x)\n", hr));
2451 pNetCfgBindIfce->Release();
2452 }
2453 else
2454 {
2455 if (hr == S_FALSE) /* No more binding interfaces? */
2456 hr = S_OK;
2457 else
2458 NonStandardLogFlow(("Next binding interface failed, hr (0x%x)\n", hr));
2459 break;
2460 }
2461 } while (!bFoundIface);
2462 pEnumNetCfgBindIface->Release();
2463 }
2464 else
2465 NonStandardLogFlow(("EnumBindingInterfaces failed, hr (0x%x)\n", hr));
2466 pNetCfgBindPath->Release();
2467 }
2468 else
2469 {
2470 if (hr == S_FALSE) /* No more binding paths? */
2471 hr = S_OK;
2472 else
2473 NonStandardLogFlow(("Next bind path failed, hr (0x%x)\n", hr));
2474 break;
2475 }
2476 } while (!bFoundIface);
2477 pEnumNetCfgBindPath->Release();
2478 }
2479 else
2480 NonStandardLogFlow(("EnumBindingPaths failed, hr (0x%x)\n", hr));
2481 pNetCfgBindings->Release();
2482 }
2483 else
2484 NonStandardLogFlow(("QueryInterface for IID_INetCfgComponentBindings failed, hr (0x%x)\n", hr));
2485 return TRUE;
2486}
2487
2488static UINT WINAPI vboxNetCfgWinPspFileCallback(
2489 PVOID Context,
2490 UINT Notification,
2491 UINT_PTR Param1,
2492 UINT_PTR Param2
2493 )
2494{
2495 switch (Notification)
2496 {
2497 case SPFILENOTIFY_TARGETNEWER:
2498 case SPFILENOTIFY_TARGETEXISTS:
2499 return TRUE;
2500 }
2501 return SetupDefaultQueueCallback(Context, Notification, Param1, Param2);
2502}
2503
2504/* The original source of the VBoxNetAdp adapter creation/destruction code has the following copyright */
2505/*
2506 Copyright 2004 by the Massachusetts Institute of Technology
2507
2508 All rights reserved.
2509
2510 Permission to use, copy, modify, and distribute this software and its
2511 documentation for any purpose and without fee is hereby granted,
2512 provided that the above copyright notice appear in all copies and that
2513 both that copyright notice and this permission notice appear in
2514 supporting documentation, and that the name of the Massachusetts
2515 Institute of Technology (M.I.T.) not be used in advertising or publicity
2516 pertaining to distribution of the software without specific, written
2517 prior permission.
2518
2519 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2520 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2521 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2522 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2523 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2524 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2525 SOFTWARE.
2526*/
2527
2528
2529/**
2530 * Use the IShellFolder API to rename the connection.
2531 */
2532static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
2533{
2534 /* This is the GUID for the network connections folder. It is constant.
2535 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
2536 const GUID MY_CLSID_NetworkConnections = {
2537 0x7007ACC7, 0x3202, 0x11D1, {
2538 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
2539 }
2540 };
2541
2542 LPITEMIDLIST pidl = NULL;
2543 IShellFolder *pShellFolder = NULL;
2544 HRESULT hr;
2545
2546 /* Build the display name in the form "::{GUID}". */
2547 if (wcslen(wGuid) >= MAX_PATH)
2548 return E_INVALIDARG;
2549 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
2550 swprintf(szAdapterGuid, L"::%ls", wGuid);
2551
2552 /* Create an instance of the network connections folder. */
2553 hr = CoCreateInstance(MY_CLSID_NetworkConnections, NULL,
2554 CLSCTX_INPROC_SERVER, IID_IShellFolder,
2555 reinterpret_cast<LPVOID *>(&pShellFolder));
2556 /* Parse the display name. */
2557 if (SUCCEEDED (hr))
2558 {
2559 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
2560 &pidl, NULL);
2561 }
2562 if (SUCCEEDED (hr))
2563 {
2564 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
2565 &pidl);
2566 }
2567
2568 CoTaskMemFree (pidl);
2569
2570 if (pShellFolder)
2571 pShellFolder->Release();
2572
2573 return hr;
2574}
2575
2576/**
2577 * Loads a system DLL.
2578 *
2579 * @returns Module handle or NULL
2580 * @param pszName The DLL name.
2581 */
2582static HMODULE loadSystemDll(const char *pszName)
2583{
2584 char szPath[MAX_PATH];
2585 UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
2586 size_t cbName = strlen(pszName) + 1;
2587 if (cchPath + 1 + cbName > sizeof(szPath))
2588 return NULL;
2589 szPath[cchPath] = '\\';
2590 memcpy(&szPath[cchPath + 1], pszName, cbName);
2591 return LoadLibraryA(szPath);
2592}
2593
2594static bool vboxNetCfgWinDetectStaleConnection(PCWSTR pName)
2595{
2596 HKEY hkeyConnection, hkeyAdapter, hkeyAdapters;
2597 WCHAR wszAdaptersKeyName[] = L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}";
2598 WCHAR wszAdapterSubKeyName[MAX_PATH];
2599 LSTATUS status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wszAdaptersKeyName, 0, KEY_ALL_ACCESS, &hkeyAdapters);
2600 if (status != ERROR_SUCCESS)
2601 return false;
2602
2603 bool fFailureImminent = false;
2604 for (DWORD i = 0; !fFailureImminent; ++i)
2605 {
2606 DWORD cbName = MAX_PATH;
2607 status = RegEnumKeyEx(hkeyAdapters, i, wszAdapterSubKeyName, &cbName, NULL, NULL, NULL, NULL);
2608 // if (status == ERROR_NO_MORE_ITEMS)
2609 // break;
2610 if (status != ERROR_SUCCESS)
2611 break;
2612
2613 status = RegOpenKeyEx(hkeyAdapters, wszAdapterSubKeyName, 0, KEY_ALL_ACCESS, &hkeyAdapter);
2614 if (status == ERROR_SUCCESS)
2615 {
2616 status = RegOpenKeyEx(hkeyAdapter, L"Connection", 0, KEY_ALL_ACCESS, &hkeyConnection);
2617 if (status == ERROR_SUCCESS)
2618 {
2619 WCHAR wszName[MAX_PATH];
2620 cbName = MAX_PATH;
2621 status = RegQueryValueEx(hkeyConnection, L"Name", NULL, NULL, (LPBYTE)wszName, &cbName);
2622 if (status == ERROR_SUCCESS)
2623 if (wcsicmp(wszName, pName) == 0)
2624 fFailureImminent = true;
2625 RegCloseKey(hkeyConnection);
2626 }
2627 RegCloseKey(hkeyAdapter);
2628 }
2629 }
2630 RegCloseKey(hkeyAdapters);
2631
2632 return fFailureImminent;
2633}
2634
2635VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection (LPWSTR pGuid, PCWSTR NewName)
2636{
2637 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
2638 lpHrRenameConnection RenameConnectionFunc = NULL;
2639 HRESULT status;
2640
2641 /*
2642 * Before attempting to rename the connection, check if there is a stale
2643 * connection with the same name. We must return ok, so the rest of
2644 * configuration process proceeds normally.
2645 */
2646 if (vboxNetCfgWinDetectStaleConnection(NewName))
2647 return S_OK;
2648 /* First try the IShellFolder interface, which was unimplemented
2649 * for the network connections folder before XP. */
2650 status = rename_shellfolder (pGuid, NewName);
2651 if (status == E_NOTIMPL)
2652 {
2653/** @todo that code doesn't seem to work! */
2654 /* The IShellFolder interface is not implemented on this platform.
2655 * Try the (undocumented) HrRenameConnection API in the netshell
2656 * library. */
2657 CLSID clsid;
2658 HINSTANCE hNetShell;
2659 status = CLSIDFromString ((LPOLESTR) pGuid, &clsid);
2660 if (FAILED(status))
2661 return E_FAIL;
2662 hNetShell = loadSystemDll("netshell.dll");
2663 if (hNetShell == NULL)
2664 return E_FAIL;
2665 RenameConnectionFunc =
2666 (lpHrRenameConnection) GetProcAddress (hNetShell,
2667 "HrRenameConnection");
2668 if (RenameConnectionFunc == NULL)
2669 {
2670 FreeLibrary (hNetShell);
2671 return E_FAIL;
2672 }
2673 status = RenameConnectionFunc (&clsid, NewName);
2674 FreeLibrary (hNetShell);
2675 }
2676 if (FAILED (status))
2677 return status;
2678
2679 return S_OK;
2680}
2681
2682#define DRIVERHWID _T("sun_VBoxNetAdp")
2683
2684#define SetErrBreak(strAndArgs) \
2685 if (1) { \
2686 hrc = E_FAIL; \
2687 NonStandardLog strAndArgs; \
2688 bstrError = bstr_printf strAndArgs; \
2689 break; \
2690 } else do {} while (0)
2691
2692VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pErrMsg)
2693{
2694 HRESULT hrc = S_OK;
2695 bstr_t bstrError;
2696
2697 do
2698 {
2699 TCHAR lszPnPInstanceId [512] = {0};
2700
2701 /* We have to find the device instance ID through a registry search */
2702
2703 HKEY hkeyNetwork = 0;
2704 HKEY hkeyConnection = 0;
2705
2706 do
2707 {
2708 WCHAR strRegLocation [256];
2709 WCHAR wszGuid[50];
2710
2711 int length = StringFromGUID2(*pGUID, wszGuid, RT_ELEMENTS(wszGuid));
2712 if (!length)
2713 SetErrBreak(("Failed to create a Guid string"));
2714
2715 swprintf (strRegLocation,
2716 L"SYSTEM\\CurrentControlSet\\Control\\Network\\"
2717 L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
2718 wszGuid);
2719
2720 LONG status;
2721 status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, strRegLocation, 0,
2722 KEY_READ, &hkeyNetwork);
2723 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
2724 SetErrBreak (("Host interface network is not found in registry (%S) [1]",
2725 strRegLocation));
2726
2727 status = RegOpenKeyExW (hkeyNetwork, L"Connection", 0,
2728 KEY_READ, &hkeyConnection);
2729 if ((status != ERROR_SUCCESS) || !hkeyConnection)
2730 SetErrBreak (("Host interface network is not found in registry (%S) [2]",
2731 strRegLocation));
2732
2733 DWORD len = sizeof (lszPnPInstanceId);
2734 DWORD dwKeyType;
2735 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
2736 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
2737 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
2738 SetErrBreak (("Host interface network is not found in registry (%S) [3]",
2739 strRegLocation));
2740 }
2741 while (0);
2742
2743 if (hkeyConnection)
2744 RegCloseKey (hkeyConnection);
2745 if (hkeyNetwork)
2746 RegCloseKey (hkeyNetwork);
2747
2748 if (FAILED (hrc))
2749 break;
2750
2751 /*
2752 * Now we are going to enumerate all network devices and
2753 * wait until we encounter the right device instance ID
2754 */
2755
2756 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2757
2758 do
2759 {
2760 BOOL ok;
2761 GUID netGuid;
2762 SP_DEVINFO_DATA DeviceInfoData;
2763 DWORD index = 0;
2764 BOOL found = FALSE;
2765 DWORD size = 0;
2766
2767 /* initialize the structure size */
2768 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2769
2770 /* copy the net class GUID */
2771 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2772
2773 /* return a device info set contains all installed devices of the Net class */
2774 hDeviceInfo = SetupDiGetClassDevs(&netGuid, NULL, NULL, DIGCF_PRESENT);
2775
2776 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2777 SetErrBreak(("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2778
2779 /* enumerate the driver info list */
2780 while (TRUE)
2781 {
2782 TCHAR *deviceHwid;
2783
2784 ok = SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData);
2785
2786 if (!ok)
2787 {
2788 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2789 break;
2790 else
2791 {
2792 index++;
2793 continue;
2794 }
2795 }
2796
2797 /* try to get the hardware ID registry property */
2798 ok = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
2799 &DeviceInfoData,
2800 SPDRP_HARDWAREID,
2801 NULL,
2802 NULL,
2803 0,
2804 &size);
2805 if (!ok)
2806 {
2807 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2808 {
2809 index++;
2810 continue;
2811 }
2812
2813 deviceHwid = (TCHAR *) malloc(size);
2814 ok = SetupDiGetDeviceRegistryProperty(hDeviceInfo,
2815 &DeviceInfoData,
2816 SPDRP_HARDWAREID,
2817 NULL,
2818 (PBYTE)deviceHwid,
2819 size,
2820 NULL);
2821 if (!ok)
2822 {
2823 free(deviceHwid);
2824 deviceHwid = NULL;
2825 index++;
2826 continue;
2827 }
2828 }
2829 else
2830 {
2831 /* something is wrong. This shouldn't have worked with a NULL buffer */
2832 index++;
2833 continue;
2834 }
2835
2836 for (TCHAR *t = deviceHwid;
2837 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
2838 t += _tcslen(t) + 1)
2839 {
2840 if (!_tcsicmp(DRIVERHWID, t))
2841 {
2842 /* get the device instance ID */
2843 TCHAR devId[MAX_DEVICE_ID_LEN];
2844 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
2845 devId, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2846 {
2847 /* compare to what we determined before */
2848 if (wcscmp(devId, lszPnPInstanceId) == 0)
2849 {
2850 found = TRUE;
2851 break;
2852 }
2853 }
2854 }
2855 }
2856
2857 if (deviceHwid)
2858 {
2859 free (deviceHwid);
2860 deviceHwid = NULL;
2861 }
2862
2863 if (found)
2864 break;
2865
2866 index++;
2867 }
2868
2869 if (found == FALSE)
2870 SetErrBreak (("Host Interface Network driver not found (0x%08X)",
2871 GetLastError()));
2872
2873 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2874 if (!ok)
2875 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2876 GetLastError()));
2877
2878 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2879 if (!ok)
2880 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
2881 GetLastError()));
2882 }
2883 while (0);
2884
2885 /* clean up the device info set */
2886 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2887 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2888
2889 if (FAILED (hrc))
2890 break;
2891 }
2892 while (0);
2893
2894 if (pErrMsg && bstrError.length())
2895 *pErrMsg = bstrError.Detach();
2896
2897 return hrc;
2898}
2899
2900VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pbRebootRequired, LPCWSTR pcsxwId)
2901{
2902 return VBoxDrvCfgDrvUpdate(pcsxwId, pcsxwInf, pbRebootRequired);
2903}
2904
2905static const char *vboxNetCfgWinGetStateText(DWORD dwState)
2906{
2907 switch (dwState)
2908 {
2909 case SERVICE_STOPPED: return "is not running";
2910 case SERVICE_STOP_PENDING: return "is stopping";
2911 case SERVICE_CONTINUE_PENDING: return "continue is pending";
2912 case SERVICE_PAUSE_PENDING: return "pause is pending";
2913 case SERVICE_PAUSED: return "is paused";
2914 case SERVICE_RUNNING: return "is running";
2915 case SERVICE_START_PENDING: return "is starting";
2916 }
2917 return "state is invalid";
2918}
2919
2920static DWORD vboxNetCfgWinGetNetSetupState(SC_HANDLE hService)
2921{
2922 SERVICE_STATUS status;
2923 status.dwCurrentState = SERVICE_RUNNING;
2924 if (hService) {
2925 if (QueryServiceStatus(hService, &status))
2926 NonStandardLogFlow(("NetSetupSvc %s\n", vboxNetCfgWinGetStateText(status.dwCurrentState)));
2927 else
2928 NonStandardLogFlow(("QueryServiceStatus failed (0x%x)\n", GetLastError()));
2929 }
2930 return status.dwCurrentState;
2931}
2932
2933DECLINLINE(bool) vboxNetCfgWinIsNetSetupRunning(SC_HANDLE hService)
2934{
2935 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_RUNNING;
2936}
2937
2938DECLINLINE(bool) vboxNetCfgWinIsNetSetupStopped(SC_HANDLE hService)
2939{
2940 return vboxNetCfgWinGetNetSetupState(hService) == SERVICE_STOPPED;
2941}
2942
2943typedef struct {
2944 BSTR bstrName;
2945 GUID *pGuid;
2946 HRESULT hr;
2947} RENAMING_CONTEXT;
2948
2949static BOOL vboxNetCfgWinRenameHostOnlyNetworkInterface(IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
2950{
2951 RT_NOREF1(pNc);
2952 RENAMING_CONTEXT *pParams = (RENAMING_CONTEXT *)pContext;
2953
2954 GUID guid;
2955 pParams->hr = pNcc->GetInstanceGuid(&guid);
2956 if ( pParams->hr == S_OK && guid == *pParams->pGuid)
2957 {
2958 /* Located our component, rename it */
2959 pParams->hr = pNcc->SetDisplayName(pParams->bstrName);
2960 return FALSE;
2961 }
2962 return TRUE;
2963}
2964
2965/* We assume the following name matches the device description in vboxnetadp6.inf */
2966#define HOSTONLY_ADAPTER_NAME "VirtualBox Host-Only Ethernet Adapter"
2967
2968/*
2969 * Enumerate all host-only adapters collecting their names into a set, then
2970 * come up with the next available name by taking the first unoccupied index.
2971 */
2972static HRESULT vboxNetCfgWinNextAvailableDevName(bstr_t& bstrName)
2973{
2974 SP_DEVINFO_DATA DeviceInfoData;
2975 /* initialize the structure size */
2976 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2977
2978 HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT);
2979 if (DeviceInfoSet == INVALID_HANDLE_VALUE)
2980 return GetLastError();
2981
2982 DWORD i;
2983 std::set<bstr_t> aExistingNames;
2984 for (i = 0; SetupDiEnumDeviceInfo(DeviceInfoSet, i, &DeviceInfoData); ++i)
2985 {
2986 /* Should be more than enough for both our device id and our device name, we do not care about the rest */
2987 WCHAR wszDevName[64];
2988 if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID,
2989 NULL, (PBYTE)wszDevName, sizeof(wszDevName), NULL))
2990 continue;
2991 /* Ignore everything except our host-only adapters */
2992 if (_wcsicmp(wszDevName, DRIVERHWID))
2993 continue;
2994 if ( SetupDiGetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_FRIENDLYNAME,
2995 NULL, (PBYTE)wszDevName, sizeof(wszDevName), NULL)
2996 || SetupDiGetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_DEVICEDESC,
2997 NULL, (PBYTE)wszDevName, sizeof(wszDevName), NULL))
2998 aExistingNames.insert(bstr_t(wszDevName));
2999 }
3000 /* Try the name without index first */
3001 bstrName = HOSTONLY_ADAPTER_NAME;
3002 if (aExistingNames.find(bstrName) != aExistingNames.end())
3003 {
3004 WCHAR wszSuffix[16];
3005 /* Try indexed names until we find unused one */
3006 for (i = 2;; ++i)
3007 {
3008 wsprintf(wszSuffix, L" #%u", i);
3009 if (aExistingNames.find(bstrName + wszSuffix) == aExistingNames.end())
3010 {
3011 bstrName += wszSuffix;
3012 break;
3013 }
3014 }
3015 }
3016
3017 if (DeviceInfoSet)
3018 SetupDiDestroyDeviceInfoList(DeviceInfoSet);
3019 return S_OK;
3020}
3021
3022static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile, IN BSTR bstrDesiredName,
3023 OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
3024{
3025 HRESULT hrc = S_OK;
3026
3027 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
3028 SP_DEVINFO_DATA DeviceInfoData;
3029 PVOID pQueueCallbackContext = NULL;
3030 DWORD ret = 0;
3031 BOOL registered = FALSE;
3032 BOOL destroyList = FALSE;
3033 WCHAR pWCfgGuidString [50];
3034 WCHAR DevName[256];
3035 HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
3036 bstr_t bstrError;
3037 bstr_t bstrNewInterfaceName;
3038
3039 if (SysStringLen(bstrDesiredName) != 0)
3040 bstrNewInterfaceName = bstrDesiredName;
3041 else
3042 {
3043 hrc = vboxNetCfgWinNextAvailableDevName(bstrNewInterfaceName);
3044 if (FAILED(hrc))
3045 NonStandardLogFlow(("vboxNetCfgWinNextAvailableDevName failed with 0x%x\n", hrc));
3046 }
3047
3048 do
3049 {
3050 BOOL found = FALSE;
3051 GUID netGuid;
3052 SP_DRVINFO_DATA DriverInfoData;
3053 SP_DEVINSTALL_PARAMS DeviceInstallParams;
3054 TCHAR className [MAX_PATH];
3055 DWORD index = 0;
3056 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
3057 /* for our purposes, 2k buffer is more
3058 * than enough to obtain the hardware ID
3059 * of the VBoxNetAdp driver. */
3060 DWORD detailBuf [2048];
3061
3062 DWORD cbSize;
3063 DWORD dwValueType;
3064
3065 /* initialize the structure size */
3066 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
3067 DriverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
3068
3069 /* copy the net class GUID */
3070 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
3071
3072 /* create an empty device info set associated with the net class GUID */
3073 hDeviceInfo = SetupDiCreateDeviceInfoList(&netGuid, NULL);
3074 if (hDeviceInfo == INVALID_HANDLE_VALUE)
3075 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
3076 GetLastError()));
3077
3078 /* get the class name from GUID */
3079 BOOL fResult = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
3080 if (!fResult)
3081 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
3082 GetLastError()));
3083
3084 /* create a device info element and add the new device instance
3085 * key to registry */
3086 fResult = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
3087 DICD_GENERATE_ID, &DeviceInfoData);
3088 if (!fResult)
3089 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
3090 GetLastError()));
3091
3092 /* select the newly created device info to be the currently
3093 selected member */
3094 fResult = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
3095 if (!fResult)
3096 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
3097 GetLastError()));
3098
3099 if (pInfPath)
3100 {
3101 /* get the device install parameters and disable filecopy */
3102 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3103 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3104 &DeviceInstallParams);
3105 if (fResult)
3106 {
3107 memset(DeviceInstallParams.DriverPath, 0, sizeof(DeviceInstallParams.DriverPath));
3108 size_t pathLenght = wcslen(pInfPath) + 1/* null terminator */;
3109 if (pathLenght < sizeof(DeviceInstallParams.DriverPath)/sizeof(DeviceInstallParams.DriverPath[0]))
3110 {
3111 memcpy(DeviceInstallParams.DriverPath, pInfPath, pathLenght*sizeof(DeviceInstallParams.DriverPath[0]));
3112
3113 if (bIsInfPathFile)
3114 {
3115 DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
3116 }
3117
3118 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
3119 &DeviceInstallParams);
3120 if (!fResult)
3121 {
3122 DWORD winEr = GetLastError();
3123 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
3124 break;
3125 }
3126 }
3127 else
3128 {
3129 NonStandardLogFlow(("SetupDiSetDeviceInstallParams faileed: INF path is too long\n"));
3130 break;
3131 }
3132 }
3133 else
3134 {
3135 DWORD winEr = GetLastError();
3136 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
3137 }
3138 }
3139
3140 /* build a list of class drivers */
3141 fResult = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
3142 SPDIT_CLASSDRIVER);
3143 if (!fResult)
3144 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
3145 GetLastError()));
3146
3147 destroyList = TRUE;
3148
3149 /* enumerate the driver info list */
3150 while (TRUE)
3151 {
3152 BOOL fRet = SetupDiEnumDriverInfo(hDeviceInfo, &DeviceInfoData, SPDIT_CLASSDRIVER, index, &DriverInfoData);
3153
3154 /* if the function failed and GetLastError() returns
3155 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
3156 * list. Otherwise there was something wrong with this
3157 * particular driver. */
3158 if (!fRet)
3159 {
3160 if (GetLastError() == ERROR_NO_MORE_ITEMS)
3161 break;
3162 index++;
3163 continue;
3164 }
3165
3166 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
3167 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
3168
3169 /* if we successfully find the hardware ID and it turns out to
3170 * be the one for the loopback driver, then we are done. */
3171 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
3172 &DeviceInfoData,
3173 &DriverInfoData,
3174 pDriverInfoDetail,
3175 sizeof (detailBuf),
3176 NULL))
3177 {
3178 TCHAR * t;
3179
3180 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
3181 * whole list and see if there is a match somewhere. */
3182 t = pDriverInfoDetail->HardwareID;
3183 while (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
3184 {
3185 if (!_tcsicmp(t, DRIVERHWID))
3186 break;
3187
3188 t += _tcslen(t) + 1;
3189 }
3190
3191 if (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
3192 {
3193 found = TRUE;
3194 break;
3195 }
3196 }
3197
3198 index ++;
3199 }
3200
3201 if (!found)
3202 SetErrBreak(("Could not find Host Interface Networking driver! Please reinstall"));
3203
3204 /* set the loopback driver to be the currently selected */
3205 fResult = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
3206 &DriverInfoData);
3207 if (!fResult)
3208 SetErrBreak(("SetupDiSetSelectedDriver failed (0x%08X)",
3209 GetLastError()));
3210
3211 /* register the phantom device to prepare for install */
3212 fResult = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
3213 &DeviceInfoData);
3214 if (!fResult)
3215 {
3216 DWORD err = GetLastError();
3217 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
3218 err));
3219 }
3220
3221 /* registered, but remove if errors occur in the following code */
3222 registered = TRUE;
3223
3224 /* ask the installer if we can install the device */
3225 fResult = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
3226 &DeviceInfoData);
3227 if (!fResult)
3228 {
3229 if (GetLastError() != ERROR_DI_DO_DEFAULT)
3230 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
3231 GetLastError()));
3232 /* that's fine */
3233 }
3234
3235 /* get the device install parameters and disable filecopy */
3236 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3237 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3238 &DeviceInstallParams);
3239 if (fResult)
3240 {
3241 pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
3242 if (pQueueCallbackContext)
3243 {
3244 DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
3245 DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
3246 fResult = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3247 &DeviceInstallParams);
3248 if (!fResult)
3249 {
3250 DWORD winEr = GetLastError();
3251 NonStandardLogFlow(("SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr));
3252 }
3253 Assert(fResult);
3254 }
3255 else
3256 {
3257 DWORD winEr = GetLastError();
3258 NonStandardLogFlow(("SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr));
3259 }
3260 }
3261 else
3262 {
3263 DWORD winEr = GetLastError();
3264 NonStandardLogFlow(("SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr));
3265 }
3266
3267 /* install the files first */
3268 fResult = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
3269 &DeviceInfoData);
3270 if (!fResult)
3271 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
3272 GetLastError()));
3273 /* get the device install parameters and disable filecopy */
3274 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
3275 fResult = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
3276 &DeviceInstallParams);
3277 if (fResult)
3278 {
3279 DeviceInstallParams.Flags |= DI_NOFILECOPY;
3280 fResult = SetupDiSetDeviceInstallParams(hDeviceInfo, &DeviceInfoData,
3281 &DeviceInstallParams);
3282 if (!fResult)
3283 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
3284 GetLastError()));
3285 }
3286
3287 /*
3288 * Register any device-specific co-installers for this device,
3289 */
3290 fResult = SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
3291 hDeviceInfo,
3292 &DeviceInfoData);
3293 if (!fResult)
3294 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
3295 GetLastError()));
3296
3297 /*
3298 * install any installer-specified interfaces.
3299 * and then do the real install
3300 */
3301 fResult = SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
3302 hDeviceInfo,
3303 &DeviceInfoData);
3304 if (!fResult)
3305 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
3306 GetLastError()));
3307
3308 fResult = SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
3309 hDeviceInfo,
3310 &DeviceInfoData);
3311 if (!fResult)
3312 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
3313 GetLastError()));
3314
3315 /* Query the instance ID; on Windows 10, the registry key may take a short
3316 * while to appear. Microsoft recommends waiting for up to 5 seconds, but
3317 * we want to be on the safe side, so let's wait for 20 seconds. Waiting
3318 * longer is harmful as network setup service will shut down after a period
3319 * of inactivity.
3320 */
3321 for (int retries = 0; retries < 2 * 20; ++retries)
3322 {
3323 Sleep(500); /* half second */
3324
3325 /* Figure out NetCfgInstanceId */
3326 hkey = SetupDiOpenDevRegKey(hDeviceInfo,
3327 &DeviceInfoData,
3328 DICS_FLAG_GLOBAL,
3329 0,
3330 DIREG_DRV,
3331 KEY_READ);
3332 if (hkey == INVALID_HANDLE_VALUE)
3333 break;
3334
3335 cbSize = sizeof(pWCfgGuidString);
3336 ret = RegQueryValueExW (hkey, L"NetCfgInstanceId", NULL,
3337 &dwValueType, (LPBYTE) pWCfgGuidString, &cbSize);
3338 /* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
3339 if (ret != ERROR_FILE_NOT_FOUND)
3340 break;
3341
3342 RegCloseKey (hkey);
3343 hkey = (HKEY)INVALID_HANDLE_VALUE;
3344 }
3345
3346 if (ret == ERROR_FILE_NOT_FOUND)
3347 {
3348 hrc = E_ABORT;
3349 break;
3350 }
3351
3352 /*
3353 * We need to check 'hkey' after we check 'ret' to distinguish the case
3354 * of failed SetupDiOpenDevRegKey from the case when we timed out.
3355 */
3356 if (hkey == INVALID_HANDLE_VALUE)
3357 SetErrBreak(("SetupDiOpenDevRegKey failed (0x%08X)", GetLastError()));
3358
3359 if (ret != ERROR_SUCCESS)
3360 SetErrBreak(("Querying NetCfgInstanceId failed (0x%08X)", ret));
3361
3362 NET_LUID luid;
3363 HRESULT hSMRes = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
3364
3365 /* Close the key as soon as possible. See @bugref{7973}. */
3366 RegCloseKey (hkey);
3367 hkey = (HKEY)INVALID_HANDLE_VALUE;
3368
3369 if (FAILED(hSMRes))
3370 {
3371 /*
3372 * The setting of Metric is not very important functionality,
3373 * So we will not break installation process due to this error.
3374 */
3375 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface Warning! "
3376 "vboxNetCfgWinGetInterfaceLUID failed, default metric "
3377 "for new interface will not be set, hr (0x%x)\n", hSMRes));
3378 }
3379 else
3380 {
3381 /*
3382 * Set default metric value of interface to fix multicast issue
3383 * See @bugref{6379} for details.
3384 */
3385 hSMRes = vboxNetCfgWinSetupMetric(&luid);
3386 if (FAILED(hSMRes))
3387 {
3388 /*
3389 * The setting of Metric is not very important functionality,
3390 * So we will not break installation process due to this error.
3391 */
3392 NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface Warning! "
3393 "vboxNetCfgWinSetupMetric failed, default metric "
3394 "for new interface will not be set, hr (0x%x)\n", hSMRes));
3395 }
3396 }
3397
3398
3399 /*
3400 * We need to query the device name after we have succeeded in querying its
3401 * instance ID to avoid similar waiting-and-retrying loop (see @bugref{7973}).
3402 */
3403 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3404 SPDRP_FRIENDLYNAME , /* IN DWORD Property,*/
3405 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3406 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
3407 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
3408 NULL /*OUT PDWORD RequiredSize OPTIONAL*/))
3409 {
3410 int err = GetLastError();
3411 if (err != ERROR_INVALID_DATA)
3412 {
3413 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
3414 err));
3415 }
3416
3417 if (!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
3418 SPDRP_DEVICEDESC, /* IN DWORD Property,*/
3419 NULL, /*OUT PDWORD PropertyRegDataType, OPTIONAL*/
3420 (PBYTE)DevName, /*OUT PBYTE PropertyBuffer,*/
3421 sizeof(DevName), /* IN DWORD PropertyBufferSize,*/
3422 NULL /*OUT PDWORD RequiredSize OPTIONAL*/
3423 ))
3424 {
3425 err = GetLastError();
3426 SetErrBreak (("SetupDiGetDeviceRegistryProperty failed (0x%08X)",
3427 err));
3428 }
3429 }
3430 /* No need to rename the device if the names match. */
3431 if (!wcscmp(bstrNewInterfaceName.GetBSTR(), DevName))
3432 bstrNewInterfaceName.Assign(NULL);
3433#ifdef VBOXNETCFG_DELAYEDRENAME
3434 /* Re-use DevName for device instance id retrieval. */
3435 if (!SetupDiGetDeviceInstanceId(hDeviceInfo, &DeviceInfoData, DevName, RT_ELEMENTS(DevName), &cbSize))
3436 SetErrBreak (("SetupDiGetDeviceInstanceId failed (0x%08X)",
3437 GetLastError()));
3438#endif /* VBOXNETCFG_DELAYEDRENAME */
3439 }
3440 while (0);
3441
3442 /*
3443 * cleanup
3444 */
3445 if (hkey != INVALID_HANDLE_VALUE)
3446 RegCloseKey (hkey);
3447
3448 if (pQueueCallbackContext)
3449 SetupTermDefaultQueueCallback(pQueueCallbackContext);
3450
3451 if (hDeviceInfo != INVALID_HANDLE_VALUE)
3452 {
3453 /* an error has occurred, but the device is registered, we must remove it */
3454 if (ret != 0 && registered)
3455 SetupDiCallClassInstaller(DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
3456
3457 SetupDiDeleteDeviceInfo(hDeviceInfo, &DeviceInfoData);
3458
3459 /* destroy the driver info list */
3460 if (destroyList)
3461 SetupDiDestroyDriverInfoList(hDeviceInfo, &DeviceInfoData,
3462 SPDIT_CLASSDRIVER);
3463 /* clean up the device info set */
3464 SetupDiDestroyDeviceInfoList (hDeviceInfo);
3465 }
3466
3467 /* return the network connection GUID on success */
3468 if (SUCCEEDED(hrc))
3469 {
3470 HRESULT hr;
3471 INetCfg *pNetCfg = NULL;
3472 LPWSTR lpszApp = NULL;
3473
3474 RENAMING_CONTEXT context;
3475 context.hr = E_FAIL;
3476
3477 if (pGuid)
3478 {
3479 hrc = CLSIDFromString(pWCfgGuidString, (LPCLSID)pGuid);
3480 if (FAILED(hrc))
3481 NonStandardLogFlow(("CLSIDFromString failed, hrc (0x%x)\n", hrc));
3482 }
3483
3484 hr = VBoxNetCfgWinQueryINetCfg(&pNetCfg, TRUE, L"VirtualBox Host-Only Creation",
3485 30 * 1000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec. */
3486 /** @todo special handling for 6to4svc.dll ???, i.e. several retrieves */
3487 &lpszApp);
3488 if (hr == S_OK)
3489 {
3490 if (!!bstrNewInterfaceName)
3491 {
3492 /* The assigned name does not match the desired one, rename the device */
3493 context.bstrName = bstrNewInterfaceName.GetBSTR();
3494 context.pGuid = pGuid;
3495 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3496 &GUID_DEVCLASS_NET,
3497 vboxNetCfgWinRenameHostOnlyNetworkInterface,
3498 &context);
3499 }
3500 if (SUCCEEDED(hr))
3501 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3502 &GUID_DEVCLASS_NETSERVICE,
3503 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3504 pGuid);
3505 if (SUCCEEDED(hr))
3506 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3507 &GUID_DEVCLASS_NETTRANS,
3508 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3509 pGuid);
3510 if (SUCCEEDED(hr))
3511 hr = vboxNetCfgWinEnumNetCfgComponents(pNetCfg,
3512 &GUID_DEVCLASS_NETCLIENT,
3513 vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
3514 pGuid);
3515 if (SUCCEEDED(hr))
3516 {
3517 hr = pNetCfg->Apply();
3518 }
3519 else
3520 NonStandardLogFlow(("Enumeration failed, hr 0x%x\n", hr));
3521 VBoxNetCfgWinReleaseINetCfg(pNetCfg, TRUE);
3522 }
3523 else if (hr == NETCFG_E_NO_WRITE_LOCK && lpszApp)
3524 {
3525 NonStandardLogFlow(("Application %ws is holding the lock, failed\n", lpszApp));
3526 CoTaskMemFree(lpszApp);
3527 }
3528 else
3529 NonStandardLogFlow(("VBoxNetCfgWinQueryINetCfg failed, hr 0x%x\n", hr));
3530
3531#ifndef VBOXNETCFG_DELAYEDRENAME
3532 if (SUCCEEDED(hr) && SUCCEEDED(context.hr))
3533 {
3534 /* The device has been successfully renamed, replace the name now. */
3535 wcscpy_s(DevName, RT_ELEMENTS(DevName), bstrDesiredName);
3536 }
3537
3538 WCHAR ConnectionName[128];
3539 ULONG cbName = sizeof(ConnectionName);
3540
3541 hr = VBoxNetCfgWinGenHostonlyConnectionName(DevName, ConnectionName, &cbName);
3542 if (SUCCEEDED(hr))
3543 hr = VBoxNetCfgWinRenameConnection(pWCfgGuidString, ConnectionName);
3544#endif
3545 if (lppszName)
3546 {
3547 *lppszName = SysAllocString((const OLECHAR *) DevName);
3548 if (!*lppszName)
3549 {
3550 NonStandardLogFlow(("SysAllocString failed\n"));
3551 hrc = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3552 }
3553 }
3554 }
3555
3556 if (pErrMsg && bstrError.length())
3557 *pErrMsg = bstrError.Detach();
3558
3559 return hrc;
3560}
3561
3562VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath, IN bool bIsInfPathFile, IN BSTR pwsDesiredName,
3563 OUT GUID *pGuid, OUT BSTR *lppszName, OUT BSTR *pErrMsg)
3564{
3565 HRESULT hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pwsDesiredName, pGuid, lppszName, pErrMsg);
3566 if (hrc == E_ABORT)
3567 {
3568 NonStandardLogFlow(("Timed out while waiting for NetCfgInstanceId, try again immediately...\n"));
3569 /*
3570 * This is the first time we fail to obtain NetCfgInstanceId, let us
3571 * retry it once. It is needed to handle the situation when network
3572 * setup fails to recognize the arrival of our device node while it
3573 * is busy removing another host-only interface, and it gets stuck
3574 * with no matching network interface created for our device node.
3575 * See @bugref{7973} for details.
3576 */
3577 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pwsDesiredName, pGuid, lppszName, pErrMsg);
3578 if (hrc == E_ABORT)
3579 {
3580 NonStandardLogFlow(("Timed out again while waiting for NetCfgInstanceId, try again after a while...\n"));
3581 /*
3582 * This is the second time we fail to obtain NetCfgInstanceId, let us
3583 * retry it once more. This time we wait to network setup service
3584 * to go down before retrying. Hopefully it will resolve all error
3585 * conditions. See @bugref{7973} for details.
3586 */
3587
3588 SC_HANDLE hSCM = NULL;
3589 SC_HANDLE hService = NULL;
3590
3591 hSCM = OpenSCManager(NULL, NULL, GENERIC_READ);
3592 if (hSCM)
3593 {
3594 hService = OpenService(hSCM, _T("NetSetupSvc"), GENERIC_READ);
3595 if (hService)
3596 {
3597 for (int retries = 0; retries < 60 && !vboxNetCfgWinIsNetSetupStopped(hService); ++retries)
3598 Sleep(1000);
3599 CloseServiceHandle(hService);
3600 hrc = vboxNetCfgWinCreateHostOnlyNetworkInterface(pInfPath, bIsInfPathFile, pwsDesiredName, pGuid, lppszName, pErrMsg);
3601 }
3602 else
3603 NonStandardLogFlow(("OpenService failed (0x%x)\n", GetLastError()));
3604 CloseServiceHandle(hSCM);
3605 }
3606 else
3607 NonStandardLogFlow(("OpenSCManager failed (0x%x)", GetLastError()));
3608 /* Give up and report the error. */
3609 if (hrc == E_ABORT)
3610 {
3611 if (pErrMsg)
3612 {
3613 bstr_t bstrError = bstr_printf("Querying NetCfgInstanceId failed (0x%08X)", ERROR_FILE_NOT_FOUND);
3614 *pErrMsg = bstrError.Detach();
3615 }
3616 hrc = E_FAIL;
3617 }
3618 }
3619 }
3620 return hrc;
3621}
3622
3623
3624HRESULT vboxLoadIpHelpFunctions(HINSTANCE& pIpHlpInstance)
3625{
3626 Assert(pIpHlpInstance != NULL);
3627
3628 pIpHlpInstance = loadSystemDll("Iphlpapi.dll");
3629 if (pIpHlpInstance == NULL)
3630 return E_FAIL;
3631
3632 g_pfnInitializeIpInterfaceEntry =
3633 (PFNINITIALIZEIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "InitializeIpInterfaceEntry");
3634 Assert(g_pfnInitializeIpInterfaceEntry);
3635
3636 if (g_pfnInitializeIpInterfaceEntry)
3637 {
3638 g_pfnGetIpInterfaceEntry =
3639 (PFNGETIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "GetIpInterfaceEntry");
3640 Assert(g_pfnGetIpInterfaceEntry);
3641 }
3642
3643 if (g_pfnGetIpInterfaceEntry)
3644 {
3645 g_pfnSetIpInterfaceEntry =
3646 (PFNSETIPINTERFACEENTRY)GetProcAddress(pIpHlpInstance, "SetIpInterfaceEntry");
3647 Assert(g_pfnSetIpInterfaceEntry);
3648 }
3649
3650 if (g_pfnInitializeIpInterfaceEntry == NULL)
3651 {
3652 FreeLibrary(pIpHlpInstance);
3653 pIpHlpInstance = NULL;
3654 return E_FAIL;
3655 }
3656
3657 return S_OK;
3658}
3659
3660
3661HRESULT vboxNetCfgWinGetLoopbackMetric(OUT int* Metric)
3662{
3663 HRESULT rc = S_OK;
3664 MIB_IPINTERFACE_ROW row;
3665
3666 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3667 Assert(g_pfnGetIpInterfaceEntry != NULL);
3668
3669 g_pfnInitializeIpInterfaceEntry(&row);
3670 row.Family = AF_INET;
3671 row.InterfaceLuid.Info.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
3672
3673 rc = g_pfnGetIpInterfaceEntry(&row);
3674 if (rc != NO_ERROR)
3675 return HRESULT_FROM_WIN32(rc);
3676
3677 *Metric = row.Metric;
3678
3679 return rc;
3680}
3681
3682
3683HRESULT vboxNetCfgWinSetInterfaceMetric(
3684 IN NET_LUID* pInterfaceLuid,
3685 IN DWORD metric)
3686{
3687 MIB_IPINTERFACE_ROW newRow;
3688
3689 Assert(g_pfnInitializeIpInterfaceEntry != NULL);
3690 Assert(g_pfnSetIpInterfaceEntry != NULL);
3691
3692 g_pfnInitializeIpInterfaceEntry(&newRow);
3693 // identificate the interface to change
3694 newRow.InterfaceLuid = *pInterfaceLuid;
3695 newRow.Family = AF_INET;
3696 // changed settings
3697 newRow.UseAutomaticMetric = false;
3698 newRow.Metric = metric;
3699
3700 // change settings
3701 return HRESULT_FROM_WIN32(g_pfnSetIpInterfaceEntry(&newRow));
3702}
3703
3704
3705HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID)
3706{
3707 HRESULT res = S_OK;
3708 DWORD luidIndex = 0;
3709 DWORD ifType = 0;
3710 DWORD cbSize = sizeof(luidIndex);
3711 DWORD dwValueType = REG_DWORD;
3712
3713 if (pLUID == NULL)
3714 return E_INVALIDARG;
3715
3716 res = RegQueryValueExW(hKey, L"NetLuidIndex", NULL,
3717 &dwValueType, (LPBYTE)&luidIndex, &cbSize);
3718 if (res != 0)
3719 return HRESULT_FROM_WIN32(res);
3720
3721 cbSize = sizeof(ifType);
3722 dwValueType = REG_DWORD;
3723 res = RegQueryValueExW(hKey, L"*IfType", NULL,
3724 &dwValueType, (LPBYTE)&ifType, &cbSize);
3725 if (res != 0)
3726 return HRESULT_FROM_WIN32(res);
3727
3728 ZeroMemory(pLUID, sizeof(NET_LUID));
3729 pLUID->Info.IfType = ifType;
3730 pLUID->Info.NetLuidIndex = luidIndex;
3731
3732 return res;
3733}
3734
3735
3736HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid)
3737{
3738 HINSTANCE hModule = NULL;
3739 HRESULT rc = vboxLoadIpHelpFunctions(hModule);
3740 if (SUCCEEDED(rc))
3741 {
3742 int loopbackMetric;
3743 rc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
3744 if (SUCCEEDED(rc))
3745 rc = vboxNetCfgWinSetInterfaceMetric(pLuid, loopbackMetric - 1);
3746 }
3747
3748 g_pfnInitializeIpInterfaceEntry = NULL;
3749 g_pfnSetIpInterfaceEntry = NULL;
3750 g_pfnGetIpInterfaceEntry = NULL;
3751
3752 FreeLibrary(hModule);
3753 return rc;
3754}
3755#ifdef VBOXNETCFG_DELAYEDRENAME
3756VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pwszId, OUT BSTR *pDevName)
3757{
3758 HRESULT hr = S_OK;
3759 WCHAR wszDevName[256];
3760 WCHAR wszConnectionNewName[128];
3761 ULONG cbName = sizeof(wszConnectionNewName);
3762
3763 HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL);
3764 if (hDevInfo != INVALID_HANDLE_VALUE)
3765 {
3766 SP_DEVINFO_DATA DevInfoData;
3767
3768 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
3769 if (SetupDiOpenDeviceInfo(hDevInfo, pwszId, NULL, 0, &DevInfoData))
3770 {
3771 DWORD err = ERROR_SUCCESS;
3772 if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData,
3773 SPDRP_FRIENDLYNAME, NULL,
3774 (PBYTE)wszDevName, RT_ELEMENTS(wszDevName), NULL))
3775 {
3776 err = GetLastError();
3777 if (err == ERROR_INVALID_DATA)
3778 {
3779 err = SetupDiGetDeviceRegistryPropertyW(hDevInfo, &DevInfoData,
3780 SPDRP_DEVICEDESC, NULL,
3781 (PBYTE)wszDevName, RT_ELEMENTS(wszDevName), NULL)
3782 ? ERROR_SUCCESS
3783 : GetLastError();
3784 }
3785 }
3786 if (err == ERROR_SUCCESS)
3787 {
3788 hr = VBoxNetCfgWinGenHostonlyConnectionName(wszDevName, wszConnectionNewName, &cbName);
3789 if (SUCCEEDED(hr))
3790 {
3791 WCHAR wszGuid[50];
3792 int cbWGuid = StringFromGUID2(*pGuid, wszGuid, RT_ELEMENTS(wszGuid));
3793 if (cbWGuid)
3794 {
3795 hr = VBoxNetCfgWinRenameConnection(wszGuid, wszConnectionNewName);
3796 if (FAILED(hr))
3797 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinRenameConnection failed (0x%x)\n", hr));
3798 }
3799 else
3800 {
3801 err = GetLastError();
3802 hr = HRESULT_FROM_WIN32(err);
3803 if (SUCCEEDED(hr))
3804 hr = E_FAIL;
3805 NonStandardLogFlow(("StringFromGUID2 failed err=%u, hr=0x%x\n", err, hr));
3806 }
3807 }
3808 else
3809 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: VBoxNetCfgWinGenHostonlyConnectionName failed (0x%x)\n", hr));
3810 if (SUCCEEDED(hr) && pDevName)
3811 {
3812 *pDevName = SysAllocString((const OLECHAR *)wszDevName);
3813 if (!*pDevName)
3814 {
3815 NonStandardLogFlow(("SysAllocString failed\n"));
3816 hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
3817 }
3818 }
3819 }
3820 else
3821 {
3822 hr = HRESULT_FROM_WIN32(err);
3823 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiGetDeviceRegistryPropertyW failed (0x%x)\n", err));
3824 }
3825 }
3826 else
3827 {
3828 DWORD err = GetLastError();
3829 hr = HRESULT_FROM_WIN32(err);
3830 NonStandardLogFlow(("VBoxNetCfgWinRenameHostOnlyConnection: SetupDiOpenDeviceInfo failed (0x%x)\n", err));
3831 }
3832 SetupDiDestroyDeviceInfoList(hDevInfo);
3833 }
3834
3835 return hr;
3836}
3837#endif /* VBOXNETCFG_DELAYEDRENAME */
3838
3839#undef SetErrBreak
3840
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