VirtualBox

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

Last change on this file since 2705 was 2587, checked in by vboxsync, 18 years ago

Darwin USB (work in progress)...

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