VirtualBox

source: vbox/trunk/src/VBox/Main/HostImpl.cpp@ 2511

Last change on this file since 2511 was 2434, checked in by vboxsync, 18 years ago

Main: Fixed: VirtualBox would allow to create host network interfaces with non-ASCII names but would not see them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 81.7 KB
Line 
1/** @file
2 * VirtualBox COM class implementation
3 */
4
5/*
6 * Copyright (C) 2006 InnoTek Systemberatung GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License as published by the Free Software Foundation,
12 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
13 * distribution. VirtualBox OSE is distributed in the hope that it will
14 * be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * If you received this file as part of a commercial VirtualBox
17 * distribution, then only the terms of your commercial VirtualBox
18 * license agreement apply instead of the previous paragraph.
19 */
20
21#ifdef __LINUX__
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <sys/ioctl.h>
26#include <fcntl.h>
27#include <mntent.h>
28/* bird: This is a hack to work around conflicts between these linux kernel headers
29 * and the GLIBC tcpip headers. They have different declarations of the 4
30 * standard byte order functions. */
31#define _LINUX_BYTEORDER_GENERIC_H
32#include <linux/cdrom.h>
33#include <errno.h>
34#endif /* __LINUX __ */
35
36#ifdef __WIN__
37#define _WIN32_DCOM
38#include <windows.h>
39#include <shellapi.h>
40#define INITGUID
41#include <guiddef.h>
42#include <devguid.h>
43#include <objbase.h>
44#include <setupapi.h>
45#include <shlobj.h>
46#include <cfgmgr32.h>
47#endif /* __WIN__ */
48
49
50
51#include "HostImpl.h"
52#include "HostDVDDriveImpl.h"
53#include "HostFloppyDriveImpl.h"
54#include "HostUSBDeviceImpl.h"
55#include "USBControllerImpl.h"
56#include "USBDeviceFilterImpl.h"
57#include "USBProxyService.h"
58#include "VirtualBoxImpl.h"
59#include "MachineImpl.h"
60#include "Logging.h"
61
62#ifdef __DARWIN__
63#include "darwin/iokit.h"
64#endif
65
66#ifdef __WIN__
67#include "HostNetworkInterfaceImpl.h"
68#endif
69
70#include <VBox/usb.h>
71#include <VBox/err.h>
72#include <iprt/string.h>
73#include <iprt/system.h>
74#include <iprt/time.h>
75#include <iprt/param.h>
76
77#include <stdio.h>
78
79#include <algorithm>
80
81// constructor / destructor
82/////////////////////////////////////////////////////////////////////////////
83
84HRESULT Host::FinalConstruct()
85{
86 return S_OK;
87}
88
89void Host::FinalRelease()
90{
91 if (isReady())
92 uninit();
93}
94
95// public initializer/uninitializer for internal purposes only
96/////////////////////////////////////////////////////////////////////////////
97
98/**
99 * Initializes the host object.
100 *
101 * @returns COM result indicator
102 * @param parent handle of our parent object
103 */
104HRESULT Host::init (VirtualBox *parent)
105{
106 LogFlowMember(("Host::init(): isReady=%d\n", isReady()));
107
108 ComAssertRet (parent, E_INVALIDARG);
109
110 AutoLock lock(this);
111 ComAssertRet (!isReady(), E_UNEXPECTED);
112
113 mParent = parent;
114
115#if defined (__LINUX__) && defined (VBOX_WITH_USB)
116 mUSBProxyService = new USBProxyServiceLinux (this);
117#elif defined (__WIN__) && defined (VBOX_WITH_USB)
118 mUSBProxyService = new USBProxyServiceWin32 (this);
119#else
120 mUSBProxyService = new USBProxyService (this);
121#endif
122 /** @todo handle !mUSBProxySerivce->isActive() and mUSBProxyService->getLastError()
123 * and somehow report or whatever that the proxy failed to startup.
124 * Also, there might be init order issues... */
125
126 setReady(true);
127 return S_OK;
128}
129
130/**
131 * Uninitializes the host object and sets the ready flag to FALSE.
132 * Called either from FinalRelease() or by the parent when it gets destroyed.
133 */
134void Host::uninit()
135{
136 LogFlowMember(("Host::uninit(): isReady=%d\n", isReady()));
137
138 AssertReturn (isReady(), (void) 0);
139
140 // uninit all USB device filters still referenced by clients
141 uninitDependentChildren();
142
143 delete mUSBProxyService;
144 mUSBProxyService = NULL;
145
146 mUSBDeviceFilters.clear();
147 mUSBDevices.clear();
148
149 setReady (FALSE);
150}
151
152// IHost properties
153/////////////////////////////////////////////////////////////////////////////
154
155/**
156 * Returns a list of host DVD drives.
157 *
158 * @returns COM status code
159 * @param drives address of result pointer
160 */
161STDMETHODIMP Host::COMGETTER(DVDDrives) (IHostDVDDriveCollection **drives)
162{
163 if (!drives)
164 return E_POINTER;
165 AutoLock lock(this);
166 CHECK_READY();
167 std::list <ComObjPtr <HostDVDDrive> > list;
168
169#if defined(__WIN__)
170 int sz = GetLogicalDriveStrings(0, NULL);
171 TCHAR *hostDrives = new TCHAR[sz+1];
172 GetLogicalDriveStrings(sz, hostDrives);
173 wchar_t driveName[3] = { '?', ':', '\0' };
174 TCHAR *p = hostDrives;
175 do
176 {
177 if (GetDriveType(p) == DRIVE_CDROM)
178 {
179 driveName[0] = *p;
180 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
181 hostDVDDriveObj.createObject();
182 hostDVDDriveObj->init (Bstr (driveName));
183 list.push_back (hostDVDDriveObj);
184 }
185 p += _tcslen(p) + 1;
186 }
187 while (*p);
188 delete[] hostDrives;
189#elif defined(__LINUX__)
190 // On Linux, the situation is much more complex. There is no simple API so
191 // we will take a more creative approach. As there is only a heuristical
192 // approach on Linux, we'll allow the user to specify a list of host CDROMs
193 // using and an environment variable.
194 // The general strategy is to try some known device names and see of they
195 // exist. At last, we'll enumerate the /etc/fstab file (luckily there's an
196 // API to parse it) for CDROM devices. Ok, let's start!
197
198 if (getenv("VBOX_CDROM"))
199 {
200 char *cdromEnv = strdupa(getenv("VBOX_CDROM"));
201 char *cdromDrive;
202 cdromDrive = strtok(cdromEnv, ":");
203 while (cdromDrive)
204 {
205 if (validateDevice(cdromDrive, true))
206 {
207 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
208 hostDVDDriveObj.createObject();
209 hostDVDDriveObj->init (Bstr (cdromDrive));
210 list.push_back (hostDVDDriveObj);
211 }
212 cdromDrive = strtok(NULL, ":");
213 }
214 }
215 else
216 {
217 // this is a good guess usually
218 if (validateDevice("/dev/cdrom", true))
219 {
220 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
221 hostDVDDriveObj.createObject();
222 hostDVDDriveObj->init (Bstr ("/dev/cdrom"));
223 list.push_back (hostDVDDriveObj);
224 }
225
226 // check the mounted drives
227 parseMountTable((char*)"/etc/mtab", list);
228
229 // check the drives that can be mounted
230 parseMountTable((char*)"/etc/fstab", list);
231 }
232#elif defined(__DARWIN__)
233 PDARWINDVD cur = DarwinGetDVDDrives();
234 while (cur)
235 {
236 ComObjPtr<HostDVDDrive> hostDVDDriveObj;
237 hostDVDDriveObj.createObject();
238 hostDVDDriveObj->init(Bstr(cur->szName));
239 list.push_back(hostDVDDriveObj);
240
241 /* next */
242 void *freeMe = cur;
243 cur = cur->pNext;
244 RTMemFree(freeMe);
245 }
246
247#else
248 /* PORTME */
249#endif
250
251 ComObjPtr<HostDVDDriveCollection> collection;
252 collection.createObject();
253 collection->init (list);
254 collection.queryInterfaceTo(drives);
255 return S_OK;
256}
257
258/**
259 * Returns a list of host floppy drives.
260 *
261 * @returns COM status code
262 * @param drives address of result pointer
263 */
264STDMETHODIMP Host::COMGETTER(FloppyDrives) (IHostFloppyDriveCollection **drives)
265{
266 if (!drives)
267 return E_POINTER;
268 AutoLock lock(this);
269 CHECK_READY();
270
271 std::list <ComObjPtr <HostFloppyDrive> > list;
272
273#ifdef __WIN__
274 int sz = GetLogicalDriveStrings(0, NULL);
275 TCHAR *hostDrives = new TCHAR[sz+1];
276 GetLogicalDriveStrings(sz, hostDrives);
277 wchar_t driveName[3] = { '?', ':', '\0' };
278 TCHAR *p = hostDrives;
279 do
280 {
281 if (GetDriveType(p) == DRIVE_REMOVABLE)
282 {
283 driveName[0] = *p;
284 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
285 hostFloppyDriveObj.createObject();
286 hostFloppyDriveObj->init (Bstr (driveName));
287 list.push_back (hostFloppyDriveObj);
288 }
289 p += _tcslen(p) + 1;
290 }
291 while (*p);
292 delete[] hostDrives;
293#elif defined(__LINUX__)
294 // As with the CDROMs, on Linux we have to take a multi-level approach
295 // involving parsing the mount tables. As this is not bulletproof, we'll
296 // give the user the chance to override the detection by an environment
297 // variable and skip the detection.
298
299 if (getenv("VBOX_FLOPPY"))
300 {
301 char *floppyEnv = getenv("VBOX_FLOPPY");
302 char *floppyDrive;
303 floppyDrive = strtok(floppyEnv, ":");
304 while (floppyDrive)
305 {
306 // check if this is an acceptable device
307 if (validateDevice(floppyDrive, false))
308 {
309 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
310 hostFloppyDriveObj.createObject();
311 hostFloppyDriveObj->init (Bstr (floppyDrive));
312 list.push_back (hostFloppyDriveObj);
313 }
314 floppyDrive = strtok(NULL, ":");
315 }
316 }
317 else
318 {
319 // we assume that a floppy is always /dev/fd[x] with x from 0 to 7
320 char devName[10];
321 for (int i = 0; i <= 7; i++)
322 {
323 sprintf(devName, "/dev/fd%d", i);
324 if (validateDevice(devName, false))
325 {
326 ComObjPtr <HostFloppyDrive> hostFloppyDriveObj;
327 hostFloppyDriveObj.createObject();
328 hostFloppyDriveObj->init (Bstr (devName));
329 list.push_back (hostFloppyDriveObj);
330 }
331 }
332 }
333#else
334 /* PORTME */
335#endif
336
337 ComObjPtr<HostFloppyDriveCollection> collection;
338 collection.createObject();
339 collection->init (list);
340 collection.queryInterfaceTo(drives);
341 return S_OK;
342}
343
344#ifdef __WIN__
345
346static bool IsTAPDevice(const char *guid)
347{
348 HKEY hNetcard;
349 LONG status;
350 DWORD len;
351 int i = 0;
352 bool ret = false;
353
354 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hNetcard);
355 if (status != ERROR_SUCCESS)
356 return false;
357
358 while(true)
359 {
360 char szEnumName[256];
361 char szNetCfgInstanceId[256];
362 DWORD dwKeyType;
363 HKEY hNetCardGUID;
364
365 len = sizeof(szEnumName);
366 status = RegEnumKeyExA(hNetcard, i, szEnumName, &len, NULL, NULL, NULL, NULL);
367 if (status != ERROR_SUCCESS)
368 break;
369
370 status = RegOpenKeyExA(hNetcard, szEnumName, 0, KEY_READ, &hNetCardGUID);
371 if (status == ERROR_SUCCESS)
372 {
373 len = sizeof (szNetCfgInstanceId);
374 status = RegQueryValueExA(hNetCardGUID, "NetCfgInstanceId", NULL, &dwKeyType, (LPBYTE)szNetCfgInstanceId, &len);
375 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
376 {
377 char szNetProductName[256];
378 char szNetProviderName[256];
379
380 szNetProductName[0] = 0;
381 len = sizeof(szNetProductName);
382 status = RegQueryValueExA(hNetCardGUID, "ProductName", NULL, &dwKeyType, (LPBYTE)szNetProductName, &len);
383
384 szNetProviderName[0] = 0;
385 len = sizeof(szNetProviderName);
386 status = RegQueryValueExA(hNetCardGUID, "ProviderName", NULL, &dwKeyType, (LPBYTE)szNetProviderName, &len);
387
388 if ( !strcmp(szNetCfgInstanceId, guid)
389 && !strcmp(szNetProductName, "VirtualBox TAP Adapter")
390 && !strcmp(szNetProviderName, "InnoTek Systemberatung GmbH"))
391 {
392 ret = true;
393 RegCloseKey(hNetCardGUID);
394 break;
395 }
396 }
397 RegCloseKey(hNetCardGUID);
398 }
399 ++i;
400 }
401
402 RegCloseKey (hNetcard);
403 return ret;
404}
405
406/**
407 * Returns a list of host network interfaces.
408 *
409 * @returns COM status code
410 * @param drives address of result pointer
411 */
412STDMETHODIMP Host::COMGETTER(NetworkInterfaces) (IHostNetworkInterfaceCollection **networkInterfaces)
413{
414 if (!networkInterfaces)
415 return E_POINTER;
416 AutoLock lock(this);
417 CHECK_READY();
418
419 std::list <ComObjPtr <HostNetworkInterface> > list;
420
421 static const char *NetworkKey = "SYSTEM\\CurrentControlSet\\Control\\Network\\"
422 "{4D36E972-E325-11CE-BFC1-08002BE10318}";
423 HKEY hCtrlNet;
424 LONG status;
425 DWORD len;
426 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, NetworkKey, 0, KEY_READ, &hCtrlNet);
427 if (status != ERROR_SUCCESS)
428 return setError (E_FAIL, tr("Could not open registry key \"%s\""), NetworkKey);
429
430 for (int i = 0;; ++ i)
431 {
432 char szNetworkGUID [256];
433 HKEY hConnection;
434 char szNetworkConnection [256];
435
436 len = sizeof (szNetworkGUID);
437 status = RegEnumKeyExA (hCtrlNet, i, szNetworkGUID, &len, NULL, NULL, NULL, NULL);
438 if (status != ERROR_SUCCESS)
439 break;
440
441 if (!IsTAPDevice(szNetworkGUID))
442 continue;
443
444 RTStrPrintf (szNetworkConnection, sizeof (szNetworkConnection),
445 "%s\\Connection", szNetworkGUID);
446 status = RegOpenKeyExA (hCtrlNet, szNetworkConnection, 0, KEY_READ, &hConnection);
447 if (status == ERROR_SUCCESS)
448 {
449 DWORD dwKeyType;
450 status = RegQueryValueExW (hConnection, TEXT("Name"), NULL,
451 &dwKeyType, NULL, &len);
452 if (status == ERROR_SUCCESS && dwKeyType == REG_SZ)
453 {
454 size_t uniLen = (len + sizeof (OLECHAR) - 1) / sizeof (OLECHAR);
455 Bstr name (uniLen + 1 /* extra zero */);
456 status = RegQueryValueExW (hConnection, TEXT("Name"), NULL,
457 &dwKeyType, (LPBYTE) name.mutableRaw(), &len);
458 if (status == ERROR_SUCCESS)
459 {
460 /* put a trailing zero, just in case (see MSDN) */
461 name.mutableRaw() [uniLen] = 0;
462 /* create a new object and add it to the list */
463 ComObjPtr <HostNetworkInterface> iface;
464 iface.createObject();
465 /* remove the curly bracket at the end */
466 szNetworkGUID [strlen(szNetworkGUID) - 1] = '\0';
467 if (SUCCEEDED (iface->init (name, Guid (szNetworkGUID + 1))))
468 list.push_back (iface);
469 }
470 }
471 RegCloseKey (hConnection);
472 }
473 }
474 RegCloseKey (hCtrlNet);
475
476 ComObjPtr <HostNetworkInterfaceCollection> collection;
477 collection.createObject();
478 collection->init (list);
479 collection.queryInterfaceTo (networkInterfaces);
480 return S_OK;
481}
482#endif /* __WIN__ */
483
484STDMETHODIMP Host::COMGETTER(USBDevices)(IHostUSBDeviceCollection **aUSBDevices)
485{
486#ifdef VBOX_WITH_USB
487 if (!aUSBDevices)
488 return E_POINTER;
489
490 AutoLock alock (this);
491 CHECK_READY();
492
493 HRESULT rc = checkUSBProxyService();
494 CheckComRCReturnRC (rc);
495
496 ComObjPtr <HostUSBDeviceCollection> collection;
497 collection.createObject();
498 collection->init (mUSBDevices);
499 collection.queryInterfaceTo (aUSBDevices);
500 return S_OK;
501#else
502 /* Note: The GUI depends on this method returning E_NOTIMPL with no
503 * extended error info to indicate that USB is simply not available
504 * (w/o treting it as a failure), for example, as in OSE */
505 return E_NOTIMPL;
506#endif
507}
508
509STDMETHODIMP Host::COMGETTER(USBDeviceFilters) (IHostUSBDeviceFilterCollection ** aUSBDeviceFilters)
510{
511#ifdef VBOX_WITH_USB
512 if (!aUSBDeviceFilters)
513 return E_POINTER;
514
515 AutoLock alock (this);
516 CHECK_READY();
517
518 HRESULT rc = checkUSBProxyService();
519 CheckComRCReturnRC (rc);
520
521 ComObjPtr <HostUSBDeviceFilterCollection> collection;
522 collection.createObject();
523 collection->init (mUSBDeviceFilters);
524 collection.queryInterfaceTo (aUSBDeviceFilters);
525 return S_OK;
526#else
527 /* Note: The GUI depends on this method returning E_NOTIMPL with no
528 * extended error info to indicate that USB is simply not available
529 * (w/o treting it as a failure), for example, as in OSE */
530 return E_NOTIMPL;
531#endif
532}
533
534/**
535 * Returns the number of installed logical processors
536 *
537 * @returns COM status code
538 * @param count address of result variable
539 */
540STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *count)
541{
542 if (!count)
543 return E_POINTER;
544 AutoLock lock(this);
545 CHECK_READY();
546 *count = RTSystemProcessorGetCount();
547 return S_OK;
548}
549
550/**
551 * Returns the (approximate) speed of the host CPU in MHz
552 *
553 * @returns COM status code
554 * @param speed address of result variable
555 */
556STDMETHODIMP Host::COMGETTER(ProcessorSpeed)(ULONG *speed)
557{
558 if (!speed)
559 return E_POINTER;
560 AutoLock lock(this);
561 CHECK_READY();
562 /** @todo Add a runtime function for this which uses GIP. */
563 return S_OK;
564}
565/**
566 * Returns a description string for the host CPU
567 *
568 * @returns COM status code
569 * @param description address of result variable
570 */
571STDMETHODIMP Host::COMGETTER(ProcessorDescription)(BSTR *description)
572{
573 if (!description)
574 return E_POINTER;
575 AutoLock lock(this);
576 CHECK_READY();
577 /** @todo */
578 return S_OK;
579}
580
581
582/**
583 * Returns the amount of installed system memory in megabytes
584 *
585 * @returns COM status code
586 * @param size address of result variable
587 */
588STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *size)
589{
590 if (!size)
591 return E_POINTER;
592 AutoLock lock(this);
593 CHECK_READY();
594 /** @todo */
595 return S_OK;
596}
597
598/**
599 * Returns the current system memory free space in megabytes
600 *
601 * @returns COM status code
602 * @param available address of result variable
603 */
604STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *available)
605{
606 if (!available)
607 return E_POINTER;
608 AutoLock lock(this);
609 CHECK_READY();
610 /** @todo */
611 return S_OK;
612}
613
614/**
615 * Returns the name string of the host operating system
616 *
617 * @returns COM status code
618 * @param os address of result variable
619 */
620STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *os)
621{
622 if (!os)
623 return E_POINTER;
624 AutoLock lock(this);
625 CHECK_READY();
626 /** @todo */
627 return S_OK;
628}
629
630/**
631 * Returns the version string of the host operating system
632 *
633 * @returns COM status code
634 * @param os address of result variable
635 */
636STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *version)
637{
638 if (!version)
639 return E_POINTER;
640 AutoLock lock(this);
641 CHECK_READY();
642 /** @todo */
643 return S_OK;
644}
645
646/**
647 * Returns the current host time in milliseconds since 1970-01-01 UTC.
648 *
649 * @returns COM status code
650 * @param time address of result variable
651 */
652STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
653{
654 if (!aUTCTime)
655 return E_POINTER;
656 AutoLock lock(this);
657 CHECK_READY();
658 RTTIMESPEC now;
659 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
660 return S_OK;
661}
662
663// IHost methods
664////////////////////////////////////////////////////////////////////////////////
665
666#ifdef __WIN__
667
668/**
669 * Returns TRUE if the Windows version is 6.0 or greater (i.e. it's Vista and
670 * later OSes) and it has the UAC (User Account Control) feature enabled.
671 */
672static BOOL IsUACEnabled()
673{
674 LONG rc = 0;
675
676 OSVERSIONINFOEX info;
677 ZeroMemory (&info, sizeof (OSVERSIONINFOEX));
678 info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
679 rc = GetVersionEx ((OSVERSIONINFO *) &info);
680 AssertReturn (rc != 0, FALSE);
681
682 LogFlowFunc (("dwMajorVersion=%d, dwMinorVersion=%d\n",
683 info.dwMajorVersion, info.dwMinorVersion));
684
685 /* we are interested only in Vista (and newer versions...). In all
686 * earlier versions UAC is not present. */
687 if (info.dwMajorVersion < 6)
688 return FALSE;
689
690 /* the default EnableLUA value is 1 (Enabled) */
691 DWORD dwEnableLUA = 1;
692
693 HKEY hKey;
694 rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
695 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
696 0, KEY_QUERY_VALUE, &hKey);
697
698 Assert (rc == ERROR_SUCCESS || rc == ERROR_PATH_NOT_FOUND);
699 if (rc == ERROR_SUCCESS)
700 {
701
702 DWORD cbEnableLUA = sizeof (dwEnableLUA);
703 rc = RegQueryValueExA (hKey, "EnableLUA", NULL, NULL,
704 (LPBYTE) &dwEnableLUA, &cbEnableLUA);
705
706 RegCloseKey (hKey);
707
708 Assert (rc == ERROR_SUCCESS || rc == ERROR_FILE_NOT_FOUND);
709 }
710
711 LogFlowFunc (("rc=%d, dwEnableLUA=%d\n", rc, dwEnableLUA));
712
713 return dwEnableLUA == 1;
714}
715
716struct NetworkInterfaceHelperClientData
717{
718 SVCHlpMsg::Code msgCode;
719 /* for SVCHlpMsg::CreateHostNetworkInterface */
720 Bstr name;
721 ComObjPtr <HostNetworkInterface> iface;
722 /* for SVCHlpMsg::RemoveHostNetworkInterface */
723 Guid guid;
724};
725
726STDMETHODIMP
727Host::CreateHostNetworkInterface (INPTR BSTR aName,
728 IHostNetworkInterface **aHostNetworkInterface,
729 IProgress **aProgress)
730{
731 if (!aName)
732 return E_INVALIDARG;
733 if (!aHostNetworkInterface)
734 return E_POINTER;
735 if (!aProgress)
736 return E_POINTER;
737
738 AutoLock lock (this);
739 CHECK_READY();
740
741 HRESULT rc = S_OK;
742
743 /* first check whether an interface with the given name already exists */
744 {
745 ComPtr <IHostNetworkInterfaceCollection> coll;
746 rc = COMGETTER(NetworkInterfaces) (coll.asOutParam());
747 CheckComRCReturnRC (rc);
748 ComPtr <IHostNetworkInterface> iface;
749 if (SUCCEEDED (coll->FindByName (aName, iface.asOutParam())))
750 return setError (E_FAIL,
751 tr ("Host network interface '%ls' already exists"), aName);
752 }
753
754 /* create a progress object */
755 ComObjPtr <Progress> progress;
756 progress.createObject();
757 rc = progress->init (mParent, (IHost *) this,
758 Bstr (tr ("Creating host network interface")),
759 FALSE /* aCancelable */);
760 CheckComRCReturnRC (rc);
761 progress.queryInterfaceTo (aProgress);
762
763 /* create a new uninitialized host interface object */
764 ComObjPtr <HostNetworkInterface> iface;
765 iface.createObject();
766 iface.queryInterfaceTo (aHostNetworkInterface);
767
768 /* create the networkInterfaceHelperClient() argument */
769 std::auto_ptr <NetworkInterfaceHelperClientData>
770 d (new NetworkInterfaceHelperClientData());
771 AssertReturn (d.get(), E_OUTOFMEMORY);
772
773 d->msgCode = SVCHlpMsg::CreateHostNetworkInterface;
774 d->name = aName;
775 d->iface = iface;
776
777 rc = mParent->startSVCHelperClient (
778 IsUACEnabled() == TRUE /* aPrivileged */,
779 networkInterfaceHelperClient,
780 static_cast <void *> (d.get()),
781 progress);
782
783 if (SUCCEEDED (rc))
784 {
785 /* d is now owned by networkInterfaceHelperClient(), so release it */
786 d.release();
787 }
788
789 return rc;
790}
791
792STDMETHODIMP
793Host::RemoveHostNetworkInterface (INPTR GUIDPARAM aId,
794 IHostNetworkInterface **aHostNetworkInterface,
795 IProgress **aProgress)
796{
797 if (!aHostNetworkInterface)
798 return E_POINTER;
799 if (!aProgress)
800 return E_POINTER;
801
802 AutoLock lock (this);
803 CHECK_READY();
804
805 HRESULT rc = S_OK;
806
807 /* first check whether an interface with the given name already exists */
808 {
809 ComPtr <IHostNetworkInterfaceCollection> coll;
810 rc = COMGETTER(NetworkInterfaces) (coll.asOutParam());
811 CheckComRCReturnRC (rc);
812 ComPtr <IHostNetworkInterface> iface;
813 if (FAILED (coll->FindById (aId, iface.asOutParam())))
814 return setError (E_FAIL,
815 tr ("Host network interface with UUID {%Vuuid} does not exist"),
816 Guid (aId).raw());
817
818 /* return the object to be removed to the caller */
819 iface.queryInterfaceTo (aHostNetworkInterface);
820 }
821
822 /* create a progress object */
823 ComObjPtr <Progress> progress;
824 progress.createObject();
825 rc = progress->init (mParent, (IHost *) this,
826 Bstr (tr ("Removing host network interface")),
827 FALSE /* aCancelable */);
828 CheckComRCReturnRC (rc);
829 progress.queryInterfaceTo (aProgress);
830
831 /* create the networkInterfaceHelperClient() argument */
832 std::auto_ptr <NetworkInterfaceHelperClientData>
833 d (new NetworkInterfaceHelperClientData());
834 AssertReturn (d.get(), E_OUTOFMEMORY);
835
836 d->msgCode = SVCHlpMsg::RemoveHostNetworkInterface;
837 d->guid = aId;
838
839 rc = mParent->startSVCHelperClient (
840 IsUACEnabled() == TRUE /* aPrivileged */,
841 networkInterfaceHelperClient,
842 static_cast <void *> (d.get()),
843 progress);
844
845 if (SUCCEEDED (rc))
846 {
847 /* d is now owned by networkInterfaceHelperClient(), so release it */
848 d.release();
849 }
850
851 return rc;
852}
853
854#endif /* __WIN__ */
855
856STDMETHODIMP Host::CreateUSBDeviceFilter (INPTR BSTR aName, IHostUSBDeviceFilter **aFilter)
857{
858#ifdef VBOX_WITH_USB
859 if (!aFilter)
860 return E_POINTER;
861
862 if (!aName || *aName == 0)
863 return E_INVALIDARG;
864
865 AutoLock lock (this);
866 CHECK_READY();
867
868 HRESULT rc = checkUSBProxyService();
869 CheckComRCReturnRC (rc);
870
871 ComObjPtr <HostUSBDeviceFilter> filter;
872 filter.createObject();
873 rc = filter->init (this, aName);
874 ComAssertComRCRet (rc, rc);
875 rc = filter.queryInterfaceTo (aFilter);
876 AssertComRCReturn (rc, rc);
877 return S_OK;
878#else
879 /* Note: The GUI depends on this method returning E_NOTIMPL with no
880 * extended error info to indicate that USB is simply not available
881 * (w/o treting it as a failure), for example, as in OSE */
882 return E_NOTIMPL;
883#endif
884}
885
886STDMETHODIMP Host::InsertUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter *aFilter)
887{
888#ifdef VBOX_WITH_USB
889 if (!aFilter)
890 return E_INVALIDARG;
891
892 AutoLock alock (this);
893 CHECK_READY();
894
895 HRESULT rc = checkUSBProxyService();
896 CheckComRCReturnRC (rc);
897
898 ComObjPtr <HostUSBDeviceFilter> filter = getDependentChild (aFilter);
899 if (!filter)
900 return setError (E_INVALIDARG,
901 tr ("The given USB device filter is not created within "
902 "this VirtualBox instance"));
903
904 if (filter->mInList)
905 return setError (E_INVALIDARG,
906 tr ("The given USB device filter is already in the list"));
907
908 /* iterate to the position... */
909 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
910 std::advance (it, aPosition);
911 /* ...and insert */
912 mUSBDeviceFilters.insert (it, filter);
913 filter->mInList = true;
914
915 /* notify the proxy (only when the filter is active) */
916 if (filter->data().mActive)
917 {
918 ComAssertRet (filter->id() == NULL, E_FAIL);
919 filter->id() =
920 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
921 }
922
923 /* save the global settings */
924 alock.unlock();
925 return mParent->saveSettings();
926#else
927 /* Note: The GUI depends on this method returning E_NOTIMPL with no
928 * extended error info to indicate that USB is simply not available
929 * (w/o treting it as a failure), for example, as in OSE */
930 return E_NOTIMPL;
931#endif
932}
933
934STDMETHODIMP Host::RemoveUSBDeviceFilter (ULONG aPosition, IHostUSBDeviceFilter **aFilter)
935{
936#ifdef VBOX_WITH_USB
937 if (!aFilter)
938 return E_POINTER;
939
940 AutoLock alock (this);
941 CHECK_READY();
942
943 HRESULT rc = checkUSBProxyService();
944 CheckComRCReturnRC (rc);
945
946 if (!mUSBDeviceFilters.size())
947 return setError (E_INVALIDARG,
948 tr ("The USB device filter list is empty"));
949
950 if (aPosition >= mUSBDeviceFilters.size())
951 return setError (E_INVALIDARG,
952 tr ("Invalid position: %lu (must be in range [0, %lu])"),
953 aPosition, mUSBDeviceFilters.size() - 1);
954
955 ComObjPtr <HostUSBDeviceFilter> filter;
956 {
957 /* iterate to the position... */
958 USBDeviceFilterList::iterator it = mUSBDeviceFilters.begin();
959 std::advance (it, aPosition);
960 /* ...get an element from there... */
961 filter = *it;
962 /* ...and remove */
963 filter->mInList = false;
964 mUSBDeviceFilters.erase (it);
965 }
966
967 filter.queryInterfaceTo (aFilter);
968
969 /* notify the proxy (only when the filter is active) */
970 if (filter->data().mActive)
971 {
972 ComAssertRet (filter->id() != NULL, E_FAIL);
973 mUSBProxyService->removeFilter (filter->id());
974 filter->id() = NULL;
975 }
976
977 /* save the global settings */
978 alock.unlock();
979 return mParent->saveSettings();
980#else
981 /* Note: The GUI depends on this method returning E_NOTIMPL with no
982 * extended error info to indicate that USB is simply not available
983 * (w/o treting it as a failure), for example, as in OSE */
984 return E_NOTIMPL;
985#endif
986}
987
988// public methods only for internal purposes
989////////////////////////////////////////////////////////////////////////////////
990
991/**
992 * Called by setter methods of all USB device filters.
993 */
994HRESULT Host::onUSBDeviceFilterChange (HostUSBDeviceFilter *aFilter,
995 BOOL aActiveChanged /* = FALSE */)
996{
997 AutoLock alock (this);
998 CHECK_READY();
999
1000 if (aFilter->mInList)
1001 {
1002 if (aActiveChanged)
1003 {
1004 // insert/remove the filter from the proxy
1005 if (aFilter->data().mActive)
1006 {
1007 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1008 aFilter->id() =
1009 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
1010 }
1011 else
1012 {
1013 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1014 mUSBProxyService->removeFilter (aFilter->id());
1015 aFilter->id() = NULL;
1016 }
1017 }
1018 else
1019 {
1020 if (aFilter->data().mActive)
1021 {
1022 // update the filter in the proxy
1023 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1024 mUSBProxyService->removeFilter (aFilter->id());
1025 aFilter->id() =
1026 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
1027 }
1028 }
1029
1030 // save the global settings... yeah, on every single filter property change
1031 alock.unlock();
1032 return mParent->saveSettings();
1033 }
1034
1035 return S_OK;
1036}
1037
1038HRESULT Host::loadSettings (CFGNODE aGlobal)
1039{
1040 AutoLock lock (this);
1041 CHECK_READY();
1042
1043 ComAssertRet (aGlobal, E_FAIL);
1044
1045 CFGNODE filters = NULL;
1046 CFGLDRGetChildNode (aGlobal, "USBDeviceFilters", 0, &filters);
1047 Assert (filters);
1048
1049 HRESULT rc = S_OK;
1050
1051 unsigned filterCount = 0;
1052 CFGLDRCountChildren (filters, "DeviceFilter", &filterCount);
1053 for (unsigned i = 0; i < filterCount && SUCCEEDED (rc); i++)
1054 {
1055 CFGNODE filter = NULL;
1056 CFGLDRGetChildNode (filters, "DeviceFilter", i, &filter);
1057 Assert (filter);
1058
1059 Bstr name;
1060 CFGLDRQueryBSTR (filter, "name", name.asOutParam());
1061 bool active;
1062 CFGLDRQueryBool (filter, "active", &active);
1063
1064 Bstr vendorId;
1065 CFGLDRQueryBSTR (filter, "vendorid", vendorId.asOutParam());
1066 Bstr productId;
1067 CFGLDRQueryBSTR (filter, "productid", productId.asOutParam());
1068 Bstr revision;
1069 CFGLDRQueryBSTR (filter, "revision", revision.asOutParam());
1070 Bstr manufacturer;
1071 CFGLDRQueryBSTR (filter, "manufacturer", manufacturer.asOutParam());
1072 Bstr product;
1073 CFGLDRQueryBSTR (filter, "product", product.asOutParam());
1074 Bstr serialNumber;
1075 CFGLDRQueryBSTR (filter, "serialnumber", serialNumber.asOutParam());
1076 Bstr port;
1077 CFGLDRQueryBSTR (filter, "port", port.asOutParam());
1078
1079 USBDeviceFilterAction_T action;
1080 action = USBDeviceFilterAction_USBDeviceFilterIgnore;
1081 Bstr actionStr;
1082 CFGLDRQueryBSTR (filter, "action", actionStr.asOutParam());
1083 if (actionStr == L"Ignore")
1084 action = USBDeviceFilterAction_USBDeviceFilterIgnore;
1085 else
1086 if (actionStr == L"Hold")
1087 action = USBDeviceFilterAction_USBDeviceFilterHold;
1088 else
1089 AssertMsgFailed (("Invalid action: %ls\n", actionStr.raw()));
1090
1091 ComObjPtr <HostUSBDeviceFilter> filterObj;
1092 filterObj.createObject();
1093 rc = filterObj->init (this,
1094 name, active, vendorId, productId, revision,
1095 manufacturer, product, serialNumber, port,
1096 action);
1097 // error info is set by init() when appropriate
1098 if (SUCCEEDED (rc))
1099 {
1100 mUSBDeviceFilters.push_back (filterObj);
1101 filterObj->mInList = true;
1102
1103 // notify the proxy (only when the filter is active)
1104 if (filterObj->data().mActive)
1105 {
1106 HostUSBDeviceFilter *flt = filterObj; // resolve ambiguity
1107 flt->id() =
1108 mUSBProxyService->insertFilter (ComPtr <IUSBDeviceFilter> (flt));
1109 }
1110 }
1111
1112 CFGLDRReleaseNode (filter);
1113 }
1114
1115 CFGLDRReleaseNode (filters);
1116
1117 return rc;
1118}
1119
1120HRESULT Host::saveSettings (CFGNODE aGlobal)
1121{
1122 AutoLock lock (this);
1123 CHECK_READY();
1124
1125 ComAssertRet (aGlobal, E_FAIL);
1126
1127 // first, delete the entry
1128 CFGNODE filters = NULL;
1129 int vrc = CFGLDRGetChildNode (aGlobal, "USBDeviceFilters", 0, &filters);
1130 if (VBOX_SUCCESS (vrc))
1131 {
1132 vrc = CFGLDRDeleteNode (filters);
1133 ComAssertRCRet (vrc, E_FAIL);
1134 }
1135 // then, recreate it
1136 vrc = CFGLDRCreateChildNode (aGlobal, "USBDeviceFilters", &filters);
1137 ComAssertRCRet (vrc, E_FAIL);
1138
1139 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1140 while (it != mUSBDeviceFilters.end())
1141 {
1142 AutoLock filterLock (*it);
1143 const HostUSBDeviceFilter::Data &data = (*it)->data();
1144
1145 CFGNODE filter = NULL;
1146 CFGLDRAppendChildNode (filters, "DeviceFilter", &filter);
1147
1148 CFGLDRSetBSTR (filter, "name", data.mName);
1149 CFGLDRSetBool (filter, "active", !!data.mActive);
1150
1151 // all are optional
1152 if (data.mVendorId.string())
1153 CFGLDRSetBSTR (filter, "vendorid", data.mVendorId.string());
1154 if (data.mProductId.string())
1155 CFGLDRSetBSTR (filter, "productid", data.mProductId.string());
1156 if (data.mRevision.string())
1157 CFGLDRSetBSTR (filter, "revision", data.mRevision.string());
1158 if (data.mManufacturer.string())
1159 CFGLDRSetBSTR (filter, "manufacturer", data.mManufacturer.string());
1160 if (data.mProduct.string())
1161 CFGLDRSetBSTR (filter, "product", data.mProduct.string());
1162 if (data.mSerialNumber.string())
1163 CFGLDRSetBSTR (filter, "serialnumber", data.mSerialNumber.string());
1164 if (data.mPort.string())
1165 CFGLDRSetBSTR (filter, "port", data.mPort.string());
1166
1167 // action is mandatory
1168 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterIgnore)
1169 CFGLDRSetString (filter, "action", "Ignore");
1170 else
1171 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterHold)
1172 CFGLDRSetString (filter, "action", "Hold");
1173 else
1174 AssertMsgFailed (("Invalid action: %d\n", data.mAction));
1175
1176 CFGLDRReleaseNode (filter);
1177
1178 ++ it;
1179 }
1180
1181 CFGLDRReleaseNode (filters);
1182
1183 return S_OK;
1184}
1185
1186/**
1187 * Marks the given host USB device as captured by the given machine and returns
1188 * it as IUSBDevice to the caller.
1189 *
1190 * Called by Console from the VM process (throug IInternalMachineControl).
1191 * Must return extended error info in case of errors.
1192 */
1193HRESULT Host::captureUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId,
1194 IUSBDevice **aHostDevice)
1195{
1196 ComAssertRet (aMachine, E_INVALIDARG);
1197 ComAssertRet (aHostDevice, E_POINTER);
1198
1199 AutoLock lock (this);
1200 CHECK_READY();
1201
1202 Guid id (aId);
1203
1204 ComObjPtr <HostUSBDevice> device;
1205 USBDeviceList::iterator it = mUSBDevices.begin();
1206 while (!device && it != mUSBDevices.end())
1207 {
1208 if ((*it)->id() == id)
1209 device = (*it);
1210 ++ it;
1211 }
1212
1213 if (!device)
1214 return setError (E_INVALIDARG,
1215 tr ("USB device with UUID {%s} is not currently attached to the host"),
1216 id.toString().raw());
1217
1218 if (device->state() == USBDeviceState_USBDeviceNotSupported)
1219 return setError (E_INVALIDARG,
1220 tr ("USB device '%s' with UUID {%s} cannot be accessed by guest "
1221 "computers"),
1222 device->name().raw(), id.toString().raw());
1223
1224 if (device->state() == USBDeviceState_USBDeviceUnavailable)
1225 return setError (E_INVALIDARG,
1226 tr ("USB device '%s' with UUID {%s} is being exclusively used by the "
1227 "host computer"),
1228 device->name().raw(), id.toString().raw());
1229
1230 if (device->state() == USBDeviceState_USBDeviceCaptured)
1231 return setError (E_INVALIDARG,
1232 tr ("USB device '%s' with UUID {%s} is already captured by the virtual "
1233 "machine '%ls'"),
1234 device->name().raw(), id.toString().raw(),
1235 aMachine->userData()->mName.raw());
1236
1237 // try capture the device
1238 bool ok = device->setCaptured (aMachine);
1239 if (!ok)
1240 {
1241 if (device->state() == USBDeviceState_USBDeviceBusy)
1242 return setError (E_FAIL,
1243 tr ("USB device with UUID {%s} is being accessed by the host "
1244 "computer and cannot be attached to the virtual machine."
1245 "Please try later"),
1246 id.toString().raw());
1247 else
1248 ComAssertRet (ok, E_FAIL);
1249 }
1250
1251 // return the device to the caller as IUSBDevice
1252 device.queryInterfaceTo (aHostDevice);
1253 return S_OK;
1254}
1255
1256/**
1257 * Replays all filters against the given USB device excluding filters of the
1258 * machine the device is currently marked as captured by.
1259 *
1260 * Called by Console from the VM process (throug IInternalMachineControl).
1261 */
1262HRESULT Host::releaseUSBDevice (SessionMachine *aMachine, INPTR GUIDPARAM aId)
1263{
1264 AutoLock lock (this);
1265 CHECK_READY();
1266
1267 ComObjPtr <HostUSBDevice> device;
1268 USBDeviceList::iterator it = mUSBDevices.begin();
1269 while (!device && it != mUSBDevices.end())
1270 {
1271 if ((*it)->id() == aId)
1272 device = (*it);
1273 ++ it;
1274 }
1275
1276 ComAssertRet (!!device, E_FAIL);
1277 ComAssertRet (device->machine() == aMachine, E_FAIL);
1278
1279 // reset the device and apply filters
1280 int vrc = device->reset();
1281 ComAssertRCRet (vrc, E_FAIL);
1282
1283 HRESULT rc = applyAllUSBFilters (device, aMachine);
1284 ComAssertComRC (rc);
1285
1286 return rc;
1287}
1288
1289/**
1290 * Runs the filters of the given machine against all currently available USB
1291 * devices, marks those that match as captured and returns them as the colection
1292 * of IUSBDevice instances.
1293 *
1294 * Called by Console from the VM process (through IInternalMachineControl).
1295 */
1296HRESULT Host::autoCaptureUSBDevices (SessionMachine *aMachine,
1297 IUSBDeviceCollection **aHostDevices)
1298{
1299 LogFlowMember (("Host::autoCaptureUSBDevices: aMachine=%p\n", aMachine));
1300
1301 AutoLock lock (this);
1302 CHECK_READY();
1303
1304 std::list <ComPtr <IUSBDevice> > list;
1305
1306 USBDeviceList::iterator it = mUSBDevices.begin();
1307 while (it != mUSBDevices.end())
1308 {
1309 ComObjPtr <HostUSBDevice> device = *it;
1310 if (device->isIgnored())
1311 continue;
1312
1313 if (device->state() == USBDeviceState_USBDeviceBusy ||
1314 device->state() == USBDeviceState_USBDeviceAvailable ||
1315 device->state() == USBDeviceState_USBDeviceHeld)
1316 {
1317 applyMachineUSBFilters (aMachine, device);
1318
1319 if (device->state() == USBDeviceState_USBDeviceCaptured)
1320 {
1321 // put the device to the return list
1322 ComPtr <IUSBDevice> d;
1323 device.queryInterfaceTo (d.asOutParam());
1324 Assert (!d.isNull());
1325 list.push_back (d);
1326 }
1327 }
1328 ++ it;
1329 }
1330
1331 ComObjPtr <IfaceUSBDeviceCollection> coll;
1332 coll.createObject();
1333 coll->init (list);
1334 coll.queryInterfaceTo (aHostDevices);
1335
1336 return S_OK;
1337}
1338
1339/**
1340 * Replays all filters against all USB devices currently marked as captured
1341 * by the given machine (excluding this machine's filters).
1342 *
1343 * Called by Console from the VM process (throug IInternalMachineControl).
1344 */
1345HRESULT Host::releaseAllUSBDevices (SessionMachine *aMachine)
1346{
1347 AutoLock lock (this);
1348 CHECK_READY();
1349
1350 USBDeviceList::iterator it = mUSBDevices.begin();
1351 while (it != mUSBDevices.end())
1352 {
1353 ComObjPtr <HostUSBDevice> device = *it;
1354 if (device->machine() == aMachine)
1355 {
1356 // reset the device and apply filters
1357 device->reset();
1358 HRESULT rc = applyAllUSBFilters (device, aMachine);
1359 ComAssertComRC (rc);
1360 }
1361 ++ it;
1362 }
1363
1364 return S_OK;
1365}
1366
1367// private methods
1368////////////////////////////////////////////////////////////////////////////////
1369
1370#ifdef __LINUX__
1371/**
1372 * Helper function to parse the given mount file and add found entries
1373 */
1374void Host::parseMountTable(char *mountTable, std::list <ComObjPtr <HostDVDDrive> > &list)
1375{
1376 FILE *mtab = setmntent(mountTable, "r");
1377 if (mtab)
1378 {
1379 struct mntent *mntent;
1380 char *mnt_type;
1381 char *mnt_dev;
1382 char *tmp;
1383 while ((mntent = getmntent(mtab)))
1384 {
1385 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
1386 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
1387 strcpy(mnt_type, mntent->mnt_type);
1388 strcpy(mnt_dev, mntent->mnt_fsname);
1389 // supermount fs case
1390 if (strcmp(mnt_type, "supermount") == 0)
1391 {
1392 tmp = strstr(mntent->mnt_opts, "fs=");
1393 if (tmp)
1394 {
1395 free(mnt_type);
1396 mnt_type = strdup(tmp + strlen("fs="));
1397 if (mnt_type)
1398 {
1399 tmp = strchr(mnt_type, ',');
1400 if (tmp)
1401 {
1402 *tmp = '\0';
1403 }
1404 }
1405 }
1406 tmp = strstr(mntent->mnt_opts, "dev=");
1407 if (tmp)
1408 {
1409 free(mnt_dev);
1410 mnt_dev = strdup(tmp + strlen("dev="));
1411 if (mnt_dev)
1412 {
1413 tmp = strchr(mnt_dev, ',');
1414 if (tmp)
1415 {
1416 *tmp = '\0';
1417 }
1418 }
1419 }
1420 }
1421 if (strcmp(mnt_type, "iso9660") == 0)
1422 {
1423 /** @todo check whether we've already got the drive in our list! */
1424 if (validateDevice(mnt_dev, true))
1425 {
1426 ComObjPtr <HostDVDDrive> hostDVDDriveObj;
1427 hostDVDDriveObj.createObject();
1428 hostDVDDriveObj->init (Bstr (mnt_dev));
1429 list.push_back (hostDVDDriveObj);
1430 }
1431 }
1432 free(mnt_dev);
1433 free(mnt_type);
1434 }
1435 endmntent(mtab);
1436 }
1437}
1438
1439/**
1440 * Helper function to check whether the given device node is a valid drive
1441 */
1442bool Host::validateDevice(const char *deviceNode, bool isCDROM)
1443{
1444 struct stat statInfo;
1445 bool retValue = false;
1446
1447 // sanity check
1448 if (!deviceNode)
1449 {
1450 return false;
1451 }
1452
1453 // first a simple stat() call
1454 if (stat(deviceNode, &statInfo) < 0)
1455 {
1456 return false;
1457 } else
1458 {
1459 if (isCDROM)
1460 {
1461 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
1462 {
1463 int fileHandle;
1464 // now try to open the device
1465 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
1466 if (fileHandle >= 0)
1467 {
1468 cdrom_subchnl cdChannelInfo;
1469 cdChannelInfo.cdsc_format = CDROM_MSF;
1470 // this call will finally reveal the whole truth
1471 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
1472 (errno == EIO) || (errno == ENOENT) ||
1473 (errno == EINVAL) || (errno == ENOMEDIUM))
1474 {
1475 retValue = true;
1476 }
1477 close(fileHandle);
1478 }
1479 }
1480 } else
1481 {
1482 // floppy case
1483 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
1484 {
1485 /// @todo do some more testing, maybe a nice IOCTL!
1486 retValue = true;
1487 }
1488 }
1489 }
1490 return retValue;
1491}
1492#endif // __LINUX__
1493
1494/**
1495 * Runs through all global filters to determine the state of the given
1496 * USB device, then unless ignored, runs trhough filters of all running machines
1497 * (excluding the given one) to automatically capture the device when there is a
1498 * match (the state of the device will be set to USBDeviceCaptured if so, and
1499 * the machine's process will be informed about the auto-capture).
1500 *
1501 * @param aDevice USB device to set state for
1502 * @param aMachine the machine whose filters are to be excluded (can be NULL)
1503 *
1504 * @note the method must be called from under this object's lock
1505 */
1506HRESULT Host::applyAllUSBFilters (ComObjPtr <HostUSBDevice> &aDevice,
1507 SessionMachine *aMachine /* = NULL */)
1508{
1509 LogFlowMember (("Host::applyAllUSBFilters: \n"));
1510
1511 // ignore unsupported devices
1512 if (aDevice->state() == USBDeviceState_USBDeviceNotSupported)
1513 return S_OK;
1514 // ignore unavailable devices as well
1515 if (aDevice->state() == USBDeviceState_USBDeviceUnavailable)
1516 return S_OK;
1517
1518 VirtualBox::SessionMachineVector machines;
1519 mParent->getOpenedMachines (machines);
1520
1521 // apply global filters
1522 USBDeviceFilterList::const_iterator it = mUSBDeviceFilters.begin();
1523 while (it != mUSBDeviceFilters.end())
1524 {
1525 AutoLock filterLock (*it);
1526 const HostUSBDeviceFilter::Data &data = (*it)->data();
1527 if (aDevice->isMatch (data))
1528 {
1529 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterIgnore)
1530 return S_OK;
1531 if (data.mAction == USBDeviceFilterAction_USBDeviceFilterHold)
1532 break;
1533 }
1534 ++ it;
1535 }
1536
1537 // apply machine filters
1538 for (size_t i = 0; i < machines.size(); i++)
1539 {
1540 if (aMachine && machines [i] == aMachine)
1541 continue;
1542
1543 applyMachineUSBFilters (machines [i], aDevice);
1544
1545 if (aDevice->state() == USBDeviceState_USBDeviceCaptured)
1546 {
1547 // inform the machine's process about the auto-capture
1548 ComPtr <IUSBDevice> d;
1549 aDevice.queryInterfaceTo (d.asOutParam());
1550 HRESULT rc = machines [i]->onUSBDeviceAttach (d);
1551 if (SUCCEEDED(rc))
1552 return rc;
1553
1554 // the machine rejected it, continue applying filters.
1555 aDevice->reset();
1556 }
1557 }
1558
1559 // no machine filters were matched.
1560 // if no global filters were matched as well, release the device
1561 // to make it available on the host
1562 if ( it == mUSBDeviceFilters.end()
1563 && aDevice->state() == USBDeviceState_USBDeviceHeld)
1564 aDevice->setHostDriven();
1565/** @todo dmik, what about USBDeviceFilterHold??? */
1566/**
1567 * bird, everything's ok from what I see. if USBDeviceFilterHold filter was
1568 * matched, setHostDevice() will not (and should not) be called
1569 * (because it != mUSBDeviceFilters.end() in that case).
1570 */
1571
1572 return S_OK;
1573}
1574
1575/**
1576 * Runs through filters of the given machine in order to automatically capture
1577 * the given USB device when there is a match (the state of the device will
1578 * be set to USBDeviceCaptured if so, but the machine's process will *NOT* be)
1579 * informed about the auto-capture).
1580 *
1581 * @param aMachine the machine whose filters are to be run
1582 * @param aDevice USB device, a candidate for auto-attaching
1583 *
1584 * @note Locks aMachine for reading.
1585 */
1586void Host::applyMachineUSBFilters (SessionMachine *aMachine,
1587 ComObjPtr <HostUSBDevice> &aDevice)
1588{
1589 LogFlowThisFunc (("\n"));
1590
1591 AssertReturn (aMachine, (void) 0);
1592 AssertReturn (aDevice->state() != USBDeviceState_USBDeviceUnavailable, (void) 0);
1593
1594 /* We're going to use aMachine which is not our child/parent, add a caller */
1595 AutoCaller autoCaller (aMachine);
1596 if (!autoCaller.isOk())
1597 {
1598 /* silently return, the machine might be not running any more */
1599 return;
1600 }
1601
1602 /* enter the machine's lock because we want to access its USB controller */
1603 AutoReaderLock machineLock (aMachine);
1604
1605 if (aMachine->usbController()->hasMatchingFilter (aDevice))
1606 {
1607 /* try capture the device */
1608 bool ok = aDevice->setCaptured (aMachine);
1609
1610 /*
1611 * false is valid only when the state remains USBDeviceBusy meaning that
1612 * the device is currently busy (being accessed by the host)
1613 */
1614 Assert (ok || aDevice->state() == USBDeviceState_USBDeviceBusy);
1615 NOREF (ok);
1616 }
1617}
1618
1619/**
1620 * Called by USB proxy service when a new device is physically attached
1621 * to the host.
1622 *
1623 * @param aDevice Pointer to the device which has been attached.
1624 */
1625void Host::onUSBDeviceAttached (HostUSBDevice *aDevice)
1626{
1627 LogFlowMember (("Host::onUSBDeviceAttached: aDevice=%p\n", aDevice));
1628 /// @todo (dmik) check locks
1629 AutoLock alock (this);
1630
1631 // add to the collecion
1632 mUSBDevices.push_back (aDevice);
1633
1634 // apply all filters (no need to lock the device, nobody can access it yet)
1635 ComObjPtr <HostUSBDevice> DevPtr(aDevice);
1636 HRESULT rc = applyAllUSBFilters (DevPtr);
1637 AssertComRC (rc);
1638}
1639
1640/**
1641 * Called by USB proxy service (?) when the device is physically detached
1642 * from the host.
1643 *
1644 * @param aDevice Pointer to the device which has been detached.
1645 */
1646void Host::onUSBDeviceDetached (HostUSBDevice *aDevice)
1647{
1648 LogFlowMember (("Host::onUSBDeviceDetached: aDevice=%p\n", aDevice));
1649 /// @todo (dmik) check locks
1650 AutoLock alock (this);
1651
1652 Guid id = aDevice->id();
1653
1654 ComObjPtr <HostUSBDevice> device;
1655 Host::USBDeviceList::iterator it = mUSBDevices.begin();
1656 while (it != mUSBDevices.end())
1657 {
1658 if ((*it)->id() == id)
1659 {
1660 device = (*it);
1661 break;
1662 }
1663 ++ it;
1664 }
1665
1666 AssertReturn (!!device, (void) 0);
1667
1668 // remove from the collecion
1669 mUSBDevices.erase (it);
1670
1671 if (device->machine())
1672 {
1673 // the device is captured by a machine, instruct it to release
1674 alock.unlock();
1675 HRESULT rc = device->machine()->onUSBDeviceDetach (device->id());
1676 AssertComRC (rc);
1677 }
1678}
1679
1680/**
1681 * Called by USB proxy service when the state of the host-driven device
1682 * has changed because of non proxy interaction.
1683 *
1684 * @param aDevice The device in question.
1685 */
1686void Host::onUSBDeviceStateChanged (HostUSBDevice *aDevice)
1687{
1688 LogFlowMember (("Host::onUSBDeviceStateChanged: \n"));
1689 /// @todo (dmik) check locks
1690 AutoLock alock (this);
1691
1692 /** @todo dmik, is there anything we should do here? For instance if the device now is available? */
1693}
1694
1695/**
1696 * Checks for the presense and status of the USB Proxy Service.
1697 * Returns S_OK when the Proxy is present and OK, or E_FAIL and a
1698 * corresponding error message otherwise. Intended to be used by methods
1699 * that rely on the Proxy Service availability.
1700 *
1701 * @note Locks this object for reading.
1702 */
1703HRESULT Host::checkUSBProxyService()
1704{
1705#ifdef VBOX_WITH_USB
1706 AutoLock lock (this);
1707 CHECK_READY();
1708
1709 AssertReturn (mUSBProxyService, E_FAIL);
1710 if (!mUSBProxyService->isActive())
1711 {
1712 /* disable the USB controller completely to avoid assertions if the
1713 * USB proxy service could not start. */
1714
1715 Assert (VBOX_FAILURE (mUSBProxyService->getLastError()));
1716 if (mUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
1717 return setError (E_FAIL,
1718 tr ("Could not load the Host USB Proxy Service (%Vrc)."
1719 "The service might be not installed on the host computer"),
1720 mUSBProxyService->getLastError());
1721 else
1722 return setError (E_FAIL,
1723 tr ("Could not load the Host USB Proxy service (%Vrc)"),
1724 mUSBProxyService->getLastError());
1725 }
1726
1727 return S_OK;
1728#else
1729 return E_NOTIMPL;
1730#endif
1731}
1732
1733#ifdef __WIN__
1734
1735/* The original source of the VBoxTAP adapter creation/destruction code has the following copyright */
1736/*
1737 Copyright 2004 by the Massachusetts Institute of Technology
1738
1739 All rights reserved.
1740
1741 Permission to use, copy, modify, and distribute this software and its
1742 documentation for any purpose and without fee is hereby granted,
1743 provided that the above copyright notice appear in all copies and that
1744 both that copyright notice and this permission notice appear in
1745 supporting documentation, and that the name of the Massachusetts
1746 Institute of Technology (M.I.T.) not be used in advertising or publicity
1747 pertaining to distribution of the software without specific, written
1748 prior permission.
1749
1750 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1751 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1752 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1753 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1754 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1755 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1756 SOFTWARE.
1757*/
1758
1759
1760#define NETSHELL_LIBRARY _T("netshell.dll")
1761
1762/**
1763 * Use the IShellFolder API to rename the connection.
1764 */
1765static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
1766{
1767 /* This is the GUID for the network connections folder. It is constant.
1768 * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
1769 const GUID CLSID_NetworkConnections = {
1770 0x7007ACC7, 0x3202, 0x11D1, {
1771 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
1772 }
1773 };
1774
1775 LPITEMIDLIST pidl = NULL;
1776 IShellFolder *pShellFolder = NULL;
1777 HRESULT hr;
1778
1779 /* Build the display name in the form "::{GUID}". */
1780 if (wcslen (wGuid) >= MAX_PATH)
1781 return E_INVALIDARG;
1782 WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
1783 swprintf (szAdapterGuid, L"::%ls", wGuid);
1784
1785 /* Create an instance of the network connections folder. */
1786 hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
1787 CLSCTX_INPROC_SERVER, IID_IShellFolder,
1788 reinterpret_cast <LPVOID *> (&pShellFolder));
1789 /* Parse the display name. */
1790 if (SUCCEEDED (hr))
1791 {
1792 hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
1793 &pidl, NULL);
1794 }
1795 if (SUCCEEDED (hr))
1796 {
1797 hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
1798 &pidl);
1799 }
1800
1801 CoTaskMemFree (pidl);
1802
1803 if (pShellFolder)
1804 pShellFolder->Release();
1805
1806 return hr;
1807}
1808
1809extern "C" HRESULT RenameConnection (PCWSTR GuidString, PCWSTR NewName)
1810{
1811 typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
1812 lpHrRenameConnection RenameConnectionFunc = NULL;
1813 HRESULT status;
1814
1815 /* First try the IShellFolder interface, which was unimplemented
1816 * for the network connections folder before XP. */
1817 status = rename_shellfolder (GuidString, NewName);
1818 if (status == E_NOTIMPL)
1819 {
1820/** @todo that code doesn't seem to work! */
1821 /* The IShellFolder interface is not implemented on this platform.
1822 * Try the (undocumented) HrRenameConnection API in the netshell
1823 * library. */
1824 CLSID clsid;
1825 HINSTANCE hNetShell;
1826 status = CLSIDFromString ((LPOLESTR) GuidString, &clsid);
1827 if (FAILED(status))
1828 return E_FAIL;
1829 hNetShell = LoadLibrary (NETSHELL_LIBRARY);
1830 if (hNetShell == NULL)
1831 return E_FAIL;
1832 RenameConnectionFunc =
1833 (lpHrRenameConnection) GetProcAddress (hNetShell,
1834 "HrRenameConnection");
1835 if (RenameConnectionFunc == NULL)
1836 {
1837 FreeLibrary (hNetShell);
1838 return E_FAIL;
1839 }
1840 status = RenameConnectionFunc (&clsid, NewName);
1841 FreeLibrary (hNetShell);
1842 }
1843 if (FAILED (status))
1844 return status;
1845
1846 return S_OK;
1847}
1848
1849#define DRIVERHWID _T("vboxtap")
1850
1851#define SetErrBreak(strAndArgs) \
1852 if (1) { \
1853 aErrMsg = Utf8StrFmt strAndArgs; vrc = VERR_GENERAL_FAILURE; break; \
1854 } else do {} while (0)
1855
1856/* static */
1857int Host::createNetworkInterface (SVCHlpClient *aClient,
1858 const Utf8Str &aName,
1859 Guid &aGUID, Utf8Str &aErrMsg)
1860{
1861 LogFlowFuncEnter();
1862 LogFlowFunc (("Network connection name = '%s'\n", aName.raw()));
1863
1864 AssertReturn (aClient, VERR_INVALID_POINTER);
1865 AssertReturn (!aName.isNull(), VERR_INVALID_PARAMETER);
1866
1867 int vrc = VINF_SUCCESS;
1868
1869 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
1870 SP_DEVINFO_DATA DeviceInfoData;
1871 DWORD ret = 0;
1872 BOOL found = FALSE;
1873 BOOL registered = FALSE;
1874 BOOL destroyList = FALSE;
1875 TCHAR pCfgGuidString [50];
1876
1877 do
1878 {
1879 BOOL ok;
1880 GUID netGuid;
1881 SP_DRVINFO_DATA DriverInfoData;
1882 SP_DEVINSTALL_PARAMS DeviceInstallParams;
1883 TCHAR className [MAX_PATH];
1884 DWORD index = 0;
1885 PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
1886 /* for our purposes, 2k buffer is more
1887 * than enough to obtain the hardware ID
1888 * of the VBoxTAP driver. */
1889 DWORD detailBuf [2048];
1890
1891 HKEY hkey = NULL;
1892 DWORD cbSize;
1893 DWORD dwValueType;
1894
1895 /* initialize the structure size */
1896 DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1897 DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
1898
1899 /* copy the net class GUID */
1900 memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
1901
1902 /* create an empty device info set associated with the net class GUID */
1903 hDeviceInfo = SetupDiCreateDeviceInfoList (&netGuid, NULL);
1904 if (hDeviceInfo == INVALID_HANDLE_VALUE)
1905 SetErrBreak (("SetupDiCreateDeviceInfoList failed (0x%08X)",
1906 GetLastError()));
1907
1908 /* get the class name from GUID */
1909 ok = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
1910 if (!ok)
1911 SetErrBreak (("SetupDiClassNameFromGuid failed (0x%08X)",
1912 GetLastError()));
1913
1914 /* create a device info element and add the new device instance
1915 * key to registry */
1916 ok = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
1917 DICD_GENERATE_ID, &DeviceInfoData);
1918 if (!ok)
1919 SetErrBreak (("SetupDiCreateDeviceInfo failed (0x%08X)",
1920 GetLastError()));
1921
1922 /* select the newly created device info to be the currently
1923 selected member */
1924 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
1925 if (!ok)
1926 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
1927 GetLastError()));
1928
1929 /* build a list of class drivers */
1930 ok = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
1931 SPDIT_CLASSDRIVER);
1932 if (!ok)
1933 SetErrBreak (("SetupDiBuildDriverInfoList failed (0x%08X)",
1934 GetLastError()));
1935
1936 destroyList = TRUE;
1937
1938 /* enumerate the driver info list */
1939 while (TRUE)
1940 {
1941 BOOL ret;
1942
1943 ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
1944 SPDIT_CLASSDRIVER, index, &DriverInfoData);
1945
1946 /* if the function failed and GetLastError() returned
1947 * ERROR_NO_MORE_ITEMS, then we have reached the end of the
1948 * list. Othewise there was something wrong with this
1949 * particular driver. */
1950 if (!ret)
1951 {
1952 if(GetLastError() == ERROR_NO_MORE_ITEMS)
1953 break;
1954 else
1955 {
1956 index++;
1957 continue;
1958 }
1959 }
1960
1961 pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
1962 pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1963
1964 /* if we successfully find the hardware ID and it turns out to
1965 * be the one for the loopback driver, then we are done. */
1966 if (SetupDiGetDriverInfoDetail (hDeviceInfo,
1967 &DeviceInfoData,
1968 &DriverInfoData,
1969 pDriverInfoDetail,
1970 sizeof (detailBuf),
1971 NULL))
1972 {
1973 TCHAR * t;
1974
1975 /* pDriverInfoDetail->HardwareID is a MULTISZ string. Go through the
1976 * whole list and see if there is a match somewhere. */
1977 t = pDriverInfoDetail->HardwareID;
1978 while (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
1979 {
1980 if (!_tcsicmp(t, DRIVERHWID))
1981 break;
1982
1983 t += _tcslen(t) + 1;
1984 }
1985
1986 if (t && *t && t < (TCHAR *) &detailBuf [sizeof(detailBuf) / sizeof (detailBuf[0])])
1987 {
1988 found = TRUE;
1989 break;
1990 }
1991 }
1992
1993 index ++;
1994 }
1995
1996 if (!found)
1997 SetErrBreak ((tr ("Could not find Host Interface Networking driver! "
1998 "Please reinstall")));
1999
2000 /* set the loopback driver to be the currently selected */
2001 ok = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
2002 &DriverInfoData);
2003 if (!ok)
2004 SetErrBreak (("SetupDiSetSelectedDriver failed (0x%08X)",
2005 GetLastError()));
2006
2007 /* register the phantom device to prepare for install */
2008 ok = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
2009 &DeviceInfoData);
2010 if (!ok)
2011 SetErrBreak (("SetupDiCallClassInstaller failed (0x%08X)",
2012 GetLastError()));
2013
2014 /* registered, but remove if errors occur in the following code */
2015 registered = TRUE;
2016
2017 /* ask the installer if we can install the device */
2018 ok = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
2019 &DeviceInfoData);
2020 if (!ok)
2021 {
2022 if (GetLastError() != ERROR_DI_DO_DEFAULT)
2023 SetErrBreak (("SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
2024 GetLastError()));
2025 /* that's fine */
2026 }
2027
2028 /* install the files first */
2029 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
2030 &DeviceInfoData);
2031 if (!ok)
2032 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
2033 GetLastError()));
2034
2035 /* get the device install parameters and disable filecopy */
2036 DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
2037 ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2038 &DeviceInstallParams);
2039 if (ok)
2040 {
2041 DeviceInstallParams.Flags |= DI_NOFILECOPY;
2042 ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
2043 &DeviceInstallParams);
2044 if (!ok)
2045 SetErrBreak (("SetupDiSetDeviceInstallParams failed (0x%08X)",
2046 GetLastError()));
2047 }
2048
2049 /*
2050 * Register any device-specific co-installers for this device,
2051 */
2052
2053 ok = SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
2054 hDeviceInfo,
2055 &DeviceInfoData);
2056 if (!ok)
2057 SetErrBreak (("SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
2058 GetLastError()));
2059
2060 /*
2061 * install any installer-specified interfaces.
2062 * and then do the real install
2063 */
2064 ok = SetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
2065 hDeviceInfo,
2066 &DeviceInfoData);
2067 if (!ok)
2068 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
2069 GetLastError()));
2070
2071 ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICE,
2072 hDeviceInfo,
2073 &DeviceInfoData);
2074 if (!ok)
2075 SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
2076 GetLastError()));
2077
2078 /* Figure out NetCfgInstanceId */
2079 hkey = SetupDiOpenDevRegKey (hDeviceInfo,
2080 &DeviceInfoData,
2081 DICS_FLAG_GLOBAL,
2082 0,
2083 DIREG_DRV,
2084 KEY_READ);
2085 if (hkey == INVALID_HANDLE_VALUE)
2086 SetErrBreak (("SetupDiOpenDevRegKey failed (0x%08X)",
2087 GetLastError()));
2088
2089 cbSize = sizeof (pCfgGuidString);
2090 DWORD ret;
2091 ret = RegQueryValueEx (hkey, _T ("NetCfgInstanceId"), NULL,
2092 &dwValueType, (LPBYTE) pCfgGuidString, &cbSize);
2093 RegCloseKey (hkey);
2094
2095 ret = RenameConnection (pCfgGuidString, Bstr (aName));
2096 if (FAILED (ret))
2097 SetErrBreak (("Failed to set interface name (ret=0x%08X, "
2098 "pCfgGuidString='%ls', cbSize=%d)",
2099 ret, pCfgGuidString, cbSize));
2100 }
2101 while (0);
2102
2103 /*
2104 * cleanup
2105 */
2106
2107 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2108 {
2109 /* an error has occured, but the device is registered, we must remove it */
2110 if (ret != 0 && registered)
2111 SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2112
2113 found = SetupDiDeleteDeviceInfo (hDeviceInfo, &DeviceInfoData);
2114
2115 /* destroy the driver info list */
2116 if (destroyList)
2117 SetupDiDestroyDriverInfoList (hDeviceInfo, &DeviceInfoData,
2118 SPDIT_CLASSDRIVER);
2119 /* clean up the device info set */
2120 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2121 }
2122
2123 /* return the network connection GUID on success */
2124 if (VBOX_SUCCESS (vrc))
2125 {
2126 /* remove the curly bracket at the end */
2127 pCfgGuidString [_tcslen (pCfgGuidString) - 1] = '\0';
2128 LogFlowFunc (("Network connection GUID string = {%ls}\n", pCfgGuidString + 1));
2129
2130 aGUID = Guid (Utf8Str (pCfgGuidString + 1));
2131 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", aGUID.raw()));
2132 Assert (!aGUID.isEmpty());
2133 }
2134
2135 LogFlowFunc (("vrc=%Vrc\n", vrc));
2136 LogFlowFuncLeave();
2137 return vrc;
2138}
2139
2140/* static */
2141int Host::removeNetworkInterface (SVCHlpClient *aClient,
2142 const Guid &aGUID,
2143 Utf8Str &aErrMsg)
2144{
2145 LogFlowFuncEnter();
2146 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", aGUID.raw()));
2147
2148 AssertReturn (aClient, VERR_INVALID_POINTER);
2149 AssertReturn (!aGUID.isEmpty(), VERR_INVALID_PARAMETER);
2150
2151 int vrc = VINF_SUCCESS;
2152
2153 do
2154 {
2155 TCHAR lszPnPInstanceId [512] = {0};
2156
2157 /* We have to find the device instance ID through a registry search */
2158
2159 HKEY hkeyNetwork = 0;
2160 HKEY hkeyConnection = 0;
2161
2162 do
2163 {
2164 char strRegLocation [256];
2165 sprintf (strRegLocation,
2166 "SYSTEM\\CurrentControlSet\\Control\\Network\\"
2167 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\{%s}",
2168 aGUID.toString().raw());
2169 LONG status;
2170 status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, strRegLocation, 0,
2171 KEY_READ, &hkeyNetwork);
2172 if ((status != ERROR_SUCCESS) || !hkeyNetwork)
2173 SetErrBreak ((
2174 tr ("Host interface network is not found in registry (%s) [1]"),
2175 strRegLocation));
2176
2177 status = RegOpenKeyExA (hkeyNetwork, "Connection", 0,
2178 KEY_READ, &hkeyConnection);
2179 if ((status != ERROR_SUCCESS) || !hkeyConnection)
2180 SetErrBreak ((
2181 tr ("Host interface network is not found in registry (%s) [2]"),
2182 strRegLocation));
2183
2184 DWORD len = sizeof (lszPnPInstanceId);
2185 DWORD dwKeyType;
2186 status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
2187 &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
2188 if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
2189 SetErrBreak ((
2190 tr ("Host interface network is not found in registry (%s) [3]"),
2191 strRegLocation));
2192 }
2193 while (0);
2194
2195 if (hkeyConnection)
2196 RegCloseKey (hkeyConnection);
2197 if (hkeyNetwork)
2198 RegCloseKey (hkeyNetwork);
2199
2200 if (VBOX_FAILURE (vrc))
2201 break;
2202
2203 /*
2204 * Now we are going to enumerate all network devices and
2205 * wait until we encounter the right device instance ID
2206 */
2207
2208 HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
2209
2210 do
2211 {
2212 BOOL ok;
2213 DWORD ret = 0;
2214 GUID netGuid;
2215 SP_DEVINFO_DATA DeviceInfoData;
2216 DWORD index = 0;
2217 BOOL found = FALSE;
2218 DWORD size = 0;
2219
2220 /* initialize the structure size */
2221 DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
2222
2223 /* copy the net class GUID */
2224 memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
2225
2226 /* return a device info set contains all installed devices of the Net class */
2227 hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
2228
2229 if (hDeviceInfo == INVALID_HANDLE_VALUE)
2230 SetErrBreak (("SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
2231
2232 /* enumerate the driver info list */
2233 while (TRUE)
2234 {
2235 TCHAR *deviceHwid;
2236
2237 ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
2238
2239 if (!ok)
2240 {
2241 if (GetLastError() == ERROR_NO_MORE_ITEMS)
2242 break;
2243 else
2244 {
2245 index++;
2246 continue;
2247 }
2248 }
2249
2250 /* try to get the hardware ID registry property */
2251 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2252 &DeviceInfoData,
2253 SPDRP_HARDWAREID,
2254 NULL,
2255 NULL,
2256 0,
2257 &size);
2258 if (!ok)
2259 {
2260 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2261 {
2262 index++;
2263 continue;
2264 }
2265
2266 deviceHwid = (TCHAR *) malloc (size);
2267 ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
2268 &DeviceInfoData,
2269 SPDRP_HARDWAREID,
2270 NULL,
2271 (PBYTE)deviceHwid,
2272 size,
2273 NULL);
2274 if (!ok)
2275 {
2276 free (deviceHwid);
2277 deviceHwid = NULL;
2278 index++;
2279 continue;
2280 }
2281 }
2282 else
2283 {
2284 /* something is wrong. This shouldn't have worked with a NULL buffer */
2285 index++;
2286 continue;
2287 }
2288
2289 for (TCHAR *t = deviceHwid;
2290 t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
2291 t += _tcslen (t) + 1)
2292 {
2293 if (!_tcsicmp (DRIVERHWID, t))
2294 {
2295 /* get the device instance ID */
2296 TCHAR devID [MAX_DEVICE_ID_LEN];
2297 if (CM_Get_Device_ID(DeviceInfoData.DevInst,
2298 devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
2299 {
2300 /* compare to what we determined before */
2301 if (wcscmp(devID, lszPnPInstanceId) == 0)
2302 {
2303 found = TRUE;
2304 break;
2305 }
2306 }
2307 }
2308 }
2309
2310 if (deviceHwid)
2311 {
2312 free (deviceHwid);
2313 deviceHwid = NULL;
2314 }
2315
2316 if (found)
2317 break;
2318
2319 index++;
2320 }
2321
2322 if (found == FALSE)
2323 SetErrBreak ((tr ("Host Interface Network driver not found (0x%08X)"),
2324 GetLastError()));
2325
2326 ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
2327 if (!ok)
2328 SetErrBreak (("SetupDiSetSelectedDevice failed (0x%08X)",
2329 GetLastError()));
2330
2331 ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
2332 if (!ok)
2333 SetErrBreak (("SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
2334 GetLastError()));
2335 }
2336 while (0);
2337
2338 /* clean up the device info set */
2339 if (hDeviceInfo != INVALID_HANDLE_VALUE)
2340 SetupDiDestroyDeviceInfoList (hDeviceInfo);
2341
2342 if (VBOX_FAILURE (vrc))
2343 break;
2344 }
2345 while (0);
2346
2347 LogFlowFunc (("vrc=%Vrc\n", vrc));
2348 LogFlowFuncLeave();
2349 return vrc;
2350}
2351
2352#undef SetErrBreak
2353
2354/* static */
2355HRESULT Host::networkInterfaceHelperClient (SVCHlpClient *aClient,
2356 Progress *aProgress,
2357 void *aUser, int *aVrc)
2358{
2359 LogFlowFuncEnter();
2360 LogFlowFunc (("aClient={%p}, aProgress={%p}, aUser={%p}\n",
2361 aClient, aProgress, aUser));
2362
2363 AssertReturn ((aClient == NULL && aProgress == NULL && aVrc == NULL) ||
2364 (aClient != NULL && aProgress != NULL && aVrc != NULL),
2365 E_POINTER);
2366 AssertReturn (aUser, E_POINTER);
2367
2368 std::auto_ptr <NetworkInterfaceHelperClientData>
2369 d (static_cast <NetworkInterfaceHelperClientData *> (aUser));
2370
2371 if (aClient == NULL)
2372 {
2373 /* "cleanup only" mode, just return (it will free aUser) */
2374 return S_OK;
2375 }
2376
2377 HRESULT rc = S_OK;
2378 int vrc = VINF_SUCCESS;
2379
2380 switch (d->msgCode)
2381 {
2382 case SVCHlpMsg::CreateHostNetworkInterface:
2383 {
2384 LogFlowFunc (("CreateHostNetworkInterface:\n"));
2385 LogFlowFunc (("Network connection name = '%ls'\n", d->name.raw()));
2386
2387 /* write message and parameters */
2388 vrc = aClient->write (d->msgCode);
2389 if (VBOX_FAILURE (vrc)) break;
2390 vrc = aClient->write (Utf8Str (d->name));
2391 if (VBOX_FAILURE (vrc)) break;
2392
2393 /* wait for a reply */
2394 bool endLoop = false;
2395 while (!endLoop)
2396 {
2397 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
2398
2399 vrc = aClient->read (reply);
2400 if (VBOX_FAILURE (vrc)) break;
2401
2402 switch (reply)
2403 {
2404 case SVCHlpMsg::CreateHostNetworkInterface_OK:
2405 {
2406 /* read the GUID */
2407 Guid guid;
2408 vrc = aClient->read (guid);
2409 if (VBOX_FAILURE (vrc)) break;
2410
2411 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", guid.raw()));
2412
2413 /* initialize the object returned to the caller by
2414 * CreateHostNetworkInterface() */
2415 rc = d->iface->init (d->name, guid);
2416 endLoop = true;
2417 break;
2418 }
2419 case SVCHlpMsg::Error:
2420 {
2421 /* read the error message */
2422 Utf8Str errMsg;
2423 vrc = aClient->read (errMsg);
2424 if (VBOX_FAILURE (vrc)) break;
2425
2426 rc = setError (E_FAIL, errMsg);
2427 endLoop = true;
2428 break;
2429 }
2430 default:
2431 {
2432 endLoop = true;
2433 ComAssertMsgFailedBreak ((
2434 "Invalid message code %d (%08lX)\n",
2435 reply, reply),
2436 rc = E_FAIL);
2437 }
2438 }
2439 }
2440
2441 break;
2442 }
2443 case SVCHlpMsg::RemoveHostNetworkInterface:
2444 {
2445 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
2446 LogFlowFunc (("Network connection GUID = {%Vuuid}\n", d->guid.raw()));
2447
2448 /* write message and parameters */
2449 vrc = aClient->write (d->msgCode);
2450 if (VBOX_FAILURE (vrc)) break;
2451 vrc = aClient->write (d->guid);
2452 if (VBOX_FAILURE (vrc)) break;
2453
2454 /* wait for a reply */
2455 bool endLoop = false;
2456 while (!endLoop)
2457 {
2458 SVCHlpMsg::Code reply = SVCHlpMsg::Null;
2459
2460 vrc = aClient->read (reply);
2461 if (VBOX_FAILURE (vrc)) break;
2462
2463 switch (reply)
2464 {
2465 case SVCHlpMsg::OK:
2466 {
2467 /* no parameters */
2468 rc = S_OK;
2469 endLoop = true;
2470 break;
2471 }
2472 case SVCHlpMsg::Error:
2473 {
2474 /* read the error message */
2475 Utf8Str errMsg;
2476 vrc = aClient->read (errMsg);
2477 if (VBOX_FAILURE (vrc)) break;
2478
2479 rc = setError (E_FAIL, errMsg);
2480 endLoop = true;
2481 break;
2482 }
2483 default:
2484 {
2485 endLoop = true;
2486 ComAssertMsgFailedBreak ((
2487 "Invalid message code %d (%08lX)\n",
2488 reply, reply),
2489 rc = E_FAIL);
2490 }
2491 }
2492 }
2493
2494 break;
2495 }
2496 default:
2497 ComAssertMsgFailedBreak ((
2498 "Invalid message code %d (%08lX)\n",
2499 d->msgCode, d->msgCode),
2500 rc = E_FAIL);
2501 }
2502
2503 if (aVrc)
2504 *aVrc = vrc;
2505
2506 LogFlowFunc (("rc=0x%08X, vrc=%Vrc\n", rc, vrc));
2507 LogFlowFuncLeave();
2508 return rc;
2509}
2510
2511/* static */
2512int Host::networkInterfaceHelperServer (SVCHlpClient *aClient,
2513 SVCHlpMsg::Code aMsgCode)
2514{
2515 LogFlowFuncEnter();
2516 LogFlowFunc (("aClient={%p}, aMsgCode=%d\n", aClient, aMsgCode));
2517
2518 AssertReturn (aClient, VERR_INVALID_POINTER);
2519
2520 int vrc = VINF_SUCCESS;
2521
2522 switch (aMsgCode)
2523 {
2524 case SVCHlpMsg::CreateHostNetworkInterface:
2525 {
2526 LogFlowFunc (("CreateHostNetworkInterface:\n"));
2527
2528 Utf8Str name;
2529 vrc = aClient->read (name);
2530 if (VBOX_FAILURE (vrc)) break;
2531
2532 Guid guid;
2533 Utf8Str errMsg;
2534 vrc = createNetworkInterface (aClient, name, guid, errMsg);
2535
2536 if (VBOX_SUCCESS (vrc))
2537 {
2538 /* write success followed by GUID */
2539 vrc = aClient->write (SVCHlpMsg::CreateHostNetworkInterface_OK);
2540 if (VBOX_FAILURE (vrc)) break;
2541 vrc = aClient->write (guid);
2542 if (VBOX_FAILURE (vrc)) break;
2543 }
2544 else
2545 {
2546 /* write failure followed by error message */
2547 if (errMsg.isEmpty())
2548 errMsg = Utf8StrFmt ("Unspecified error (%Vrc)", vrc);
2549 vrc = aClient->write (SVCHlpMsg::Error);
2550 if (VBOX_FAILURE (vrc)) break;
2551 vrc = aClient->write (errMsg);
2552 if (VBOX_FAILURE (vrc)) break;
2553 }
2554
2555 break;
2556 }
2557 case SVCHlpMsg::RemoveHostNetworkInterface:
2558 {
2559 LogFlowFunc (("RemoveHostNetworkInterface:\n"));
2560
2561 Guid guid;
2562 vrc = aClient->read (guid);
2563 if (VBOX_FAILURE (vrc)) break;
2564
2565 Utf8Str errMsg;
2566 vrc = removeNetworkInterface (aClient, guid, errMsg);
2567
2568 if (VBOX_SUCCESS (vrc))
2569 {
2570 /* write parameter-less success */
2571 vrc = aClient->write (SVCHlpMsg::OK);
2572 if (VBOX_FAILURE (vrc)) break;
2573 }
2574 else
2575 {
2576 /* write failure followed by error message */
2577 if (errMsg.isEmpty())
2578 errMsg = Utf8StrFmt ("Unspecified error (%Vrc)", vrc);
2579 vrc = aClient->write (SVCHlpMsg::Error);
2580 if (VBOX_FAILURE (vrc)) break;
2581 vrc = aClient->write (errMsg);
2582 if (VBOX_FAILURE (vrc)) break;
2583 }
2584
2585 break;
2586 }
2587 default:
2588 AssertMsgFailedBreak ((
2589 "Invalid message code %d (%08lX)\n", aMsgCode, aMsgCode),
2590 VERR_GENERAL_FAILURE);
2591 }
2592
2593 LogFlowFunc (("vrc=%Vrc\n", vrc));
2594 LogFlowFuncLeave();
2595 return vrc;
2596}
2597
2598#endif /* __WIN__ */
2599
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