VirtualBox

source: vbox/trunk/src/VBox/Main/win/NetIfList-win.cpp@ 17799

Last change on this file since 17799 was 17774, checked in by vboxsync, 16 years ago

burn fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.0 KB
Line 
1/* $Id: NetIfList-win.cpp 17774 2009-03-12 18:35:36Z vboxsync $ */
2/** @file
3 * Main - NetIfList, Windows implementation.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_MAIN
28
29#include <iprt/asm.h>
30#include <iprt/err.h>
31#include <list>
32
33#define _WIN32_DCOM
34#include <winsock2.h>
35#include <ws2tcpip.h>
36#include <windows.h>
37
38#ifdef VBOX_WITH_NETFLT
39#include "VBox/WinNetConfig.h"
40#include "devguid.h"
41#endif
42
43#include <iphlpapi.h>
44
45#include "Logging.h"
46#include "HostNetworkInterfaceImpl.h"
47#include "ProgressImpl.h"
48#include "VirtualBoxImpl.h"
49#include "netif.h"
50
51#ifdef VBOX_WITH_NETFLT
52#include <Wbemidl.h>
53#include <comdef.h>
54
55#include "svchlp.h"
56
57#include <shellapi.h>
58#define INITGUID
59#include <guiddef.h>
60#include <devguid.h>
61#include <objbase.h>
62#include <setupapi.h>
63#include <shlobj.h>
64#include <cfgmgr32.h>
65
66#define VBOX_APP_NAME L"VirtualBox"
67
68static HRESULT netIfWinCreateIWbemServices(IWbemServices ** ppSvc)
69{
70 HRESULT hres;
71
72 // Step 3: ---------------------------------------------------
73 // Obtain the initial locator to WMI -------------------------
74
75 IWbemLocator *pLoc = NULL;
76
77 hres = CoCreateInstance(
78 CLSID_WbemLocator,
79 0,
80 CLSCTX_INPROC_SERVER,
81 IID_IWbemLocator, (LPVOID *) &pLoc);
82 if(SUCCEEDED(hres))
83 {
84 // Step 4: -----------------------------------------------------
85 // Connect to WMI through the IWbemLocator::ConnectServer method
86
87 IWbemServices *pSvc = NULL;
88
89 // Connect to the root\cimv2 namespace with
90 // the current user and obtain pointer pSvc
91 // to make IWbemServices calls.
92 hres = pLoc->ConnectServer(
93 _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
94 NULL, // User name. NULL = current user
95 NULL, // User password. NULL = current
96 0, // Locale. NULL indicates current
97 NULL, // Security flags.
98 0, // Authority (e.g. Kerberos)
99 0, // Context object
100 &pSvc // pointer to IWbemServices proxy
101 );
102 if(SUCCEEDED(hres))
103 {
104 LogRel(("Connected to ROOT\\CIMV2 WMI namespace\n"));
105
106 // Step 5: --------------------------------------------------
107 // Set security levels on the proxy -------------------------
108
109 hres = CoSetProxyBlanket(
110 pSvc, // Indicates the proxy to set
111 RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
112 RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
113 NULL, // Server principal name
114 RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
115 RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
116 NULL, // client identity
117 EOAC_NONE // proxy capabilities
118 );
119 if(SUCCEEDED(hres))
120 {
121 *ppSvc = pSvc;
122 /* do not need it any more */
123 pLoc->Release();
124 return hres;
125 }
126 else
127 {
128 LogRel(("Could not set proxy blanket. Error code = 0x%x\n", hres));
129 }
130
131 pSvc->Release();
132 }
133 else
134 {
135 LogRel(("Could not connect. Error code = 0x%x\n", hres));
136 }
137
138 pLoc->Release();
139 }
140 else
141 {
142 LogRel(("Failed to create IWbemLocator object. Err code = 0x%x\n", hres));
143// CoUninitialize();
144 }
145
146 return hres;
147}
148
149static HRESULT netIfWinFindAdapterClassById(IWbemServices * pSvc, const Guid &guid, IWbemClassObject **pAdapterConfig)
150{
151 HRESULT hres;
152 WCHAR aQueryString[256];
153// char uuidStr[RTUUID_STR_LENGTH];
154// int rc = RTUuidToStr(guid.toString().raw(), uuidStr, sizeof(uuidStr));
155 {
156 swprintf(aQueryString, L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"{%S}\"", guid.toString().raw());
157 // Step 6: --------------------------------------------------
158 // Use the IWbemServices pointer to make requests of WMI ----
159
160 IEnumWbemClassObject* pEnumerator = NULL;
161 hres = pSvc->ExecQuery(
162 bstr_t("WQL"),
163 bstr_t(aQueryString),
164 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
165 NULL,
166 &pEnumerator);
167 if(SUCCEEDED(hres))
168 {
169 // Step 7: -------------------------------------------------
170 // Get the data from the query in step 6 -------------------
171
172 IWbemClassObject *pclsObj;
173 ULONG uReturn = 0;
174
175 while (pEnumerator)
176 {
177 HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
178 &pclsObj, &uReturn);
179
180 if(SUCCEEDED(hres))
181 {
182 if(uReturn)
183 {
184 pEnumerator->Release();
185 *pAdapterConfig = pclsObj;
186 hres = S_OK;
187 return hres;
188 }
189 else
190 {
191 hres = S_FALSE;
192 }
193 }
194
195 }
196 pEnumerator->Release();
197 }
198 else
199 {
200 Log(("Query for operating system name failed. Error code = 0x%x\n", hres));
201 }
202 }
203
204 return hres;
205}
206
207static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, BSTR * pStr)
208{
209 VARIANT index;
210
211 // Get the value of the key property
212 HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
213 if(SUCCEEDED(hr))
214 {
215 WCHAR strIndex[8];
216 swprintf(strIndex, L"%u", index.uintVal);
217 *pStr = (bstr_t(L"Win32_NetworkAdapterConfiguration.Index='") + strIndex + "'").copy();
218 }
219 else
220 {
221 DWORD dwError = GetLastError();
222 Assert(0);
223 hr = HRESULT_FROM_WIN32( dwError );
224 }
225 return hr;
226}
227
228static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, BSTR ObjPath,
229 BSTR MethodName, LPWSTR *pArgNames, LPVARIANT *pArgs, UINT cArgs,
230 IWbemClassObject** ppOutParams
231 )
232{
233 HRESULT hres = S_OK;
234 // Step 6: --------------------------------------------------
235 // Use the IWbemServices pointer to make requests of WMI ----
236
237 ComPtr<IWbemClassObject> pInParamsDefinition;
238 ComPtr<IWbemClassObject> pClassInstance;
239
240 if(cArgs)
241 {
242 hres = pClass->GetMethod(MethodName, 0,
243 pInParamsDefinition.asOutParam(), NULL);
244 if(SUCCEEDED(hres))
245 {
246 hres = pInParamsDefinition->SpawnInstance(0, pClassInstance.asOutParam());
247
248 if(SUCCEEDED(hres))
249 {
250 for(UINT i = 0; i < cArgs; i++)
251 {
252 // Store the value for the in parameters
253 hres = pClassInstance->Put(pArgNames[i], 0,
254 pArgs[i], 0);
255 if(FAILED(hres))
256 {
257 break;
258 }
259 }
260 }
261 }
262 }
263
264 if(SUCCEEDED(hres))
265 {
266 IWbemClassObject* pOutParams = NULL;
267 hres = pSvc->ExecMethod(ObjPath, MethodName, 0,
268 NULL, pClassInstance, &pOutParams, NULL);
269 if(SUCCEEDED(hres))
270 {
271 *ppOutParams = pOutParams;
272 }
273 }
274
275 return hres;
276}
277
278static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr* aIp, UINT cIp)
279{
280 HRESULT hr;
281 SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIp);
282 if(pIpArray)
283 {
284 for(UINT i = 0; i < cIp; i++)
285 {
286 char* addr = inet_ntoa(aIp[i]);
287 BSTR val = bstr_t(addr).copy();
288 long aIndex[1];
289 aIndex[0] = i;
290 hr = SafeArrayPutElement(pIpArray, aIndex, val);
291 if(FAILED(hr))
292 {
293 SysFreeString(val);
294 SafeArrayDestroy(pIpArray);
295 break;
296 }
297 }
298
299 if(SUCCEEDED(hr))
300 {
301 *ppArray = pIpArray;
302 }
303 }
304 else
305 {
306 DWORD dwError = GetLastError();
307 Assert(0);
308 hr = HRESULT_FROM_WIN32( dwError );
309 }
310
311 return hr;
312}
313
314static HRESULT netIfWinCreateIpArrayV4V6(SAFEARRAY **ppArray, BSTR Ip)
315{
316 HRESULT hr;
317 SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, 1);
318 if(pIpArray)
319 {
320 BSTR val = bstr_t(Ip, false).copy();
321 long aIndex[1];
322 aIndex[0] = 0;
323 hr = SafeArrayPutElement(pIpArray, aIndex, val);
324 if(FAILED(hr))
325 {
326 SysFreeString(val);
327 SafeArrayDestroy(pIpArray);
328 }
329
330 if(SUCCEEDED(hr))
331 {
332 *ppArray = pIpArray;
333 }
334 }
335 else
336 {
337 DWORD dwError = GetLastError();
338 Assert(0);
339 hr = HRESULT_FROM_WIN32( dwError );
340 }
341
342 return hr;
343}
344
345
346static HRESULT netIfWinCreateIpArrayVariantV4(VARIANT * pIpAddresses, in_addr* aIp, UINT cIp)
347{
348 HRESULT hr;
349 VariantInit(pIpAddresses);
350 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
351 SAFEARRAY *pIpArray;
352 hr = netIfWinCreateIpArray(&pIpArray, aIp, cIp);
353 if(SUCCEEDED(hr))
354 {
355 pIpAddresses->parray = pIpArray;
356 }
357 return hr;
358}
359
360static HRESULT netIfWinCreateIpArrayVariantV4V6(VARIANT * pIpAddresses, BSTR Ip)
361{
362 HRESULT hr;
363 VariantInit(pIpAddresses);
364 pIpAddresses->vt = VT_ARRAY | VT_BSTR;
365 SAFEARRAY *pIpArray;
366 hr = netIfWinCreateIpArrayV4V6(&pIpArray, Ip);
367 if(SUCCEEDED(hr))
368 {
369 pIpAddresses->parray = pIpArray;
370 }
371 return hr;
372}
373
374static HRESULT netIfWinEnableStatic(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pIp, VARIANT * pMask)
375{
376 ComPtr<IWbemClassObject> pClass;
377 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
378 HRESULT hr;
379 if(ClassName)
380 {
381 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
382 if(SUCCEEDED(hr))
383 {
384 LPWSTR argNames[] = {L"IPAddress", L"SubnetMask"};
385 LPVARIANT args[] = {pIp, pMask};
386 ComPtr<IWbemClassObject> pOutParams;
387
388 hr = netIfExecMethod(pSvc, pClass, ObjPath,
389 bstr_t(L"EnableStatic"), argNames, args, 2, pOutParams.asOutParam());
390 if(SUCCEEDED(hr))
391 {
392 VARIANT varReturnValue;
393 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
394 &varReturnValue, NULL, 0);
395 Assert(SUCCEEDED(hr));
396 if(SUCCEEDED(hr))
397 {
398// Assert(varReturnValue.vt == VT_UINT);
399 int winEr = varReturnValue.uintVal;
400 switch(winEr)
401 {
402 case 0:
403 hr = S_OK;
404 break;
405 default:
406 hr = HRESULT_FROM_WIN32( winEr );
407 break;
408 }
409 }
410 }
411 }
412 SysFreeString(ClassName);
413 }
414 else
415 {
416 DWORD dwError = GetLastError();
417 Assert(0);
418 hr = HRESULT_FROM_WIN32( dwError );
419 }
420
421 return hr;
422}
423
424
425static HRESULT netIfWinEnableStaticV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aIp, in_addr * aMask, UINT cIp)
426{
427 VARIANT ipAddresses;
428 HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, aIp, cIp);
429 if(SUCCEEDED(hr))
430 {
431 VARIANT ipMasks;
432 hr = netIfWinCreateIpArrayVariantV4(&ipMasks, aMask, cIp);
433 if(SUCCEEDED(hr))
434 {
435 netIfWinEnableStatic(pSvc, ObjPath, &ipAddresses, &ipMasks);
436 VariantClear(&ipMasks);
437 }
438 VariantClear(&ipAddresses);
439 }
440 return hr;
441}
442
443static HRESULT netIfWinEnableStaticV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Ip, BSTR Mask)
444{
445 VARIANT ipAddresses;
446 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&ipAddresses, Ip);
447 if(SUCCEEDED(hr))
448 {
449 VARIANT ipMasks;
450 hr = netIfWinCreateIpArrayVariantV4V6(&ipMasks, Mask);
451 if(SUCCEEDED(hr))
452 {
453 netIfWinEnableStatic(pSvc, ObjPath, &ipAddresses, &ipMasks);
454 VariantClear(&ipMasks);
455 }
456 VariantClear(&ipAddresses);
457 }
458 return hr;
459}
460
461/* win API allows to set gw metrics as well, we are not setting them */
462static HRESULT netIfWinSetGateways(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pGw)
463{
464 ComPtr<IWbemClassObject> pClass;
465 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
466 HRESULT hr;
467 if(ClassName)
468 {
469 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
470 if(SUCCEEDED(hr))
471 {
472 LPWSTR argNames[] = {L"DefaultIPGateway"};
473 LPVARIANT args[] = {pGw};
474 ComPtr<IWbemClassObject> pOutParams;
475
476 hr = netIfExecMethod(pSvc, pClass, ObjPath,
477 bstr_t(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
478 if(SUCCEEDED(hr))
479 {
480 VARIANT varReturnValue;
481 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
482 &varReturnValue, NULL, 0);
483 Assert(SUCCEEDED(hr));
484 if(SUCCEEDED(hr))
485 {
486// Assert(varReturnValue.vt == VT_UINT);
487 int winEr = varReturnValue.uintVal;
488 switch(winEr)
489 {
490 case 0:
491 hr = S_OK;
492 break;
493 default:
494 hr = HRESULT_FROM_WIN32( winEr );
495 break;
496 }
497 }
498 } }
499 SysFreeString(ClassName);
500 }
501 else
502 {
503 DWORD dwError = GetLastError();
504 Assert(0);
505 hr = HRESULT_FROM_WIN32( dwError );
506 }
507
508 return hr;
509}
510
511/* win API allows to set gw metrics as well, we are not setting them */
512static HRESULT netIfWinSetGatewaysV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aGw, UINT cGw)
513{
514 VARIANT gwais;
515 HRESULT hr = netIfWinCreateIpArrayVariantV4(&gwais, aGw, cGw);
516 if(SUCCEEDED(hr))
517 {
518 netIfWinSetGateways(pSvc, ObjPath, &gwais);
519 VariantClear(&gwais);
520 }
521 return hr;
522}
523
524/* win API allows to set gw metrics as well, we are not setting them */
525static HRESULT netIfWinSetGatewaysV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Gw)
526{
527 VARIANT vGw;
528 HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&vGw, Gw);
529 if(SUCCEEDED(hr))
530 {
531 netIfWinSetGateways(pSvc, ObjPath, &vGw);
532 VariantClear(&vGw);
533 }
534 return hr;
535}
536
537static HRESULT netIfWinEnableDHCP(IWbemServices * pSvc, BSTR ObjPath)
538{
539 ComPtr<IWbemClassObject> pClass;
540 BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
541 HRESULT hr;
542 if(ClassName)
543 {
544 hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
545 if(SUCCEEDED(hr))
546 {
547 ComPtr<IWbemClassObject> pOutParams;
548
549 hr = netIfExecMethod(pSvc, pClass, ObjPath,
550 bstr_t(L"EnableDHCP"), NULL, NULL, 0, pOutParams.asOutParam());
551 if(SUCCEEDED(hr))
552 {
553 VARIANT varReturnValue;
554 hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
555 &varReturnValue, NULL, 0);
556 Assert(SUCCEEDED(hr));
557 if(SUCCEEDED(hr))
558 {
559// Assert(varReturnValue.vt == VT_UINT);
560 int winEr = varReturnValue.uintVal;
561 switch(winEr)
562 {
563 case 0:
564 hr = S_OK;
565 break;
566 default:
567 hr = HRESULT_FROM_WIN32( winEr );
568 break;
569 }
570 }
571 }
572 }
573 SysFreeString(ClassName);
574 }
575 else
576 {
577 DWORD dwError = GetLastError();
578 Assert(0);
579 hr = HRESULT_FROM_WIN32( dwError );
580 }
581
582 return hr;
583}
584
585static int netIfWinIsDhcpEnabled(const Guid &guid, BOOL *pEnabled)
586{
587 HRESULT hr;
588 ComPtr <IWbemServices> pSvc;
589 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
590 if(SUCCEEDED(hr))
591 {
592 ComPtr <IWbemClassObject> pAdapterConfig;
593 hr = netIfWinFindAdapterClassById(pSvc, guid, pAdapterConfig.asOutParam());
594 if(SUCCEEDED(hr))
595 {
596 VARIANT vtEnabled;
597 hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
598 if(SUCCEEDED(hr))
599 {
600 *pEnabled = vtEnabled.boolVal;
601 }
602 }
603 }
604
605 return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
606}
607
608static int collectNetIfInfo(Bstr &strName, Guid &guid, PNETIFINFO pInfo)
609{
610 DWORD dwRc;
611 int rc = VINF_SUCCESS;
612 /*
613 * Most of the hosts probably have less than 10 adapters,
614 * so we'll mostly succeed from the first attempt.
615 */
616 ULONG uBufLen = sizeof(IP_ADAPTER_ADDRESSES) * 10;
617 PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen);
618 if (!pAddresses)
619 return VERR_NO_MEMORY;
620 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
621 if (dwRc == ERROR_BUFFER_OVERFLOW)
622 {
623 /* Impressive! More than 10 adapters! Get more memory and try again. */
624 RTMemFree(pAddresses);
625 pAddresses = (PIP_ADAPTER_ADDRESSES)RTMemAlloc(uBufLen);
626 if (!pAddresses)
627 return VERR_NO_MEMORY;
628 dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
629 }
630 if (dwRc == NO_ERROR)
631 {
632 PIP_ADAPTER_ADDRESSES pAdapter;
633 for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next)
634 {
635 char *pszUuid = RTStrDup(pAdapter->AdapterName);
636 size_t len = strlen(pszUuid) - 1;
637 if (pszUuid[0] == '{' && pszUuid[len] == '}')
638 {
639 pszUuid[len] = 0;
640 if (!RTUuidCompareStr(&pInfo->Uuid, pszUuid + 1))
641 {
642 bool fIPFound, fIPv6Found;
643 PIP_ADAPTER_UNICAST_ADDRESS pAddr;
644 fIPFound = fIPv6Found = false;
645 for (pAddr = pAdapter->FirstUnicastAddress; pAddr; pAddr = pAddr->Next)
646 {
647 switch (pAddr->Address.lpSockaddr->sa_family)
648 {
649 case AF_INET:
650 if (!fIPFound)
651 {
652 fIPFound = true;
653 memcpy(&pInfo->IPAddress,
654 &((struct sockaddr_in *)pAddr->Address.lpSockaddr)->sin_addr.s_addr,
655 sizeof(pInfo->IPAddress));
656 }
657 break;
658 case AF_INET6:
659 if (!fIPv6Found)
660 {
661 fIPv6Found = true;
662 memcpy(&pInfo->IPv6Address,
663 ((struct sockaddr_in6 *)pAddr->Address.lpSockaddr)->sin6_addr.s6_addr,
664 sizeof(pInfo->IPv6Address));
665 }
666 break;
667 }
668 }
669 PIP_ADAPTER_PREFIX pPrefix;
670 fIPFound = fIPv6Found = false;
671 for (pPrefix = pAdapter->FirstPrefix; pPrefix; pPrefix = pPrefix->Next)
672 {
673 switch (pPrefix->Address.lpSockaddr->sa_family)
674 {
675 case AF_INET:
676 if (!fIPFound)
677 {
678 fIPFound = true;
679 ASMBitSetRange(&pInfo->IPNetMask, 0, pPrefix->PrefixLength);
680 }
681 break;
682 case AF_INET6:
683 if (!fIPv6Found)
684 {
685 fIPv6Found = true;
686 ASMBitSetRange(&pInfo->IPv6NetMask, 0, pPrefix->PrefixLength);
687 }
688 break;
689 }
690 }
691 if (sizeof(pInfo->MACAddress) != pAdapter->PhysicalAddressLength)
692 Log(("collectNetIfInfo: Unexpected physical address length: %u\n", pAdapter->PhysicalAddressLength));
693 else
694 memcpy(pInfo->MACAddress.au8, pAdapter->PhysicalAddress, sizeof(pInfo->MACAddress));
695 pInfo->enmMediumType = NETIF_T_ETHERNET;
696 pInfo->enmStatus = pAdapter->OperStatus == IfOperStatusUp ? NETIF_S_UP : NETIF_S_DOWN;
697 RTStrFree(pszUuid);
698 break;
699 }
700 }
701 RTStrFree(pszUuid);
702 }
703
704 BOOL bEnabled;
705 rc = netIfWinIsDhcpEnabled(guid, &bEnabled);
706 Assert(RT_SUCCESS(rc));
707 if(RT_SUCCESS(rc))
708 {
709 pInfo->bDhcpEnabled = bEnabled;
710 }
711 }
712 RTMemFree(pAddresses);
713
714 return VINF_SUCCESS;
715}
716
717static int netIfEnableStaticIpConfig(const Guid &guid, ULONG ip, ULONG mask)
718{
719 HRESULT hr;
720 ComPtr <IWbemServices> pSvc;
721 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
722 if(SUCCEEDED(hr))
723 {
724 ComPtr <IWbemClassObject> pAdapterConfig;
725 hr = netIfWinFindAdapterClassById(pSvc, guid, pAdapterConfig.asOutParam());
726 if(SUCCEEDED(hr))
727 {
728 in_addr aIp[1];
729 in_addr aMask[1];
730 aIp[0].S_un.S_addr = ip;
731 aMask[0].S_un.S_addr = mask;
732
733 BSTR ObjPath;
734 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
735 if(SUCCEEDED(hr))
736 {
737 hr = netIfWinEnableStaticV4(pSvc, ObjPath, aIp, aMask, 1);
738 if(SUCCEEDED(hr))
739 {
740#if 0
741 in_addr aGw[1];
742 aGw[0].S_un.S_addr = gw;
743 hr = netIfWinSetGatewaysV4(pSvc, ObjPath, aGw, 1);
744 if(SUCCEEDED(hr))
745#endif
746 {
747// hr = netIfWinUpdateConfig(pIf);
748 }
749 }
750 SysFreeString(ObjPath);
751 }
752 }
753 }
754
755 return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
756}
757
758static int netIfEnableStaticIpConfigV6(const Guid & guid, IN_BSTR aIPV6Address, IN_BSTR aIPV6Mask, IN_BSTR aIPV6DefaultGateway)
759{
760 HRESULT hr;
761 ComPtr <IWbemServices> pSvc;
762 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
763 if(SUCCEEDED(hr))
764 {
765 ComPtr <IWbemClassObject> pAdapterConfig;
766 hr = netIfWinFindAdapterClassById(pSvc, guid, pAdapterConfig.asOutParam());
767 if(SUCCEEDED(hr))
768 {
769 BSTR ObjPath;
770 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
771 if(SUCCEEDED(hr))
772 {
773 hr = netIfWinEnableStaticV4V6(pSvc, ObjPath, aIPV6Address, aIPV6Mask);
774 if(SUCCEEDED(hr))
775 {
776 if(aIPV6DefaultGateway)
777 {
778 hr = netIfWinSetGatewaysV4V6(pSvc, ObjPath, aIPV6DefaultGateway);
779 }
780 if(SUCCEEDED(hr))
781 {
782// hr = netIfWinUpdateConfig(pIf);
783 }
784 }
785 SysFreeString(ObjPath);
786 }
787 }
788 }
789
790 return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
791}
792
793static int netIfEnableStaticIpConfigV6(const Guid &guid, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
794{
795 RTNETADDRIPV6 Mask;
796 int rc = prefixLength2IPv6Address(aIPV6MaskPrefixLength, &Mask);
797 if(RT_SUCCESS(rc))
798 {
799 Bstr maskStr = composeIPv6Address(&Mask);
800 rc = netIfEnableStaticIpConfigV6(guid, aIPV6Address, maskStr, NULL);
801 }
802 return rc;
803}
804
805static HRESULT netIfEnableDynamicIpConfig(const Guid &guid)
806{
807 HRESULT hr;
808 ComPtr <IWbemServices> pSvc;
809 hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
810 if(SUCCEEDED(hr))
811 {
812 ComPtr <IWbemClassObject> pAdapterConfig;
813 hr = netIfWinFindAdapterClassById(pSvc, guid, pAdapterConfig.asOutParam());
814 if(SUCCEEDED(hr))
815 {
816 BSTR ObjPath;
817 hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
818 if(SUCCEEDED(hr))
819 {
820 hr = netIfWinEnableDHCP(pSvc, ObjPath);
821 if(SUCCEEDED(hr))
822 {
823// hr = netIfWinUpdateConfig(pIf);
824 }
825 SysFreeString(ObjPath);
826 }
827 }
828 }
829
830
831 return hr;
832}
833
834/* svc helper func */
835
836struct StaticIpConfig
837{
838 ULONG IPAddress;
839 ULONG IPNetMask;
840};
841
842struct StaticIpV6Config
843{
844 BSTR IPV6Address;
845 ULONG IPV6NetMaskLength;
846};
847
848struct NetworkInterfaceHelperClientData
849{
850 SVCHlpMsg::Code msgCode;
851 /* for SVCHlpMsg::CreateHostOnlyNetworkInterface */
852 Bstr name;
853 ComObjPtr <HostNetworkInterface> iface;
854 /* for SVCHlpMsg::RemoveHostOnlyNetworkInterface */
855 Guid guid;
856
857 union
858 {
859 StaticIpConfig StaticIP;
860 StaticIpV6Config StaticIPV6;
861 } u;
862
863
864};
865
866static HRESULT netIfNetworkInterfaceHelperClient (SVCHlpClient *aClient,
867 Progress *aProgress,
868 void *aUser, int *aVrc)
869{
870 LogFlowFuncEnter();
871 LogFlowFunc (("aClient={%p}, aProgress={%p}, aUser={%p}\n",
872 aClient, aProgress, aUser));
873
874 AssertReturn ((aClient == NULL && aProgress == NULL && aVrc == NULL) ||
875 (aClient != NULL && aProgress != NULL && aVrc != NULL),
876 E_POINTER);
877 AssertReturn (aUser, E_POINTER);
878
879 std::auto_ptr <NetworkInterfaceHelperClientData>
880 d (static_cast <NetworkInterfaceHelperClientData *> (aUser));
881
882 if (aClient == NULL)
883 {
884 /* "cleanup only" mode, just return (it will free aUser) */
885 return S_OK;
886 }
887
888 HRESULT rc = S_OK;
889 int vrc = VINF_SUCCESS;
890
891 switch (d->msgCode)
892 {
893 case SVCHlpMsg::CreateHostOnlyNetworkInterface:
894 {
895 LogFlowFunc (("CreateHostOnlyNetworkInterface:\n"));
896 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
897
898 /* write message and parameters */
899 vrc = aClient->write (d->msgCode);
900 if (RT_FAILURE (vrc)) break;
901// vrc = aClient->write (Utf8Str (d->name));
902// if (RT_FAILURE (vrc)) break;
903
904 /* wait for a reply */
905 bool endLoop = false;
906 while (!endLoop)
907 {
908 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
909
910 vrc = aClient->read (reply);
911 if (RT_FAILURE (vrc)) break;
912
913 switch (reply)
914 {
915 case SVCHlpMsg::CreateHostOnlyNetworkInterface_OK:
916 {
917 /* read the GUID */
918 Guid guid;
919 Utf8Str name;
920 vrc = aClient->read (name);
921 if (RT_FAILURE (vrc)) break;
922 vrc = aClient->read (guid);
923 if (RT_FAILURE (vrc)) break;
924
925 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", guid.raw()));
926
927 /* initialize the object returned to the caller by
928 * CreateHostOnlyNetworkInterface() */
929 rc = d->iface->init (Bstr(name), guid, HostNetworkInterfaceType_HostOnly);
930 endLoop = true;
931 break;
932 }
933 case SVCHlpMsg::Error:
934 {
935 /* read the error message */
936 Utf8Str errMsg;
937 vrc = aClient->read (errMsg);
938 if (RT_FAILURE (vrc)) break;
939
940 rc = E_FAIL;//TODO: setError (E_FAIL, errMsg);
941 endLoop = true;
942 break;
943 }
944 default:
945 {
946 endLoop = true;
947 rc = E_FAIL;//TODO: ComAssertMsgFailedBreak ((
948 //"Invalid message code %d (%08lX)\n",
949 //reply, reply),
950 //rc = E_FAIL);
951 }
952 }
953 }
954
955 break;
956 }
957 case SVCHlpMsg::RemoveHostOnlyNetworkInterface:
958 {
959 LogFlowFunc (("RemoveHostOnlyNetworkInterface:\n"));
960 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", d->guid.raw()));
961
962 /* write message and parameters */
963 vrc = aClient->write (d->msgCode);
964 if (RT_FAILURE (vrc)) break;
965 vrc = aClient->write (d->guid);
966 if (RT_FAILURE (vrc)) break;
967
968 /* wait for a reply */
969 bool endLoop = false;
970 while (!endLoop)
971 {
972 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
973
974 vrc = aClient->read (reply);
975 if (RT_FAILURE (vrc)) break;
976
977 switch (reply)
978 {
979 case SVCHlpMsg::OK:
980 {
981 /* no parameters */
982 rc = S_OK;
983 endLoop = true;
984 break;
985 }
986 case SVCHlpMsg::Error:
987 {
988 /* read the error message */
989 Utf8Str errMsg;
990 vrc = aClient->read (errMsg);
991 if (RT_FAILURE (vrc)) break;
992
993 rc = E_FAIL; // TODO: setError (E_FAIL, errMsg);
994 endLoop = true;
995 break;
996 }
997 default:
998 {
999 endLoop = true;
1000 rc = E_FAIL; // TODO: ComAssertMsgFailedBreak ((
1001 //"Invalid message code %d (%08lX)\n",
1002 //reply, reply),
1003 //rc = E_FAIL);
1004 }
1005 }
1006 }
1007
1008 break;
1009 }
1010 case SVCHlpMsg::EnableDynamicIpConfig: /* see usage in code */
1011 {
1012 LogFlowFunc (("EnableDynamicIpConfig:\n"));
1013 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
1014
1015 /* write message and parameters */
1016 vrc = aClient->write (d->msgCode);
1017 if (RT_FAILURE (vrc)) break;
1018 vrc = aClient->write (d->guid);
1019 if (RT_FAILURE (vrc)) break;
1020
1021 /* wait for a reply */
1022 bool endLoop = false;
1023 while (!endLoop)
1024 {
1025 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
1026
1027 vrc = aClient->read (reply);
1028 if (RT_FAILURE (vrc)) break;
1029
1030 switch (reply)
1031 {
1032 case SVCHlpMsg::OK:
1033 {
1034 /* no parameters */
1035 rc = d->iface->updateConfig();
1036 endLoop = true;
1037 break;
1038 }
1039 case SVCHlpMsg::Error:
1040 {
1041 /* read the error message */
1042 Utf8Str errMsg;
1043 vrc = aClient->read (errMsg);
1044 if (RT_FAILURE (vrc)) break;
1045
1046 rc = E_FAIL; // TODO: setError (E_FAIL, errMsg);
1047 endLoop = true;
1048 break;
1049 }
1050 default:
1051 {
1052 endLoop = true;
1053 rc = E_FAIL; // TODO: ComAssertMsgFailedBreak ((
1054 //"Invalid message code %d (%08lX)\n",
1055 //reply, reply),
1056 //rc = E_FAIL);
1057 }
1058 }
1059 }
1060
1061 break;
1062 }
1063 case SVCHlpMsg::EnableStaticIpConfig: /* see usage in code */
1064 {
1065 LogFlowFunc (("EnableStaticIpConfig:\n"));
1066 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
1067
1068 /* write message and parameters */
1069 vrc = aClient->write (d->msgCode);
1070 if (RT_FAILURE (vrc)) break;
1071 vrc = aClient->write (d->guid);
1072 if (RT_FAILURE (vrc)) break;
1073 vrc = aClient->write (d->u.StaticIP.IPAddress);
1074 if (RT_FAILURE (vrc)) break;
1075 vrc = aClient->write (d->u.StaticIP.IPNetMask);
1076 if (RT_FAILURE (vrc)) break;
1077
1078 /* wait for a reply */
1079 bool endLoop = false;
1080 while (!endLoop)
1081 {
1082 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
1083
1084 vrc = aClient->read (reply);
1085 if (RT_FAILURE (vrc)) break;
1086
1087 switch (reply)
1088 {
1089 case SVCHlpMsg::OK:
1090 {
1091 /* no parameters */
1092 rc = d->iface->updateConfig();
1093 endLoop = true;
1094 break;
1095 }
1096 case SVCHlpMsg::Error:
1097 {
1098 /* read the error message */
1099 Utf8Str errMsg;
1100 vrc = aClient->read (errMsg);
1101 if (RT_FAILURE (vrc)) break;
1102
1103 rc = E_FAIL; // TODO: setError (E_FAIL, errMsg);
1104 endLoop = true;
1105 break;
1106 }
1107 default:
1108 {
1109 endLoop = true;
1110 rc = E_FAIL; // TODO: ComAssertMsgFailedBreak ((
1111 //"Invalid message code %d (%08lX)\n",
1112 //reply, reply),
1113 //rc = E_FAIL);
1114 }
1115 }
1116 }
1117
1118 break;
1119 }
1120 case SVCHlpMsg::EnableStaticIpConfigV6: /* see usage in code */
1121 {
1122 LogFlowFunc (("EnableStaticIpConfigV6:\n"));
1123 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
1124
1125 /* write message and parameters */
1126 vrc = aClient->write (d->msgCode);
1127 if (RT_FAILURE (vrc)) break;
1128 vrc = aClient->write (d->guid);
1129 if (RT_FAILURE (vrc)) break;
1130 vrc = aClient->write (Utf8Str(d->u.StaticIPV6.IPV6Address));
1131 if (RT_FAILURE (vrc)) break;
1132 vrc = aClient->write (d->u.StaticIPV6.IPV6NetMaskLength);
1133 if (RT_FAILURE (vrc)) break;
1134
1135 /* wait for a reply */
1136 bool endLoop = false;
1137 while (!endLoop)
1138 {
1139 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
1140
1141 vrc = aClient->read (reply);
1142 if (RT_FAILURE (vrc)) break;
1143
1144 switch (reply)
1145 {
1146 case SVCHlpMsg::OK:
1147 {
1148 /* no parameters */
1149 rc = d->iface->updateConfig();
1150 endLoop = true;
1151 break;
1152 }
1153 case SVCHlpMsg::Error:
1154 {
1155 /* read the error message */
1156 Utf8Str errMsg;
1157 vrc = aClient->read (errMsg);
1158 if (RT_FAILURE (vrc)) break;
1159
1160 rc = E_FAIL; // TODO: setError (E_FAIL, errMsg);
1161 endLoop = true;
1162 break;
1163 }
1164 default:
1165 {
1166 endLoop = true;
1167 rc = E_FAIL; // TODO: ComAssertMsgFailedBreak ((
1168 //"Invalid message code %d (%08lX)\n",
1169 //reply, reply),
1170 //rc = E_FAIL);
1171 }
1172 }
1173 }
1174
1175 break;
1176 }
1177 default:
1178 rc = E_FAIL; // TODO: ComAssertMsgFailedBreak ((
1179// "Invalid message code %d (%08lX)\n",
1180// d->msgCode, d->msgCode),
1181// rc = E_FAIL);
1182 }
1183
1184 if (aVrc)
1185 *aVrc = vrc;
1186
1187 LogFlowFunc (("rc=0x%08X, vrc=%Rrc\n", rc, vrc));
1188 LogFlowFuncLeave();
1189 return rc;
1190}
1191
1192
1193/* The original source of the VBoxTAP adapter creation/destruction code has the following copyright */
1194/*
1195 Copyright 2004 by the Massachusetts Institute of Technology
1196
1197 All rights reserved.
1198
1199 Permission to use, copy, modify, and distribute this software and its
1200 documentation for any purpose and without fee is hereby granted,
1201 provided that the above copyright notice appear in all copies and that
1202 both that copyright notice and this permission notice appear in
1203 supporting documentation, and that the name of the Massachusetts
1204 Institute of Technology (M.I.T.) not be used in advertising or publicity
1205 pertaining to distribution of the software without specific, written
1206 prior permission.
1207
1208 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1209 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1210 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1211 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1212 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1213 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1214 SOFTWARE.
1215*/
1216
1217
1218#define NETSHELL_LIBRARY _T("netshell.dll")
1219
1220/**
1221 * Use the IShellFolder API to rename the connection.
1222 */
1223static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
1224{
1225 /* This is the GUID for the network connections folder. It is constant.
1226 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
1227 const GUID CLSID_NetworkConnections = {
1228 0x7007ACC7, 0x3202, 0x11D1, {
1229 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
1230 }
1231 };
1232
1233 LPITEMIDLIST pidl = NULL;
1234 IShellFolder *pShellFolder = NULL;
1235 HRESULT hr;
1236
1237 /* Build the display name in the form "::{GUID}". */
1238 if (wcslen (wGuid) >= MAX_PATH)
1239 return E_INVALIDARG;
1240 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
1241 swprintf (szAdapterGuid, L"::%ls", wGuid);
1242
1243 /* Create an instance of the network connections folder. */
1244 hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
1245 CLSCTX_INPROC_SERVER, IID_IShellFolder,
1246 reinterpret_cast <LPVOID *> (&pShellFolder));
1247 /* Parse the display name. */
1248 if (SUCCEEDED (hr))
1249 {
1250 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
1251 &pidl, NULL);
1252 }
1253 if (SUCCEEDED (hr))
1254 {
1255 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
1256 &pidl);
1257 }
1258
1259 CoTaskMemFree (pidl);
1260
1261 if (pShellFolder)
1262 pShellFolder->Release();
1263
1264 return hr;
1265}
1266
1267static HRESULT netIfRenameConnection (PCWSTR GuidString, PCWSTR NewName)
1268{
1269 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
1270 lpHrRenameConnection RenameConnectionFunc = NULL;
1271 HRESULT status;
1272
1273 /* First try the IShellFolder interface, which was unimplemented
1274 * for the network connections folder before XP. */
1275 status = rename_shellfolder (GuidString, NewName);
1276 if (status == E_NOTIMPL)
1277 {
1278/** @todo that code doesn't seem to work! */
1279 /* The IShellFolder interface is not implemented on this platform.
1280 * Try the (undocumented) HrRenameConnection API in the netshell
1281 * library. */
1282 CLSID clsid;
1283 HINSTANCE hNetShell;
1284 status = CLSIDFromString ((LPOLESTR) GuidString, &clsid);
1285 if (FAILED(status))
1286 return E_FAIL;
1287 hNetShell = LoadLibrary (NETSHELL_LIBRARY);
1288 if (hNetShell == NULL)
1289 return E_FAIL;
1290 RenameConnectionFunc =
1291 (lpHrRenameConnection) GetProcAddress (hNetShell,
1292 "HrRenameConnection");
1293 if (RenameConnectionFunc == NULL)
1294 {
1295 FreeLibrary (hNetShell);
1296 return E_FAIL;
1297 }
1298 status = RenameConnectionFunc (&clsid, NewName);
1299 FreeLibrary (hNetShell);
1300 }
1301 if (FAILED (status))
1302 return status;
1303
1304 return S_OK;
1305}
1306#define VBOX_CONNECTION_NAME L"Virtualbox Host-Only Network"
1307static HRESULT netIfGenConnectionName (PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf)
1308{
1309 const WCHAR * pSuffix = wcsrchr( DevName, L'#' );
1310 ULONG cbSize = sizeof(VBOX_CONNECTION_NAME);
1311 ULONG cbSufSize = 0;
1312
1313 if(pSuffix)
1314 {
1315 cbSize += (ULONG)wcslen(pSuffix) * 2;
1316 }
1317
1318 if(*pcbBuf < cbSize)
1319 {
1320 *pcbBuf = cbSize;
1321 return E_FAIL;
1322 }
1323
1324 wcscpy(pBuf, VBOX_CONNECTION_NAME);
1325 if(pSuffix)
1326 {
1327 wcscat(pBuf, pSuffix);
1328 }
1329
1330 return S_OK;
1331}
1332
1333#define DRIVERHWID _T("sun_VBoxNetAdp")
1334
1335#define SetErrBreak(strAndArgs) \
1336 if (1) { \
1337 aErrMsg = Utf8StrFmt strAndArgs; vrc = VERR_GENERAL_FAILURE; break; \
1338 } else do {} while (0)
1339
1340/* static */
1341static int createNetworkInterface (SVCHlpClient *aClient,
1342 BSTR * pName,
1343 Guid &aGUID, Utf8Str &aErrMsg)
1344{
1345 LogFlowFuncEnter();
1346// LogFlowFunc (("Network connection name = '%s'\n", aName.raw()));
1347
1348 AssertReturn (aClient, VERR_INVALID_POINTER);
1349// AssertReturn (!aName.isNull(), VERR_INVALID_PARAMETER);
1350
1351 int vrc = VINF_SUCCESS;
1352
1353 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1354 SP_DEVINFO_DATA DeviceInfoData;
1355 DWORD ret = 0;
1356 BOOL found = FALSE;
1357 BOOL registered = FALSE;
1358 BOOL destroyList = FALSE;
1359 TCHAR pCfgGuidString [50];
1360
1361 do
1362 {
1363 BOOL ok;
1364 GUID netGuid;
1365 SP_DRVINFO_DATA DriverInfoData;
1366 SP_DEVINSTALL_PARAMS DeviceInstallParams;
1367 TCHAR className [MAX_PATH];
1368 DWORD index = 0;
1369 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
1370 /* for our purposes, 2k buffer is more
1371 * than enough to obtain the hardware ID
1372 * of the VBoxTAP driver. */
1373 DWORD detailBuf [2048];
1374
1375 HKEY hkey = NULL;
1376 DWORD cbSize;
1377 DWORD dwValueType;
1378
1379 /* initialize the structure size */
1380 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1381 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
1382
1383 /* copy the net class GUID */
1384 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
1385
1386 /* create an empty device info set associated with the net class GUID */
1387 hDeviceInfo = SetupDiCreateDeviceInfoList (&netGuid, NULL);
1388 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1389 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
1390 GetLastError()));
1391
1392 /* get the class name from GUID */
1393 ok = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
1394 if (!ok)
1395 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
1396 GetLastError()));
1397
1398 /* create a device info element and add the new device instance
1399 * key to registry */
1400 ok = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
1401 DICD_GENERATE_ID, &DeviceInfoData);
1402 if (!ok)
1403 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
1404 GetLastError()));
1405
1406 /* select the newly created device info to be the currently
1407 selected member */
1408 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
1409 if (!ok)
1410 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
1411 GetLastError()));
1412
1413 /* build a list of class drivers */
1414 ok = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
1415 SPDIT_CLASSDRIVER);
1416 if (!ok)
1417 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
1418 GetLastError()));
1419
1420 destroyList = TRUE;
1421
1422 /* enumerate the driver info list */
1423 while (TRUE)
1424 {
1425 BOOL ret;
1426
1427 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
1428 SPDIT_CLASSDRIVER, index, &DriverInfoData);
1429
1430 /* if the function failed and GetLastError() returned
1431 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
1432 * list. Othewise there was something wrong with this
1433 * particular driver. */
1434 if (!ret)
1435 {
1436 if(GetLastError() == ERROR_NO_MORE_ITEMS)
1437 break;
1438 else
1439 {
1440 index++;
1441 continue;
1442 }
1443 }
1444
1445 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
1446 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1447
1448 /* if we successfully find the hardware ID and it turns out to
1449 * be the one for the loopback driver, then we are done. */
1450 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
1451 &DeviceInfoData,
1452 &DriverInfoData,
1453 pDriverInfoDetail,
1454 sizeof (detailBuf),
1455 NULL))
1456 {
1457 TCHAR * t;
1458
1459 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
1460 * whole list and see if there is a match somewhere. */
1461 t = pDriverInfoDetail->HardwareID;
1462 while (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
1463 {
1464 if (!_tcsicmp(t, DRIVERHWID))
1465 break;
1466
1467 t += _tcslen(t) + 1;
1468 }
1469
1470 if (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
1471 {
1472 found = TRUE;
1473 break;
1474 }
1475 }
1476
1477 index ++;
1478 }
1479
1480 if (!found)
1481 SetErrBreak (("Could not find Host Interface Networking driver! "
1482 "Please reinstall"));
1483
1484 /* set the loopback driver to be the currently selected */
1485 ok = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
1486 &DriverInfoData);
1487 if (!ok)
1488 SetErrBreak (("SetupDiSetSelectedDriver failed (0x%08X)",
1489 GetLastError()));
1490
1491 /* register the phantom device to prepare for install */
1492 ok = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
1493 &DeviceInfoData);
1494 if (!ok)
1495 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
1496 GetLastError()));
1497
1498 /* registered, but remove if errors occur in the following code */
1499 registered = TRUE;
1500
1501 /* ask the installer if we can install the device */
1502 ok = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
1503 &DeviceInfoData);
1504 if (!ok)
1505 {
1506 if (GetLastError() != ERROR_DI_DO_DEFAULT)
1507 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
1508 GetLastError()));
1509 /* that's fine */
1510 }
1511
1512 /* install the files first */
1513 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
1514 &DeviceInfoData);
1515 if (!ok)
1516 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
1517 GetLastError()));
1518
1519 /* get the device install parameters and disable filecopy */
1520 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1521 ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
1522 &DeviceInstallParams);
1523 if (ok)
1524 {
1525 DeviceInstallParams.Flags |= DI_NOFILECOPY;
1526 ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
1527 &DeviceInstallParams);
1528 if (!ok)
1529 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
1530 GetLastError()));
1531 }
1532
1533 /*
1534 * Register any device-specific co-installers for this device,
1535 */
1536
1537 ok = SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
1538 hDeviceInfo,
1539 &DeviceInfoData);
1540 if (!ok)
1541 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
1542 GetLastError()));
1543
1544 /*
1545 * install any installer-specified interfaces.
1546 * and then do the real install
1547 */
1548 ok = SetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
1549 hDeviceInfo,
1550 &DeviceInfoData);
1551 if (!ok)
1552 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
1553 GetLastError()));
1554
1555 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICE,
1556 hDeviceInfo,
1557 &DeviceInfoData);
1558 if (!ok)
1559 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
1560 GetLastError()));
1561
1562 /* Figure out NetCfgInstanceId */
1563 hkey = SetupDiOpenDevRegKey (hDeviceInfo,
1564 &DeviceInfoData,
1565 DICS_FLAG_GLOBAL,
1566 0,
1567 DIREG_DRV,
1568 KEY_READ);
1569 if (hkey == INVALID_HANDLE_VALUE)
1570 SetErrBreak (("SetupDiOpenDevRegKey failed (0x%08X)",
1571 GetLastError()));
1572
1573 cbSize = sizeof (pCfgGuidString);
1574 DWORD ret;
1575 ret = RegQueryValueEx (hkey, _T("NetCfgInstanceId"), NULL,
1576 &dwValueType, (LPBYTE) pCfgGuidString, &cbSize);
1577 RegCloseKey (hkey);
1578 }
1579 while (0);
1580
1581 /*
1582 * cleanup
1583 */
1584
1585 if (hDeviceInfo != INVALID_HANDLE_VALUE)
1586 {
1587 /* an error has occured, but the device is registered, we must remove it */
1588 if (ret != 0 && registered)
1589 SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
1590
1591 found = SetupDiDeleteDeviceInfo (hDeviceInfo, &DeviceInfoData);
1592
1593 /* destroy the driver info list */
1594 if (destroyList)
1595 SetupDiDestroyDriverInfoList (hDeviceInfo, &DeviceInfoData,
1596 SPDIT_CLASSDRIVER);
1597 /* clean up the device info set */
1598 SetupDiDestroyDeviceInfoList (hDeviceInfo);
1599 }
1600
1601 /* return the network connection GUID on success */
1602 if (RT_SUCCESS (vrc))
1603 {
1604 /* remove the curly bracket at the end */
1605 pCfgGuidString [_tcslen (pCfgGuidString) - 1] = '\0';
1606 LogFlowFunc (("Network connection GUID string = {%ls}\n", pCfgGuidString + 1));
1607
1608 aGUID = Guid (Utf8Str (pCfgGuidString + 1));
1609 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", aGUID.raw()));
1610 Assert (!aGUID.isEmpty());
1611
1612 INetCfg *pNc;
1613 INetCfgComponent *pMpNcc;
1614 LPWSTR lpszApp;
1615
1616 HRESULT hr = VBoxNetCfgWinQueryINetCfg( FALSE,
1617 VBOX_APP_NAME,
1618 &pNc,
1619 &lpszApp );
1620 if(hr == S_OK)
1621 {
1622 hr = VBoxNetCfgWinGetComponentByGuid(pNc,
1623 &GUID_DEVCLASS_NET,
1624 aGUID.asOutParam(),
1625 &pMpNcc);
1626 if(hr == S_OK)
1627 {
1628 LPWSTR name;
1629 hr = pMpNcc->GetDisplayName(&name);
1630 if(hr == S_OK)
1631 {
1632 Bstr str(name);
1633 str.detachTo(pName);
1634 WCHAR ConnectoinName[128];
1635 ULONG cbBuf = sizeof(ConnectoinName);
1636
1637 /* return back the bracket */
1638 pCfgGuidString [_tcslen (pCfgGuidString)] = '}';
1639
1640 hr = netIfGenConnectionName (name, ConnectoinName, &cbBuf);
1641 if(hr == S_OK)
1642 {
1643 hr = netIfRenameConnection (pCfgGuidString, ConnectoinName);
1644 }
1645
1646 CoTaskMemFree (name);
1647 }
1648
1649 VBoxNetCfgWinReleaseRef(pMpNcc);
1650 }
1651 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
1652 }
1653
1654 if(hr != S_OK)
1655 {
1656 vrc = VERR_GENERAL_FAILURE;
1657 }
1658
1659 }
1660
1661 LogFlowFunc (("vrc=%Rrc\n", vrc));
1662 LogFlowFuncLeave();
1663 return vrc;
1664}
1665
1666/* static */
1667static int removeNetworkInterface (SVCHlpClient *aClient,
1668 const Guid &aGUID,
1669 Utf8Str &aErrMsg)
1670{
1671 LogFlowFuncEnter();
1672 LogFlowFunc (("Network connection GUID = {%RTuuid}\n", aGUID.raw()));
1673
1674 AssertReturn (aClient, VERR_INVALID_POINTER);
1675 AssertReturn (!aGUID.isEmpty(), VERR_INVALID_PARAMETER);
1676
1677 int vrc = VINF_SUCCESS;
1678
1679 do
1680 {
1681 TCHAR lszPnPInstanceId [512] = {0};
1682
1683 /* We have to find the device instance ID through a registry search */
1684
1685 HKEY hkeyNetwork = 0;
1686 HKEY hkeyConnection = 0;
1687
1688 do
1689 {
1690 char strRegLocation [256];
1691 sprintf (strRegLocation,
1692 "SYSTEM\\CurrentControlSet\\Control\\Network\\"
1693 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\{%s}",
1694 aGUID.toString().raw());
1695 LONG status;
1696 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, strRegLocation, 0,
1697 KEY_READ, &hkeyNetwork);
1698 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
1699 SetErrBreak ((
1700 "Host interface network is not found in registry (%s) [1]",
1701 strRegLocation));
1702
1703 status = RegOpenKeyExA (hkeyNetwork, "Connection", 0,
1704 KEY_READ, &hkeyConnection);
1705 if ((status != ERROR_SUCCESS) || !hkeyConnection)
1706 SetErrBreak ((
1707 "Host interface network is not found in registry (%s) [2]",
1708 strRegLocation));
1709
1710 DWORD len = sizeof (lszPnPInstanceId);
1711 DWORD dwKeyType;
1712 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
1713 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
1714 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
1715 SetErrBreak ((
1716 "Host interface network is not found in registry (%s) [3]",
1717 strRegLocation));
1718 }
1719 while (0);
1720
1721 if (hkeyConnection)
1722 RegCloseKey (hkeyConnection);
1723 if (hkeyNetwork)
1724 RegCloseKey (hkeyNetwork);
1725
1726 if (RT_FAILURE (vrc))
1727 break;
1728
1729 /*
1730 * Now we are going to enumerate all network devices and
1731 * wait until we encounter the right device instance ID
1732 */
1733
1734 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1735
1736 do
1737 {
1738 BOOL ok;
1739 DWORD ret = 0;
1740 GUID netGuid;
1741 SP_DEVINFO_DATA DeviceInfoData;
1742 DWORD index = 0;
1743 BOOL found = FALSE;
1744 DWORD size = 0;
1745
1746 /* initialize the structure size */
1747 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
1748
1749 /* copy the net class GUID */
1750 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
1751
1752 /* return a device info set contains all installed devices of the Net class */
1753 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
1754
1755 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1756 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
1757
1758 /* enumerate the driver info list */
1759 while (TRUE)
1760 {
1761 TCHAR *deviceHwid;
1762
1763 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
1764
1765 if (!ok)
1766 {
1767 if (GetLastError() == ERROR_NO_MORE_ITEMS)
1768 break;
1769 else
1770 {
1771 index++;
1772 continue;
1773 }
1774 }
1775
1776 /* try to get the hardware ID registry property */
1777 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
1778 &DeviceInfoData,
1779 SPDRP_HARDWAREID,
1780 NULL,
1781 NULL,
1782 0,
1783 &size);
1784 if (!ok)
1785 {
1786 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1787 {
1788 index++;
1789 continue;
1790 }
1791
1792 deviceHwid = (TCHAR *) malloc (size);
1793 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
1794 &DeviceInfoData,
1795 SPDRP_HARDWAREID,
1796 NULL,
1797 (PBYTE)deviceHwid,
1798 size,
1799 NULL);
1800 if (!ok)
1801 {
1802 free (deviceHwid);
1803 deviceHwid = NULL;
1804 index++;
1805 continue;
1806 }
1807 }
1808 else
1809 {
1810 /* something is wrong. This shouldn't have worked with a NULL buffer */
1811 index++;
1812 continue;
1813 }
1814
1815 for (TCHAR *t = deviceHwid;
1816 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
1817 t += _tcslen (t) + 1)
1818 {
1819 if (!_tcsicmp (DRIVERHWID, t))
1820 {
1821 /* get the device instance ID */
1822 TCHAR devID [MAX_DEVICE_ID_LEN];
1823 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
1824 devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
1825 {
1826 /* compare to what we determined before */
1827 if (wcscmp(devID, lszPnPInstanceId) == 0)
1828 {
1829 found = TRUE;
1830 break;
1831 }
1832 }
1833 }
1834 }
1835
1836 if (deviceHwid)
1837 {
1838 free (deviceHwid);
1839 deviceHwid = NULL;
1840 }
1841
1842 if (found)
1843 break;
1844
1845 index++;
1846 }
1847
1848 if (found == FALSE)
1849 SetErrBreak (("Host Interface Network driver not found (0x%08X)",
1850 GetLastError()));
1851
1852 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
1853 if (!ok)
1854 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
1855 GetLastError()));
1856
1857 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
1858 if (!ok)
1859 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
1860 GetLastError()));
1861 }
1862 while (0);
1863
1864 /* clean up the device info set */
1865 if (hDeviceInfo != INVALID_HANDLE_VALUE)
1866 SetupDiDestroyDeviceInfoList (hDeviceInfo);
1867
1868 if (RT_FAILURE (vrc))
1869 break;
1870 }
1871 while (0);
1872
1873 LogFlowFunc (("vrc=%Rrc\n", vrc));
1874 LogFlowFuncLeave();
1875 return vrc;
1876}
1877
1878#undef SetErrBreak
1879
1880int netIfNetworkInterfaceHelperServer (SVCHlpClient *aClient,
1881 SVCHlpMsg::Code aMsgCode)
1882{
1883 LogFlowFuncEnter();
1884 LogFlowFunc (("aClient={%p}, aMsgCode=%d\n", aClient, aMsgCode));
1885
1886 AssertReturn (aClient, VERR_INVALID_POINTER);
1887
1888 int vrc = VINF_SUCCESS;
1889
1890 switch (aMsgCode)
1891 {
1892 case SVCHlpMsg::CreateHostOnlyNetworkInterface:
1893 {
1894 LogFlowFunc (("CreateHostOnlyNetworkInterface:\n"));
1895
1896// Utf8Str name;
1897// vrc = aClient->read (name);
1898// if (RT_FAILURE (vrc)) break;
1899
1900 Guid guid;
1901 Utf8Str errMsg;
1902 Bstr name;
1903 vrc = createNetworkInterface (aClient, name.asOutParam(), guid, errMsg);
1904
1905 if (RT_SUCCESS (vrc))
1906 {
1907 /* write success followed by GUID */
1908 vrc = aClient->write (SVCHlpMsg::CreateHostOnlyNetworkInterface_OK);
1909 if (RT_FAILURE (vrc)) break;
1910 vrc = aClient->write (Utf8Str (name));
1911 if (RT_FAILURE (vrc)) break;
1912 vrc = aClient->write (guid);
1913 if (RT_FAILURE (vrc)) break;
1914 }
1915 else
1916 {
1917 /* write failure followed by error message */
1918 if (errMsg.isEmpty())
1919 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
1920 vrc = aClient->write (SVCHlpMsg::Error);
1921 if (RT_FAILURE (vrc)) break;
1922 vrc = aClient->write (errMsg);
1923 if (RT_FAILURE (vrc)) break;
1924 }
1925
1926 break;
1927 }
1928 case SVCHlpMsg::RemoveHostOnlyNetworkInterface:
1929 {
1930 LogFlowFunc (("RemoveHostOnlyNetworkInterface:\n"));
1931
1932 Guid guid;
1933 vrc = aClient->read (guid);
1934 if (RT_FAILURE (vrc)) break;
1935
1936 Utf8Str errMsg;
1937 vrc = removeNetworkInterface (aClient, guid, errMsg);
1938
1939 if (RT_SUCCESS (vrc))
1940 {
1941 /* write parameter-less success */
1942 vrc = aClient->write (SVCHlpMsg::OK);
1943 if (RT_FAILURE (vrc)) break;
1944 }
1945 else
1946 {
1947 /* write failure followed by error message */
1948 if (errMsg.isEmpty())
1949 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
1950 vrc = aClient->write (SVCHlpMsg::Error);
1951 if (RT_FAILURE (vrc)) break;
1952 vrc = aClient->write (errMsg);
1953 if (RT_FAILURE (vrc)) break;
1954 }
1955
1956 break;
1957 }
1958 case SVCHlpMsg::EnableStaticIpConfigV6:
1959 {
1960 LogFlowFunc (("EnableStaticIpConfigV6:\n"));
1961
1962 Guid guid;
1963 Utf8Str ipV6;
1964 ULONG maskLengthV6;
1965 vrc = aClient->read (guid);
1966 if (RT_FAILURE (vrc)) break;
1967 vrc = aClient->read (ipV6);
1968 if (RT_FAILURE (vrc)) break;
1969 vrc = aClient->read (maskLengthV6);
1970 if (RT_FAILURE (vrc)) break;
1971
1972 Utf8Str errMsg;
1973 vrc = netIfEnableStaticIpConfigV6 (guid, Bstr(ipV6), maskLengthV6);
1974
1975 if (RT_SUCCESS (vrc))
1976 {
1977 /* write success followed by GUID */
1978 vrc = aClient->write (SVCHlpMsg::OK);
1979 if (RT_FAILURE (vrc)) break;
1980 }
1981 else
1982 {
1983 /* write failure followed by error message */
1984 if (errMsg.isEmpty())
1985 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
1986 vrc = aClient->write (SVCHlpMsg::Error);
1987 if (RT_FAILURE (vrc)) break;
1988 vrc = aClient->write (errMsg);
1989 if (RT_FAILURE (vrc)) break;
1990 }
1991
1992 break;
1993 }
1994 case SVCHlpMsg::EnableStaticIpConfig:
1995 {
1996 LogFlowFunc (("EnableStaticIpConfig:\n"));
1997
1998 Guid guid;
1999 ULONG ip, mask;
2000 vrc = aClient->read (guid);
2001 if (RT_FAILURE (vrc)) break;
2002 vrc = aClient->read (ip);
2003 if (RT_FAILURE (vrc)) break;
2004 vrc = aClient->read (mask);
2005 if (RT_FAILURE (vrc)) break;
2006
2007 Utf8Str errMsg;
2008 vrc = netIfEnableStaticIpConfig (guid, ip, mask);
2009
2010 if (RT_SUCCESS (vrc))
2011 {
2012 /* write success followed by GUID */
2013 vrc = aClient->write (SVCHlpMsg::OK);
2014 if (RT_FAILURE (vrc)) break;
2015 }
2016 else
2017 {
2018 /* write failure followed by error message */
2019 if (errMsg.isEmpty())
2020 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
2021 vrc = aClient->write (SVCHlpMsg::Error);
2022 if (RT_FAILURE (vrc)) break;
2023 vrc = aClient->write (errMsg);
2024 if (RT_FAILURE (vrc)) break;
2025 }
2026
2027 break;
2028 }
2029 case SVCHlpMsg::EnableDynamicIpConfig:
2030 {
2031 LogFlowFunc (("EnableDynamicIpConfig:\n"));
2032
2033 Guid guid;
2034 vrc = aClient->read (guid);
2035 if (RT_FAILURE (vrc)) break;
2036
2037 Utf8Str errMsg;
2038 vrc = netIfEnableDynamicIpConfig (guid);
2039
2040 if (RT_SUCCESS (vrc))
2041 {
2042 /* write success followed by GUID */
2043 vrc = aClient->write (SVCHlpMsg::OK);
2044 if (RT_FAILURE (vrc)) break;
2045 }
2046 else
2047 {
2048 /* write failure followed by error message */
2049 if (errMsg.isEmpty())
2050 errMsg = Utf8StrFmt ("Unspecified error (%Rrc)", vrc);
2051 vrc = aClient->write (SVCHlpMsg::Error);
2052 if (RT_FAILURE (vrc)) break;
2053 vrc = aClient->write (errMsg);
2054 if (RT_FAILURE (vrc)) break;
2055 }
2056
2057 break;
2058 }
2059 default:
2060 AssertMsgFailedBreakStmt (
2061 ("Invalid message code %d (%08lX)\n", aMsgCode, aMsgCode),
2062 VERR_GENERAL_FAILURE);
2063 }
2064
2065 LogFlowFunc (("vrc=%Rrc\n", vrc));
2066 LogFlowFuncLeave();
2067 return vrc;
2068}
2069
2070/** @todo REMOVE. OBSOLETE NOW. */
2071/**
2072 * Returns TRUE if the Windows version is 6.0 or greater (i.e. it's Vista and
2073 * later OSes) and it has the UAC (User Account Control) feature enabled.
2074 */
2075static BOOL IsUACEnabled()
2076{
2077 LONG rc = 0;
2078
2079 OSVERSIONINFOEX info;
2080 ZeroMemory (&info, sizeof (OSVERSIONINFOEX));
2081 info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
2082 rc = GetVersionEx ((OSVERSIONINFO *) &info);
2083 AssertReturn (rc != 0, FALSE);
2084
2085 LogFlowFunc (("dwMajorVersion=%d, dwMinorVersion=%d\n",
2086 info.dwMajorVersion, info.dwMinorVersion));
2087
2088 /* we are interested only in Vista (and newer versions...). In all
2089 * earlier versions UAC is not present. */
2090 if (info.dwMajorVersion < 6)
2091 return FALSE;
2092
2093 /* the default EnableLUA value is 1 (Enabled) */
2094 DWORD dwEnableLUA = 1;
2095
2096 HKEY hKey;
2097 rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
2098 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
2099 0, KEY_QUERY_VALUE, &hKey);
2100
2101 Assert (rc == ERROR_SUCCESS || rc == ERROR_PATH_NOT_FOUND);
2102 if (rc == ERROR_SUCCESS)
2103 {
2104
2105 DWORD cbEnableLUA = sizeof (dwEnableLUA);
2106 rc = RegQueryValueExA (hKey, "EnableLUA", NULL, NULL,
2107 (LPBYTE) &dwEnableLUA, &cbEnableLUA);
2108
2109 RegCloseKey (hKey);
2110
2111 Assert (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND);
2112 }
2113
2114 LogFlowFunc (("rc=%d, dwEnableLUA=%d\n", rc, dwEnableLUA));
2115
2116 return dwEnableLUA == 1;
2117}
2118
2119/* end */
2120
2121static int vboxNetWinAddComponent(std::list <ComObjPtr <HostNetworkInterface> > * pPist, INetCfgComponent * pncc, HostNetworkInterfaceType enmType)
2122{
2123 LPWSTR lpszName;
2124 GUID IfGuid;
2125 HRESULT hr;
2126 int rc = VERR_GENERAL_FAILURE;
2127
2128 hr = pncc->GetDisplayName( &lpszName );
2129 Assert(hr == S_OK);
2130 if(hr == S_OK)
2131 {
2132 size_t cUnicodeName = wcslen(lpszName) + 1;
2133 size_t uniLen = (cUnicodeName * 2 + sizeof (OLECHAR) - 1) / sizeof (OLECHAR);
2134 Bstr name (uniLen + 1 /* extra zero */);
2135 wcscpy((wchar_t *) name.mutableRaw(), lpszName);
2136
2137 hr = pncc->GetInstanceGuid(&IfGuid);
2138 Assert(hr == S_OK);
2139 if (hr == S_OK)
2140 {
2141 NETIFINFO Info;
2142 memset(&Info, 0, sizeof(Info));
2143 Info.Uuid = *(Guid(IfGuid).raw());
2144 rc = collectNetIfInfo(name, Guid(IfGuid), &Info);
2145 if (RT_FAILURE(rc))
2146 {
2147 Log(("vboxNetWinAddComponent: collectNetIfInfo() -> %Vrc\n", rc));
2148 }
2149 /* create a new object and add it to the list */
2150 ComObjPtr <HostNetworkInterface> iface;
2151 iface.createObject();
2152 /* remove the curly bracket at the end */
2153 if (SUCCEEDED (iface->init (name, enmType, &Info)))
2154 {
2155 pPist->push_back (iface);
2156 rc = VINF_SUCCESS;
2157 }
2158 else
2159 {
2160 Assert(0);
2161 }
2162 }
2163 CoTaskMemFree(lpszName);
2164 }
2165
2166 return rc;
2167}
2168
2169#endif /* #ifndef VBOX_WITH_NETFLT */
2170
2171
2172static int netIfListHostAdapters(std::list <ComObjPtr <HostNetworkInterface> > &list)
2173{
2174#ifndef VBOX_WITH_NETFLT
2175 /* VBoxNetAdp is available only when VBOX_WITH_NETFLT is enabled */
2176 return VERR_NOT_IMPLEMENTED;
2177#else /* # if defined VBOX_WITH_NETFLT */
2178 INetCfg *pNc;
2179 INetCfgComponent *pMpNcc;
2180 LPWSTR lpszApp = NULL;
2181 HRESULT hr;
2182 IEnumNetCfgComponent *pEnumComponent;
2183
2184 /* we are using the INetCfg API for getting the list of miniports */
2185 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
2186 VBOX_APP_NAME,
2187 &pNc,
2188 &lpszApp );
2189 Assert(hr == S_OK);
2190 if(hr == S_OK)
2191 {
2192 hr = VBoxNetCfgWinGetComponentEnum(pNc, &GUID_DEVCLASS_NET, &pEnumComponent);
2193 if(hr == S_OK)
2194 {
2195 while((hr = VBoxNetCfgWinGetNextComponent(pEnumComponent, &pMpNcc)) == S_OK)
2196 {
2197 ULONG uComponentStatus;
2198 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
2199//#ifndef DEBUG_bird
2200// Assert(hr == S_OK);
2201//#endif
2202 if(hr == S_OK)
2203 {
2204 if(uComponentStatus == 0)
2205 {
2206 LPWSTR pId;
2207 hr = pMpNcc->GetId(&pId);
2208 Assert(hr == S_OK);
2209 if(hr == S_OK)
2210 {
2211 if(!_wcsnicmp(pId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2))
2212 {
2213 vboxNetWinAddComponent(&list, pMpNcc, HostNetworkInterfaceType_HostOnly);
2214 }
2215 CoTaskMemFree(pId);
2216 }
2217 }
2218 }
2219 VBoxNetCfgWinReleaseRef(pMpNcc);
2220 }
2221 Assert(hr == S_OK || hr == S_FALSE);
2222
2223 VBoxNetCfgWinReleaseRef(pEnumComponent);
2224 }
2225 else
2226 {
2227 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
2228 }
2229
2230 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
2231 }
2232 else if(lpszApp)
2233 {
2234 CoTaskMemFree(lpszApp);
2235 }
2236#endif /* # if defined VBOX_WITH_NETFLT */
2237 return VINF_SUCCESS;
2238}
2239
2240int NetIfGetConfig(HostNetworkInterface * pIf, NETIFINFO *pInfo)
2241{
2242#ifndef VBOX_WITH_NETFLT
2243 return VERR_NOT_IMPLEMENTED;
2244#else
2245 Bstr name;
2246 HRESULT hr = pIf->COMGETTER(Name)(name.asOutParam());
2247 if(hr == S_OK)
2248 {
2249 GUID IfGuid;
2250 hr = pIf->COMGETTER(Id)(&IfGuid);
2251 Assert(hr == S_OK);
2252 if (hr == S_OK)
2253 {
2254 return collectNetIfInfo(name, Guid(IfGuid), pInfo);
2255 }
2256 }
2257 return VERR_GENERAL_FAILURE;
2258#endif
2259}
2260
2261int NetIfCreateHostOnlyNetworkInterface (VirtualBox *pVBox,
2262 IHostNetworkInterface **aHostNetworkInterface,
2263 IProgress **aProgress)
2264{
2265 /* create a progress object */
2266 ComObjPtr <Progress> progress;
2267 progress.createObject();
2268
2269 ComPtr<IHost> host;
2270 HRESULT rc = pVBox->COMGETTER(Host)(host.asOutParam());
2271 if(SUCCEEDED(rc))
2272 {
2273 rc = progress->init (pVBox, host,
2274 Bstr (_T ("Creating host only network interface")),
2275 FALSE /* aCancelable */);
2276 if(SUCCEEDED(rc))
2277 {
2278 CheckComRCReturnRC (rc);
2279 progress.queryInterfaceTo (aProgress);
2280
2281 /* create a new uninitialized host interface object */
2282 ComObjPtr <HostNetworkInterface> iface;
2283 iface.createObject();
2284 iface.queryInterfaceTo (aHostNetworkInterface);
2285
2286 /* create the networkInterfaceHelperClient() argument */
2287 std::auto_ptr <NetworkInterfaceHelperClientData>
2288 d (new NetworkInterfaceHelperClientData());
2289 AssertReturn (d.get(), E_OUTOFMEMORY);
2290
2291 d->msgCode = SVCHlpMsg::CreateHostOnlyNetworkInterface;
2292// d->name = aName;
2293 d->iface = iface;
2294
2295 rc = pVBox->startSVCHelperClient (
2296 IsUACEnabled() == TRUE /* aPrivileged */,
2297 netIfNetworkInterfaceHelperClient,
2298 static_cast <void *> (d.get()),
2299 progress);
2300
2301 if (SUCCEEDED (rc))
2302 {
2303 /* d is now owned by netIfNetworkInterfaceHelperClient(), so release it */
2304 d.release();
2305 }
2306 }
2307 }
2308
2309 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
2310}
2311
2312int NetIfRemoveHostOnlyNetworkInterface (VirtualBox *pVBox, IN_GUID aId,
2313 IHostNetworkInterface **aHostNetworkInterface,
2314 IProgress **aProgress)
2315{
2316 /* create a progress object */
2317 ComObjPtr <Progress> progress;
2318 progress.createObject();
2319 ComPtr<IHost> host;
2320 HRESULT rc = pVBox->COMGETTER(Host)(host.asOutParam());
2321 if(SUCCEEDED(rc))
2322 {
2323 rc = progress->init (pVBox, host,
2324 Bstr (_T ("Removing host network interface")),
2325 FALSE /* aCancelable */);
2326 if(SUCCEEDED(rc))
2327 {
2328 CheckComRCReturnRC (rc);
2329 progress.queryInterfaceTo (aProgress);
2330
2331 /* create the networkInterfaceHelperClient() argument */
2332 std::auto_ptr <NetworkInterfaceHelperClientData>
2333 d (new NetworkInterfaceHelperClientData());
2334 AssertReturn (d.get(), E_OUTOFMEMORY);
2335
2336 d->msgCode = SVCHlpMsg::RemoveHostOnlyNetworkInterface;
2337 d->guid = aId;
2338
2339 rc = pVBox->startSVCHelperClient (
2340 IsUACEnabled() == TRUE /* aPrivileged */,
2341 netIfNetworkInterfaceHelperClient,
2342 static_cast <void *> (d.get()),
2343 progress);
2344
2345 if (SUCCEEDED (rc))
2346 {
2347 /* d is now owned by netIfNetworkInterfaceHelperClient(), so release it */
2348 d.release();
2349 }
2350 }
2351 }
2352
2353 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
2354}
2355
2356int NetIfEnableStaticIpConfig(VirtualBox *vBox, HostNetworkInterface * pIf, ULONG ip, ULONG mask)
2357{
2358 HRESULT rc;
2359 GUID guid;
2360 rc = pIf->COMGETTER(Id) (&guid);
2361 if(SUCCEEDED(rc))
2362 {
2363// ComPtr<VirtualBox> vBox;
2364// rc = pIf->getVirtualBox (vBox.asOutParam());
2365// if(SUCCEEDED(rc))
2366 {
2367 /* create a progress object */
2368 ComObjPtr <Progress> progress;
2369 progress.createObject();
2370// ComPtr<IHost> host;
2371// HRESULT rc = vBox->COMGETTER(Host)(host.asOutParam());
2372// if(SUCCEEDED(rc))
2373 {
2374 rc = progress->init (vBox, (IHostNetworkInterface*)pIf,
2375 Bstr ("Enabling Dynamic Ip Configuration"),
2376 FALSE /* aCancelable */);
2377 if(SUCCEEDED(rc))
2378 {
2379 CheckComRCReturnRC (rc);
2380// progress.queryInterfaceTo (aProgress);
2381
2382 /* create the networkInterfaceHelperClient() argument */
2383 std::auto_ptr <NetworkInterfaceHelperClientData>
2384 d (new NetworkInterfaceHelperClientData());
2385 AssertReturn (d.get(), E_OUTOFMEMORY);
2386
2387 d->msgCode = SVCHlpMsg::EnableStaticIpConfig;
2388 d->guid = guid;
2389 d->iface = pIf;
2390 d->u.StaticIP.IPAddress = ip;
2391 d->u.StaticIP.IPNetMask = mask;
2392
2393 rc = vBox->startSVCHelperClient (
2394 IsUACEnabled() == TRUE /* aPrivileged */,
2395 netIfNetworkInterfaceHelperClient,
2396 static_cast <void *> (d.get()),
2397 progress);
2398
2399 if (SUCCEEDED (rc))
2400 {
2401 /* d is now owned by netIfNetworkInterfaceHelperClient(), so release it */
2402 d.release();
2403
2404 progress->WaitForCompletion(-1);
2405 }
2406 }
2407 }
2408 }
2409 }
2410
2411 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
2412}
2413
2414int NetIfEnableStaticIpConfigV6(VirtualBox *vBox, HostNetworkInterface * pIf, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
2415{
2416 HRESULT rc;
2417 GUID guid;
2418 rc = pIf->COMGETTER(Id) (&guid);
2419 if(SUCCEEDED(rc))
2420 {
2421// ComPtr<VirtualBox> vBox;
2422// rc = pIf->getVirtualBox (vBox.asOutParam());
2423// if(SUCCEEDED(rc))
2424 {
2425 /* create a progress object */
2426 ComObjPtr <Progress> progress;
2427 progress.createObject();
2428// ComPtr<IHost> host;
2429// HRESULT rc = vBox->COMGETTER(Host)(host.asOutParam());
2430// if(SUCCEEDED(rc))
2431 {
2432 rc = progress->init (vBox, (IHostNetworkInterface*)pIf,
2433 Bstr ("Enabling Dynamic Ip Configuration"),
2434 FALSE /* aCancelable */);
2435 if(SUCCEEDED(rc))
2436 {
2437 CheckComRCReturnRC (rc);
2438// progress.queryInterfaceTo (aProgress);
2439
2440 /* create the networkInterfaceHelperClient() argument */
2441 std::auto_ptr <NetworkInterfaceHelperClientData>
2442 d (new NetworkInterfaceHelperClientData());
2443 AssertReturn (d.get(), E_OUTOFMEMORY);
2444
2445 d->msgCode = SVCHlpMsg::EnableStaticIpConfigV6;
2446 d->guid = guid;
2447 d->iface = pIf;
2448 d->u.StaticIPV6.IPV6Address = aIPV6Address;
2449 d->u.StaticIPV6.IPV6NetMaskLength = aIPV6MaskPrefixLength;
2450
2451 rc = vBox->startSVCHelperClient (
2452 IsUACEnabled() == TRUE /* aPrivileged */,
2453 netIfNetworkInterfaceHelperClient,
2454 static_cast <void *> (d.get()),
2455 progress);
2456
2457 if (SUCCEEDED (rc))
2458 {
2459 /* d is now owned by netIfNetworkInterfaceHelperClient(), so release it */
2460 d.release();
2461
2462 progress->WaitForCompletion(-1);
2463 }
2464 }
2465 }
2466 }
2467 }
2468
2469 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
2470}
2471
2472int NetIfEnableDynamicIpConfig(VirtualBox *vBox, HostNetworkInterface * pIf)
2473{
2474 HRESULT rc;
2475 GUID guid;
2476 rc = pIf->COMGETTER(Id) (&guid);
2477 if(SUCCEEDED(rc))
2478 {
2479// ComPtr<VirtualBox> vBox;
2480// rc = pIf->getVirtualBox (vBox.asOutParam());
2481// if(SUCCEEDED(rc))
2482 {
2483 /* create a progress object */
2484 ComObjPtr <Progress> progress;
2485 progress.createObject();
2486// ComPtr<IHost> host;
2487// HRESULT rc = vBox->COMGETTER(Host)(host.asOutParam());
2488// if(SUCCEEDED(rc))
2489 {
2490 rc = progress->init (vBox, (IHostNetworkInterface*)pIf,
2491 Bstr ("Enabling Dynamic Ip Configuration"),
2492 FALSE /* aCancelable */);
2493 if(SUCCEEDED(rc))
2494 {
2495 CheckComRCReturnRC (rc);
2496// progress.queryInterfaceTo (aProgress);
2497
2498 /* create the networkInterfaceHelperClient() argument */
2499 std::auto_ptr <NetworkInterfaceHelperClientData>
2500 d (new NetworkInterfaceHelperClientData());
2501 AssertReturn (d.get(), E_OUTOFMEMORY);
2502
2503 d->msgCode = SVCHlpMsg::EnableDynamicIpConfig;
2504 d->guid = guid;
2505 d->iface = pIf;
2506
2507 rc = vBox->startSVCHelperClient (
2508 IsUACEnabled() == TRUE /* aPrivileged */,
2509 netIfNetworkInterfaceHelperClient,
2510 static_cast <void *> (d.get()),
2511 progress);
2512
2513 if (SUCCEEDED (rc))
2514 {
2515 /* d is now owned by netIfNetworkInterfaceHelperClient(), so release it */
2516 d.release();
2517
2518 progress->WaitForCompletion(-1);
2519 }
2520 }
2521 }
2522 }
2523 }
2524
2525 return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
2526}
2527
2528int NetIfList(std::list <ComObjPtr <HostNetworkInterface> > &list)
2529{
2530#ifndef VBOX_WITH_NETFLT
2531 return VERR_NOT_IMPLEMENTED;
2532#else /* # if defined VBOX_WITH_NETFLT */
2533 INetCfg *pNc;
2534 INetCfgComponent *pMpNcc;
2535 INetCfgComponent *pTcpIpNcc;
2536 LPWSTR lpszApp;
2537 HRESULT hr;
2538 IEnumNetCfgBindingPath *pEnumBp;
2539 INetCfgBindingPath *pBp;
2540 IEnumNetCfgBindingInterface *pEnumBi;
2541 INetCfgBindingInterface *pBi;
2542
2543 /* we are using the INetCfg API for getting the list of miniports */
2544 hr = VBoxNetCfgWinQueryINetCfg( FALSE,
2545 VBOX_APP_NAME,
2546 &pNc,
2547 &lpszApp );
2548 Assert(hr == S_OK);
2549 if(hr == S_OK)
2550 {
2551# ifdef VBOX_NETFLT_ONDEMAND_BIND
2552 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
2553 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
2554# else
2555 /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
2556 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
2557# ifndef VBOX_WITH_HARDENING
2558 if(hr != S_OK)
2559 {
2560 /* TODO: try to install the netflt from here */
2561 }
2562# endif
2563
2564# endif
2565
2566 if(hr == S_OK)
2567 {
2568 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
2569 Assert(hr == S_OK);
2570 if ( hr == S_OK )
2571 {
2572 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
2573 Assert(hr == S_OK || hr == S_FALSE);
2574 while( hr == S_OK )
2575 {
2576 /* S_OK == enabled, S_FALSE == disabled */
2577 if(pBp->IsEnabled() == S_OK)
2578 {
2579 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
2580 Assert(hr == S_OK);
2581 if ( hr == S_OK )
2582 {
2583 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
2584 Assert(hr == S_OK);
2585 while(hr == S_OK)
2586 {
2587 hr = pBi->GetLowerComponent( &pMpNcc );
2588 Assert(hr == S_OK);
2589 if(hr == S_OK)
2590 {
2591 ULONG uComponentStatus;
2592 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
2593//#ifndef DEBUG_bird
2594// Assert(hr == S_OK);
2595//#endif
2596 if(hr == S_OK)
2597 {
2598 if(uComponentStatus == 0)
2599 {
2600 vboxNetWinAddComponent(&list, pMpNcc, HostNetworkInterfaceType_Bridged);
2601 }
2602 }
2603 VBoxNetCfgWinReleaseRef( pMpNcc );
2604 }
2605 VBoxNetCfgWinReleaseRef(pBi);
2606
2607 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
2608 }
2609 VBoxNetCfgWinReleaseRef(pEnumBi);
2610 }
2611 }
2612 VBoxNetCfgWinReleaseRef(pBp);
2613
2614 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
2615 }
2616 VBoxNetCfgWinReleaseRef(pEnumBp);
2617 }
2618 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
2619 }
2620 else
2621 {
2622 LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
2623 }
2624
2625 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
2626 }
2627
2628 netIfListHostAdapters(list);
2629
2630 return VINF_SUCCESS;
2631#endif /* # if defined VBOX_WITH_NETFLT */
2632}
Note: See TracBrowser for help on using the repository browser.

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